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


Reply via email to