webrtcbin: support using an a=mid value from the sink/transceiver caps
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1664>
This commit is contained in:
parent
400faf7361
commit
9a758d78a9
@ -2974,7 +2974,7 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
|
|||||||
* multiple dtls fingerprints https://tools.ietf.org/html/draft-ietf-mmusic-4572-update-05
|
* multiple dtls fingerprints https://tools.ietf.org/html/draft-ietf-mmusic-4572-update-05
|
||||||
*/
|
*/
|
||||||
GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
|
GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
|
||||||
gchar *direction, *sdp_mid, *ufrag, *pwd;
|
gchar *direction, *ufrag, *pwd, *mid;
|
||||||
gboolean bundle_only;
|
gboolean bundle_only;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstStructure *extmap;
|
GstStructure *extmap;
|
||||||
@ -3156,17 +3156,34 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
|
|||||||
/* Some identifier; we also add the media name to it so it's identifiable */
|
/* Some identifier; we also add the media name to it so it's identifiable */
|
||||||
if (trans->mid) {
|
if (trans->mid) {
|
||||||
gst_sdp_media_add_attribute (media, "mid", trans->mid);
|
gst_sdp_media_add_attribute (media, "mid", trans->mid);
|
||||||
|
mid = g_strdup (trans->mid);
|
||||||
} else {
|
} else {
|
||||||
/* Make sure to avoid mid collisions */
|
const GstStructure *s = gst_caps_get_structure (caps, 0);
|
||||||
while (TRUE) {
|
|
||||||
sdp_mid = g_strdup_printf ("%s%u", gst_sdp_media_get_media (media),
|
mid = g_strdup (gst_structure_get_string (s, "a-mid"));
|
||||||
webrtc->priv->media_counter++);
|
|
||||||
if (g_hash_table_contains (all_mids, (gpointer) sdp_mid)) {
|
if (mid) {
|
||||||
g_free (sdp_mid);
|
if (g_hash_table_contains (all_mids, (gpointer) mid)) {
|
||||||
} else {
|
g_set_error (error, GST_WEBRTC_ERROR,
|
||||||
gst_sdp_media_add_attribute (media, "mid", sdp_mid);
|
GST_WEBRTC_ERROR_INTERNAL_FAILURE,
|
||||||
g_hash_table_insert (all_mids, sdp_mid, NULL);
|
"Cannot re-use mid \'%s\' from the caps in m= line %u that has "
|
||||||
break;
|
"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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3190,12 +3207,12 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bundled_mids) {
|
if (bundled_mids) {
|
||||||
const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
|
|
||||||
|
|
||||||
g_assert (mid);
|
g_assert (mid);
|
||||||
g_string_append_printf (bundled_mids, " %s", mid);
|
g_string_append_printf (bundled_mids, " %s", mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_pointer (&mid, g_free);
|
||||||
|
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -4155,12 +4172,13 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options,
|
|||||||
rtp_trans->mline, rtp_trans->kind,
|
rtp_trans->mline, rtp_trans->kind,
|
||||||
webrtc_kind_from_caps (answer_caps));
|
webrtc_kind_from_caps (answer_caps));
|
||||||
|
|
||||||
if (!trans->do_nack) {
|
answer_caps = gst_caps_make_writable (answer_caps);
|
||||||
answer_caps = gst_caps_make_writable (answer_caps);
|
for (k = 0; k < gst_caps_get_size (answer_caps); k++) {
|
||||||
for (k = 0; k < gst_caps_get_size (answer_caps); k++) {
|
GstStructure *s = gst_caps_get_structure (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_structure_remove_fields (s, "rtcp-fb-nack", NULL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_sdp_media_set_media_from_caps (answer_caps, media);
|
gst_sdp_media_set_media_from_caps (answer_caps, media);
|
||||||
|
@ -1628,6 +1628,30 @@ GST_START_TEST (test_get_transceivers)
|
|||||||
|
|
||||||
GST_END_TEST;
|
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)
|
GST_START_TEST (test_add_recvonly_transceiver)
|
||||||
{
|
{
|
||||||
struct test_webrtc *t = test_webrtc_new ();
|
struct test_webrtc *t = test_webrtc_new ();
|
||||||
@ -1640,11 +1664,12 @@ GST_START_TEST (test_add_recvonly_transceiver)
|
|||||||
media_format_count, &no_duplicate_payloads);
|
media_format_count, &no_duplicate_payloads);
|
||||||
VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
|
VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
|
||||||
&media_formats);
|
&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", };
|
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", };
|
const gchar *expected_answer_setup[] = { "active", };
|
||||||
VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
|
VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
|
||||||
&count);
|
|
||||||
const gchar *expected_offer_direction[] = { "recvonly", };
|
const gchar *expected_offer_direction[] = { "recvonly", };
|
||||||
VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
|
VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
|
||||||
&offer_setup);
|
&offer_setup);
|
||||||
@ -1661,7 +1686,7 @@ GST_START_TEST (test_add_recvonly_transceiver)
|
|||||||
t->on_pad_added = _pad_added_fakesink;
|
t->on_pad_added = _pad_added_fakesink;
|
||||||
|
|
||||||
/* setup recvonly transceiver */
|
/* 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;
|
direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
|
||||||
g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
|
g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
|
||||||
&trans);
|
&trans);
|
||||||
@ -4425,6 +4450,69 @@ GST_START_TEST (test_renego_rtx)
|
|||||||
|
|
||||||
GST_END_TEST;
|
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 *
|
static Suite *
|
||||||
webrtcbin_suite (void)
|
webrtcbin_suite (void)
|
||||||
{
|
{
|
||||||
@ -4480,6 +4568,7 @@ webrtcbin_suite (void)
|
|||||||
tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
|
tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
|
||||||
tcase_add_test (tc, test_codec_preferences_invalid_extmap);
|
tcase_add_test (tc, test_codec_preferences_invalid_extmap);
|
||||||
tcase_add_test (tc, test_renego_rtx);
|
tcase_add_test (tc, test_renego_rtx);
|
||||||
|
tcase_add_test (tc, test_bundle_mid_header_extension);
|
||||||
if (sctpenc && sctpdec) {
|
if (sctpenc && sctpdec) {
|
||||||
tcase_add_test (tc, test_data_channel_create);
|
tcase_add_test (tc, test_data_channel_create);
|
||||||
tcase_add_test (tc, test_data_channel_remote_notify);
|
tcase_add_test (tc, test_data_channel_remote_notify);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user