rtp: gstreamer: Account for rounding errors in RTP timestamp conversion
authorArun Raghavan <arun@asymptotic.io>
Thu, 22 Oct 2020 14:12:03 +0000 (10:12 -0400)
committerArun Raghavan <arun@asymptotic.io>
Fri, 23 Oct 2020 16:11:35 +0000 (12:11 -0400)
Since the RTP timestamp is converted to time units and back, a small
error can creep up, which then results in a single frame error in where
we place the buffer in the output memblockq. This results in minor
glitches, so we check for and eliminate the error.

src/modules/rtp/rtp-gstreamer.c

index 1d253cfa079c2b3abef97c8c8e3535955c0bf173..28d367bfbd7c3eb5428be4b23deb7bfcde3ee0f3 100644 (file)
@@ -54,6 +54,7 @@ struct pa_rtp_context {
     GstElement *appsink;
     GstCaps *meta_reference;
 
+    bool first_buffer;
     uint32_t last_timestamp;
 
     uint8_t *send_buf;
@@ -482,6 +483,7 @@ pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample
     c->fdsem = pa_fdsem_new();
     c->ss = *ss;
     c->send_buf = NULL;
+    c->first_buffer = true;
 
     if (!gst_init_check(NULL, NULL, &error)) {
         pa_log_error("Could not initialise GStreamer: %s", error->message);
@@ -598,6 +600,21 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_
     if (timestamp != GST_CLOCK_TIME_NONE)
         pa_timeval_rtstore(tstamp, timestamp / PA_NSEC_PER_USEC, false);
 
+    if (c->first_buffer) {
+        c->first_buffer = false;
+        c->last_timestamp = *rtp_tstamp;
+    } else {
+        /* The RTP clock -> time domain -> RTP clock transformation above might
+         * add a ±1 rounding error, so let's get rid of that */
+        uint32_t expected = c->last_timestamp + (uint32_t) (data_len / pa_rtp_context_get_frame_size(c));
+        int delta = *rtp_tstamp - expected;
+
+        if (delta == 1 || delta == -1)
+            *rtp_tstamp -= delta;
+
+        c->last_timestamp = *rtp_tstamp;
+    }
+
     gst_buffer_list_unref(buf_list);
     gst_object_unref(adapter);