mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
webrtcbin: Store pending mid to make create-offer idempotent
If the mid is not stored in the transceiver, but it is stored in last_offer, then a further create-offer call will just ignore that transceiver. Also include unit test for ensure it doesn't regress. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2439>
This commit is contained in:
parent
3c9e4f4886
commit
3503599e0a
4 changed files with 101 additions and 19 deletions
|
@ -3213,7 +3213,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, *ufrag, *pwd, *mid;
|
gchar *direction, *ufrag, *pwd, *mid = NULL;
|
||||||
gboolean bundle_only;
|
gboolean bundle_only;
|
||||||
guint rtp_session_idx;
|
guint rtp_session_idx;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
@ -3422,11 +3422,13 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
mid = g_strdup (trans->mid);
|
mid = g_strdup (trans->mid);
|
||||||
} else {
|
g_hash_table_insert (all_mids, g_strdup (mid), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mid == NULL) {
|
||||||
const GstStructure *s = gst_caps_get_structure (caps, 0);
|
const GstStructure *s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
mid = g_strdup (gst_structure_get_string (s, "a-mid"));
|
mid = g_strdup (gst_structure_get_string (s, "a-mid"));
|
||||||
|
|
||||||
if (mid) {
|
if (mid) {
|
||||||
if (g_hash_table_contains (all_mids, (gpointer) mid)) {
|
if (g_hash_table_contains (all_mids, (gpointer) mid)) {
|
||||||
g_set_error (error, GST_WEBRTC_ERROR,
|
g_set_error (error, GST_WEBRTC_ERROR,
|
||||||
|
@ -3436,19 +3438,39 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
|
||||||
media_idx);
|
media_idx);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
g_free (WEBRTC_TRANSCEIVER (trans)->pending_mid);
|
||||||
|
WEBRTC_TRANSCEIVER (trans)->pending_mid = g_strdup (mid);
|
||||||
g_hash_table_insert (all_mids, g_strdup (mid), NULL);
|
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),
|
if (mid == NULL) {
|
||||||
webrtc->priv->media_counter++);
|
mid = g_strdup (WEBRTC_TRANSCEIVER (trans)->pending_mid);
|
||||||
if (g_hash_table_contains (all_mids, (gpointer) mid)) {
|
if (mid) {
|
||||||
g_free (mid);
|
/* If it's already used, just ignore the pending one and generate
|
||||||
} else {
|
* a new one */
|
||||||
gst_sdp_media_add_attribute (media, "mid", mid);
|
if (g_hash_table_contains (all_mids, (gpointer) mid)) {
|
||||||
g_hash_table_insert (all_mids, g_strdup (mid), NULL);
|
g_clear_pointer (&mid, free);
|
||||||
break;
|
g_clear_pointer (&WEBRTC_TRANSCEIVER (trans)->pending_mid, free);
|
||||||
}
|
} else {
|
||||||
|
gst_sdp_media_add_attribute (media, "mid", mid);
|
||||||
|
g_hash_table_insert (all_mids, g_strdup (mid), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mid == NULL) {
|
||||||
|
/* 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);
|
||||||
|
WEBRTC_TRANSCEIVER (trans)->pending_mid = g_strdup (mid);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3706,14 +3728,22 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
|
||||||
|| g_strcmp0 (gst_sdp_media_get_media (last_media), "video") == 0) {
|
|| g_strcmp0 (gst_sdp_media_get_media (last_media), "video") == 0) {
|
||||||
const gchar *last_mid;
|
const gchar *last_mid;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
last_mid = gst_sdp_media_get_attribute_val (last_media, "mid");
|
last_mid = gst_sdp_media_get_attribute_val (last_media, "mid");
|
||||||
|
|
||||||
for (j = 0; j < webrtc->priv->transceivers->len; j++) {
|
for (j = 0; j < webrtc->priv->transceivers->len; j++) {
|
||||||
trans = g_ptr_array_index (webrtc->priv->transceivers, j);
|
WebRTCTransceiver *wtrans;
|
||||||
|
const gchar *mid;
|
||||||
|
|
||||||
if (trans->mid && g_strcmp0 (trans->mid, last_mid) == 0) {
|
trans = g_ptr_array_index (webrtc->priv->transceivers, j);
|
||||||
WebRTCTransceiver *wtrans = WEBRTC_TRANSCEIVER (trans);
|
wtrans = WEBRTC_TRANSCEIVER (trans);
|
||||||
const char *mid;
|
|
||||||
|
if (trans->mid)
|
||||||
|
mid = trans->mid;
|
||||||
|
else
|
||||||
|
mid = wtrans->pending_mid;
|
||||||
|
|
||||||
|
if (mid && g_strcmp0 (mid, last_mid) == 0) {
|
||||||
GstSDPMedia media;
|
GstSDPMedia media;
|
||||||
|
|
||||||
memset (&media, 0, sizeof (media));
|
memset (&media, 0, sizeof (media));
|
||||||
|
@ -3800,6 +3830,11 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_hash_table_insert (all_mids, g_strdup (trans->mid), NULL);
|
g_hash_table_insert (all_mids, g_strdup (trans->mid), NULL);
|
||||||
|
} else if (WEBRTC_TRANSCEIVER (trans)->pending_mid &&
|
||||||
|
!g_hash_table_contains (all_mids,
|
||||||
|
WEBRTC_TRANSCEIVER (trans)->pending_mid)) {
|
||||||
|
g_hash_table_insert (all_mids,
|
||||||
|
g_strdup (WEBRTC_TRANSCEIVER (trans)->pending_mid), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@ webrtc_transceiver_finalize (GObject * object)
|
||||||
gst_caps_replace (&trans->last_retrieved_caps, NULL);
|
gst_caps_replace (&trans->last_retrieved_caps, NULL);
|
||||||
gst_caps_replace (&trans->last_send_configured_caps, NULL);
|
gst_caps_replace (&trans->last_send_configured_caps, NULL);
|
||||||
|
|
||||||
|
g_free (trans->pending_mid);
|
||||||
|
|
||||||
gst_event_replace (&trans->tos_event, NULL);
|
gst_event_replace (&trans->tos_event, NULL);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
|
|
@ -54,6 +54,8 @@ struct _WebRTCTransceiver
|
||||||
*/
|
*/
|
||||||
GstCaps *last_send_configured_caps;
|
GstCaps *last_send_configured_caps;
|
||||||
|
|
||||||
|
gchar *pending_mid;
|
||||||
|
|
||||||
gboolean mline_locked;
|
gboolean mline_locked;
|
||||||
|
|
||||||
GstElement *ulpfecdec;
|
GstElement *ulpfecdec;
|
||||||
|
|
|
@ -5426,6 +5426,48 @@ GST_START_TEST (test_invalid_add_media_in_answer)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_data_channel_recreate_offer)
|
||||||
|
{
|
||||||
|
GstHarness *h;
|
||||||
|
GstWebRTCDataChannel *channel;
|
||||||
|
GstPromise *promise;
|
||||||
|
const GstStructure *s;
|
||||||
|
GstPromiseResult res;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
h = gst_harness_new_with_padnames ("webrtcbin", "sink_0", NULL);
|
||||||
|
add_audio_test_src_harness (h, 0xDEADBEEF);
|
||||||
|
|
||||||
|
g_signal_emit_by_name (h->element, "create-data-channel", "label", NULL,
|
||||||
|
&channel);
|
||||||
|
fail_unless (GST_IS_WEBRTC_DATA_CHANNEL (channel));
|
||||||
|
|
||||||
|
pad = gst_element_get_static_pad (h->element, "sink_0");
|
||||||
|
fail_unless (pad != NULL);
|
||||||
|
|
||||||
|
promise = gst_promise_new ();
|
||||||
|
g_signal_emit_by_name (h->element, "create-offer", NULL, promise);
|
||||||
|
res = gst_promise_wait (promise);
|
||||||
|
fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
|
||||||
|
s = gst_promise_get_reply (promise);
|
||||||
|
fail_unless (s != NULL);
|
||||||
|
gst_promise_unref (promise);
|
||||||
|
|
||||||
|
promise = gst_promise_new ();
|
||||||
|
g_signal_emit_by_name (h->element, "create-offer", NULL, promise);
|
||||||
|
res = gst_promise_wait (promise);
|
||||||
|
fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
|
||||||
|
s = gst_promise_get_reply (promise);
|
||||||
|
fail_unless (s != NULL);
|
||||||
|
gst_promise_unref (promise);
|
||||||
|
|
||||||
|
gst_object_unref (pad);
|
||||||
|
gst_object_unref (channel);
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
webrtcbin_suite (void)
|
webrtcbin_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -5502,6 +5544,7 @@ webrtcbin_suite (void)
|
||||||
tcase_add_test (tc, test_renego_stream_add_data_channel);
|
tcase_add_test (tc, test_renego_stream_add_data_channel);
|
||||||
tcase_add_test (tc, test_renego_data_channel_add_stream);
|
tcase_add_test (tc, test_renego_data_channel_add_stream);
|
||||||
tcase_add_test (tc, test_renego_stream_data_channel_add_stream);
|
tcase_add_test (tc, test_renego_stream_data_channel_add_stream);
|
||||||
|
tcase_add_test (tc, test_data_channel_recreate_offer);
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING ("Some required elements were not found. "
|
GST_WARNING ("Some required elements were not found. "
|
||||||
"All datachannel tests are disabled. sctpenc %p, sctpdec %p", sctpenc,
|
"All datachannel tests are disabled. sctpenc %p, sctpdec %p", sctpenc,
|
||||||
|
|
Loading…
Reference in a new issue