gstdtlsrtpenc: Add rtp-sync property
authorJan Schmidt <jan@centricular.com>
Thu, 13 Feb 2020 14:38:14 +0000 (01:38 +1100)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 27 Feb 2020 12:30:32 +0000 (12:30 +0000)
Add an rtp-sync property which synchronises RTP streams
to the pipeline clock before passing them to funnel for
merging with RTCP.

https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/1212

ext/dtls/gstdtlssrtpenc.c
ext/dtls/gstdtlssrtpenc.h

index d993549..283ad9d 100644 (file)
@@ -78,12 +78,14 @@ enum
   PROP_0,
   PROP_IS_CLIENT,
   PROP_CONNECTION_STATE,
+  PROP_RTP_SYNC,
   NUM_PROPERTIES
 };
 
 static GParamSpec *properties[NUM_PROPERTIES];
 
 #define DEFAULT_IS_CLIENT FALSE
+#define DEFAULT_RTP_SYNC FALSE
 
 static gboolean transform_enum (GBinding *, const GValue * source_value,
     GValue * target_value, GEnumClass *);
@@ -145,6 +147,12 @@ gst_dtls_srtp_enc_class_init (GstDtlsSrtpEncClass * klass)
       GST_DTLS_TYPE_CONNECTION_STATE,
       GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+
+  properties[PROP_RTP_SYNC] =
+      g_param_spec_boolean ("rtp-sync", "Synchronize RTP",
+      "Synchronize RTP to the pipeline clock before merging with RTCP",
+      DEFAULT_RTP_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
 
   gst_element_class_add_static_pad_template (element_class, &rtp_sink_template);
@@ -178,15 +186,20 @@ gst_dtls_srtp_enc_init (GstDtlsSrtpEnc * self)
   gboolean ret;
 
 /*
-                 +--------------------+     +-----------------+
-     rtp_sink-R-o|rtp_sink     rtp_src|o-R-o|                 |
-                 |       srtpenc      |     |                 |
-    rtcp_sink-R-o|srtcp_sink  rtcp_src|o-R-o|                 |
-                 +--------------------+     |     funnel      |o---src
-                                            |                 |
-                 +--------------------+     |                 |
-    data_sink-R-o|       dtlsenc      |o---o|                 |
-                 +--------------------+     +-----------------+
+                 +--------------------+    +--------------+     +-----------------+
+     rtp_sink-R-o|rtp_sink     rtp_src|o-R-o   clocksync  |o-R-o|                 |
+                 |       srtpenc      |    +--------------+     |                 |
+                 |                    |                         |                 |
+    rtcp_sink-R-o|srtcp_sink  rtcp_src|o-----------R-----------o|                 |
+                 +--------------------+                         |     funnel      |o---src
+                                                                |                 |
+                 +--------------------+                         |                 |
+    data_sink-R-o|       dtlsenc      |o-----------------------o|                 |
+                 +--------------------+                         +-----------------+
+
+    The clocksync element is tied to the sync property. If sync=true, RTP output will be
+    synchronised to the clock, so it doesn't slow down RTCP traffic by being synched later
+    in the pipeline
 */
 
   self->srtp_enc = gst_element_factory_make ("srtpenc", NULL);
@@ -289,6 +302,9 @@ gst_dtls_srtp_enc_set_property (GObject * object,
             "tried to set is-client after disabling DTLS");
       }
       break;
+    case PROP_RTP_SYNC:
+      self->rtp_sync = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
   }
@@ -314,6 +330,9 @@ gst_dtls_srtp_enc_get_property (GObject * object,
       g_object_get_property (G_OBJECT (self->bin.dtls_element),
           "connection-state", value);
       break;
+    case PROP_RTP_SYNC:
+      g_value_set_boolean (value, self->rtp_sync);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
   }
@@ -356,13 +375,32 @@ gst_dtls_srtp_enc_request_new_pad (GstElement * element,
   g_return_val_if_fail (self->srtp_enc, NULL);
 
   if (templ == gst_element_class_get_pad_template (klass, "rtp_sink_%d")) {
+    gchar *clocksync_name;
+    GstElement *clocksync;
+
+    sscanf (name, "rtp_sink_%d", &pad_n);
+
+    clocksync_name = g_strdup_printf ("clocksync_%d", pad_n);
+    clocksync = gst_element_factory_make ("clocksync", clocksync_name);
+    g_free (clocksync_name);
+
+    if (clocksync == NULL) {
+      goto fail_create;
+    }
+
+    g_object_bind_property (self, "rtp-sync", clocksync, "sync",
+        G_BINDING_SYNC_CREATE);
+
+    gst_bin_add (GST_BIN (self), clocksync);
+    gst_element_sync_state_with_parent (clocksync);
+
     target_pad = gst_element_get_request_pad (self->srtp_enc, name);
     g_return_val_if_fail (target_pad, NULL);
 
-    sscanf (GST_PAD_NAME (target_pad), "rtp_sink_%d", &pad_n);
     srtp_src_name = g_strdup_printf ("rtp_src_%d", pad_n);
 
-    gst_element_link_pads (self->srtp_enc, srtp_src_name, self->funnel, NULL);
+    gst_element_link_pads (self->srtp_enc, srtp_src_name, clocksync, NULL);
+    gst_element_link_pads (clocksync, "src", self->funnel, NULL);
 
     g_free (srtp_src_name);
 
@@ -400,6 +438,11 @@ gst_dtls_srtp_enc_request_new_pad (GstElement * element,
   }
 
   return ghost_pad;
+
+fail_create:
+  GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, NULL,
+      ("%s", "Failed to create internal clocksync element"));
+  return NULL;
 }
 
 static void
index 5dd603d..a2a86b5 100644 (file)
@@ -44,6 +44,8 @@ typedef struct _GstDtlsSrtpEncClass GstDtlsSrtpEncClass;
 struct _GstDtlsSrtpEnc {
     GstDtlsSrtpBin bin;
 
+    gboolean rtp_sync;
+
     GstElement *srtp_enc;
     GstElement *funnel;
 };