webrtcbin: fix pt selection for FEC and RTX when BUNDLE
authorMathieu Duponchelle <mathieu@centricular.com>
Fri, 15 Mar 2019 15:47:35 +0000 (16:47 +0100)
committerMathieu Duponchelle <mathieu@centricular.com>
Fri, 15 Mar 2019 17:37:51 +0000 (18:37 +0100)
When we offer bundled media, payload types must be unique
across all bundled media, as they will be multiplexed in the
same session.

ext/webrtc/gstwebrtcbin.c

index 76c99edf0dad30d4506b0161a00d28f6210f03ce..9236753d1d09a43ddcb7adc234180ce791d1f6fd 100644 (file)
@@ -1946,7 +1946,8 @@ _add_fingerprint_to_media (GstWebRTCDTLSTransport * transport,
 static gboolean
 sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
     GstWebRTCRTPTransceiver * trans, GstWebRTCSDPType type, guint media_idx,
-    GString * bundled_mids, guint bundle_idx, gboolean bundle_only)
+    GString * bundled_mids, guint bundle_idx, gboolean bundle_only,
+    GArray * reserved_pts)
 {
   /* TODO:
    * rtp header extensions
@@ -2028,14 +2029,14 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
   }
 
   if (type == GST_WEBRTC_SDP_TYPE_OFFER) {
-    GArray *reserved_pts = g_array_new (FALSE, FALSE, sizeof (guint));
     const GstStructure *s = gst_caps_get_structure (caps, 0);
     gint clockrate = -1;
     gint rtx_target_pt;
     gint original_rtx_target_pt;        /* Workaround chrome bug: https://bugs.chromium.org/p/webrtc/issues/detail?id=6196 */
     guint rtx_target_ssrc = -1;
 
-    if (gst_structure_get_int (s, "payload", &rtx_target_pt))
+    if (gst_structure_get_int (s, "payload", &rtx_target_pt) &&
+        webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE)
       g_array_append_val (reserved_pts, rtx_target_pt);
 
     original_rtx_target_pt = rtx_target_pt;
@@ -2054,7 +2055,6 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
     if (original_rtx_target_pt != rtx_target_pt)
       _pick_rtx_payload_types (webrtc, WEBRTC_TRANSCEIVER (trans), reserved_pts,
           clockrate, original_rtx_target_pt, rtx_target_ssrc, media);
-    g_array_free (reserved_pts, TRUE);
   }
 
   _media_add_ssrcs (media, caps, webrtc, WEBRTC_TRANSCEIVER (trans));
@@ -2084,6 +2084,34 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
   return TRUE;
 }
 
+static void
+gather_pad_pt (GstWebRTCBinPad * pad, GArray * reserved_pts)
+{
+  if (pad->received_caps) {
+    GstStructure *s = gst_caps_get_structure (pad->received_caps, 0);
+    gint pt;
+
+    if (gst_structure_get_int (s, "payload", &pt)) {
+      g_array_append_val (reserved_pts, pt);
+    }
+  }
+}
+
+static GArray *
+gather_reserved_pts (GstWebRTCBin * webrtc)
+{
+  GstElement *element = GST_ELEMENT (webrtc);
+  GArray *reserved_pts = g_array_new (FALSE, FALSE, sizeof (guint));
+
+  GST_OBJECT_LOCK (webrtc);
+  g_list_foreach (element->sinkpads, (GFunc) gather_pad_pt, reserved_pts);
+  g_list_foreach (webrtc->priv->pending_pads, (GFunc) gather_pad_pt,
+      reserved_pts);
+  GST_OBJECT_UNLOCK (webrtc);
+
+  return reserved_pts;
+}
+
 /* TODO: use the options argument */
 static GstSDPMessage *
 _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
@@ -2093,6 +2121,7 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
   GString *bundled_mids = NULL;
   gchar *bundle_ufrag = NULL;
   gchar *bundle_pwd = NULL;
+  GArray *reserved_pts = NULL;
 
   gst_sdp_message_new (&ret);
 
@@ -2115,6 +2144,7 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
 
   if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
     _generate_ice_credentials (&bundle_ufrag, &bundle_pwd);
+    reserved_pts = gather_reserved_pts (webrtc);
   }
 
   /* for each rtp transceiver */
@@ -2136,6 +2166,7 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
 
     /* FIXME: only needed when restarting ICE */
     if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
+      reserved_pts = g_array_new (FALSE, FALSE, sizeof (guint));
       _generate_ice_credentials (&ufrag, &pwd);
     } else {
       ufrag = g_strdup (bundle_ufrag);
@@ -2147,8 +2178,11 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
     g_free (ufrag);
     g_free (pwd);
 
+    g_assert (reserved_pts != NULL);
+
     if (sdp_media_from_transceiver (webrtc, &media, trans,
-            GST_WEBRTC_SDP_TYPE_OFFER, i, bundled_mids, 0, bundle_only)) {
+            GST_WEBRTC_SDP_TYPE_OFFER, i, bundled_mids, 0, bundle_only,
+            reserved_pts)) {
       if (bundled_mids) {
         const gchar *mid = gst_sdp_media_get_attribute_val (&media, "mid");
 
@@ -2159,6 +2193,14 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
     } else {
       gst_sdp_media_uninit (&media);
     }
+
+    if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
+      g_array_free (reserved_pts, TRUE);
+    }
+  }
+
+  if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
+    g_array_free (reserved_pts, TRUE);
   }
 
   /* add data channel support */