mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
webrtc/datachannel: fix support for prenegotiated channels
With prenegotiated channels, the data-channel protocol is not used and instead the channel's negotiation is intended to be performed out of band in some application-specific manner. Comes with test!
This commit is contained in:
parent
7bf18ad258
commit
21bf3a35ac
2 changed files with 108 additions and 4 deletions
|
@ -46,8 +46,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||||
#define gst_webrtc_data_channel_parent_class parent_class
|
#define gst_webrtc_data_channel_parent_class parent_class
|
||||||
G_DEFINE_TYPE_WITH_CODE (GstWebRTCDataChannel, gst_webrtc_data_channel,
|
G_DEFINE_TYPE_WITH_CODE (GstWebRTCDataChannel, gst_webrtc_data_channel,
|
||||||
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_data_channel_debug,
|
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_data_channel_debug,
|
||||||
"webrtcdatachannel", 0, "webrtcdatachannel");
|
"webrtcdatachannel", 0, "webrtcdatachannel"););
|
||||||
);
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -844,7 +843,8 @@ gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
g_return_if_fail (!channel->negotiated && channel->opened);
|
if (!channel->negotiated)
|
||||||
|
g_return_if_fail (channel->opened);
|
||||||
g_return_if_fail (channel->sctp_transport != NULL);
|
g_return_if_fail (channel->sctp_transport != NULL);
|
||||||
|
|
||||||
if (!str) {
|
if (!str) {
|
||||||
|
@ -893,6 +893,28 @@ gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_sctp_notify_state_unlocked (GObject * sctp_transport,
|
||||||
|
GstWebRTCDataChannel * channel)
|
||||||
|
{
|
||||||
|
GstWebRTCSCTPTransportState state;
|
||||||
|
|
||||||
|
g_object_get (sctp_transport, "state", &state, NULL);
|
||||||
|
if (state == GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED) {
|
||||||
|
if (channel->negotiated)
|
||||||
|
_channel_enqueue_task (channel, (ChannelTask) _emit_on_open, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_sctp_notify_state (GObject * sctp_transport, GParamSpec * pspec,
|
||||||
|
GstWebRTCDataChannel * channel)
|
||||||
|
{
|
||||||
|
GST_OBJECT_LOCK (channel);
|
||||||
|
_on_sctp_notify_state_unlocked (sctp_transport, channel);
|
||||||
|
GST_OBJECT_UNLOCK (channel);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_webrtc_data_channel_set_sctp_transport (GstWebRTCDataChannel * channel,
|
gst_webrtc_data_channel_set_sctp_transport (GstWebRTCDataChannel * channel,
|
||||||
GstWebRTCSCTPTransport * sctp)
|
GstWebRTCSCTPTransport * sctp)
|
||||||
|
@ -907,9 +929,13 @@ gst_webrtc_data_channel_set_sctp_transport (GstWebRTCDataChannel * channel,
|
||||||
gst_object_replace ((GstObject **) & channel->sctp_transport,
|
gst_object_replace ((GstObject **) & channel->sctp_transport,
|
||||||
GST_OBJECT (sctp));
|
GST_OBJECT (sctp));
|
||||||
|
|
||||||
if (sctp)
|
if (sctp) {
|
||||||
g_signal_connect (sctp, "stream-reset", G_CALLBACK (_on_sctp_reset_stream),
|
g_signal_connect (sctp, "stream-reset", G_CALLBACK (_on_sctp_reset_stream),
|
||||||
channel);
|
channel);
|
||||||
|
g_signal_connect (sctp, "notify::state", G_CALLBACK (_on_sctp_notify_state),
|
||||||
|
channel);
|
||||||
|
_on_sctp_notify_state_unlocked (G_OBJECT (sctp), channel);
|
||||||
|
}
|
||||||
GST_OBJECT_UNLOCK (channel);
|
GST_OBJECT_UNLOCK (channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1993,6 +1993,83 @@ GST_START_TEST (test_data_channel_max_message_size)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_ready_state_notify (GObject * channel, GParamSpec * pspec,
|
||||||
|
struct test_webrtc *t)
|
||||||
|
{
|
||||||
|
gint *n_ready = t->data_channel_data;
|
||||||
|
GstWebRTCDataChannelState ready_state;
|
||||||
|
|
||||||
|
g_object_get (channel, "ready-state", &ready_state, NULL);
|
||||||
|
|
||||||
|
if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
|
||||||
|
if (++(*n_ready) >= 2)
|
||||||
|
test_webrtc_signal_state (t, STATE_CUSTOM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_data_channel_pre_negotiated)
|
||||||
|
{
|
||||||
|
struct test_webrtc *t = test_webrtc_new ();
|
||||||
|
GObject *channel1 = NULL, *channel2 = NULL;
|
||||||
|
struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
|
||||||
|
struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
|
||||||
|
GstStructure *s;
|
||||||
|
gint n_ready = 0;
|
||||||
|
|
||||||
|
t->on_negotiation_needed = NULL;
|
||||||
|
t->offer_data = &offer;
|
||||||
|
t->on_offer_created = validate_sdp;
|
||||||
|
t->answer_data = &answer;
|
||||||
|
t->on_answer_created = validate_sdp;
|
||||||
|
t->on_ice_candidate = NULL;
|
||||||
|
|
||||||
|
fail_if (gst_element_set_state (t->webrtc1,
|
||||||
|
GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
|
||||||
|
fail_if (gst_element_set_state (t->webrtc2,
|
||||||
|
GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
|
||||||
|
|
||||||
|
s = gst_structure_new ("application/data-channel", "negotiated",
|
||||||
|
G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
|
||||||
|
|
||||||
|
g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
|
||||||
|
&channel1);
|
||||||
|
g_assert_nonnull (channel1);
|
||||||
|
g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
|
||||||
|
&channel2);
|
||||||
|
g_assert_nonnull (channel2);
|
||||||
|
|
||||||
|
fail_if (gst_element_set_state (t->webrtc1,
|
||||||
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
|
||||||
|
fail_if (gst_element_set_state (t->webrtc2,
|
||||||
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
|
||||||
|
|
||||||
|
test_webrtc_create_offer (t, t->webrtc1);
|
||||||
|
test_webrtc_wait_for_answer_error_eos (t);
|
||||||
|
fail_unless (t->state == STATE_ANSWER_CREATED);
|
||||||
|
|
||||||
|
t->data_channel_data = &n_ready;
|
||||||
|
|
||||||
|
g_signal_connect (channel1, "notify::ready-state",
|
||||||
|
G_CALLBACK (_on_ready_state_notify), t);
|
||||||
|
g_signal_connect (channel2, "notify::ready-state",
|
||||||
|
G_CALLBACK (_on_ready_state_notify), t);
|
||||||
|
|
||||||
|
test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
|
||||||
|
test_webrtc_signal_state (t, STATE_NEW);
|
||||||
|
|
||||||
|
have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
|
||||||
|
|
||||||
|
test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
|
||||||
|
|
||||||
|
g_object_unref (channel1);
|
||||||
|
g_object_unref (channel2);
|
||||||
|
gst_structure_free (s);
|
||||||
|
test_webrtc_free (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
webrtcbin_suite (void)
|
webrtcbin_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -2032,6 +2109,7 @@ webrtcbin_suite (void)
|
||||||
tcase_add_test (tc, test_data_channel_create_after_negotiate);
|
tcase_add_test (tc, test_data_channel_create_after_negotiate);
|
||||||
tcase_add_test (tc, test_data_channel_low_threshold);
|
tcase_add_test (tc, test_data_channel_low_threshold);
|
||||||
tcase_add_test (tc, test_data_channel_max_message_size);
|
tcase_add_test (tc, test_data_channel_max_message_size);
|
||||||
|
tcase_add_test (tc, test_data_channel_pre_negotiated);
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING ("Some required elements were not found. "
|
GST_WARNING ("Some required elements were not found. "
|
||||||
"All datachannel are disabled. sctpenc %p, sctpdec %p", sctpenc,
|
"All datachannel are disabled. sctpenc %p, sctpdec %p", sctpenc,
|
||||||
|
|
Loading…
Reference in a new issue