3 * Unit tests for webrtcbin
5 * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
29 #include <gst/check/gstcheck.h>
30 #include <gst/check/gstharness.h>
31 #include <gst/webrtc/webrtc.h>
32 #include "../../../ext/webrtc/webrtcsdp.h"
33 #include "../../../ext/webrtc/webrtcsdp.c"
34 #include "../../../ext/webrtc/utils.h"
35 #include "../../../ext/webrtc/utils.c"
37 #define OPUS_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=OPUS,media=audio,clock-rate=48000,ssrc=(uint)3384078950"
38 #define VP8_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=VP8,media=video,clock-rate=90000,ssrc=(uint)3484078950"
43 STATE_NEGOTIATION_NEEDED,
51 /* basic premise of this is that webrtc1 and webrtc2 are attempting to connect
52 * to each other in various configurations */
68 GDestroyNotify data_notify;
70 void (*on_negotiation_needed) (struct test_webrtc * t,
73 gpointer negotiation_data;
74 GDestroyNotify negotiation_notify;
75 void (*on_ice_candidate) (struct test_webrtc * t,
81 gpointer ice_candidate_data;
82 GDestroyNotify ice_candidate_notify;
83 GstWebRTCSessionDescription * (*on_offer_created) (struct test_webrtc * t,
88 GDestroyNotify offer_notify;
89 GstWebRTCSessionDescription * (*on_answer_created) (struct test_webrtc * t,
93 gpointer data_channel_data;
94 GDestroyNotify data_channel_notify;
95 void (*on_data_channel) (struct test_webrtc * t,
97 GObject *data_channel,
100 GDestroyNotify answer_notify;
101 void (*on_pad_added) (struct test_webrtc * t,
102 GstElement * element,
105 gpointer pad_added_data;
106 GDestroyNotify pad_added_notify;
107 void (*bus_message) (struct test_webrtc * t,
112 GDestroyNotify bus_notify;
117 _on_answer_received (GstPromise * promise, gpointer user_data)
119 struct test_webrtc *t = user_data;
120 GstElement *offeror = t->offerror == 1 ? t->webrtc1 : t->webrtc2;
121 GstElement *answerer = t->offerror == 2 ? t->webrtc1 : t->webrtc2;
122 const GstStructure *reply;
123 GstWebRTCSessionDescription *answer = NULL;
126 reply = gst_promise_get_reply (promise);
127 gst_structure_get (reply, "answer",
128 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
129 desc = gst_sdp_message_as_text (answer->sdp);
130 GST_INFO ("Created Answer: %s", desc);
133 g_mutex_lock (&t->lock);
134 if (t->on_answer_created) {
135 gst_webrtc_session_description_free (answer);
136 answer = t->on_answer_created (t, answerer, promise, t->answer_data);
138 gst_promise_unref (promise);
140 g_signal_emit_by_name (answerer, "set-local-description", answer, NULL);
141 g_signal_emit_by_name (offeror, "set-remote-description", answer, NULL);
143 t->state = STATE_ANSWER_CREATED;
144 g_cond_broadcast (&t->cond);
145 g_mutex_unlock (&t->lock);
147 gst_webrtc_session_description_free (answer);
151 _on_offer_received (GstPromise * promise, gpointer user_data)
153 struct test_webrtc *t = user_data;
154 GstElement *offeror = t->offerror == 1 ? t->webrtc1 : t->webrtc2;
155 GstElement *answerer = t->offerror == 2 ? t->webrtc1 : t->webrtc2;
156 const GstStructure *reply;
157 GstWebRTCSessionDescription *offer = NULL;
160 reply = gst_promise_get_reply (promise);
161 gst_structure_get (reply, "offer",
162 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
163 desc = gst_sdp_message_as_text (offer->sdp);
164 GST_INFO ("Created offer: %s", desc);
167 g_mutex_lock (&t->lock);
168 if (t->on_offer_created) {
169 gst_webrtc_session_description_free (offer);
170 offer = t->on_offer_created (t, offeror, promise, t->offer_data);
172 gst_promise_unref (promise);
174 g_signal_emit_by_name (offeror, "set-local-description", offer, NULL);
175 g_signal_emit_by_name (answerer, "set-remote-description", offer, NULL);
177 promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
178 g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
180 t->state = STATE_OFFER_CREATED;
181 g_cond_broadcast (&t->cond);
182 g_mutex_unlock (&t->lock);
184 gst_webrtc_session_description_free (offer);
188 _bus_watch (GstBus * bus, GstMessage * msg, struct test_webrtc *t)
190 g_mutex_lock (&t->lock);
191 switch (GST_MESSAGE_TYPE (msg)) {
192 case GST_MESSAGE_STATE_CHANGED:
193 if (GST_ELEMENT (msg->src) == t->webrtc1
194 || GST_ELEMENT (msg->src) == t->webrtc2) {
195 GstState old, new, pending;
197 gst_message_parse_state_changed (msg, &old, &new, &pending);
200 gchar *dump_name = g_strconcat ("%s-state_changed-",
201 GST_OBJECT_NAME (msg->src), gst_element_state_get_name (old), "_",
202 gst_element_state_get_name (new), NULL);
203 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
204 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
209 case GST_MESSAGE_ERROR:{
211 gchar *dbg_info = NULL;
216 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc1), NULL);
217 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
218 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
221 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc2), NULL);
222 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
223 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
227 gst_message_parse_error (msg, &err, &dbg_info);
228 GST_WARNING ("ERROR from element %s: %s\n",
229 GST_OBJECT_NAME (msg->src), err->message);
230 GST_WARNING ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
233 t->state = STATE_ERROR;
234 g_cond_broadcast (&t->cond);
237 case GST_MESSAGE_EOS:{
240 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc1), NULL);
241 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
242 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
244 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc2), NULL);
245 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
246 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
249 GST_INFO ("EOS received\n");
250 t->state = STATE_EOS;
251 g_cond_broadcast (&t->cond);
259 t->bus_message (t, bus, msg, t->bus_data);
260 g_mutex_unlock (&t->lock);
266 _on_negotiation_needed (GstElement * webrtc, struct test_webrtc *t)
268 g_mutex_lock (&t->lock);
269 if (t->on_negotiation_needed)
270 t->on_negotiation_needed (t, webrtc, t->negotiation_data);
271 if (t->state == STATE_NEW)
272 t->state = STATE_NEGOTIATION_NEEDED;
273 g_cond_broadcast (&t->cond);
274 g_mutex_unlock (&t->lock);
278 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
279 struct test_webrtc *t)
283 g_mutex_lock (&t->lock);
284 other = webrtc == t->webrtc1 ? t->webrtc2 : t->webrtc1;
286 if (t->on_ice_candidate)
287 t->on_ice_candidate (t, webrtc, mlineindex, candidate, other,
288 t->ice_candidate_data);
290 g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
291 g_mutex_unlock (&t->lock);
295 _on_pad_added (GstElement * webrtc, GstPad * new_pad, struct test_webrtc *t)
297 g_mutex_lock (&t->lock);
299 t->on_pad_added (t, webrtc, new_pad, t->pad_added_data);
300 g_mutex_unlock (&t->lock);
304 _on_data_channel (GstElement * webrtc, GObject * data_channel,
305 struct test_webrtc *t)
307 g_mutex_lock (&t->lock);
308 if (t->on_data_channel)
309 t->on_data_channel (t, webrtc, data_channel, t->data_channel_data);
310 g_mutex_unlock (&t->lock);
314 _pad_added_not_reached (struct test_webrtc *t, GstElement * element,
315 GstPad * pad, gpointer user_data)
317 g_assert_not_reached ();
321 _ice_candidate_not_reached (struct test_webrtc *t, GstElement * element,
322 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
324 g_assert_not_reached ();
328 _negotiation_not_reached (struct test_webrtc *t, GstElement * element,
331 g_assert_not_reached ();
335 _bus_no_errors (struct test_webrtc *t, GstBus * bus, GstMessage * msg,
338 switch (GST_MESSAGE_TYPE (msg)) {
339 case GST_MESSAGE_ERROR:{
340 g_assert_not_reached ();
348 static GstWebRTCSessionDescription *
349 _offer_answer_not_reached (struct test_webrtc *t, GstElement * element,
350 GstPromise * promise, gpointer user_data)
352 g_assert_not_reached ();
356 _on_data_channel_not_reached (struct test_webrtc *t, GstElement * element,
357 GObject * data_channel, gpointer user_data)
359 g_assert_not_reached ();
363 _broadcast (struct test_webrtc *t)
365 g_mutex_lock (&t->lock);
366 g_cond_broadcast (&t->cond);
367 g_mutex_unlock (&t->lock);
371 _unlock_create_thread (GMutex * lock)
373 g_mutex_unlock (lock);
374 return G_SOURCE_REMOVE;
378 _bus_thread (struct test_webrtc *t)
380 g_mutex_lock (&t->lock);
381 t->loop = g_main_loop_new (NULL, FALSE);
382 g_idle_add ((GSourceFunc) _unlock_create_thread, &t->lock);
383 g_cond_broadcast (&t->cond);
385 g_main_loop_run (t->loop);
387 g_mutex_lock (&t->lock);
388 g_main_loop_unref (t->loop);
390 g_cond_broadcast (&t->cond);
391 g_mutex_unlock (&t->lock);
397 element_added_disable_sync (GstBin * bin, GstBin * sub_bin,
398 GstElement * element, gpointer user_data)
400 GObjectClass *class = G_OBJECT_GET_CLASS (element);
401 if (g_object_class_find_property (class, "async"))
402 g_object_set (element, "async", FALSE, NULL);
403 if (g_object_class_find_property (class, "sync"))
404 g_object_set (element, "sync", FALSE, NULL);
407 static struct test_webrtc *
408 test_webrtc_new (void)
410 struct test_webrtc *ret = g_new0 (struct test_webrtc, 1);
412 ret->on_negotiation_needed = _negotiation_not_reached;
413 ret->on_ice_candidate = _ice_candidate_not_reached;
414 ret->on_pad_added = _pad_added_not_reached;
415 ret->on_offer_created = _offer_answer_not_reached;
416 ret->on_answer_created = _offer_answer_not_reached;
417 ret->on_data_channel = _on_data_channel_not_reached;
418 ret->bus_message = _bus_no_errors;
420 g_mutex_init (&ret->lock);
421 g_cond_init (&ret->cond);
423 ret->bus1 = gst_bus_new ();
424 ret->bus2 = gst_bus_new ();
425 gst_bus_add_watch (ret->bus1, (GstBusFunc) _bus_watch, ret);
426 gst_bus_add_watch (ret->bus2, (GstBusFunc) _bus_watch, ret);
427 ret->webrtc1 = gst_element_factory_make ("webrtcbin", NULL);
428 ret->webrtc2 = gst_element_factory_make ("webrtcbin", NULL);
429 fail_unless (ret->webrtc1 != NULL && ret->webrtc2 != NULL);
431 gst_element_set_bus (ret->webrtc1, ret->bus1);
432 gst_element_set_bus (ret->webrtc2, ret->bus2);
434 g_signal_connect (ret->webrtc1, "deep-element-added",
435 G_CALLBACK (element_added_disable_sync), NULL);
436 g_signal_connect (ret->webrtc2, "deep-element-added",
437 G_CALLBACK (element_added_disable_sync), NULL);
438 g_signal_connect (ret->webrtc1, "on-negotiation-needed",
439 G_CALLBACK (_on_negotiation_needed), ret);
440 g_signal_connect (ret->webrtc2, "on-negotiation-needed",
441 G_CALLBACK (_on_negotiation_needed), ret);
442 g_signal_connect (ret->webrtc1, "on-ice-candidate",
443 G_CALLBACK (_on_ice_candidate), ret);
444 g_signal_connect (ret->webrtc2, "on-ice-candidate",
445 G_CALLBACK (_on_ice_candidate), ret);
446 g_signal_connect (ret->webrtc1, "on-data-channel",
447 G_CALLBACK (_on_data_channel), ret);
448 g_signal_connect (ret->webrtc2, "on-data-channel",
449 G_CALLBACK (_on_data_channel), ret);
450 g_signal_connect (ret->webrtc1, "pad-added", G_CALLBACK (_on_pad_added), ret);
451 g_signal_connect (ret->webrtc2, "pad-added", G_CALLBACK (_on_pad_added), ret);
452 g_signal_connect_swapped (ret->webrtc1, "notify::ice-gathering-state",
453 G_CALLBACK (_broadcast), ret);
454 g_signal_connect_swapped (ret->webrtc2, "notify::ice-gathering-state",
455 G_CALLBACK (_broadcast), ret);
456 g_signal_connect_swapped (ret->webrtc1, "notify::ice-connection-state",
457 G_CALLBACK (_broadcast), ret);
458 g_signal_connect_swapped (ret->webrtc2, "notify::ice-connection-state",
459 G_CALLBACK (_broadcast), ret);
461 ret->thread = g_thread_new ("test-webrtc", (GThreadFunc) _bus_thread, ret);
463 g_mutex_lock (&ret->lock);
465 g_cond_wait (&ret->cond, &ret->lock);
466 g_mutex_unlock (&ret->lock);
472 test_webrtc_free (struct test_webrtc *t)
474 /* Otherwise while one webrtcbin is being destroyed, the other could
475 * generate a signal that calls into the destroyed webrtcbin */
476 g_signal_handlers_disconnect_by_data (t->webrtc1, t);
477 g_signal_handlers_disconnect_by_data (t->webrtc2, t);
479 g_main_loop_quit (t->loop);
480 g_mutex_lock (&t->lock);
482 g_cond_wait (&t->cond, &t->lock);
483 g_mutex_unlock (&t->lock);
485 g_thread_join (t->thread);
487 gst_bus_remove_watch (t->bus1);
488 gst_bus_remove_watch (t->bus2);
490 gst_bus_set_flushing (t->bus1, TRUE);
491 gst_bus_set_flushing (t->bus2, TRUE);
493 gst_object_unref (t->bus1);
494 gst_object_unref (t->bus2);
496 g_list_free_full (t->harnesses, (GDestroyNotify) gst_harness_teardown);
499 t->data_notify (t->user_data);
500 if (t->negotiation_notify)
501 t->negotiation_notify (t->negotiation_data);
502 if (t->ice_candidate_notify)
503 t->ice_candidate_notify (t->ice_candidate_data);
505 t->offer_notify (t->offer_data);
506 if (t->answer_notify)
507 t->answer_notify (t->answer_data);
508 if (t->pad_added_notify)
509 t->pad_added_notify (t->pad_added_data);
510 if (t->data_channel_notify)
511 t->data_channel_notify (t->data_channel_data);
513 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
514 gst_element_set_state (t->webrtc1, GST_STATE_NULL));
515 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
516 gst_element_set_state (t->webrtc2, GST_STATE_NULL));
518 gst_object_unref (t->webrtc1);
519 gst_object_unref (t->webrtc2);
521 g_mutex_clear (&t->lock);
522 g_cond_clear (&t->cond);
528 test_webrtc_create_offer (struct test_webrtc *t, GstElement * webrtc)
532 t->offerror = webrtc == t->webrtc1 ? 1 : 2;
533 promise = gst_promise_new_with_change_func (_on_offer_received, t, NULL);
534 g_signal_emit_by_name (webrtc, "create-offer", NULL, promise);
538 test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
540 g_mutex_lock (&t->lock);
541 while (((1 << t->state) & state) == 0) {
542 GST_INFO ("test state 0x%x, current 0x%x", state, (1 << t->state));
543 g_cond_wait (&t->cond, &t->lock);
545 GST_INFO ("have test state 0x%x, current 0x%x", state, 1 << t->state);
546 g_mutex_unlock (&t->lock);
550 test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t)
552 TestState states = 0;
553 states |= (1 << STATE_ANSWER_CREATED);
554 states |= (1 << STATE_EOS);
555 states |= (1 << STATE_ERROR);
556 test_webrtc_wait_for_state_mask (t, states);
560 test_webrtc_signal_state_unlocked (struct test_webrtc *t, TestState state)
563 g_cond_broadcast (&t->cond);
567 test_webrtc_signal_state (struct test_webrtc *t, TestState state)
569 g_mutex_lock (&t->lock);
570 test_webrtc_signal_state_unlocked (t, state);
571 g_mutex_unlock (&t->lock);
576 test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
578 GstWebRTCICEGatheringState ice_state1, ice_state2;
579 g_mutex_lock (&t->lock);
580 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
581 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
582 while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE &&
583 ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
584 g_cond_wait (&t->cond, &t->lock);
585 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
586 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
588 g_mutex_unlock (&t->lock);
592 test_webrtc_wait_for_ice_connection (struct test_webrtc *t,
593 GstWebRTCICEConnectionState states)
595 GstWebRTCICEConnectionState ice_state1, ice_state2, current;
596 g_mutex_lock (&t->lock);
597 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
598 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
599 current = (1 << ice_state1) | (1 << ice_state2);
600 while ((current & states) == 0 || (current & ~states)) {
601 g_cond_wait (&t->cond, &t->lock);
602 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
603 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
604 current = (1 << ice_state1) | (1 << ice_state2);
606 g_mutex_unlock (&t->lock);
610 _pad_added_fakesink (struct test_webrtc *t, GstElement * element,
611 GstPad * pad, gpointer user_data)
615 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
618 h = gst_harness_new_with_element (element, NULL, "src_%u");
619 gst_harness_add_sink_parse (h, "fakesink async=false sync=false");
621 t->harnesses = g_list_prepend (t->harnesses, h);
625 _count_num_sdp_media (struct test_webrtc *t, GstElement * element,
626 GstWebRTCSessionDescription * desc, gpointer user_data)
628 guint expected = GPOINTER_TO_UINT (user_data);
630 fail_unless_equals_int (gst_sdp_message_medias_len (desc->sdp), expected);
633 typedef void (*ValidateSDPFunc) (struct test_webrtc * t, GstElement * element,
634 GstWebRTCSessionDescription * desc, gpointer user_data);
639 ValidateSDPFunc validate;
641 struct validate_sdp *next;
644 static GstWebRTCSessionDescription *
645 _check_validate_sdp (struct test_webrtc *t, GstElement * element,
646 GstPromise * promise, gpointer user_data)
648 struct validate_sdp *validate = user_data;
649 GstWebRTCSessionDescription *offer = NULL;
650 const GstStructure *reply;
653 field = t->offerror == 1 && t->webrtc1 == element ? "offer" : "answer";
655 reply = gst_promise_get_reply (promise);
656 gst_structure_get (reply, field,
657 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
660 validate->validate (t, element, offer, validate->user_data);
661 validate = validate->next;
668 test_validate_sdp (struct test_webrtc *t, struct validate_sdp *offer,
669 struct validate_sdp *answer)
672 t->offer_data = offer;
673 t->on_offer_created = _check_validate_sdp;
675 t->offer_data = NULL;
676 t->on_offer_created = NULL;
679 t->answer_data = answer;
680 t->on_answer_created = _check_validate_sdp;
682 t->answer_data = NULL;
683 t->on_answer_created = NULL;
686 fail_if (gst_element_set_state (t->webrtc1,
687 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
688 fail_if (gst_element_set_state (t->webrtc2,
689 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
691 test_webrtc_create_offer (t, t->webrtc1);
693 test_webrtc_wait_for_answer_error_eos (t);
694 fail_unless (t->state == STATE_ANSWER_CREATED);
697 GST_START_TEST (test_sdp_no_media)
699 struct test_webrtc *t = test_webrtc_new ();
700 struct validate_sdp offer =
701 { _count_num_sdp_media, GUINT_TO_POINTER (0), NULL };
702 struct validate_sdp answer =
703 { _count_num_sdp_media, GUINT_TO_POINTER (0), NULL };
705 /* check that a no stream connection creates 0 media sections */
707 t->on_negotiation_needed = NULL;
708 test_validate_sdp (t, &offer, &answer);
710 test_webrtc_free (t);
716 add_fake_audio_src_harness (GstHarness * h, gint pt)
718 GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
719 GstStructure *s = gst_caps_get_structure (caps, 0);
720 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
721 gst_harness_set_src_caps (h, caps);
722 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
726 add_fake_video_src_harness (GstHarness * h, gint pt)
728 GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
729 GstStructure *s = gst_caps_get_structure (caps, 0);
730 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
731 gst_harness_set_src_caps (h, caps);
732 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
735 static struct test_webrtc *
736 create_audio_test (void)
738 struct test_webrtc *t = test_webrtc_new ();
741 t->on_negotiation_needed = NULL;
742 t->on_ice_candidate = NULL;
743 t->on_pad_added = _pad_added_fakesink;
745 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
746 add_fake_audio_src_harness (h, 96);
747 t->harnesses = g_list_prepend (t->harnesses, h);
752 GST_START_TEST (test_audio)
754 struct test_webrtc *t = create_audio_test ();
755 struct validate_sdp offer =
756 { _count_num_sdp_media, GUINT_TO_POINTER (1), NULL };
757 struct validate_sdp answer =
758 { _count_num_sdp_media, GUINT_TO_POINTER (1), NULL };
760 /* check that a single stream connection creates the associated number
761 * of media sections */
763 test_validate_sdp (t, &offer, &answer);
764 test_webrtc_free (t);
769 static struct test_webrtc *
770 create_audio_video_test (void)
772 struct test_webrtc *t = create_audio_test ();
775 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
776 add_fake_video_src_harness (h, 97);
777 t->harnesses = g_list_prepend (t->harnesses, h);
782 GST_START_TEST (test_audio_video)
784 struct test_webrtc *t = create_audio_video_test ();
785 struct validate_sdp offer =
786 { _count_num_sdp_media, GUINT_TO_POINTER (2), NULL };
787 struct validate_sdp answer =
788 { _count_num_sdp_media, GUINT_TO_POINTER (2), NULL };
790 /* check that a dual stream connection creates the associated number
791 * of media sections */
793 test_validate_sdp (t, &offer, &answer);
794 test_webrtc_free (t);
800 on_sdp_media_direction (struct test_webrtc *t, GstElement * element,
801 GstWebRTCSessionDescription * desc, gpointer user_data)
803 gchar **expected_directions = user_data;
806 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
807 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
809 if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0
810 || g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) {
811 gboolean have_direction = FALSE;
814 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
815 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
817 if (g_strcmp0 (attr->key, "inactive") == 0) {
818 fail_unless (have_direction == FALSE,
819 "duplicate/multiple directions for media %u", j);
820 have_direction = TRUE;
821 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
822 } else if (g_strcmp0 (attr->key, "sendonly") == 0) {
823 fail_unless (have_direction == FALSE,
824 "duplicate/multiple directions for media %u", j);
825 have_direction = TRUE;
826 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
827 } else if (g_strcmp0 (attr->key, "recvonly") == 0) {
828 fail_unless (have_direction == FALSE,
829 "duplicate/multiple directions for media %u", j);
830 have_direction = TRUE;
831 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
832 } else if (g_strcmp0 (attr->key, "sendrecv") == 0) {
833 fail_unless (have_direction == FALSE,
834 "duplicate/multiple directions for media %u", j);
835 have_direction = TRUE;
836 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
839 fail_unless (have_direction, "no direction attribute in media %u", j);
844 GST_START_TEST (test_media_direction)
846 struct test_webrtc *t = create_audio_video_test ();
847 const gchar *expected_offer[] = { "sendrecv", "sendrecv" };
848 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
849 struct validate_sdp offer_direction =
850 { on_sdp_media_direction, expected_offer, NULL };
851 struct validate_sdp offer =
852 { _count_num_sdp_media, GUINT_TO_POINTER (2), &offer_direction };
853 struct validate_sdp answer_direction =
854 { on_sdp_media_direction, expected_answer, NULL };
855 struct validate_sdp answer =
856 { _count_num_sdp_media, GUINT_TO_POINTER (2), &answer_direction };
859 /* check the default media directions for transceivers */
861 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
862 add_fake_audio_src_harness (h, 96);
863 t->harnesses = g_list_prepend (t->harnesses, h);
865 test_validate_sdp (t, &offer, &answer);
866 test_webrtc_free (t);
872 on_sdp_media_payload_types (struct test_webrtc *t, GstElement * element,
873 GstWebRTCSessionDescription * desc, gpointer user_data)
875 const GstSDPMedia *vmedia;
878 vmedia = gst_sdp_message_get_media (desc->sdp, 1);
880 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
881 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
883 if (!g_strcmp0 (attr->key, "rtpmap")) {
884 if (g_str_has_prefix (attr->value, "97")) {
885 fail_unless_equals_string (attr->value, "97 VP8/90000");
886 } else if (g_str_has_prefix (attr->value, "96")) {
887 fail_unless_equals_string (attr->value, "96 red/90000");
888 } else if (g_str_has_prefix (attr->value, "98")) {
889 fail_unless_equals_string (attr->value, "98 ulpfec/90000");
890 } else if (g_str_has_prefix (attr->value, "99")) {
891 fail_unless_equals_string (attr->value, "99 rtx/90000");
892 } else if (g_str_has_prefix (attr->value, "100")) {
893 fail_unless_equals_string (attr->value, "100 rtx/90000");
899 /* In this test we verify that webrtcbin will pick available payload
900 * types when it needs to, in that example for RTX and FEC */
901 GST_START_TEST (test_payload_types)
903 struct test_webrtc *t = create_audio_video_test ();
904 struct validate_sdp payloads = { on_sdp_media_payload_types, NULL, NULL };
905 struct validate_sdp offer =
906 { _count_num_sdp_media, GUINT_TO_POINTER (2), &payloads };
907 GstWebRTCRTPTransceiver *trans;
908 GArray *transceivers;
910 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
911 fail_unless_equals_int (transceivers->len, 2);
912 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
913 g_object_set (trans, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, "do-nack", TRUE,
915 g_array_unref (transceivers);
917 /* We don't really care about the answer here */
918 test_validate_sdp (t, &offer, NULL);
919 test_webrtc_free (t);
925 on_sdp_media_setup (struct test_webrtc *t, GstElement * element,
926 GstWebRTCSessionDescription * desc, gpointer user_data)
928 gchar **expected_setup = user_data;
931 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
932 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
933 gboolean have_setup = FALSE;
936 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
937 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
939 if (g_strcmp0 (attr->key, "setup") == 0) {
940 fail_unless (have_setup == FALSE,
941 "duplicate/multiple setup for media %u", j);
943 fail_unless (g_strcmp0 (attr->value, expected_setup[i]) == 0);
946 fail_unless (have_setup, "no setup attribute in media %u", j);
950 GST_START_TEST (test_media_setup)
952 struct test_webrtc *t = create_audio_test ();
953 const gchar *expected_offer[] = { "actpass" };
954 const gchar *expected_answer[] = { "active" };
955 struct validate_sdp offer = { on_sdp_media_setup, expected_offer, NULL };
956 struct validate_sdp answer = { on_sdp_media_setup, expected_answer, NULL };
958 /* check the default dtls setup negotiation values */
959 test_validate_sdp (t, &offer, &answer);
960 test_webrtc_free (t);
965 GST_START_TEST (test_no_nice_elements_request_pad)
967 struct test_webrtc *t = test_webrtc_new ();
968 GstPluginFeature *nicesrc, *nicesink;
969 GstRegistry *registry;
972 /* check that the absence of libnice elements posts an error on the bus
973 * when requesting a pad */
975 registry = gst_registry_get ();
976 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
977 nicesink = gst_registry_lookup_feature (registry, "nicesink");
980 gst_registry_remove_feature (registry, nicesrc);
982 gst_registry_remove_feature (registry, nicesink);
984 t->bus_message = NULL;
986 pad = gst_element_get_request_pad (t->webrtc1, "sink_0");
987 fail_unless (pad == NULL);
989 test_webrtc_wait_for_answer_error_eos (t);
990 fail_unless_equals_int (STATE_ERROR, t->state);
991 test_webrtc_free (t);
994 gst_registry_add_feature (registry, nicesrc);
996 gst_registry_add_feature (registry, nicesink);
1001 GST_START_TEST (test_no_nice_elements_state_change)
1003 struct test_webrtc *t = test_webrtc_new ();
1004 GstPluginFeature *nicesrc, *nicesink;
1005 GstRegistry *registry;
1007 /* check that the absence of libnice elements posts an error on the bus */
1009 registry = gst_registry_get ();
1010 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1011 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1014 gst_registry_remove_feature (registry, nicesrc);
1016 gst_registry_remove_feature (registry, nicesink);
1018 t->bus_message = NULL;
1019 gst_element_set_state (t->webrtc1, GST_STATE_READY);
1021 test_webrtc_wait_for_answer_error_eos (t);
1022 fail_unless_equals_int (STATE_ERROR, t->state);
1023 test_webrtc_free (t);
1026 gst_registry_add_feature (registry, nicesrc);
1028 gst_registry_add_feature (registry, nicesink);
1034 validate_rtc_stats (const GstStructure * s)
1036 GstWebRTCStatsType type = 0;
1040 fail_unless (gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type,
1042 fail_unless (gst_structure_get (s, "id", G_TYPE_STRING, &id, NULL));
1043 fail_unless (gst_structure_get (s, "timestamp", G_TYPE_DOUBLE, &ts, NULL));
1044 fail_unless (type != 0);
1045 fail_unless (ts != 0.);
1046 fail_unless (id != NULL);
1052 validate_codec_stats (const GstStructure * s)
1054 guint pt = 0, clock_rate = 0;
1056 fail_unless (gst_structure_get (s, "payload-type", G_TYPE_UINT, &pt, NULL));
1057 fail_unless (gst_structure_get (s, "clock-rate", G_TYPE_UINT, &clock_rate,
1059 fail_unless (pt >= 0 && pt <= 127);
1060 fail_unless (clock_rate >= 0);
1064 validate_rtc_stream_stats (const GstStructure * s, const GstStructure * stats)
1066 gchar *codec_id, *transport_id;
1067 GstStructure *codec, *transport;
1069 fail_unless (gst_structure_get (s, "codec-id", G_TYPE_STRING, &codec_id,
1071 fail_unless (gst_structure_get (s, "transport-id", G_TYPE_STRING,
1072 &transport_id, NULL));
1074 fail_unless (gst_structure_get (stats, codec_id, GST_TYPE_STRUCTURE, &codec,
1076 fail_unless (gst_structure_get (stats, transport_id, GST_TYPE_STRUCTURE,
1079 fail_unless (codec != NULL);
1080 fail_unless (transport != NULL);
1082 gst_structure_free (transport);
1083 gst_structure_free (codec);
1086 g_free (transport_id);
1090 validate_inbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1092 guint ssrc, fir, pli, nack;
1094 guint64 packets_received, bytes_received;
1097 GstStructure *remote;
1099 validate_rtc_stream_stats (s, stats);
1101 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1102 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1103 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1104 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1105 fail_unless (gst_structure_get (s, "packets-received", G_TYPE_UINT64,
1106 &packets_received, NULL));
1107 fail_unless (gst_structure_get (s, "bytes-received", G_TYPE_UINT64,
1108 &bytes_received, NULL));
1109 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1110 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1112 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1114 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1116 fail_unless (remote != NULL);
1118 gst_structure_free (remote);
1123 validate_remote_inbound_rtp_stats (const GstStructure * s,
1124 const GstStructure * stats)
1130 GstStructure *local;
1132 validate_rtc_stream_stats (s, stats);
1134 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1135 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1136 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1138 fail_unless (gst_structure_get (s, "round-trip-time", G_TYPE_DOUBLE, &rtt,
1140 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1142 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1144 fail_unless (local != NULL);
1146 gst_structure_free (local);
1151 validate_outbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1153 guint ssrc, fir, pli, nack;
1154 guint64 packets_sent, bytes_sent;
1156 GstStructure *remote;
1158 validate_rtc_stream_stats (s, stats);
1160 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1161 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1162 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1163 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1164 fail_unless (gst_structure_get (s, "packets-sent", G_TYPE_UINT64,
1165 &packets_sent, NULL));
1166 fail_unless (gst_structure_get (s, "bytes-sent", G_TYPE_UINT64, &bytes_sent,
1168 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1170 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1172 fail_unless (remote != NULL);
1174 gst_structure_free (remote);
1179 validate_remote_outbound_rtp_stats (const GstStructure * s,
1180 const GstStructure * stats)
1184 GstStructure *local;
1186 validate_rtc_stream_stats (s, stats);
1188 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1189 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1191 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1193 fail_unless (local != NULL);
1195 gst_structure_free (local);
1200 validate_stats_foreach (GQuark field_id, const GValue * value,
1201 const GstStructure * stats)
1203 const gchar *field = g_quark_to_string (field_id);
1204 GstWebRTCStatsType type;
1205 const GstStructure *s;
1207 fail_unless (GST_VALUE_HOLDS_STRUCTURE (value));
1209 s = gst_value_get_structure (value);
1211 GST_INFO ("validating field %s %" GST_PTR_FORMAT, field, s);
1213 validate_rtc_stats (s);
1214 gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type, NULL);
1215 if (type == GST_WEBRTC_STATS_CODEC) {
1216 validate_codec_stats (s);
1217 } else if (type == GST_WEBRTC_STATS_INBOUND_RTP) {
1218 validate_inbound_rtp_stats (s, stats);
1219 } else if (type == GST_WEBRTC_STATS_OUTBOUND_RTP) {
1220 validate_outbound_rtp_stats (s, stats);
1221 } else if (type == GST_WEBRTC_STATS_REMOTE_INBOUND_RTP) {
1222 validate_remote_inbound_rtp_stats (s, stats);
1223 } else if (type == GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP) {
1224 validate_remote_outbound_rtp_stats (s, stats);
1225 } else if (type == GST_WEBRTC_STATS_CSRC) {
1226 } else if (type == GST_WEBRTC_STATS_PEER_CONNECTION) {
1227 } else if (type == GST_WEBRTC_STATS_DATA_CHANNEL) {
1228 } else if (type == GST_WEBRTC_STATS_STREAM) {
1229 } else if (type == GST_WEBRTC_STATS_TRANSPORT) {
1230 } else if (type == GST_WEBRTC_STATS_CANDIDATE_PAIR) {
1231 } else if (type == GST_WEBRTC_STATS_LOCAL_CANDIDATE) {
1232 } else if (type == GST_WEBRTC_STATS_REMOTE_CANDIDATE) {
1233 } else if (type == GST_WEBRTC_STATS_CERTIFICATE) {
1235 g_assert_not_reached ();
1242 validate_stats (const GstStructure * stats)
1244 gst_structure_foreach (stats,
1245 (GstStructureForeachFunc) validate_stats_foreach, (gpointer) stats);
1249 _on_stats (GstPromise * promise, gpointer user_data)
1251 struct test_webrtc *t = user_data;
1252 const GstStructure *reply = gst_promise_get_reply (promise);
1255 validate_stats (reply);
1256 i = GPOINTER_TO_INT (t->user_data);
1258 t->user_data = GINT_TO_POINTER (i);
1260 test_webrtc_signal_state (t, STATE_CUSTOM);
1262 gst_promise_unref (promise);
1265 GST_START_TEST (test_session_stats)
1267 struct test_webrtc *t = test_webrtc_new ();
1270 /* test that the stats generated without any streams are sane */
1271 t->on_negotiation_needed = NULL;
1272 test_validate_sdp (t, NULL, NULL);
1274 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1275 g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p);
1276 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1277 g_signal_emit_by_name (t->webrtc2, "get-stats", NULL, p);
1279 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1281 test_webrtc_free (t);
1286 GST_START_TEST (test_add_transceiver)
1288 struct test_webrtc *t = test_webrtc_new ();
1289 GstWebRTCRTPTransceiverDirection direction;
1290 GstWebRTCRTPTransceiver *trans;
1292 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
1293 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, NULL,
1295 fail_unless (trans != NULL);
1296 fail_unless_equals_int (direction, trans->direction);
1298 gst_object_unref (trans);
1300 test_webrtc_free (t);
1305 GST_START_TEST (test_get_transceivers)
1307 struct test_webrtc *t = create_audio_test ();
1308 GstWebRTCRTPTransceiver *trans;
1309 GArray *transceivers;
1311 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1312 fail_unless (transceivers != NULL);
1313 fail_unless_equals_int (1, transceivers->len);
1315 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
1316 fail_unless (trans != NULL);
1318 g_array_unref (transceivers);
1320 test_webrtc_free (t);
1325 GST_START_TEST (test_add_recvonly_transceiver)
1327 struct test_webrtc *t = test_webrtc_new ();
1328 GstWebRTCRTPTransceiverDirection direction;
1329 GstWebRTCRTPTransceiver *trans;
1330 const gchar *expected_offer[] = { "recvonly" };
1331 const gchar *expected_answer[] = { "sendonly" };
1332 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
1333 struct validate_sdp answer =
1334 { on_sdp_media_direction, expected_answer, NULL };
1338 /* add a transceiver that will only receive an opus stream and check that
1339 * the created offer is marked as recvonly */
1340 t->on_negotiation_needed = NULL;
1341 t->on_ice_candidate = NULL;
1342 t->on_pad_added = _pad_added_fakesink;
1344 /* setup recvonly transceiver */
1345 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1346 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1347 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1349 gst_caps_unref (caps);
1350 fail_unless (trans != NULL);
1351 gst_object_unref (trans);
1353 /* setup sendonly peer */
1354 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1355 add_fake_audio_src_harness (h, 96);
1356 t->harnesses = g_list_prepend (t->harnesses, h);
1357 test_validate_sdp (t, &offer, &answer);
1359 test_webrtc_free (t);
1364 GST_START_TEST (test_recvonly_sendonly)
1366 struct test_webrtc *t = test_webrtc_new ();
1367 GstWebRTCRTPTransceiverDirection direction;
1368 GstWebRTCRTPTransceiver *trans;
1369 const gchar *expected_offer[] = { "recvonly", "sendonly" };
1370 const gchar *expected_answer[] = { "sendonly", "recvonly" };
1371 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
1372 struct validate_sdp answer =
1373 { on_sdp_media_direction, expected_answer, NULL };
1376 GArray *transceivers;
1378 /* add a transceiver that will only receive an opus stream and check that
1379 * the created offer is marked as recvonly */
1380 t->on_negotiation_needed = NULL;
1381 t->on_ice_candidate = NULL;
1382 t->on_pad_added = _pad_added_fakesink;
1384 /* setup recvonly transceiver */
1385 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1386 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1387 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1389 gst_caps_unref (caps);
1390 fail_unless (trans != NULL);
1391 gst_object_unref (trans);
1393 /* setup sendonly stream */
1394 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1395 add_fake_audio_src_harness (h, 96);
1396 t->harnesses = g_list_prepend (t->harnesses, h);
1397 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1398 fail_unless (transceivers != NULL);
1399 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1400 trans->direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
1402 g_array_unref (transceivers);
1404 /* setup sendonly peer */
1405 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1406 add_fake_audio_src_harness (h, 96);
1407 t->harnesses = g_list_prepend (t->harnesses, h);
1409 test_validate_sdp (t, &offer, &answer);
1411 test_webrtc_free (t);
1417 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1418 GstWebRTCSessionDescription * desc, gpointer user_data)
1420 gboolean have_data_channel = FALSE;
1423 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1424 if (_message_media_is_datachannel (desc->sdp, i)) {
1425 /* there should only be one data channel m= section */
1426 fail_unless_equals_int (FALSE, have_data_channel);
1427 have_data_channel = TRUE;
1431 fail_unless_equals_int (TRUE, have_data_channel);
1435 on_channel_error_not_reached (GObject * channel, GError * error,
1438 g_assert_not_reached ();
1441 GST_START_TEST (test_data_channel_create)
1443 struct test_webrtc *t = test_webrtc_new ();
1444 GObject *channel = NULL;
1445 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1446 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1449 t->on_negotiation_needed = NULL;
1450 t->on_ice_candidate = NULL;
1452 fail_if (gst_element_set_state (t->webrtc1,
1453 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1454 fail_if (gst_element_set_state (t->webrtc2,
1455 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1457 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1459 g_assert_nonnull (channel);
1460 g_object_get (channel, "label", &label, NULL);
1461 g_assert_cmpstr (label, ==, "label");
1462 g_signal_connect (channel, "on-error",
1463 G_CALLBACK (on_channel_error_not_reached), NULL);
1465 test_validate_sdp (t, &offer, &answer);
1467 g_object_unref (channel);
1469 test_webrtc_free (t);
1475 have_data_channel (struct test_webrtc *t, GstElement * element,
1476 GObject * our, gpointer user_data)
1478 GObject *other = user_data;
1479 gchar *our_label, *other_label;
1481 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1484 g_object_get (our, "label", &our_label, NULL);
1485 g_object_get (other, "label", &other_label, NULL);
1487 g_assert_cmpstr (our_label, ==, other_label);
1490 g_free (other_label);
1492 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1495 GST_START_TEST (test_data_channel_remote_notify)
1497 struct test_webrtc *t = test_webrtc_new ();
1498 GObject *channel = NULL;
1499 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1500 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1502 t->on_negotiation_needed = NULL;
1503 t->offer_data = &offer;
1504 t->on_offer_created = _check_validate_sdp;
1505 t->answer_data = &answer;
1506 t->on_answer_created = _check_validate_sdp;
1507 t->on_ice_candidate = NULL;
1508 t->on_data_channel = have_data_channel;
1510 fail_if (gst_element_set_state (t->webrtc1,
1511 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1512 fail_if (gst_element_set_state (t->webrtc2,
1513 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1515 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1517 g_assert_nonnull (channel);
1518 t->data_channel_data = channel;
1519 g_signal_connect (channel, "on-error",
1520 G_CALLBACK (on_channel_error_not_reached), NULL);
1522 fail_if (gst_element_set_state (t->webrtc1,
1523 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1524 fail_if (gst_element_set_state (t->webrtc2,
1525 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1527 test_webrtc_create_offer (t, t->webrtc1);
1529 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1531 g_object_unref (channel);
1532 test_webrtc_free (t);
1537 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1540 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1542 gchar *expected = g_object_steal_data (channel, "expected");
1543 g_assert_cmpstr (expected, ==, str);
1546 test_webrtc_signal_state (t, STATE_CUSTOM);
1550 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1551 GObject * our, gpointer user_data)
1553 GObject *other = user_data;
1554 GstWebRTCDataChannelState state;
1556 g_object_get (our, "ready-state", &state, NULL);
1557 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1558 g_object_get (other, "ready-state", &state, NULL);
1559 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1561 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1562 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1565 g_signal_connect (other, "on-error",
1566 G_CALLBACK (on_channel_error_not_reached), NULL);
1567 g_signal_emit_by_name (other, "send-string", test_string);
1570 GST_START_TEST (test_data_channel_transfer_string)
1572 struct test_webrtc *t = test_webrtc_new ();
1573 GObject *channel = NULL;
1574 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1575 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1577 t->on_negotiation_needed = NULL;
1578 t->offer_data = &offer;
1579 t->on_offer_created = _check_validate_sdp;
1580 t->answer_data = &answer;
1581 t->on_answer_created = _check_validate_sdp;
1582 t->on_ice_candidate = NULL;
1583 t->on_data_channel = have_data_channel_transfer_string;
1585 fail_if (gst_element_set_state (t->webrtc1,
1586 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1587 fail_if (gst_element_set_state (t->webrtc2,
1588 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1590 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1592 g_assert_nonnull (channel);
1593 t->data_channel_data = channel;
1594 g_signal_connect (channel, "on-error",
1595 G_CALLBACK (on_channel_error_not_reached), NULL);
1597 fail_if (gst_element_set_state (t->webrtc1,
1598 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1599 fail_if (gst_element_set_state (t->webrtc2,
1600 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1602 test_webrtc_create_offer (t, t->webrtc1);
1604 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1606 g_object_unref (channel);
1607 test_webrtc_free (t);
1612 #define g_assert_cmpbytes(b1, b2) \
1615 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1616 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1617 g_assert_cmpmem (d1, l1, d2, l2); \
1621 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1623 GBytes *expected = g_object_steal_data (channel, "expected");
1624 g_assert_cmpbytes (data, expected);
1625 g_bytes_unref (expected);
1627 test_webrtc_signal_state (t, STATE_CUSTOM);
1631 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1632 GObject * our, gpointer user_data)
1634 GObject *other = user_data;
1635 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1636 GstWebRTCDataChannelState state;
1638 g_object_get (our, "ready-state", &state, NULL);
1639 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1640 g_object_get (other, "ready-state", &state, NULL);
1641 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1643 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1644 (GDestroyNotify) g_bytes_unref);
1645 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1647 g_signal_connect (other, "on-error",
1648 G_CALLBACK (on_channel_error_not_reached), NULL);
1649 g_signal_emit_by_name (other, "send-data", data);
1652 GST_START_TEST (test_data_channel_transfer_data)
1654 struct test_webrtc *t = test_webrtc_new ();
1655 GObject *channel = NULL;
1656 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1657 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1659 t->on_negotiation_needed = NULL;
1660 t->offer_data = &offer;
1661 t->on_offer_created = _check_validate_sdp;
1662 t->answer_data = &answer;
1663 t->on_answer_created = _check_validate_sdp;
1664 t->on_ice_candidate = NULL;
1665 t->on_data_channel = have_data_channel_transfer_data;
1667 fail_if (gst_element_set_state (t->webrtc1,
1668 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1669 fail_if (gst_element_set_state (t->webrtc2,
1670 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1672 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1674 g_assert_nonnull (channel);
1675 t->data_channel_data = channel;
1676 g_signal_connect (channel, "on-error",
1677 G_CALLBACK (on_channel_error_not_reached), NULL);
1679 fail_if (gst_element_set_state (t->webrtc1,
1680 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1681 fail_if (gst_element_set_state (t->webrtc2,
1682 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1684 test_webrtc_create_offer (t, t->webrtc1);
1686 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1688 g_object_unref (channel);
1689 test_webrtc_free (t);
1695 have_data_channel_create_data_channel (struct test_webrtc *t,
1696 GstElement * element, GObject * our, gpointer user_data)
1700 t->on_data_channel = have_data_channel_transfer_string;
1702 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1704 g_assert_nonnull (another);
1705 t->data_channel_data = another;
1706 g_signal_connect (another, "on-error",
1707 G_CALLBACK (on_channel_error_not_reached), NULL);
1710 GST_START_TEST (test_data_channel_create_after_negotiate)
1712 struct test_webrtc *t = test_webrtc_new ();
1713 GObject *channel = NULL;
1714 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1715 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1717 t->on_negotiation_needed = NULL;
1718 t->offer_data = &offer;
1719 t->on_offer_created = _check_validate_sdp;
1720 t->answer_data = &answer;
1721 t->on_answer_created = _check_validate_sdp;
1722 t->on_ice_candidate = NULL;
1723 t->on_data_channel = have_data_channel_create_data_channel;
1725 fail_if (gst_element_set_state (t->webrtc1,
1726 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1727 fail_if (gst_element_set_state (t->webrtc2,
1728 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1730 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
1732 g_assert_nonnull (channel);
1733 t->data_channel_data = channel;
1734 g_signal_connect (channel, "on-error",
1735 G_CALLBACK (on_channel_error_not_reached), NULL);
1737 fail_if (gst_element_set_state (t->webrtc1,
1738 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1739 fail_if (gst_element_set_state (t->webrtc2,
1740 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1742 test_webrtc_create_offer (t, t->webrtc1);
1744 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1746 g_object_unref (channel);
1747 test_webrtc_free (t);
1753 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
1755 test_webrtc_signal_state (t, STATE_CUSTOM);
1759 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
1760 GstElement * element, GObject * our, gpointer user_data)
1762 g_signal_connect (our, "on-buffered-amount-low",
1763 G_CALLBACK (on_buffered_amount_low_emitted), t);
1764 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
1766 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1768 g_signal_emit_by_name (our, "send-string", "DATA");
1771 GST_START_TEST (test_data_channel_low_threshold)
1773 struct test_webrtc *t = test_webrtc_new ();
1774 GObject *channel = NULL;
1775 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1776 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1778 t->on_negotiation_needed = NULL;
1779 t->offer_data = &offer;
1780 t->on_offer_created = _check_validate_sdp;
1781 t->answer_data = &answer;
1782 t->on_answer_created = _check_validate_sdp;
1783 t->on_ice_candidate = NULL;
1784 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
1786 fail_if (gst_element_set_state (t->webrtc1,
1787 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1788 fail_if (gst_element_set_state (t->webrtc2,
1789 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1791 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1793 g_assert_nonnull (channel);
1794 t->data_channel_data = channel;
1795 g_signal_connect (channel, "on-error",
1796 G_CALLBACK (on_channel_error_not_reached), NULL);
1798 fail_if (gst_element_set_state (t->webrtc1,
1799 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1800 fail_if (gst_element_set_state (t->webrtc2,
1801 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1803 test_webrtc_create_offer (t, t->webrtc1);
1805 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1807 g_object_unref (channel);
1808 test_webrtc_free (t);
1814 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
1816 g_assert_nonnull (error);
1818 test_webrtc_signal_state (t, STATE_CUSTOM);
1822 have_data_channel_transfer_large_data (struct test_webrtc *t,
1823 GstElement * element, GObject * our, gpointer user_data)
1825 GObject *other = user_data;
1826 const gsize size = 1024 * 1024;
1827 guint8 *random_data = g_new (guint8, size);
1831 for (i = 0; i < size; i++)
1832 random_data[i] = (guint8) (i & 0xff);
1834 data = g_bytes_new_static (random_data, size);
1836 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1837 (GDestroyNotify) g_bytes_unref);
1838 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1840 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
1841 g_signal_emit_by_name (other, "send-data", data);
1844 GST_START_TEST (test_data_channel_max_message_size)
1846 struct test_webrtc *t = test_webrtc_new ();
1847 GObject *channel = NULL;
1848 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1849 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1851 t->on_negotiation_needed = NULL;
1852 t->offer_data = &offer;
1853 t->on_offer_created = _check_validate_sdp;
1854 t->answer_data = &answer;
1855 t->on_answer_created = _check_validate_sdp;
1856 t->on_ice_candidate = NULL;
1857 t->on_data_channel = have_data_channel_transfer_large_data;
1859 fail_if (gst_element_set_state (t->webrtc1,
1860 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1861 fail_if (gst_element_set_state (t->webrtc2,
1862 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1864 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1866 g_assert_nonnull (channel);
1867 t->data_channel_data = channel;
1869 fail_if (gst_element_set_state (t->webrtc1,
1870 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1871 fail_if (gst_element_set_state (t->webrtc2,
1872 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1874 test_webrtc_create_offer (t, t->webrtc1);
1876 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1878 g_object_unref (channel);
1879 test_webrtc_free (t);
1885 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
1886 struct test_webrtc *t)
1888 gint *n_ready = t->data_channel_data;
1889 GstWebRTCDataChannelState ready_state;
1891 g_object_get (channel, "ready-state", &ready_state, NULL);
1893 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
1894 if (++(*n_ready) >= 2)
1895 test_webrtc_signal_state (t, STATE_CUSTOM);
1899 GST_START_TEST (test_data_channel_pre_negotiated)
1901 struct test_webrtc *t = test_webrtc_new ();
1902 GObject *channel1 = NULL, *channel2 = NULL;
1903 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1904 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1908 t->on_negotiation_needed = NULL;
1909 t->offer_data = &offer;
1910 t->on_offer_created = _check_validate_sdp;
1911 t->answer_data = &answer;
1912 t->on_answer_created = _check_validate_sdp;
1913 t->on_ice_candidate = NULL;
1915 fail_if (gst_element_set_state (t->webrtc1,
1916 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1917 fail_if (gst_element_set_state (t->webrtc2,
1918 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1920 s = gst_structure_new ("application/data-channel", "negotiated",
1921 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
1923 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
1925 g_assert_nonnull (channel1);
1926 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
1928 g_assert_nonnull (channel2);
1930 fail_if (gst_element_set_state (t->webrtc1,
1931 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1932 fail_if (gst_element_set_state (t->webrtc2,
1933 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1935 test_webrtc_create_offer (t, t->webrtc1);
1936 test_webrtc_wait_for_answer_error_eos (t);
1937 fail_unless (t->state == STATE_ANSWER_CREATED);
1939 t->data_channel_data = &n_ready;
1941 g_signal_connect (channel1, "notify::ready-state",
1942 G_CALLBACK (_on_ready_state_notify), t);
1943 g_signal_connect (channel2, "notify::ready-state",
1944 G_CALLBACK (_on_ready_state_notify), t);
1946 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1947 test_webrtc_signal_state (t, STATE_NEW);
1949 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
1951 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1953 g_object_unref (channel1);
1954 g_object_unref (channel2);
1955 gst_structure_free (s);
1956 test_webrtc_free (t);
1964 guint num_active_media;
1965 const gchar **bundled;
1966 const gchar **bundled_only;
1970 _check_bundled_sdp_media (struct test_webrtc *t, GstElement * element,
1971 GstWebRTCSessionDescription * sd, gpointer user_data)
1973 gchar **bundled = NULL;
1974 BundleCheckData *data = (BundleCheckData *) user_data;
1978 fail_unless_equals_int (gst_sdp_message_medias_len (sd->sdp),
1981 fail_unless (_parse_bundle (sd->sdp, &bundled));
1984 fail_unless_equals_int (g_strv_length ((GStrv) data->bundled), 0);
1986 fail_unless_equals_int (g_strv_length (bundled),
1987 g_strv_length ((GStrv) data->bundled));
1990 for (i = 0; data->bundled[i]; i++) {
1991 fail_unless (g_strv_contains ((const gchar **) bundled, data->bundled[i]));
1996 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
1997 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
1998 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2000 if (g_strv_contains ((const gchar **) data->bundled_only, mid))
2001 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2003 if (gst_sdp_media_get_port (media) != 0)
2007 fail_unless_equals_int (active_media, data->num_active_media);
2010 g_strfreev (bundled);
2013 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2015 struct test_webrtc *t = create_audio_video_test ();
2016 const gchar *bundle[] = { "audio0", "video1", NULL };
2017 const gchar *offer_bundle_only[] = { "video1", NULL };
2018 const gchar *answer_bundle_only[] = { NULL };
2019 /* We set a max-bundle policy on the offering webrtcbin,
2020 * this means that all the offered medias should be part
2021 * of the group:BUNDLE attribute, and they should be marked
2024 BundleCheckData offer_data = {
2030 /* We also set a max-bundle policy on the answering webrtcbin,
2031 * this means that all the offered medias should be part
2032 * of the group:BUNDLE attribute, but need not be marked
2035 BundleCheckData answer_data = {
2041 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2042 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2044 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2046 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2049 test_validate_sdp (t, &offer, &answer);
2051 test_webrtc_free (t);
2056 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2058 struct test_webrtc *t = create_audio_video_test ();
2059 const gchar *bundle[] = { "audio0", "video1", NULL };
2060 const gchar *bundle_only[] = { NULL };
2061 /* We set a max-compat policy on the offering webrtcbin,
2062 * this means that all the offered medias should be part
2063 * of the group:BUNDLE attribute, and they should *not* be marked
2066 BundleCheckData offer_data = {
2072 /* We set a max-bundle policy on the answering webrtcbin,
2073 * this means that all the offered medias should be part
2074 * of the group:BUNDLE attribute, but need not be marked
2077 BundleCheckData answer_data = {
2083 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2084 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2086 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2088 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2091 test_validate_sdp (t, &offer, &answer);
2093 test_webrtc_free (t);
2098 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2100 struct test_webrtc *t = create_audio_video_test ();
2101 const gchar *offer_bundle[] = { "audio0", "video1", NULL };
2102 const gchar *offer_bundle_only[] = { "video1", NULL };
2103 const gchar *answer_bundle[] = { NULL };
2104 const gchar *answer_bundle_only[] = { NULL };
2105 /* We set a max-bundle policy on the offering webrtcbin,
2106 * this means that all the offered medias should be part
2107 * of the group:BUNDLE attribute, and they should be marked
2110 BundleCheckData offer_data = {
2116 /* We set a none policy on the answering webrtcbin,
2117 * this means that the answer should contain no bundled
2118 * medias, and as the bundle-policy of the offering webrtcbin
2119 * is set to max-bundle, only one media should be active.
2121 BundleCheckData answer_data = {
2127 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2128 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2130 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2132 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2134 test_validate_sdp (t, &offer, &answer);
2136 test_webrtc_free (t);
2141 GST_START_TEST (test_bundle_audio_video_data)
2143 struct test_webrtc *t = create_audio_video_test ();
2144 const gchar *bundle[] = { "audio0", "video1", "application2", NULL };
2145 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2146 const gchar *answer_bundle_only[] = { NULL };
2147 GObject *channel = NULL;
2148 /* We set a max-bundle policy on the offering webrtcbin,
2149 * this means that all the offered medias should be part
2150 * of the group:BUNDLE attribute, and they should be marked
2153 BundleCheckData offer_data = {
2159 /* We also set a max-bundle policy on the answering webrtcbin,
2160 * this means that all the offered medias should be part
2161 * of the group:BUNDLE attribute, but need not be marked
2164 BundleCheckData answer_data = {
2170 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2171 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2173 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2175 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2178 fail_if (gst_element_set_state (t->webrtc1,
2179 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2180 fail_if (gst_element_set_state (t->webrtc2,
2181 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2183 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2186 test_validate_sdp (t, &offer, &answer);
2188 g_object_unref (channel);
2189 test_webrtc_free (t);
2194 GST_START_TEST (test_duplicate_nego)
2196 struct test_webrtc *t = create_audio_video_test ();
2197 const gchar *expected_offer[] = { "sendrecv", "sendrecv" };
2198 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
2199 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
2200 struct validate_sdp answer =
2201 { on_sdp_media_direction, expected_answer, NULL };
2204 /* check that negotiating twice succeeds */
2206 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2207 add_fake_audio_src_harness (h, 96);
2208 t->harnesses = g_list_prepend (t->harnesses, h);
2210 t->on_negotiation_needed = NULL;
2211 test_validate_sdp (t, &offer, &answer);
2212 test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED);
2213 test_validate_sdp (t, &offer, &answer);
2215 test_webrtc_free (t);
2220 GST_START_TEST (test_dual_audio)
2222 struct test_webrtc *t = create_audio_test ();
2223 const gchar *expected_offer[] = { "sendrecv", "sendrecv", };
2224 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
2225 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
2226 struct validate_sdp answer =
2227 { on_sdp_media_direction, expected_answer, NULL };
2229 GstWebRTCRTPTransceiver *trans;
2230 GArray *transceivers;
2232 /* test that each mline gets a unique transceiver even with the same caps */
2234 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
2235 add_fake_audio_src_harness (h, 96);
2236 t->harnesses = g_list_prepend (t->harnesses, h);
2238 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2239 add_fake_audio_src_harness (h, 96);
2240 t->harnesses = g_list_prepend (t->harnesses, h);
2242 t->on_negotiation_needed = NULL;
2243 test_validate_sdp (t, &offer, &answer);
2245 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
2246 fail_unless (transceivers != NULL);
2247 fail_unless_equals_int (2, transceivers->len);
2249 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
2250 fail_unless (trans != NULL);
2251 fail_unless_equals_int (trans->mline, 0);
2253 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
2254 fail_unless (trans != NULL);
2255 fail_unless_equals_int (trans->mline, 1);
2257 g_array_unref (transceivers);
2258 test_webrtc_free (t);
2262 webrtcbin_suite (void)
2264 Suite *s = suite_create ("webrtcbin");
2265 TCase *tc = tcase_create ("general");
2266 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
2267 GstPluginFeature *sctpenc, *sctpdec;
2268 GstRegistry *registry;
2270 registry = gst_registry_get ();
2271 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
2272 nicesink = gst_registry_lookup_feature (registry, "nicesink");
2273 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
2274 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
2275 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
2276 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
2278 tcase_add_test (tc, test_no_nice_elements_request_pad);
2279 tcase_add_test (tc, test_no_nice_elements_state_change);
2280 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
2281 tcase_add_test (tc, test_sdp_no_media);
2282 tcase_add_test (tc, test_session_stats);
2283 tcase_add_test (tc, test_audio);
2284 tcase_add_test (tc, test_audio_video);
2285 tcase_add_test (tc, test_media_direction);
2286 tcase_add_test (tc, test_media_setup);
2287 tcase_add_test (tc, test_add_transceiver);
2288 tcase_add_test (tc, test_get_transceivers);
2289 tcase_add_test (tc, test_add_recvonly_transceiver);
2290 tcase_add_test (tc, test_recvonly_sendonly);
2291 tcase_add_test (tc, test_payload_types);
2292 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
2293 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
2294 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
2295 tcase_add_test (tc, test_dual_audio);
2296 tcase_add_test (tc, test_duplicate_nego);
2297 if (sctpenc && sctpdec) {
2298 tcase_add_test (tc, test_data_channel_create);
2299 tcase_add_test (tc, test_data_channel_remote_notify);
2300 tcase_add_test (tc, test_data_channel_transfer_string);
2301 tcase_add_test (tc, test_data_channel_transfer_data);
2302 tcase_add_test (tc, test_data_channel_create_after_negotiate);
2303 tcase_add_test (tc, test_data_channel_low_threshold);
2304 tcase_add_test (tc, test_data_channel_max_message_size);
2305 tcase_add_test (tc, test_data_channel_pre_negotiated);
2306 tcase_add_test (tc, test_bundle_audio_video_data);
2308 GST_WARNING ("Some required elements were not found. "
2309 "All datachannel are disabled. sctpenc %p, sctpdec %p", sctpenc,
2313 GST_WARNING ("Some required elements were not found. "
2314 "All media tests are disabled. nicesrc %p, nicesink %p, "
2315 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
2320 gst_object_unref (nicesrc);
2322 gst_object_unref (nicesink);
2324 gst_object_unref (dtlssrtpdec);
2326 gst_object_unref (dtlssrtpenc);
2328 gst_object_unref (sctpenc);
2330 gst_object_unref (sctpdec);
2332 suite_add_tcase (s, tc);
2337 GST_CHECK_MAIN (webrtcbin);