aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 d8fde15d1..e29f26ccf 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;