The RTP stream is generated or forwarded by OpenBSC to nanoBTS. Due to
switching of streams (hold/retrieve call), packet loss or even stalling
of sender's process, the time stamp must be corrected. If outdated
packets are received, they get dropped.
---
openbsc/src/libtrau/rtp_proxy.c | 80 ++++++++++++++++++++++++++++++-----------
1 file changed, 59 insertions(+), 21 deletions(-)
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index ed7479d..3e6c462 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -236,6 +236,12 @@ 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
+
/* "to - from" */
static void tv_difference(struct timeval *diff, const struct timeval *from,
const struct timeval *__to)
@@ -244,13 +250,60 @@ static void tv_difference(struct timeval *diff, const struct timeval
*from,
if (to->tv_usec < from->tv_usec) {
to->tv_sec -= 1;
- to->tv_usec += 1000000;
+ to->tv_usec += USEC_1S;
}
diff->tv_usec = to->tv_usec - from->tv_usec;
diff->tv_sec = to->tv_sec - from->tv_sec;
}
+/* add sec,usec to tv */
+static void tv_add(struct timeval *tv, int sec, int usec)
+{
+
+ if (usec < 0)
+ usec += USEC_1S;
+ tv->tv_sec += sec;
+ tv->tv_usec += usec;
+ if (tv->tv_usec >= USEC_1S) {
+ tv->tv_sec++;
+ tv->tv_usec -= USEC_1S;
+ }
+}
+
+static int correct_timestamp(struct rtp_socket *rs, int duration)
+{
+ struct timeval tv, tv_diff;
+ long int usec_diff, frame_diff;
+
+ gettimeofday(&tv, NULL);
+ tv_difference(&tv_diff, &rs->transmit.last_tv, &tv);
+ tv_add(&rs->transmit.last_tv, 0, USEC_20MS);
+
+ usec_diff = tv_diff.tv_sec * USEC_1S + tv_diff.tv_usec;
+ frame_diff = ((usec_diff + (USEC_10MS)) / USEC_20MS); /* round */
+
+ if (abs(frame_diff - 1) > 1) {
+ long int frame_diff_excess = frame_diff - 1;
+ long int sample_diff_excess = frame_diff_excess * duration;
+
+ /* correct last_tv */
+ tv_add(&rs->transmit.last_tv, sample_diff_excess / SAMPLES_1S,
+ (sample_diff_excess % SAMPLES_1S) * USEC_SAMPLE);
+ /* drop frame, if time stamp is in the past */
+ if (frame_diff_excess < 0)
+ return -1;
+ LOGP(DLMUX, LOGL_NOTICE,
+ "Correcting timestamp difference of %ld frames "
+ "(to %s)\n", frame_diff_excess,
+ (rs->rx_action == RTP_RECV_L4) ? "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
@@ -265,6 +318,7 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame
*frame)
int duration; /* in samples */
int amr = 0;
uint8_t dynamic_pt = 0;
+ int rc;
if (rs->rx_action == RTP_RECV_L4)
dynamic_pt = rs->receive.payload_type;
@@ -275,6 +329,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) {
@@ -313,26 +368,9 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame
*frame)
return -EINVAL;
}
- {
- struct timeval tv, tv_diff;
- long int usec_diff, frame_diff;
-
- gettimeofday(&tv, NULL);
- tv_difference(&tv_diff, &rs->transmit.last_tv, &tv);
- rs->transmit.last_tv = tv;
-
- usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec;
- frame_diff = (usec_diff / 20000);
-
- if (abs(frame_diff) > 1) {
- long int frame_diff_excess = frame_diff - 1;
-
- LOGP(DLMUX, LOGL_NOTICE,
- "Correcting frame difference of %ld frames\n", frame_diff_excess);
- rs->transmit.sequence += frame_diff_excess;
- rs->transmit.timestamp += frame_diff_excess * duration;
- }
- }
+ rc = correct_timestamp(rs, duration);
+ if (rc)
+ return 0;
if (frame->msg_type == GSM_BAD_FRAME)
return 0;
--
1.8.1.5
--------------090106010400060202050508--