diff options
author | Matthew Waters <matthew@centricular.com> | 2023-05-11 17:28:52 +1000 |
---|---|---|
committer | GStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org> | 2023-05-12 04:52:22 +0000 |
commit | b10ec569d74f65568d365543fa441eb33304889f (patch) | |
tree | 5bb2417427411e4ed772273e0a9f33c023696f79 | |
parent | 5e45a1b1bd0ec4355346c60ef40c14fa91aa9b6c (diff) | |
download | gstreamer-b10ec569d74f65568d365543fa441eb33304889f.tar.gz |
webrtc: advertise end-of-candidate with an empty candidate string
Just like what is done in the browsers. When this is sent to the peer,
they will be able to know that no more candidates are coming and can
complete ICE.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4598>
-rw-r--r-- | subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 93 | ||||
-rw-r--r-- | subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c | 61 |
2 files changed, 138 insertions, 16 deletions
diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c index 4e9cd2e7f5..c235b5ac81 100644 --- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c +++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c @@ -821,6 +821,30 @@ _find_transport_for_session (GstWebRTCBin * webrtc, guint session_id) return stream; } +static gboolean +match_stream_for_ice_transport (TransportStream * trans, + GstWebRTCICETransport * transport) +{ + return trans->transport && trans->transport->transport == transport; +} + +static TransportStream * +_find_transport_for_ice_transport (GstWebRTCBin * webrtc, + GstWebRTCICETransport * transport) +{ + TransportStream *stream; + + stream = _find_transport (webrtc, transport, + (FindTransportFunc) match_stream_for_ice_transport); + + GST_TRACE_OBJECT (webrtc, + "Found transport %" GST_PTR_FORMAT " for ice transport %" GST_PTR_FORMAT, + stream, transport); + + return stream; +} + + typedef gboolean (*FindPadFunc) (GstWebRTCBinPad * p1, gconstpointer data); static GstWebRTCBinPad * @@ -1601,13 +1625,6 @@ _update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data) return NULL; } -static void -_update_ice_gathering_state (GstWebRTCBin * webrtc) -{ - gst_webrtc_bin_enqueue_task (webrtc, _update_ice_gathering_state_task, NULL, - NULL, NULL); -} - static GstStructure * _update_ice_connection_state_task (GstWebRTCBin * webrtc, gpointer data) { @@ -2117,10 +2134,26 @@ _on_ice_transport_notify_state (GstWebRTCICETransport * transport, } static void +_on_local_ice_candidate_cb (GstWebRTCICE * ice, guint session_id, + gchar * candidate, GstWebRTCBin * webrtc); + +static void _on_ice_transport_notify_gathering_state (GstWebRTCICETransport * transport, GParamSpec * pspec, GstWebRTCBin * webrtc) { - _update_ice_gathering_state (webrtc); + GstWebRTCICEGatheringState ice_state; + + g_object_get (transport, "gathering-state", &ice_state, NULL); + if (ice_state == GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) { + TransportStream *stream = + _find_transport_for_ice_transport (webrtc, transport); + /* signal end-of-candidates */ + _on_local_ice_candidate_cb (webrtc->priv->ice, stream->session_id, + (char *) "", webrtc); + } + + gst_webrtc_bin_enqueue_task (webrtc, _update_ice_gathering_state_task, NULL, + NULL, NULL); } static void @@ -5411,6 +5444,24 @@ _add_ice_candidate_to_sdp (GstWebRTCBin * webrtc, gst_sdp_media_add_attribute (media, "candidate", candidate + 10); } +static void +_add_end_of_candidate_to_sdp (GstWebRTCBin * webrtc, + GstSDPMessage * sdp, gint mline_index) +{ + GstSDPMedia *media = NULL; + + if (mline_index < sdp->medias->len) { + media = &g_array_index (sdp->medias, GstSDPMedia, mline_index); + } + + if (media == NULL) { + GST_WARNING_OBJECT (webrtc, "Couldn't find mline %d to merge ICE candidate", + mline_index); + return; + } + gst_sdp_media_add_attribute (media, "end-of-candidates", ""); +} + static gboolean _filter_sdp_fields (GQuark field_id, const GValue * value, GstStructure * new_structure) @@ -6861,7 +6912,7 @@ _on_local_ice_candidate_task (GstWebRTCBin * webrtc) IceCandidateItem *item = &g_array_index (items, IceCandidateItem, i); const gchar *cand = item->candidate; - if (!g_ascii_strncasecmp (cand, "a=candidate:", 12)) { + if (cand && !g_ascii_strncasecmp (cand, "a=candidate:", 12)) { /* stripping away "a=" */ cand += 2; } @@ -6876,12 +6927,24 @@ _on_local_ice_candidate_task (GstWebRTCBin * webrtc) * FIXME: This ICE candidate should be stored somewhere with * the associated mid and also merged back into any subsequent * local descriptions on renegotiation */ - if (webrtc->current_local_description) - _add_ice_candidate_to_sdp (webrtc, webrtc->current_local_description->sdp, - item->mlineindex, cand); - if (webrtc->pending_local_description) - _add_ice_candidate_to_sdp (webrtc, webrtc->pending_local_description->sdp, - item->mlineindex, cand); + if (webrtc->current_local_description) { + if (cand && cand[0] != '\0') { + _add_ice_candidate_to_sdp (webrtc, + webrtc->current_local_description->sdp, item->mlineindex, cand); + } else { + _add_end_of_candidate_to_sdp (webrtc, + webrtc->current_local_description->sdp, item->mlineindex); + } + } + if (webrtc->pending_local_description) { + if (cand && cand[0] != '\0') { + _add_ice_candidate_to_sdp (webrtc, + webrtc->pending_local_description->sdp, item->mlineindex, cand); + } else { + _add_end_of_candidate_to_sdp (webrtc, + webrtc->pending_local_description->sdp, item->mlineindex); + } + } PC_UNLOCK (webrtc); g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_ICE_CANDIDATE_SIGNAL], diff --git a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c index 617dee57c6..0b09ca0e9f 100644 --- a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c +++ b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c @@ -845,7 +845,7 @@ test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t) g_mutex_lock (&t->lock); g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL); g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL); - while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE && + while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE || ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) { g_cond_wait (&t->cond, &t->lock); g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL); @@ -1211,6 +1211,9 @@ _check_ice_port_restriction (struct test_webrtc *t, GstElement * element, guint port_as_int; guint peer_number; + if (!candidate || candidate[0] == '\0') + return; + regex = g_regex_new ("candidate:(\\d+) (1) (UDP|TCP) (\\d+) ([0-9.]+|[0-9a-f:]+)" " (\\d+) typ ([a-z]+)", 0, 0, NULL); @@ -5708,6 +5711,61 @@ GST_START_TEST (test_msid) GST_END_TEST; +static void +_check_ice_end_of_candidates (struct test_webrtc *t, GstElement * element, + guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data) +{ + gint *end_count = user_data; + + if (!candidate || candidate[0] == '\0') { + g_atomic_int_inc (end_count); + } +} + +static void +sdp_media_has_end_of_candidates (struct test_webrtc *t, GstElement * element, + GstWebRTCSessionDescription * desc, gpointer 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); + + fail_unless_equals_string (gst_sdp_media_get_attribute_val_n (media, + "end-of-candidates", 0), ""); + + fail_unless (gst_sdp_media_get_attribute_val_n (media, "end-of-candidates", + 1) == NULL); + } +} + +GST_START_TEST (test_ice_end_of_candidates) +{ + struct test_webrtc *t = create_audio_test (); + GstWebRTCSessionDescription *local_desc; + gint end_candidate_count = 0; + + VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL); + VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL); + + + t->on_ice_candidate = _check_ice_end_of_candidates; + t->ice_candidate_data = &end_candidate_count; + test_validate_sdp (t, &offer, &answer); + + test_webrtc_wait_for_ice_gathering_complete (t); + + fail_unless_equals_int (end_candidate_count, 2); + + g_object_get (t->webrtc1, "current-local-description", &local_desc, NULL); + sdp_media_has_end_of_candidates (t, t->webrtc1, local_desc, NULL); + gst_webrtc_session_description_free (local_desc); + + test_webrtc_free (t); +} + +GST_END_TEST; + static Suite * webrtcbin_suite (void) { @@ -5773,6 +5831,7 @@ webrtcbin_suite (void) tcase_add_test (tc, test_invalid_add_media_in_answer); tcase_add_test (tc, test_add_turn_server); tcase_add_test (tc, test_msid); + tcase_add_test (tc, test_ice_end_of_candidates); if (sctpenc && sctpdec) { tcase_add_test (tc, test_data_channel_create); tcase_add_test (tc, test_data_channel_remote_notify); |