summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-03-08 11:08:37 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2015-12-27 20:19:50 +0100
commit4622fbe25d9a8a0d03e260f5d3fcf1669c996d00 (patch)
tree1e25c0fa1c50da732b7f1a63a6e59bb2c44c115e
parentfa032ac8b3c1f49c908dcd5380b48f198439494e (diff)
Fixed (ipaccess BTS) delay/silence problems, if RTP stream jitters too much
After OpenBSC stalled for some reason (e.g. CPU overload or database access) or after speech frames have been lost (MNCC application problems / hold/retrieve call), the timestamp and the sequence number of the RTP socket state must be corrected. The amount of incrmentation is calculated from the elapsed time. Not incrementing timestamp and sequence number would cause all frames to be dropped by ipaccess BTS, because the BTS expects frames with more recent timestamps. If speech frames are received too fast, they must be dropped. The timestamp and sequence number of the RTP socket state are not changed in this case. Incmenetating timestamp and sequence number would causes high delay at ipaccess BTS, because the BTS would queue the frames until the timestamp matches the current time. There is a simple test case: Make a call between two phones and check the delay. (When using LCR, make a call to the echo test.) The press CTRL+z to suspend OpenBSC process for a few seconds and enter "fg" to continue OpenBSC process. There shall be no change in the delay, even after repeating this test many times.
-rw-r--r--openbsc/src/libtrau/rtp_proxy.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index d8fde15..e29f26c 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -210,6 +210,67 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data, in
return 0;
}
+#define USEC_1S 1000000
+#define USEC_10MS 10000
+#define USEC_20MS 20000
+#define SAMPLES_1S 8000
+#define USEC_SAMPLE 125
+
+/* add usec to tv */
+static void tv_add_usec(struct timeval *tv, long int usec)
+{
+ struct timeval tv_add;
+
+ tv_add.tv_sec = usec / USEC_1S;
+ tv_add.tv_usec = usec % USEC_1S;
+ timeradd(tv, &tv_add, tv);
+}
+
+static int correct_timestamp(struct rtp_socket *rs, int duration)
+{
+ struct timeval tv, tv_diff;
+ long int usec_diff, frame_diff;
+ int usec_duration = duration * USEC_SAMPLE;
+
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &rs->transmit.last_tv, &tv_diff);
+
+ usec_diff = tv_diff.tv_sec * USEC_1S + tv_diff.tv_usec;
+ frame_diff = (usec_diff + (usec_duration >> 1)) / usec_duration; /* round */
+
+ /* Drop frame, if current time to too much in advance of the last_tv.
+ * < 0 means that the time difference in frames must be at lease 2
+ * frames below the expected difference of 1.
+ */
+ if (frame_diff < 0)
+ return -1;
+
+ /* Increment last_tv by the duration of one frame. */
+ tv_add_usec(&rs->transmit.last_tv, usec_duration);
+
+ /* Increment last_tv, if the current time is too much afterwards.
+ * Also increment timestamp and sequence number of RTP socket state.
+ * > 2 means that the time difference in frames must be at least 2
+ * frames above the expected difference of 1.
+ */
+ if (frame_diff > 2) {
+ long int frame_diff_excess = frame_diff - 1;
+ long int sample_diff_excess = frame_diff_excess * duration;
+
+ /* correct last_tv */
+ tv_add_usec(&rs->transmit.last_tv,
+ sample_diff_excess * USEC_SAMPLE);
+ LOGP(DLMUX, LOGL_NOTICE,
+ "Correcting timestamp difference of %ld frames "
+ "(to %s)\n", frame_diff_excess,
+ (rs->rx_action == RTP_RECV_APP) ? "app" : "BTS");
+ rs->transmit.sequence += frame_diff_excess;
+ rs->transmit.timestamp += sample_diff_excess;
+ }
+
+ return 0;
+}
+
/*! \brief encode and send a rtp frame
* \param[in] rs RTP socket through which we shall send
* \param[in] frame GSM RTP frame to be sent
@@ -225,6 +286,7 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
int duration; /* in samples */
int is_bfi = 0;
uint8_t dynamic_pt = 0;
+ int rc;
if (rs->rx_action == RTP_RECV_APP)
dynamic_pt = rs->receive.payload_type;
@@ -235,6 +297,7 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
rs->transmit.ssrc = rand();
rs->transmit.sequence = random();
rs->transmit.timestamp = random();
+ gettimeofday(&rs->transmit.last_tv, NULL);
}
switch (frame->msg_type) {
@@ -276,6 +339,10 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
return -EINVAL;
}
+ rc = correct_timestamp(rs, duration);
+ if (rc)
+ return 0;
+
if (is_bfi) {
/* In case of a bad frame, just count and drop packet. */
rs->transmit.timestamp += duration;