* multiple dtls fingerprints https://tools.ietf.org/html/draft-ietf-mmusic-4572-update-05
*/
GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
- gchar *direction, *sdp_mid, *ufrag, *pwd;
+ gchar *direction, *ufrag, *pwd, *mid;
gboolean bundle_only;
GstCaps *caps;
GstStructure *extmap;
/* Some identifier; we also add the media name to it so it's identifiable */
if (trans->mid) {
gst_sdp_media_add_attribute (media, "mid", trans->mid);
+ mid = g_strdup (trans->mid);
} else {
- /* Make sure to avoid mid collisions */
- while (TRUE) {
- sdp_mid = g_strdup_printf ("%s%u", gst_sdp_media_get_media (media),
- webrtc->priv->media_counter++);
- if (g_hash_table_contains (all_mids, (gpointer) sdp_mid)) {
- g_free (sdp_mid);
- } else {
- gst_sdp_media_add_attribute (media, "mid", sdp_mid);
- g_hash_table_insert (all_mids, sdp_mid, NULL);
- break;
+ const GstStructure *s = gst_caps_get_structure (caps, 0);
+
+ mid = g_strdup (gst_structure_get_string (s, "a-mid"));
+
+ if (mid) {
+ if (g_hash_table_contains (all_mids, (gpointer) mid)) {
+ g_set_error (error, GST_WEBRTC_ERROR,
+ GST_WEBRTC_ERROR_INTERNAL_FAILURE,
+ "Cannot re-use mid \'%s\' from the caps in m= line %u that has "
+ "already been used for a previous m= line in the SDP", mid,
+ media_idx);
+ return FALSE;
+ }
+ g_hash_table_insert (all_mids, g_strdup (mid), NULL);
+ } else {
+ /* Make sure to avoid mid collisions */
+ while (TRUE) {
+ mid = g_strdup_printf ("%s%u", gst_sdp_media_get_media (media),
+ webrtc->priv->media_counter++);
+ if (g_hash_table_contains (all_mids, (gpointer) mid)) {
+ g_free (mid);
+ } else {
+ gst_sdp_media_add_attribute (media, "mid", mid);
+ g_hash_table_insert (all_mids, g_strdup (mid), NULL);
+ break;
+ }
}
}
}
}
if (bundled_mids) {
- const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
-
g_assert (mid);
g_string_append_printf (bundled_mids, " %s", mid);
}
+ g_clear_pointer (&mid, g_free);
+
gst_caps_unref (caps);
return TRUE;
rtp_trans->mline, rtp_trans->kind,
webrtc_kind_from_caps (answer_caps));
- if (!trans->do_nack) {
- answer_caps = gst_caps_make_writable (answer_caps);
- for (k = 0; k < gst_caps_get_size (answer_caps); k++) {
- GstStructure *s = gst_caps_get_structure (answer_caps, k);
+ answer_caps = gst_caps_make_writable (answer_caps);
+ for (k = 0; k < gst_caps_get_size (answer_caps); k++) {
+ GstStructure *s = gst_caps_get_structure (answer_caps, k);
+ /* taken from the offer sdp already and already intersected above */
+ gst_structure_remove_field (s, "a-mid");
+ if (!trans->do_nack)
gst_structure_remove_fields (s, "rtcp-fb-nack", NULL);
- }
}
gst_sdp_media_set_media_from_caps (answer_caps, media);
GST_END_TEST;
+static void
+on_sdp_media_check_mid (struct test_webrtc *t, GstElement * element,
+ GstWebRTCSessionDescription * desc, gpointer user_data)
+{
+ const char **mid = user_data;
+ guint i;
+
+ for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
+ const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
+ gboolean seen_mid = FALSE;
+ guint j;
+
+ for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
+ const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
+
+ if (g_strcmp0 (attr->key, "mid") == 0) {
+ fail_unless (!seen_mid);
+ seen_mid = TRUE;
+ fail_unless_equals_string (attr->value, mid[i]);
+ }
+ }
+ }
+}
+
GST_START_TEST (test_add_recvonly_transceiver)
{
struct test_webrtc *t = test_webrtc_new ();
media_format_count, &no_duplicate_payloads);
VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
&media_formats);
+ const char *expected_mid[] = { "gst", };
+ VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
const gchar *expected_offer_setup[] = { "actpass", };
- VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
const gchar *expected_answer_setup[] = { "active", };
- VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
- &count);
+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
const gchar *expected_offer_direction[] = { "recvonly", };
VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
&offer_setup);
t->on_pad_added = _pad_added_fakesink;
/* setup recvonly transceiver */
- caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
+ caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
&trans);
GST_END_TEST;
+GST_START_TEST (test_bundle_mid_header_extension)
+{
+ struct test_webrtc *t = test_webrtc_new ();
+ GstWebRTCRTPTransceiverDirection direction;
+ GstWebRTCRTPTransceiver *trans;
+ VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
+ NULL, NULL);
+ guint media_format_count[] = { 1, 1, };
+ VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
+ media_format_count, &no_duplicate_payloads);
+ VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
+ &media_formats);
+ const char *expected_mid[] = { "gst", };
+ VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
+ const gchar *expected_offer_setup[] = { "actpass", };
+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
+ const gchar *expected_answer_setup[] = { "active", };
+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
+ const gchar *expected_offer_direction[] = { "recvonly", };
+ VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
+ &offer_setup);
+ const gchar *expected_answer_direction[] = { "sendonly", };
+ VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
+ &answer_setup);
+ GstCaps *caps;
+ GstHarness *h;
+ guint mline;
+ char *trans_mid;
+
+ /* add a transceiver that will only receive an opus stream and check that
+ * the created offer is marked as recvonly */
+ t->on_negotiation_needed = NULL;
+ t->on_ice_candidate = NULL;
+ t->on_pad_added = _pad_added_fakesink;
+
+ /* setup recvonly transceiver */
+ caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
+ direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
+ g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
+ &trans);
+ gst_caps_unref (caps);
+ fail_unless (trans != NULL);
+ g_object_get (trans, "mlineindex", &mline, NULL);
+ fail_unless_equals_int (mline, -1);
+
+ /* setup sendonly peer */
+ 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);
+
+ test_validate_sdp (t, &offer, &answer);
+
+ g_object_get (trans, "mlineindex", &mline, "mid", &trans_mid, NULL);
+ fail_unless_equals_int (mline, 0);
+ fail_unless_equals_string (trans_mid, "gst");
+ g_clear_pointer (&trans_mid, g_free);
+ gst_object_unref (trans);
+
+ test_webrtc_free (t);
+}
+
+GST_END_TEST;
+
static Suite *
webrtcbin_suite (void)
{
tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
tcase_add_test (tc, test_codec_preferences_invalid_extmap);
tcase_add_test (tc, test_renego_rtx);
+ tcase_add_test (tc, test_bundle_mid_header_extension);
if (sctpenc && sctpdec) {
tcase_add_test (tc, test_data_channel_create);
tcase_add_test (tc, test_data_channel_remote_notify);