mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-30 07:42:32 +00:00
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>
This commit is contained in:
parent
5e45a1b1bd
commit
b10ec569d7
2 changed files with 138 additions and 16 deletions
|
@ -821,6 +821,30 @@ _find_transport_for_session (GstWebRTCBin * webrtc, guint session_id)
|
||||||
return stream;
|
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);
|
typedef gboolean (*FindPadFunc) (GstWebRTCBinPad * p1, gconstpointer data);
|
||||||
|
|
||||||
static GstWebRTCBinPad *
|
static GstWebRTCBinPad *
|
||||||
|
@ -1601,13 +1625,6 @@ _update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data)
|
||||||
return NULL;
|
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 *
|
static GstStructure *
|
||||||
_update_ice_connection_state_task (GstWebRTCBin * webrtc, gpointer data)
|
_update_ice_connection_state_task (GstWebRTCBin * webrtc, gpointer data)
|
||||||
{
|
{
|
||||||
|
@ -2116,11 +2133,27 @@ _on_ice_transport_notify_state (GstWebRTCICETransport * transport,
|
||||||
_update_peer_connection_state (webrtc);
|
_update_peer_connection_state (webrtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_local_ice_candidate_cb (GstWebRTCICE * ice, guint session_id,
|
||||||
|
gchar * candidate, GstWebRTCBin * webrtc);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_on_ice_transport_notify_gathering_state (GstWebRTCICETransport * transport,
|
_on_ice_transport_notify_gathering_state (GstWebRTCICETransport * transport,
|
||||||
GParamSpec * pspec, GstWebRTCBin * webrtc)
|
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
|
static void
|
||||||
|
@ -5411,6 +5444,24 @@ _add_ice_candidate_to_sdp (GstWebRTCBin * webrtc,
|
||||||
gst_sdp_media_add_attribute (media, "candidate", candidate + 10);
|
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
|
static gboolean
|
||||||
_filter_sdp_fields (GQuark field_id, const GValue * value,
|
_filter_sdp_fields (GQuark field_id, const GValue * value,
|
||||||
GstStructure * new_structure)
|
GstStructure * new_structure)
|
||||||
|
@ -6861,7 +6912,7 @@ _on_local_ice_candidate_task (GstWebRTCBin * webrtc)
|
||||||
IceCandidateItem *item = &g_array_index (items, IceCandidateItem, i);
|
IceCandidateItem *item = &g_array_index (items, IceCandidateItem, i);
|
||||||
const gchar *cand = item->candidate;
|
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=" */
|
/* stripping away "a=" */
|
||||||
cand += 2;
|
cand += 2;
|
||||||
}
|
}
|
||||||
|
@ -6876,12 +6927,24 @@ _on_local_ice_candidate_task (GstWebRTCBin * webrtc)
|
||||||
* FIXME: This ICE candidate should be stored somewhere with
|
* FIXME: This ICE candidate should be stored somewhere with
|
||||||
* the associated mid and also merged back into any subsequent
|
* the associated mid and also merged back into any subsequent
|
||||||
* local descriptions on renegotiation */
|
* local descriptions on renegotiation */
|
||||||
if (webrtc->current_local_description)
|
if (webrtc->current_local_description) {
|
||||||
_add_ice_candidate_to_sdp (webrtc, webrtc->current_local_description->sdp,
|
if (cand && cand[0] != '\0') {
|
||||||
item->mlineindex, cand);
|
_add_ice_candidate_to_sdp (webrtc,
|
||||||
if (webrtc->pending_local_description)
|
webrtc->current_local_description->sdp, item->mlineindex, cand);
|
||||||
_add_ice_candidate_to_sdp (webrtc, webrtc->pending_local_description->sdp,
|
} else {
|
||||||
item->mlineindex, cand);
|
_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);
|
PC_UNLOCK (webrtc);
|
||||||
g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_ICE_CANDIDATE_SIGNAL],
|
g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_ICE_CANDIDATE_SIGNAL],
|
||||||
|
|
|
@ -845,7 +845,7 @@ test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
|
||||||
g_mutex_lock (&t->lock);
|
g_mutex_lock (&t->lock);
|
||||||
g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
|
g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
|
||||||
g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, 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) {
|
ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
|
||||||
g_cond_wait (&t->cond, &t->lock);
|
g_cond_wait (&t->cond, &t->lock);
|
||||||
g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
|
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 port_as_int;
|
||||||
guint peer_number;
|
guint peer_number;
|
||||||
|
|
||||||
|
if (!candidate || candidate[0] == '\0')
|
||||||
|
return;
|
||||||
|
|
||||||
regex =
|
regex =
|
||||||
g_regex_new ("candidate:(\\d+) (1) (UDP|TCP) (\\d+) ([0-9.]+|[0-9a-f:]+)"
|
g_regex_new ("candidate:(\\d+) (1) (UDP|TCP) (\\d+) ([0-9.]+|[0-9a-f:]+)"
|
||||||
" (\\d+) typ ([a-z]+)", 0, 0, NULL);
|
" (\\d+) typ ([a-z]+)", 0, 0, NULL);
|
||||||
|
@ -5708,6 +5711,61 @@ GST_START_TEST (test_msid)
|
||||||
|
|
||||||
GST_END_TEST;
|
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 *
|
static Suite *
|
||||||
webrtcbin_suite (void)
|
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_invalid_add_media_in_answer);
|
||||||
tcase_add_test (tc, test_add_turn_server);
|
tcase_add_test (tc, test_add_turn_server);
|
||||||
tcase_add_test (tc, test_msid);
|
tcase_add_test (tc, test_msid);
|
||||||
|
tcase_add_test (tc, test_ice_end_of_candidates);
|
||||||
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…
Reference in a new issue