webrtc: fix answer creation with multiple streams and similar caps
authorMatthew Waters <matthew@centricular.com>
Mon, 26 Nov 2018 11:10:57 +0000 (22:10 +1100)
committerMatthew Waters <matthew@centricular.com>
Thu, 30 May 2019 11:26:46 +0000 (21:26 +1000)
ext/webrtc/gstwebrtcbin.c
tests/check/elements/webrtcbin.c

index 6d4a49b..fa07ed4 100644 (file)
@@ -2396,6 +2396,7 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
   GString *bundled_mids = NULL;
   gchar *bundle_ufrag = NULL;
   gchar *bundle_pwd = NULL;
+  GList *seen_transceivers = NULL;
 
   if (!webrtc->pending_remote_description) {
     GST_ERROR_OBJECT (webrtc,
@@ -2576,6 +2577,13 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
         rtp_trans =
             g_array_index (webrtc->priv->transceivers,
             GstWebRTCRTPTransceiver *, j);
+
+        if (g_list_find (seen_transceivers, rtp_trans)) {
+          /* Don't double allocate a transceiver to multiple mlines */
+          rtp_trans = NULL;
+          continue;
+        }
+
         trans_caps =
             _find_codec_preferences (webrtc, rtp_trans, GST_PAD_SINK, j);
 
@@ -2590,7 +2598,7 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
           if (answer_caps && !gst_caps_is_empty (answer_caps)) {
             GST_LOG_OBJECT (webrtc,
                 "found compatible transceiver %" GST_PTR_FORMAT
-                " for offer media %u", trans, i);
+                " for offer media %u", rtp_trans, i);
             if (trans_caps)
               gst_caps_unref (trans_caps);
             break;
@@ -2619,6 +2627,7 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
         answer_dir = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
         answer_caps = gst_caps_ref (offer_caps);
       }
+      seen_transceivers = g_list_prepend (seen_transceivers, rtp_trans);
 
       if (!rtp_trans) {
         trans = _create_webrtc_transceiver (webrtc, answer_dir, i);
@@ -2724,6 +2733,8 @@ out:
   if (bundled)
     g_strfreev (bundled);
 
+  g_list_free (seen_transceivers);
+
   return ret;
 }
 
index 523d3b0..7bed3e7 100644 (file)
@@ -2213,6 +2213,47 @@ GST_START_TEST (test_duplicate_nego)
 
 GST_END_TEST;
 
+GST_START_TEST (test_dual_audio)
+{
+  struct test_webrtc *t = create_audio_test ();
+  const gchar *expected_offer[] = { "sendrecv", "sendrecv", };
+  const gchar *expected_answer[] = { "sendrecv", "recvonly" };
+  struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
+  struct validate_sdp answer =
+      { on_sdp_media_direction, expected_answer, NULL };
+  GstHarness *h;
+  GstWebRTCRTPTransceiver *trans;
+  GArray *transceivers;
+
+  /* test that each mline gets a unique transceiver even with the same caps */
+
+  h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
+  add_fake_audio_src_harness (h, 96);
+  t->harnesses = g_list_prepend (t->harnesses, h);
+
+  h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
+  add_fake_audio_src_harness (h, 96);
+  t->harnesses = g_list_prepend (t->harnesses, h);
+
+  t->on_negotiation_needed = NULL;
+  test_validate_sdp (t, &offer, &answer);
+
+  g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
+  fail_unless (transceivers != NULL);
+  fail_unless_equals_int (2, transceivers->len);
+
+  trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
+  fail_unless (trans != NULL);
+  fail_unless_equals_int (trans->mline, 0);
+
+  trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
+  fail_unless (trans != NULL);
+  fail_unless_equals_int (trans->mline, 1);
+
+  g_array_unref (transceivers);
+  test_webrtc_free (t);
+}
+
 static Suite *
 webrtcbin_suite (void)
 {
@@ -2247,6 +2288,7 @@ webrtcbin_suite (void)
     tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
     tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
     tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
+    tcase_add_test (tc, test_dual_audio);
     tcase_add_test (tc, test_duplicate_nego);
     if (sctpenc && sctpdec) {
       tcase_add_test (tc, test_data_channel_create);