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"
39 #define H264_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=H264,media=video,clock-rate=90000,ssrc=(uint)3484078951"
41 #define TEST_IS_OFFER_ELEMENT(t, e) ((((t)->offerror == 1 && (e) == (t)->webrtc1) || ((t)->offerror == 2 && (e) == (t)->webrtc2)) ? TRUE : FALSE)
42 #define TEST_GET_OFFEROR(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc1 : t->webrtc2)
43 #define TEST_GET_ANSWERER(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc2 : t->webrtc1)
45 #define TEST_SDP_IS_LOCAL(t, e, d) ((TEST_IS_OFFER_ELEMENT (t, e) ^ ((d)->type == GST_WEBRTC_SDP_TYPE_OFFER)) == 0)
50 STATE_NEGOTIATION_NEEDED,
60 /* basic premise of this is that webrtc1 and webrtc2 are attempting to connect
61 * to each other in various configurations */
66 GstTestClock *test_clock;
78 GDestroyNotify data_notify;
80 void (*on_negotiation_needed) (struct test_webrtc * t,
83 gpointer negotiation_data;
84 GDestroyNotify negotiation_notify;
85 void (*on_ice_candidate) (struct test_webrtc * t,
91 gpointer ice_candidate_data;
92 GDestroyNotify ice_candidate_notify;
93 void (*on_offer_created) (struct test_webrtc * t,
97 GstWebRTCSessionDescription *offer_desc;
98 guint offer_set_count;
100 GDestroyNotify offer_notify;
101 void (*on_offer_set) (struct test_webrtc * t,
102 GstElement * element,
103 GstPromise * promise,
105 gpointer offer_set_data;
106 GDestroyNotify offer_set_notify;
107 void (*on_answer_created) (struct test_webrtc * t,
108 GstElement * element,
109 GstPromise * promise,
111 GstWebRTCSessionDescription *answer_desc;
112 guint answer_set_count;
113 gpointer answer_data;
114 GDestroyNotify answer_notify;
115 void (*on_answer_set) (struct test_webrtc * t,
116 GstElement * element,
117 GstPromise * promise,
119 gpointer answer_set_data;
120 GDestroyNotify answer_set_notify;
121 void (*on_data_channel) (struct test_webrtc * t,
122 GstElement * element,
123 GObject *data_channel,
125 gpointer data_channel_data;
126 GDestroyNotify data_channel_notify;
127 void (*on_pad_added) (struct test_webrtc * t,
128 GstElement * element,
131 gpointer pad_added_data;
132 GDestroyNotify pad_added_notify;
133 void (*bus_message) (struct test_webrtc * t,
138 GDestroyNotify bus_notify;
143 test_webrtc_signal_state_unlocked (struct test_webrtc *t, TestState state)
146 g_cond_broadcast (&t->cond);
150 test_webrtc_signal_state (struct test_webrtc *t, TestState state)
152 g_mutex_lock (&t->lock);
153 test_webrtc_signal_state_unlocked (t, state);
154 g_mutex_unlock (&t->lock);
158 _on_answer_set (GstPromise * promise, gpointer user_data)
160 struct test_webrtc *t = user_data;
161 GstElement *answerer = TEST_GET_ANSWERER (t);
163 g_mutex_lock (&t->lock);
164 if (++t->answer_set_count >= 2) {
165 if (t->on_answer_set)
166 t->on_answer_set (t, answerer, promise, t->answer_set_data);
167 if (t->state == STATE_ANSWER_CREATED)
168 t->state = STATE_ANSWER_SET;
169 g_cond_broadcast (&t->cond);
171 gst_promise_unref (promise);
172 g_mutex_unlock (&t->lock);
176 _on_answer_received (GstPromise * promise, gpointer user_data)
178 struct test_webrtc *t = user_data;
179 GstElement *offeror = TEST_GET_OFFEROR (t);
180 GstElement *answerer = TEST_GET_ANSWERER (t);
181 const GstStructure *reply;
182 GstWebRTCSessionDescription *answer = NULL;
183 GError *error = NULL;
185 reply = gst_promise_get_reply (promise);
186 if (gst_structure_get (reply, "answer",
187 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL)) {
188 gchar *desc = gst_sdp_message_as_text (answer->sdp);
189 GST_INFO ("Created Answer: %s", desc);
191 } else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
192 GST_INFO ("Creating answer resulted in error: %s", error->message);
194 g_assert_not_reached ();
197 g_mutex_lock (&t->lock);
199 g_assert (t->answer_desc == NULL);
200 t->answer_desc = answer;
202 if (t->on_answer_created) {
203 t->on_answer_created (t, answerer, promise, t->answer_data);
205 gst_promise_unref (promise);
210 if (t->answer_desc) {
211 promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
212 g_signal_emit_by_name (answerer, "set-local-description", t->answer_desc,
214 promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
215 g_signal_emit_by_name (offeror, "set-remote-description", t->answer_desc,
219 test_webrtc_signal_state_unlocked (t, STATE_ANSWER_CREATED);
220 g_mutex_unlock (&t->lock);
224 g_clear_error (&error);
225 if (t->state < STATE_ERROR)
226 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
227 g_mutex_unlock (&t->lock);
232 _on_offer_set (GstPromise * promise, gpointer user_data)
234 struct test_webrtc *t = user_data;
235 GstElement *offeror = TEST_GET_OFFEROR (t);
237 g_mutex_lock (&t->lock);
238 if (++t->offer_set_count >= 2) {
240 t->on_offer_set (t, offeror, promise, t->offer_set_data);
241 if (t->state == STATE_OFFER_CREATED)
242 t->state = STATE_OFFER_SET;
243 g_cond_broadcast (&t->cond);
245 gst_promise_unref (promise);
246 g_mutex_unlock (&t->lock);
250 _on_offer_received (GstPromise * promise, gpointer user_data)
252 struct test_webrtc *t = user_data;
253 GstElement *offeror = TEST_GET_OFFEROR (t);
254 GstElement *answerer = TEST_GET_ANSWERER (t);
255 const GstStructure *reply;
256 GstWebRTCSessionDescription *offer = NULL;
257 GError *error = NULL;
259 reply = gst_promise_get_reply (promise);
260 if (gst_structure_get (reply, "offer",
261 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL)) {
262 gchar *desc = gst_sdp_message_as_text (offer->sdp);
263 GST_INFO ("Created offer: %s", desc);
265 } else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
266 GST_INFO ("Creating offer resulted in error: %s", error->message);
268 g_assert_not_reached ();
271 g_mutex_lock (&t->lock);
273 g_assert (t->offer_desc == NULL);
274 t->offer_desc = offer;
276 if (t->on_offer_created) {
277 t->on_offer_created (t, offeror, promise, t->offer_data);
279 gst_promise_unref (promise);
285 promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
286 g_signal_emit_by_name (offeror, "set-local-description", t->offer_desc,
288 promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
289 g_signal_emit_by_name (answerer, "set-remote-description", t->offer_desc,
292 promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
293 g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
296 test_webrtc_signal_state_unlocked (t, STATE_OFFER_CREATED);
297 g_mutex_unlock (&t->lock);
301 g_clear_error (&error);
302 if (t->state < STATE_ERROR)
303 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
304 g_mutex_unlock (&t->lock);
309 _bus_watch (GstBus * bus, GstMessage * msg, struct test_webrtc *t)
311 g_mutex_lock (&t->lock);
312 switch (GST_MESSAGE_TYPE (msg)) {
313 case GST_MESSAGE_STATE_CHANGED:
314 if (GST_ELEMENT (msg->src) == t->webrtc1
315 || GST_ELEMENT (msg->src) == t->webrtc2) {
316 GstState old, new, pending;
318 gst_message_parse_state_changed (msg, &old, &new, &pending);
321 gchar *dump_name = g_strconcat ("%s-state_changed-",
322 GST_OBJECT_NAME (msg->src), gst_element_state_get_name (old), "_",
323 gst_element_state_get_name (new), NULL);
324 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
325 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
330 case GST_MESSAGE_ERROR:{
332 gchar *dbg_info = NULL;
337 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc1), NULL);
338 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
339 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
342 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc2), NULL);
343 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
344 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
348 gst_message_parse_error (msg, &err, &dbg_info);
349 GST_WARNING ("ERROR from element %s: %s",
350 GST_OBJECT_NAME (msg->src), err->message);
351 GST_WARNING ("Debugging info: %s", (dbg_info) ? dbg_info : "none");
354 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
357 case GST_MESSAGE_EOS:{
360 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc1), NULL);
361 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
362 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
364 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc2), NULL);
365 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
366 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
369 GST_INFO ("EOS received");
370 test_webrtc_signal_state_unlocked (t, STATE_EOS);
378 t->bus_message (t, bus, msg, t->bus_data);
379 g_mutex_unlock (&t->lock);
385 _on_negotiation_needed (GstElement * webrtc, struct test_webrtc *t)
387 g_mutex_lock (&t->lock);
388 if (t->on_negotiation_needed)
389 t->on_negotiation_needed (t, webrtc, t->negotiation_data);
390 if (t->state == STATE_NEW)
391 t->state = STATE_NEGOTIATION_NEEDED;
392 g_cond_broadcast (&t->cond);
393 g_mutex_unlock (&t->lock);
397 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
398 struct test_webrtc *t)
402 g_mutex_lock (&t->lock);
403 other = webrtc == t->webrtc1 ? t->webrtc2 : t->webrtc1;
405 if (t->on_ice_candidate)
406 t->on_ice_candidate (t, webrtc, mlineindex, candidate, other,
407 t->ice_candidate_data);
409 g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
410 g_mutex_unlock (&t->lock);
414 _on_pad_added (GstElement * webrtc, GstPad * new_pad, struct test_webrtc *t)
416 g_mutex_lock (&t->lock);
418 t->on_pad_added (t, webrtc, new_pad, t->pad_added_data);
419 g_mutex_unlock (&t->lock);
423 _on_data_channel (GstElement * webrtc, GObject * data_channel,
424 struct test_webrtc *t)
426 g_mutex_lock (&t->lock);
427 if (t->on_data_channel)
428 t->on_data_channel (t, webrtc, data_channel, t->data_channel_data);
429 g_mutex_unlock (&t->lock);
433 _pad_added_not_reached (struct test_webrtc *t, GstElement * element,
434 GstPad * pad, gpointer user_data)
436 g_assert_not_reached ();
440 _ice_candidate_not_reached (struct test_webrtc *t, GstElement * element,
441 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
443 g_assert_not_reached ();
447 _negotiation_not_reached (struct test_webrtc *t, GstElement * element,
450 g_assert_not_reached ();
454 _bus_no_errors (struct test_webrtc *t, GstBus * bus, GstMessage * msg,
457 switch (GST_MESSAGE_TYPE (msg)) {
458 case GST_MESSAGE_ERROR:{
462 gst_message_parse_error (msg, &err, &dbg);
463 g_error ("ERROR from element %s: %s (Debugging info: %s)",
464 GST_OBJECT_NAME (msg->src), err->message, (dbg) ? dbg : "none");
467 g_assert_not_reached ();
476 _offer_answer_not_reached (struct test_webrtc *t, GstElement * element,
477 GstPromise * promise, gpointer user_data)
479 g_assert_not_reached ();
483 _on_data_channel_not_reached (struct test_webrtc *t, GstElement * element,
484 GObject * data_channel, gpointer user_data)
486 g_assert_not_reached ();
490 _broadcast (struct test_webrtc *t)
492 g_mutex_lock (&t->lock);
493 g_cond_broadcast (&t->cond);
494 g_mutex_unlock (&t->lock);
498 _unlock_create_thread (GMutex * lock)
500 g_mutex_unlock (lock);
501 return G_SOURCE_REMOVE;
505 _bus_thread (struct test_webrtc *t)
507 g_mutex_lock (&t->lock);
508 t->loop = g_main_loop_new (NULL, FALSE);
509 g_idle_add ((GSourceFunc) _unlock_create_thread, &t->lock);
510 g_cond_broadcast (&t->cond);
512 g_main_loop_run (t->loop);
514 g_mutex_lock (&t->lock);
515 g_main_loop_unref (t->loop);
517 g_cond_broadcast (&t->cond);
518 g_mutex_unlock (&t->lock);
524 element_added_disable_sync (GstBin * bin, GstBin * sub_bin,
525 GstElement * element, gpointer user_data)
527 GObjectClass *class = G_OBJECT_GET_CLASS (element);
528 if (g_object_class_find_property (class, "async"))
529 g_object_set (element, "async", FALSE, NULL);
530 if (g_object_class_find_property (class, "sync"))
531 g_object_set (element, "sync", FALSE, NULL);
534 static struct test_webrtc *
535 test_webrtc_new (void)
537 struct test_webrtc *ret = g_new0 (struct test_webrtc, 1);
539 ret->on_negotiation_needed = _negotiation_not_reached;
540 ret->on_ice_candidate = _ice_candidate_not_reached;
541 ret->on_pad_added = _pad_added_not_reached;
542 ret->on_offer_created = _offer_answer_not_reached;
543 ret->on_answer_created = _offer_answer_not_reached;
544 ret->on_data_channel = _on_data_channel_not_reached;
545 ret->bus_message = _bus_no_errors;
548 g_mutex_init (&ret->lock);
549 g_cond_init (&ret->cond);
551 ret->test_clock = GST_TEST_CLOCK (gst_test_clock_new ());
553 ret->thread = g_thread_new ("test-webrtc", (GThreadFunc) _bus_thread, ret);
555 g_mutex_lock (&ret->lock);
557 g_cond_wait (&ret->cond, &ret->lock);
558 g_mutex_unlock (&ret->lock);
560 ret->bus1 = gst_bus_new ();
561 ret->bus2 = gst_bus_new ();
562 gst_bus_add_watch (ret->bus1, (GstBusFunc) _bus_watch, ret);
563 gst_bus_add_watch (ret->bus2, (GstBusFunc) _bus_watch, ret);
564 ret->webrtc1 = gst_element_factory_make ("webrtcbin", NULL);
565 ret->webrtc2 = gst_element_factory_make ("webrtcbin", NULL);
566 fail_unless (ret->webrtc1 != NULL && ret->webrtc2 != NULL);
568 gst_element_set_clock (ret->webrtc1, GST_CLOCK (ret->test_clock));
569 gst_element_set_clock (ret->webrtc2, GST_CLOCK (ret->test_clock));
571 gst_element_set_bus (ret->webrtc1, ret->bus1);
572 gst_element_set_bus (ret->webrtc2, ret->bus2);
574 g_signal_connect (ret->webrtc1, "deep-element-added",
575 G_CALLBACK (element_added_disable_sync), NULL);
576 g_signal_connect (ret->webrtc2, "deep-element-added",
577 G_CALLBACK (element_added_disable_sync), NULL);
578 g_signal_connect (ret->webrtc1, "on-negotiation-needed",
579 G_CALLBACK (_on_negotiation_needed), ret);
580 g_signal_connect (ret->webrtc2, "on-negotiation-needed",
581 G_CALLBACK (_on_negotiation_needed), ret);
582 g_signal_connect (ret->webrtc1, "on-ice-candidate",
583 G_CALLBACK (_on_ice_candidate), ret);
584 g_signal_connect (ret->webrtc2, "on-ice-candidate",
585 G_CALLBACK (_on_ice_candidate), ret);
586 g_signal_connect (ret->webrtc1, "on-data-channel",
587 G_CALLBACK (_on_data_channel), ret);
588 g_signal_connect (ret->webrtc2, "on-data-channel",
589 G_CALLBACK (_on_data_channel), ret);
590 g_signal_connect (ret->webrtc1, "pad-added", G_CALLBACK (_on_pad_added), ret);
591 g_signal_connect (ret->webrtc2, "pad-added", G_CALLBACK (_on_pad_added), ret);
592 g_signal_connect_swapped (ret->webrtc1, "notify::ice-gathering-state",
593 G_CALLBACK (_broadcast), ret);
594 g_signal_connect_swapped (ret->webrtc2, "notify::ice-gathering-state",
595 G_CALLBACK (_broadcast), ret);
596 g_signal_connect_swapped (ret->webrtc1, "notify::ice-connection-state",
597 G_CALLBACK (_broadcast), ret);
598 g_signal_connect_swapped (ret->webrtc2, "notify::ice-connection-state",
599 G_CALLBACK (_broadcast), ret);
605 test_webrtc_reset_negotiation (struct test_webrtc *t)
608 gst_webrtc_session_description_free (t->offer_desc);
609 t->offer_desc = NULL;
610 t->offer_set_count = 0;
612 gst_webrtc_session_description_free (t->answer_desc);
613 t->answer_desc = NULL;
614 t->answer_set_count = 0;
616 test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED);
620 test_webrtc_free (struct test_webrtc *t)
622 /* Otherwise while one webrtcbin is being destroyed, the other could
623 * generate a signal that calls into the destroyed webrtcbin */
624 g_signal_handlers_disconnect_by_data (t->webrtc1, t);
625 g_signal_handlers_disconnect_by_data (t->webrtc2, t);
627 g_main_loop_quit (t->loop);
628 g_mutex_lock (&t->lock);
630 g_cond_wait (&t->cond, &t->lock);
631 g_mutex_unlock (&t->lock);
633 g_thread_join (t->thread);
635 g_object_unref (t->test_clock);
637 gst_bus_remove_watch (t->bus1);
638 gst_bus_remove_watch (t->bus2);
640 gst_bus_set_flushing (t->bus1, TRUE);
641 gst_bus_set_flushing (t->bus2, TRUE);
643 gst_object_unref (t->bus1);
644 gst_object_unref (t->bus2);
646 g_list_free_full (t->harnesses, (GDestroyNotify) gst_harness_teardown);
649 t->data_notify (t->user_data);
650 if (t->negotiation_notify)
651 t->negotiation_notify (t->negotiation_data);
652 if (t->ice_candidate_notify)
653 t->ice_candidate_notify (t->ice_candidate_data);
655 t->offer_notify (t->offer_data);
656 if (t->offer_set_notify)
657 t->offer_set_notify (t->offer_set_data);
658 if (t->answer_notify)
659 t->answer_notify (t->answer_data);
660 if (t->answer_set_notify)
661 t->answer_set_notify (t->answer_set_data);
662 if (t->pad_added_notify)
663 t->pad_added_notify (t->pad_added_data);
664 if (t->data_channel_notify)
665 t->data_channel_notify (t->data_channel_data);
667 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
668 gst_element_set_state (t->webrtc1, GST_STATE_NULL));
669 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
670 gst_element_set_state (t->webrtc2, GST_STATE_NULL));
672 test_webrtc_reset_negotiation (t);
674 gst_object_unref (t->webrtc1);
675 gst_object_unref (t->webrtc2);
677 g_mutex_clear (&t->lock);
678 g_cond_clear (&t->cond);
684 test_webrtc_create_offer (struct test_webrtc *t)
687 GstElement *offeror = TEST_GET_OFFEROR (t);
689 promise = gst_promise_new_with_change_func (_on_offer_received, t, NULL);
690 g_signal_emit_by_name (offeror, "create-offer", NULL, promise);
694 test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
696 g_mutex_lock (&t->lock);
697 while (((1 << t->state) & state) == 0) {
698 GST_INFO ("test state 0x%x, current 0x%x", state, (1 << t->state));
699 g_cond_wait (&t->cond, &t->lock);
701 GST_INFO ("have test state 0x%x, current 0x%x", state, 1 << t->state);
702 g_mutex_unlock (&t->lock);
706 test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t)
708 TestState states = 0;
709 states |= (1 << STATE_ANSWER_SET);
710 states |= (1 << STATE_EOS);
711 states |= (1 << STATE_ERROR);
712 test_webrtc_wait_for_state_mask (t, states);
716 test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
718 GstWebRTCICEGatheringState ice_state1, ice_state2;
719 g_mutex_lock (&t->lock);
720 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
721 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
722 while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE &&
723 ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
724 g_cond_wait (&t->cond, &t->lock);
725 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
726 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
728 g_mutex_unlock (&t->lock);
733 test_webrtc_wait_for_ice_connection (struct test_webrtc *t,
734 GstWebRTCICEConnectionState states)
736 GstWebRTCICEConnectionState ice_state1, ice_state2, current;
737 g_mutex_lock (&t->lock);
738 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
739 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
740 current = (1 << ice_state1) | (1 << ice_state2);
741 while ((current & states) == 0 || (current & ~states)) {
742 g_cond_wait (&t->cond, &t->lock);
743 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
744 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
745 current = (1 << ice_state1) | (1 << ice_state2);
747 g_mutex_unlock (&t->lock);
752 _pad_added_fakesink (struct test_webrtc *t, GstElement * element,
753 GstPad * pad, gpointer user_data)
757 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
760 h = gst_harness_new_with_element (element, NULL, "src_%u");
761 gst_harness_add_sink_parse (h, "fakesink async=false sync=false");
763 t->harnesses = g_list_prepend (t->harnesses, h);
767 on_negotiation_needed_hit (struct test_webrtc *t, GstElement * element,
770 guint *flag = (guint *) user_data;
772 *flag |= 1 << ((element == t->webrtc1) ? 1 : 2);
775 typedef void (*ValidateSDPFunc) (struct test_webrtc * t, GstElement * element,
776 GstWebRTCSessionDescription * desc, gpointer user_data);
781 ValidateSDPFunc validate;
783 struct validate_sdp *next;
786 #define VAL_SDP_INIT(name,func,data,next) \
787 struct validate_sdp name = { func, data, next }
790 _check_validate_sdp (struct test_webrtc *t, GstElement * element,
791 GstPromise * promise, gpointer user_data)
793 struct validate_sdp *validate = user_data;
794 GstWebRTCSessionDescription *desc = NULL;
796 if (TEST_IS_OFFER_ELEMENT (t, element))
797 desc = t->offer_desc;
799 desc = t->answer_desc;
802 validate->validate (t, element, desc, validate->user_data);
803 validate = validate->next;
808 test_validate_sdp_full (struct test_webrtc *t, struct validate_sdp *offer,
809 struct validate_sdp *answer, TestState wait_mask,
810 gboolean perform_state_change)
813 t->offer_data = offer;
814 t->on_offer_created = _check_validate_sdp;
816 t->offer_data = NULL;
817 t->on_offer_created = NULL;
820 t->answer_data = answer;
821 t->on_answer_created = _check_validate_sdp;
823 t->answer_data = NULL;
824 t->on_answer_created = NULL;
827 if (perform_state_change) {
828 fail_if (gst_element_set_state (t->webrtc1,
829 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
830 fail_if (gst_element_set_state (t->webrtc2,
831 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
834 test_webrtc_create_offer (t);
836 if (wait_mask == 0) {
837 test_webrtc_wait_for_answer_error_eos (t);
838 fail_unless (t->state == STATE_ANSWER_SET);
840 test_webrtc_wait_for_state_mask (t, wait_mask);
845 test_validate_sdp (struct test_webrtc *t, struct validate_sdp *offer,
846 struct validate_sdp *answer)
848 test_validate_sdp_full (t, offer, answer, 0, TRUE);
852 _count_num_sdp_media (struct test_webrtc *t, GstElement * element,
853 GstWebRTCSessionDescription * desc, gpointer user_data)
855 guint expected = GPOINTER_TO_UINT (user_data);
857 fail_unless_equals_int (gst_sdp_message_medias_len (desc->sdp), expected);
860 GST_START_TEST (test_sdp_no_media)
862 struct test_webrtc *t = test_webrtc_new ();
863 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (0), NULL);
865 /* check that a no stream connection creates 0 media sections */
867 t->on_negotiation_needed = NULL;
868 test_validate_sdp (t, &count, &count);
870 test_webrtc_free (t);
876 on_sdp_media_direction (struct test_webrtc *t, GstElement * element,
877 GstWebRTCSessionDescription * desc, gpointer user_data)
879 gchar **expected_directions = user_data;
882 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
883 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
885 if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0
886 || g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) {
887 gboolean have_direction = FALSE;
890 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
891 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
893 if (g_strcmp0 (attr->key, "inactive") == 0) {
894 fail_unless (have_direction == FALSE,
895 "duplicate/multiple directions for media %u", j);
896 have_direction = TRUE;
897 fail_unless_equals_string (attr->key, expected_directions[i]);
898 } else if (g_strcmp0 (attr->key, "sendonly") == 0) {
899 fail_unless (have_direction == FALSE,
900 "duplicate/multiple directions for media %u", j);
901 have_direction = TRUE;
902 fail_unless_equals_string (attr->key, expected_directions[i]);
903 } else if (g_strcmp0 (attr->key, "recvonly") == 0) {
904 fail_unless (have_direction == FALSE,
905 "duplicate/multiple directions for media %u", j);
906 have_direction = TRUE;
907 fail_unless_equals_string (attr->key, expected_directions[i]);
908 } else if (g_strcmp0 (attr->key, "sendrecv") == 0) {
909 fail_unless (have_direction == FALSE,
910 "duplicate/multiple directions for media %u", j);
911 have_direction = TRUE;
912 fail_unless_equals_string (attr->key, expected_directions[i]);
915 fail_unless (have_direction, "no direction attribute in media %u", i);
921 on_sdp_media_no_duplicate_payloads (struct test_webrtc *t, GstElement * element,
922 GstWebRTCSessionDescription * desc, gpointer user_data)
926 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
927 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
929 GArray *media_formats = g_array_new (FALSE, FALSE, sizeof (int));
930 for (j = 0; j < gst_sdp_media_formats_len (media); j++) {
931 int pt = atoi (gst_sdp_media_get_format (media, j));
932 for (k = 0; k < media_formats->len; k++) {
933 int val = g_array_index (media_formats, int, k);
935 fail ("found an unexpected duplicate payload type %u within media %u",
938 g_array_append_val (media_formats, pt);
940 g_array_free (media_formats, TRUE);
945 on_sdp_media_count_formats (struct test_webrtc *t, GstElement * element,
946 GstWebRTCSessionDescription * desc, gpointer user_data)
948 guint *expected_n_media_formats = user_data;
951 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
952 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
953 fail_unless_equals_int (gst_sdp_media_formats_len (media),
954 expected_n_media_formats[i]);
959 on_sdp_media_setup (struct test_webrtc *t, GstElement * element,
960 GstWebRTCSessionDescription * desc, gpointer user_data)
962 gchar **expected_setup = user_data;
965 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
966 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
967 gboolean have_setup = FALSE;
970 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
971 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
973 if (g_strcmp0 (attr->key, "setup") == 0) {
974 fail_unless (have_setup == FALSE,
975 "duplicate/multiple setup for media %u", j);
977 fail_unless_equals_string (attr->value, expected_setup[i]);
980 fail_unless (have_setup, "no setup attribute in media %u", i);
985 add_fake_audio_src_harness (GstHarness * h, gint pt)
987 GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
988 GstStructure *s = gst_caps_get_structure (caps, 0);
989 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
990 gst_harness_set_src_caps (h, caps);
991 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
995 add_fake_video_src_harness (GstHarness * h, gint pt)
997 GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
998 GstStructure *s = gst_caps_get_structure (caps, 0);
999 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
1000 gst_harness_set_src_caps (h, caps);
1001 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
1004 static struct test_webrtc *
1005 create_audio_test (void)
1007 struct test_webrtc *t = test_webrtc_new ();
1010 t->on_negotiation_needed = NULL;
1011 t->on_ice_candidate = NULL;
1012 t->on_pad_added = _pad_added_fakesink;
1014 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
1015 add_fake_audio_src_harness (h, 96);
1016 t->harnesses = g_list_prepend (t->harnesses, h);
1021 GST_START_TEST (test_audio)
1023 struct test_webrtc *t = create_audio_test ();
1024 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1026 guint media_format_count[] = { 1 };
1027 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1028 media_format_count, &no_duplicate_payloads);
1029 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
1031 const gchar *expected_offer_setup[] = { "actpass", };
1032 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1033 const gchar *expected_answer_setup[] = { "active", };
1034 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1036 const gchar *expected_offer_direction[] = { "sendrecv", };
1037 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1039 const gchar *expected_answer_direction[] = { "recvonly", };
1040 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1043 /* check that a single stream connection creates the associated number
1044 * of media sections */
1046 test_validate_sdp (t, &offer, &answer);
1047 test_webrtc_free (t);
1053 _check_ice_port_restriction (struct test_webrtc *t, GstElement * element,
1054 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
1057 GMatchInfo *match_info;
1059 gchar *candidate_port;
1060 gchar *candidate_protocol;
1061 gchar *candidate_typ;
1066 g_regex_new ("candidate:(\\d+) (1) (UDP|TCP) (\\d+) ([0-9.]+|[0-9a-f:]+)"
1067 " (\\d+) typ ([a-z]+)", 0, 0, NULL);
1069 g_regex_match (regex, candidate, 0, &match_info);
1070 fail_unless (g_match_info_get_match_count (match_info) == 8, candidate);
1072 candidate_protocol = g_match_info_fetch (match_info, 2);
1073 candidate_port = g_match_info_fetch (match_info, 6);
1074 candidate_typ = g_match_info_fetch (match_info, 7);
1076 peer_number = t->webrtc1 == element ? 1 : 2;
1078 port_as_int = atoi (candidate_port);
1080 if (!g_strcmp0 (candidate_typ, "host") && port_as_int != 9) {
1081 guint expected_min = peer_number * 10000 + 1000;
1082 guint expected_max = expected_min + 999;
1084 fail_unless (port_as_int >= expected_min);
1085 fail_unless (port_as_int <= expected_max);
1088 g_free (candidate_port);
1089 g_free (candidate_protocol);
1090 g_free (candidate_typ);
1091 g_match_info_free (match_info);
1092 g_regex_unref (regex);
1095 GST_START_TEST (test_ice_port_restriction)
1097 struct test_webrtc *t = create_audio_test ();
1100 VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1101 VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1104 * Ports are defined as follows "{peer}{protocol}000"
1105 * - peer number: "1" for t->webrtc1, "2" for t->webrtc2
1107 g_object_get (t->webrtc1, "ice-agent", &webrtcice, NULL);
1108 g_object_set (webrtcice, "min-rtp-port", 11000, "max-rtp-port", 11999, NULL);
1109 g_object_unref (webrtcice);
1111 g_object_get (t->webrtc2, "ice-agent", &webrtcice, NULL);
1112 g_object_set (webrtcice, "min-rtp-port", 21000, "max-rtp-port", 21999, NULL);
1113 g_object_unref (webrtcice);
1115 t->on_ice_candidate = _check_ice_port_restriction;
1116 test_validate_sdp (t, &offer, &answer);
1118 test_webrtc_wait_for_ice_gathering_complete (t);
1119 test_webrtc_free (t);
1124 static struct test_webrtc *
1125 create_audio_video_test (void)
1127 struct test_webrtc *t = create_audio_test ();
1130 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1131 add_fake_video_src_harness (h, 97);
1132 t->harnesses = g_list_prepend (t->harnesses, h);
1137 GST_START_TEST (test_audio_video)
1139 struct test_webrtc *t = create_audio_video_test ();
1140 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1142 guint media_format_count[] = { 1, 1 };
1143 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1144 media_format_count, &no_duplicate_payloads);
1145 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1147 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1148 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1149 const gchar *expected_answer_setup[] = { "active", "active" };
1150 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1152 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1153 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1155 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
1156 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1159 /* check that a dual stream connection creates the associated number
1160 * of media sections */
1162 test_validate_sdp (t, &offer, &answer);
1163 test_webrtc_free (t);
1168 GST_START_TEST (test_media_direction)
1170 struct test_webrtc *t = create_audio_video_test ();
1171 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1173 guint media_format_count[] = { 1, 1 };
1174 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1175 media_format_count, &no_duplicate_payloads);
1176 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1178 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1179 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1180 const gchar *expected_answer_setup[] = { "active", "active" };
1181 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1184 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1185 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1187 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
1188 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1192 /* check the default media directions for transceivers */
1194 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1195 add_fake_audio_src_harness (h, 96);
1196 t->harnesses = g_list_prepend (t->harnesses, h);
1198 test_validate_sdp (t, &offer, &answer);
1199 test_webrtc_free (t);
1205 on_sdp_media_payload_types (struct test_webrtc *t, GstElement * element,
1206 GstWebRTCSessionDescription * desc, gpointer user_data)
1208 const GstSDPMedia *vmedia;
1209 guint video_mline = GPOINTER_TO_UINT (user_data);
1212 vmedia = gst_sdp_message_get_media (desc->sdp, video_mline);
1214 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
1215 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
1217 if (!g_strcmp0 (attr->key, "rtpmap")) {
1218 if (g_str_has_prefix (attr->value, "97")) {
1219 fail_unless_equals_string (attr->value, "97 VP8/90000");
1220 } else if (g_str_has_prefix (attr->value, "96")) {
1221 fail_unless_equals_string (attr->value, "96 red/90000");
1222 } else if (g_str_has_prefix (attr->value, "98")) {
1223 fail_unless_equals_string (attr->value, "98 ulpfec/90000");
1224 } else if (g_str_has_prefix (attr->value, "99")) {
1225 fail_unless_equals_string (attr->value, "99 rtx/90000");
1226 } else if (g_str_has_prefix (attr->value, "100")) {
1227 fail_unless_equals_string (attr->value, "100 rtx/90000");
1228 } else if (g_str_has_prefix (attr->value, "101")) {
1229 fail_unless_equals_string (attr->value, "101 H264/90000");
1235 /* In this test we verify that webrtcbin will pick available payload
1236 * types when it needs to, in that example for RTX and FEC */
1237 GST_START_TEST (test_payload_types)
1239 struct test_webrtc *t = create_audio_video_test ();
1240 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1242 guint media_format_count[] = { 1, 5, };
1243 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1244 media_format_count, &no_duplicate_payloads);
1245 VAL_SDP_INIT (payloads, on_sdp_media_payload_types, GUINT_TO_POINTER (1),
1247 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2), &payloads);
1248 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1249 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1250 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1251 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1253 GstWebRTCRTPTransceiver *trans;
1254 GArray *transceivers;
1256 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1257 fail_unless_equals_int (transceivers->len, 2);
1258 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1259 g_object_set (trans, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, "do-nack", TRUE,
1261 g_array_unref (transceivers);
1263 /* We don't really care about the answer here */
1264 test_validate_sdp (t, &offer, NULL);
1265 test_webrtc_free (t);
1270 GST_START_TEST (test_no_nice_elements_request_pad)
1272 struct test_webrtc *t = test_webrtc_new ();
1273 GstPluginFeature *nicesrc, *nicesink;
1274 GstRegistry *registry;
1277 /* check that the absence of libnice elements posts an error on the bus
1278 * when requesting a pad */
1280 registry = gst_registry_get ();
1281 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1282 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1285 gst_registry_remove_feature (registry, nicesrc);
1287 gst_registry_remove_feature (registry, nicesink);
1289 t->bus_message = NULL;
1291 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
1292 fail_unless (pad == NULL);
1294 test_webrtc_wait_for_answer_error_eos (t);
1295 fail_unless_equals_int (STATE_ERROR, t->state);
1296 test_webrtc_free (t);
1299 gst_registry_add_feature (registry, nicesrc);
1301 gst_registry_add_feature (registry, nicesink);
1306 GST_START_TEST (test_no_nice_elements_state_change)
1308 struct test_webrtc *t = test_webrtc_new ();
1309 GstPluginFeature *nicesrc, *nicesink;
1310 GstRegistry *registry;
1312 /* check that the absence of libnice elements posts an error on the bus */
1314 registry = gst_registry_get ();
1315 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1316 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1319 gst_registry_remove_feature (registry, nicesrc);
1321 gst_registry_remove_feature (registry, nicesink);
1323 t->bus_message = NULL;
1324 gst_element_set_state (t->webrtc1, GST_STATE_READY);
1326 test_webrtc_wait_for_answer_error_eos (t);
1327 fail_unless_equals_int (STATE_ERROR, t->state);
1328 test_webrtc_free (t);
1331 gst_registry_add_feature (registry, nicesrc);
1333 gst_registry_add_feature (registry, nicesink);
1339 validate_rtc_stats (const GstStructure * s)
1341 GstWebRTCStatsType type = 0;
1345 fail_unless (gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type,
1347 fail_unless (gst_structure_get (s, "id", G_TYPE_STRING, &id, NULL));
1348 fail_unless (gst_structure_get (s, "timestamp", G_TYPE_DOUBLE, &ts, NULL));
1349 fail_unless (type != 0);
1350 fail_unless (ts != 0.);
1351 fail_unless (id != NULL);
1357 validate_codec_stats (const GstStructure * s)
1359 guint pt = 0, clock_rate = 0;
1361 fail_unless (gst_structure_get (s, "payload-type", G_TYPE_UINT, &pt, NULL));
1362 fail_unless (gst_structure_get (s, "clock-rate", G_TYPE_UINT, &clock_rate,
1364 fail_unless (pt >= 0 && pt <= 127);
1365 fail_unless (clock_rate >= 0);
1369 validate_rtc_stream_stats (const GstStructure * s, const GstStructure * stats)
1371 gchar *codec_id, *transport_id;
1372 GstStructure *codec, *transport;
1374 fail_unless (gst_structure_get (s, "codec-id", G_TYPE_STRING, &codec_id,
1376 fail_unless (gst_structure_get (s, "transport-id", G_TYPE_STRING,
1377 &transport_id, NULL));
1379 fail_unless (gst_structure_get (stats, codec_id, GST_TYPE_STRUCTURE, &codec,
1381 fail_unless (gst_structure_get (stats, transport_id, GST_TYPE_STRUCTURE,
1384 fail_unless (codec != NULL);
1385 fail_unless (transport != NULL);
1387 gst_structure_free (transport);
1388 gst_structure_free (codec);
1391 g_free (transport_id);
1395 validate_inbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1397 guint ssrc, fir, pli, nack;
1399 guint64 packets_received, bytes_received;
1402 GstStructure *remote;
1404 validate_rtc_stream_stats (s, stats);
1406 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1407 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1408 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1409 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1410 fail_unless (gst_structure_get (s, "packets-received", G_TYPE_UINT64,
1411 &packets_received, NULL));
1412 fail_unless (gst_structure_get (s, "bytes-received", G_TYPE_UINT64,
1413 &bytes_received, NULL));
1414 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1415 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1417 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1419 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1421 fail_unless (remote != NULL);
1423 gst_structure_free (remote);
1428 validate_remote_inbound_rtp_stats (const GstStructure * s,
1429 const GstStructure * stats)
1435 GstStructure *local;
1437 validate_rtc_stream_stats (s, stats);
1439 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1440 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1441 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1443 fail_unless (gst_structure_get (s, "round-trip-time", G_TYPE_DOUBLE, &rtt,
1445 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1447 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1449 fail_unless (local != NULL);
1451 gst_structure_free (local);
1456 validate_outbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1458 guint ssrc, fir, pli, nack;
1459 guint64 packets_sent, bytes_sent;
1461 GstStructure *remote;
1463 validate_rtc_stream_stats (s, stats);
1465 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1466 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1467 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1468 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1469 fail_unless (gst_structure_get (s, "packets-sent", G_TYPE_UINT64,
1470 &packets_sent, NULL));
1471 fail_unless (gst_structure_get (s, "bytes-sent", G_TYPE_UINT64, &bytes_sent,
1473 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1475 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1477 fail_unless (remote != NULL);
1479 gst_structure_free (remote);
1484 validate_remote_outbound_rtp_stats (const GstStructure * s,
1485 const GstStructure * stats)
1489 GstStructure *local;
1491 validate_rtc_stream_stats (s, stats);
1493 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1494 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1496 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1498 fail_unless (local != NULL);
1500 gst_structure_free (local);
1505 validate_stats_foreach (GQuark field_id, const GValue * value,
1506 const GstStructure * stats)
1508 const gchar *field = g_quark_to_string (field_id);
1509 GstWebRTCStatsType type;
1510 const GstStructure *s;
1512 fail_unless (GST_VALUE_HOLDS_STRUCTURE (value));
1514 s = gst_value_get_structure (value);
1516 GST_INFO ("validating field %s %" GST_PTR_FORMAT, field, s);
1518 validate_rtc_stats (s);
1519 gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type, NULL);
1520 if (type == GST_WEBRTC_STATS_CODEC) {
1521 validate_codec_stats (s);
1522 } else if (type == GST_WEBRTC_STATS_INBOUND_RTP) {
1523 validate_inbound_rtp_stats (s, stats);
1524 } else if (type == GST_WEBRTC_STATS_OUTBOUND_RTP) {
1525 validate_outbound_rtp_stats (s, stats);
1526 } else if (type == GST_WEBRTC_STATS_REMOTE_INBOUND_RTP) {
1527 validate_remote_inbound_rtp_stats (s, stats);
1528 } else if (type == GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP) {
1529 validate_remote_outbound_rtp_stats (s, stats);
1530 } else if (type == GST_WEBRTC_STATS_CSRC) {
1531 } else if (type == GST_WEBRTC_STATS_PEER_CONNECTION) {
1532 } else if (type == GST_WEBRTC_STATS_DATA_CHANNEL) {
1533 } else if (type == GST_WEBRTC_STATS_STREAM) {
1534 } else if (type == GST_WEBRTC_STATS_TRANSPORT) {
1535 } else if (type == GST_WEBRTC_STATS_CANDIDATE_PAIR) {
1536 } else if (type == GST_WEBRTC_STATS_LOCAL_CANDIDATE) {
1537 } else if (type == GST_WEBRTC_STATS_REMOTE_CANDIDATE) {
1538 } else if (type == GST_WEBRTC_STATS_CERTIFICATE) {
1540 g_assert_not_reached ();
1547 validate_stats (const GstStructure * stats)
1549 gst_structure_foreach (stats,
1550 (GstStructureForeachFunc) validate_stats_foreach, (gpointer) stats);
1554 _on_stats (GstPromise * promise, gpointer user_data)
1556 struct test_webrtc *t = user_data;
1557 const GstStructure *reply = gst_promise_get_reply (promise);
1560 validate_stats (reply);
1561 i = GPOINTER_TO_INT (t->user_data);
1563 t->user_data = GINT_TO_POINTER (i);
1565 test_webrtc_signal_state (t, STATE_CUSTOM);
1567 gst_promise_unref (promise);
1570 GST_START_TEST (test_session_stats)
1572 struct test_webrtc *t = test_webrtc_new ();
1575 /* test that the stats generated without any streams are sane */
1576 t->on_negotiation_needed = NULL;
1577 test_validate_sdp (t, NULL, NULL);
1579 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1580 g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p);
1581 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1582 g_signal_emit_by_name (t->webrtc2, "get-stats", NULL, p);
1584 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1586 test_webrtc_free (t);
1591 GST_START_TEST (test_add_transceiver)
1593 struct test_webrtc *t = test_webrtc_new ();
1594 GstWebRTCRTPTransceiverDirection direction, trans_direction;
1595 GstWebRTCRTPTransceiver *trans;
1597 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
1598 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, NULL,
1600 fail_unless (trans != NULL);
1601 g_object_get (trans, "direction", &trans_direction, NULL);
1602 fail_unless_equals_int (direction, trans_direction);
1604 gst_object_unref (trans);
1606 test_webrtc_free (t);
1611 GST_START_TEST (test_get_transceivers)
1613 struct test_webrtc *t = create_audio_test ();
1614 GstWebRTCRTPTransceiver *trans;
1615 GArray *transceivers;
1617 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1618 fail_unless (transceivers != NULL);
1619 fail_unless_equals_int (1, transceivers->len);
1621 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
1622 fail_unless (trans != NULL);
1624 g_array_unref (transceivers);
1626 test_webrtc_free (t);
1631 GST_START_TEST (test_add_recvonly_transceiver)
1633 struct test_webrtc *t = test_webrtc_new ();
1634 GstWebRTCRTPTransceiverDirection direction;
1635 GstWebRTCRTPTransceiver *trans;
1636 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1638 guint media_format_count[] = { 1, 1, };
1639 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1640 media_format_count, &no_duplicate_payloads);
1641 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
1643 const gchar *expected_offer_setup[] = { "actpass", };
1644 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1645 const gchar *expected_answer_setup[] = { "active", };
1646 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1648 const gchar *expected_offer_direction[] = { "recvonly", };
1649 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1651 const gchar *expected_answer_direction[] = { "sendonly", };
1652 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1657 /* add a transceiver that will only receive an opus stream and check that
1658 * the created offer is marked as recvonly */
1659 t->on_negotiation_needed = NULL;
1660 t->on_ice_candidate = NULL;
1661 t->on_pad_added = _pad_added_fakesink;
1663 /* setup recvonly transceiver */
1664 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1665 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1666 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1668 gst_caps_unref (caps);
1669 fail_unless (trans != NULL);
1670 gst_object_unref (trans);
1672 /* setup sendonly peer */
1673 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1674 add_fake_audio_src_harness (h, 96);
1675 t->harnesses = g_list_prepend (t->harnesses, h);
1676 test_validate_sdp (t, &offer, &answer);
1678 test_webrtc_free (t);
1683 GST_START_TEST (test_recvonly_sendonly)
1685 struct test_webrtc *t = test_webrtc_new ();
1686 GstWebRTCRTPTransceiverDirection direction;
1687 GstWebRTCRTPTransceiver *trans;
1688 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1690 guint media_format_count[] = { 1, 1, };
1691 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1692 media_format_count, &no_duplicate_payloads);
1693 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1695 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1696 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1697 const gchar *expected_answer_setup[] = { "active", "active" };
1698 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1700 const gchar *expected_offer_direction[] = { "recvonly", "sendonly" };
1701 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1703 const gchar *expected_answer_direction[] = { "sendonly", "recvonly" };
1704 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1708 GArray *transceivers;
1710 /* add a transceiver that will only receive an opus stream and check that
1711 * the created offer is marked as recvonly */
1712 t->on_negotiation_needed = NULL;
1713 t->on_ice_candidate = NULL;
1714 t->on_pad_added = _pad_added_fakesink;
1716 /* setup recvonly transceiver */
1717 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1718 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1719 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1721 gst_caps_unref (caps);
1722 fail_unless (trans != NULL);
1723 gst_object_unref (trans);
1725 /* setup sendonly stream */
1726 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1727 add_fake_audio_src_harness (h, 96);
1728 t->harnesses = g_list_prepend (t->harnesses, h);
1729 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1730 fail_unless (transceivers != NULL);
1731 fail_unless_equals_int (transceivers->len, 2);
1732 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1733 g_object_set (trans, "direction",
1734 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, NULL);
1736 g_array_unref (transceivers);
1738 /* setup sendonly peer */
1739 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1740 add_fake_audio_src_harness (h, 96);
1741 t->harnesses = g_list_prepend (t->harnesses, h);
1743 test_validate_sdp (t, &offer, &answer);
1745 test_webrtc_free (t);
1751 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1752 GstWebRTCSessionDescription * desc, gpointer user_data)
1754 gboolean have_data_channel = FALSE;
1757 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1758 if (_message_media_is_datachannel (desc->sdp, i)) {
1759 /* there should only be one data channel m= section */
1760 fail_unless_equals_int (FALSE, have_data_channel);
1761 have_data_channel = TRUE;
1765 fail_unless_equals_int (TRUE, have_data_channel);
1769 on_channel_error_not_reached (GObject * channel, GError * error,
1772 g_assert_not_reached ();
1775 GST_START_TEST (test_data_channel_create)
1777 struct test_webrtc *t = test_webrtc_new ();
1778 GObject *channel = NULL;
1779 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1780 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1783 t->on_negotiation_needed = NULL;
1784 t->on_ice_candidate = NULL;
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 g_object_get (channel, "label", &label, NULL);
1795 g_assert_cmpstr (label, ==, "label");
1796 g_signal_connect (channel, "on-error",
1797 G_CALLBACK (on_channel_error_not_reached), NULL);
1799 test_validate_sdp (t, &offer, &offer);
1801 g_object_unref (channel);
1803 test_webrtc_free (t);
1809 have_data_channel (struct test_webrtc *t, GstElement * element,
1810 GObject * our, gpointer user_data)
1812 GObject *other = user_data;
1813 gchar *our_label, *other_label;
1815 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1818 g_object_get (our, "label", &our_label, NULL);
1819 g_object_get (other, "label", &other_label, NULL);
1821 g_assert_cmpstr (our_label, ==, other_label);
1824 g_free (other_label);
1826 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1829 GST_START_TEST (test_data_channel_remote_notify)
1831 struct test_webrtc *t = test_webrtc_new ();
1832 GObject *channel = NULL;
1833 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1834 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1836 t->on_negotiation_needed = NULL;
1837 t->on_ice_candidate = NULL;
1838 t->on_data_channel = have_data_channel;
1840 fail_if (gst_element_set_state (t->webrtc1,
1841 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1842 fail_if (gst_element_set_state (t->webrtc2,
1843 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1845 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1847 g_assert_nonnull (channel);
1848 t->data_channel_data = channel;
1849 g_signal_connect (channel, "on-error",
1850 G_CALLBACK (on_channel_error_not_reached), NULL);
1852 fail_if (gst_element_set_state (t->webrtc1,
1853 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1854 fail_if (gst_element_set_state (t->webrtc2,
1855 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1857 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1859 g_object_unref (channel);
1860 test_webrtc_free (t);
1865 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1868 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1870 GstWebRTCDataChannelState state;
1873 g_object_get (channel, "ready-state", &state, NULL);
1874 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1876 expected = g_object_steal_data (channel, "expected");
1877 g_assert_cmpstr (expected, ==, str);
1880 test_webrtc_signal_state (t, STATE_CUSTOM);
1884 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1885 GObject * our, gpointer user_data)
1887 GObject *other = user_data;
1888 GstWebRTCDataChannelState state;
1890 g_object_get (our, "ready-state", &state, NULL);
1891 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1893 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1894 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1897 g_signal_connect (other, "on-error",
1898 G_CALLBACK (on_channel_error_not_reached), NULL);
1899 g_signal_emit_by_name (other, "send-string", test_string);
1902 GST_START_TEST (test_data_channel_transfer_string)
1904 struct test_webrtc *t = test_webrtc_new ();
1905 GObject *channel = NULL;
1906 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1907 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1909 t->on_negotiation_needed = NULL;
1910 t->on_ice_candidate = NULL;
1911 t->on_data_channel = have_data_channel_transfer_string;
1913 fail_if (gst_element_set_state (t->webrtc1,
1914 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1915 fail_if (gst_element_set_state (t->webrtc2,
1916 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1918 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1920 g_assert_nonnull (channel);
1921 t->data_channel_data = channel;
1922 g_signal_connect (channel, "on-error",
1923 G_CALLBACK (on_channel_error_not_reached), NULL);
1925 fail_if (gst_element_set_state (t->webrtc1,
1926 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1927 fail_if (gst_element_set_state (t->webrtc2,
1928 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1930 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1932 g_object_unref (channel);
1933 test_webrtc_free (t);
1938 #define g_assert_cmpbytes(b1, b2) \
1941 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1942 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1943 g_assert_cmpmem (d1, l1, d2, l2); \
1947 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1949 GstWebRTCDataChannelState state;
1952 g_object_get (channel, "ready-state", &state, NULL);
1953 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1955 expected = g_object_steal_data (channel, "expected");
1956 g_assert_cmpbytes (data, expected);
1957 g_bytes_unref (expected);
1959 test_webrtc_signal_state (t, STATE_CUSTOM);
1963 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1964 GObject * our, gpointer user_data)
1966 GObject *other = user_data;
1967 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1968 GstWebRTCDataChannelState state;
1970 g_object_get (our, "ready-state", &state, NULL);
1971 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1973 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1974 (GDestroyNotify) g_bytes_unref);
1975 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1977 g_signal_connect (other, "on-error",
1978 G_CALLBACK (on_channel_error_not_reached), NULL);
1979 g_signal_emit_by_name (other, "send-data", data);
1980 g_bytes_unref (data);
1983 GST_START_TEST (test_data_channel_transfer_data)
1985 struct test_webrtc *t = test_webrtc_new ();
1986 GObject *channel = NULL;
1987 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1988 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1990 t->on_negotiation_needed = NULL;
1991 t->on_ice_candidate = NULL;
1992 t->on_data_channel = have_data_channel_transfer_data;
1994 fail_if (gst_element_set_state (t->webrtc1,
1995 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1996 fail_if (gst_element_set_state (t->webrtc2,
1997 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1999 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2001 g_assert_nonnull (channel);
2002 t->data_channel_data = channel;
2003 g_signal_connect (channel, "on-error",
2004 G_CALLBACK (on_channel_error_not_reached), NULL);
2006 fail_if (gst_element_set_state (t->webrtc1,
2007 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2008 fail_if (gst_element_set_state (t->webrtc2,
2009 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2011 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2013 g_object_unref (channel);
2014 test_webrtc_free (t);
2020 have_data_channel_create_data_channel (struct test_webrtc *t,
2021 GstElement * element, GObject * our, gpointer user_data)
2025 t->on_data_channel = have_data_channel_transfer_string;
2027 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2029 g_assert_nonnull (another);
2030 t->data_channel_data = another;
2031 t->data_channel_notify = (GDestroyNotify) g_object_unref;
2032 g_signal_connect (another, "on-error",
2033 G_CALLBACK (on_channel_error_not_reached), NULL);
2036 GST_START_TEST (test_data_channel_create_after_negotiate)
2038 struct test_webrtc *t = test_webrtc_new ();
2039 GObject *channel = NULL;
2040 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2041 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2043 t->on_negotiation_needed = NULL;
2044 t->on_ice_candidate = NULL;
2045 t->on_data_channel = have_data_channel_create_data_channel;
2047 fail_if (gst_element_set_state (t->webrtc1,
2048 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2049 fail_if (gst_element_set_state (t->webrtc2,
2050 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2052 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
2054 g_assert_nonnull (channel);
2055 t->data_channel_data = channel;
2056 g_signal_connect (channel, "on-error",
2057 G_CALLBACK (on_channel_error_not_reached), NULL);
2059 fail_if (gst_element_set_state (t->webrtc1,
2060 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2061 fail_if (gst_element_set_state (t->webrtc2,
2062 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2064 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2066 g_object_unref (channel);
2067 test_webrtc_free (t);
2072 struct test_data_channel
2082 have_data_channel_mark_open (struct test_webrtc *t,
2083 GstElement * element, GObject * our, gpointer user_data)
2085 struct test_data_channel *tdc = t->data_channel_data;
2088 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2089 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
2094 is_data_channel_open (GObject * channel)
2096 GstWebRTCDataChannelState ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
2099 g_object_get (channel, "ready-state", &ready_state, NULL);
2102 return ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
2106 on_data_channel_open (GObject * channel, GParamSpec * pspec,
2107 struct test_webrtc *t)
2109 struct test_data_channel *tdc = t->data_channel_data;
2111 if (is_data_channel_open (channel)) {
2112 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2113 test_webrtc_signal_state (t, STATE_CUSTOM);
2119 on_data_channel_close (GObject * channel, GParamSpec * pspec,
2120 struct test_webrtc *t)
2122 struct test_data_channel *tdc = t->data_channel_data;
2123 GstWebRTCDataChannelState ready_state;
2125 g_object_get (channel, "ready-state", &ready_state, NULL);
2127 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
2128 g_atomic_int_add (&tdc->n_closed, 1);
2133 on_data_channel_destroyed (gpointer data, GObject * where_the_object_was)
2135 struct test_webrtc *t = data;
2136 struct test_data_channel *tdc = t->data_channel_data;
2138 if (where_the_object_was == tdc->dc1) {
2140 } else if (where_the_object_was == tdc->dc2) {
2144 if (g_atomic_int_add (&tdc->n_destroyed, 1) == 1) {
2145 test_webrtc_signal_state (t, STATE_CUSTOM);
2149 GST_START_TEST (test_data_channel_close)
2151 #define NUM_CHANNELS 3
2152 struct test_webrtc *t = test_webrtc_new ();
2153 struct test_data_channel tdc = { NULL, NULL, 0, 0, 0 };
2154 guint channel_id[NUM_CHANNELS] = { 0, 1, 2 };
2157 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2158 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2160 t->on_negotiation_needed = NULL;
2161 t->on_ice_candidate = NULL;
2162 t->on_data_channel = have_data_channel_mark_open;
2163 t->data_channel_data = &tdc;
2165 fail_if (gst_element_set_state (t->webrtc1,
2166 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2167 fail_if (gst_element_set_state (t->webrtc2,
2168 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2170 /* open and close NUM_CHANNELS data channels to verify that we can reuse the
2171 * stream id of a previously closed data channel and that we have the same
2172 * behaviour no matter if we create the channel in READY or PLAYING state */
2173 for (i = 0; i < NUM_CHANNELS; i++) {
2176 tdc.n_destroyed = 0;
2178 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2180 g_assert_nonnull (tdc.dc1);
2181 g_object_unref (tdc.dc1); /* webrtcbin should still hold a ref */
2182 g_object_weak_ref (tdc.dc1, on_data_channel_destroyed, t);
2183 g_signal_connect (tdc.dc1, "on-error",
2184 G_CALLBACK (on_channel_error_not_reached), NULL);
2185 sigid = g_signal_connect (tdc.dc1, "notify::ready-state",
2186 G_CALLBACK (on_data_channel_open), t);
2189 fail_if (gst_element_set_state (t->webrtc1,
2190 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2191 fail_if (gst_element_set_state (t->webrtc2,
2192 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2194 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2196 /* FIXME: Creating a data channel may result in "on-open" being sent
2197 * before we even had a chance to register the signal. For this test we
2198 * want to make sure that the channel is actually open before we try to
2199 * close it. So if we didn't receive the signal we fall back to a 1s
2200 * timeout where we explicitly check if both channels are open. */
2201 gint64 timeout = g_get_monotonic_time () + 1 * G_TIME_SPAN_SECOND;
2202 g_mutex_lock (&t->lock);
2203 while (((1 << t->state) & STATE_CUSTOM) == 0) {
2204 if (!g_cond_wait_until (&t->cond, &t->lock, timeout)) {
2205 g_assert (is_data_channel_open (tdc.dc1)
2206 && is_data_channel_open (tdc.dc2));
2210 g_mutex_unlock (&t->lock);
2213 g_object_get (tdc.dc1, "id", &channel_id[i], NULL);
2215 g_signal_handler_disconnect (tdc.dc1, sigid);
2216 g_object_weak_ref (tdc.dc2, on_data_channel_destroyed, t);
2217 g_signal_connect (tdc.dc1, "notify::ready-state",
2218 G_CALLBACK (on_data_channel_close), t);
2219 g_signal_connect (tdc.dc2, "notify::ready-state",
2220 G_CALLBACK (on_data_channel_close), t);
2221 test_webrtc_signal_state (t, STATE_NEW);
2223 /* currently we assume there is no renegotiation if the last data channel is
2224 * removed but if it changes this test could be extended to verify both
2225 * the behaviour of removing the last channel as well as the behaviour when
2226 * there are still data channels remaining */
2227 t->on_negotiation_needed = _negotiation_not_reached;
2228 g_signal_emit_by_name (tdc.dc1, "close");
2230 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2232 assert_equals_int (g_atomic_int_get (&tdc.n_closed), 2);
2233 assert_equals_pointer (tdc.dc1, NULL);
2234 assert_equals_pointer (tdc.dc2, NULL);
2236 test_webrtc_signal_state (t, STATE_NEW);
2239 /* verify the same stream id has been reused for each data channel */
2240 assert_equals_int (channel_id[0], channel_id[1]);
2241 assert_equals_int (channel_id[0], channel_id[2]);
2243 test_webrtc_free (t);
2250 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
2252 test_webrtc_signal_state (t, STATE_CUSTOM);
2256 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
2257 GstElement * element, GObject * our, gpointer user_data)
2259 g_signal_connect (our, "on-buffered-amount-low",
2260 G_CALLBACK (on_buffered_amount_low_emitted), t);
2261 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
2263 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
2265 g_signal_emit_by_name (our, "send-string", "A");
2268 GST_START_TEST (test_data_channel_low_threshold)
2270 struct test_webrtc *t = test_webrtc_new ();
2271 GObject *channel = NULL;
2272 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2273 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2275 t->on_negotiation_needed = NULL;
2276 t->on_ice_candidate = NULL;
2277 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
2279 fail_if (gst_element_set_state (t->webrtc1,
2280 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2281 fail_if (gst_element_set_state (t->webrtc2,
2282 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2284 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2286 g_assert_nonnull (channel);
2287 t->data_channel_data = channel;
2288 g_signal_connect (channel, "on-error",
2289 G_CALLBACK (on_channel_error_not_reached), NULL);
2291 fail_if (gst_element_set_state (t->webrtc1,
2292 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2293 fail_if (gst_element_set_state (t->webrtc2,
2294 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2296 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2298 g_object_unref (channel);
2299 test_webrtc_free (t);
2305 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
2307 g_assert_nonnull (error);
2309 test_webrtc_signal_state (t, STATE_CUSTOM);
2313 have_data_channel_transfer_large_data (struct test_webrtc *t,
2314 GstElement * element, GObject * our, gpointer user_data)
2316 GObject *other = user_data;
2317 const gsize size = 1024 * 1024;
2318 guint8 *random_data = g_new (guint8, size);
2322 for (i = 0; i < size; i++)
2323 random_data[i] = (guint8) (i & 0xff);
2325 data = g_bytes_new_with_free_func (random_data, size,
2326 (GDestroyNotify) g_free, random_data);
2328 g_object_set_data_full (our, "expected", g_bytes_ref (data),
2329 (GDestroyNotify) g_bytes_unref);
2330 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
2332 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
2333 g_signal_emit_by_name (other, "send-data", data);
2334 g_bytes_unref (data);
2337 GST_START_TEST (test_data_channel_max_message_size)
2339 struct test_webrtc *t = test_webrtc_new ();
2340 GObject *channel = NULL;
2341 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2342 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2344 t->on_negotiation_needed = NULL;
2345 t->on_ice_candidate = NULL;
2346 t->on_data_channel = have_data_channel_transfer_large_data;
2348 fail_if (gst_element_set_state (t->webrtc1,
2349 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2350 fail_if (gst_element_set_state (t->webrtc2,
2351 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2353 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2355 g_assert_nonnull (channel);
2356 t->data_channel_data = channel;
2358 fail_if (gst_element_set_state (t->webrtc1,
2359 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2360 fail_if (gst_element_set_state (t->webrtc2,
2361 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2363 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2365 g_object_unref (channel);
2366 test_webrtc_free (t);
2372 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
2373 struct test_webrtc *t)
2375 gint *n_ready = t->data_channel_data;
2376 GstWebRTCDataChannelState ready_state;
2378 g_object_get (channel, "ready-state", &ready_state, NULL);
2380 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
2381 if (g_atomic_int_add (n_ready, 1) >= 1) {
2382 test_webrtc_signal_state (t, STATE_CUSTOM);
2387 GST_START_TEST (test_data_channel_pre_negotiated)
2389 struct test_webrtc *t = test_webrtc_new ();
2390 GObject *channel1 = NULL, *channel2 = NULL;
2391 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2392 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2396 t->on_negotiation_needed = NULL;
2397 t->on_ice_candidate = NULL;
2399 fail_if (gst_element_set_state (t->webrtc1,
2400 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2401 fail_if (gst_element_set_state (t->webrtc2,
2402 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2404 s = gst_structure_new ("application/data-channel", "negotiated",
2405 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
2407 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
2409 g_assert_nonnull (channel1);
2410 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
2412 g_assert_nonnull (channel2);
2414 fail_if (gst_element_set_state (t->webrtc1,
2415 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2416 fail_if (gst_element_set_state (t->webrtc2,
2417 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2419 test_validate_sdp_full (t, &offer, &offer, 0, FALSE);
2421 t->data_channel_data = &n_ready;
2423 g_signal_connect (channel1, "notify::ready-state",
2424 G_CALLBACK (_on_ready_state_notify), t);
2425 g_signal_connect (channel2, "notify::ready-state",
2426 G_CALLBACK (_on_ready_state_notify), t);
2428 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2429 test_webrtc_signal_state (t, STATE_NEW);
2431 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
2433 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2435 g_object_unref (channel1);
2436 g_object_unref (channel2);
2437 gst_structure_free (s);
2438 test_webrtc_free (t);
2444 _count_non_rejected_media (struct test_webrtc *t, GstElement * element,
2445 GstWebRTCSessionDescription * sd, gpointer user_data)
2447 guint expected = GPOINTER_TO_UINT (user_data);
2448 guint non_rejected_media;
2451 non_rejected_media = 0;
2453 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2454 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2456 if (gst_sdp_media_get_port (media) != 0)
2457 non_rejected_media += 1;
2460 fail_unless_equals_int (non_rejected_media, expected);
2464 _check_bundle_tag (struct test_webrtc *t, GstElement * element,
2465 GstWebRTCSessionDescription * sd, gpointer user_data)
2467 gchar **bundled = NULL;
2468 GStrv expected = user_data;
2471 fail_unless (_parse_bundle (sd->sdp, &bundled, NULL));
2474 fail_unless_equals_int (g_strv_length (expected), 0);
2476 fail_unless_equals_int (g_strv_length (bundled), g_strv_length (expected));
2479 for (i = 0; i < g_strv_length (expected); i++) {
2480 fail_unless (g_strv_contains ((const gchar **) bundled, expected[i]));
2483 g_strfreev (bundled);
2487 _check_bundle_only_media (struct test_webrtc *t, GstElement * element,
2488 GstWebRTCSessionDescription * sd, gpointer user_data)
2490 gchar **expected_bundle_only = user_data;
2493 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2494 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2495 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2497 if (g_strv_contains ((const gchar **) expected_bundle_only, mid))
2498 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2502 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2504 struct test_webrtc *t = create_audio_video_test ();
2505 const gchar *bundle[] = { "audio0", "video1", NULL };
2506 const gchar *offer_bundle_only[] = { "video1", NULL };
2507 const gchar *answer_bundle_only[] = { NULL };
2509 guint media_format_count[] = { 1, 1, };
2510 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2511 media_format_count, NULL);
2512 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2514 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2515 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &payloads);
2516 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2517 GUINT_TO_POINTER (1), &bundle_tag);
2518 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2519 GUINT_TO_POINTER (2), &bundle_tag);
2520 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2522 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2523 &answer_non_reject);
2524 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2525 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2527 const gchar *expected_answer_setup[] = { "active", "active" };
2528 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2530 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2531 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2533 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2534 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2537 /* We set a max-bundle policy on the offering webrtcbin,
2538 * this means that all the offered medias should be part
2539 * of the group:BUNDLE attribute, and they should be marked
2542 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2544 /* We also set a max-bundle policy on the answering webrtcbin,
2545 * this means that all the offered medias should be part
2546 * of the group:BUNDLE attribute, but need not be marked
2549 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2552 test_validate_sdp (t, &offer, &answer);
2554 test_webrtc_free (t);
2559 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2561 struct test_webrtc *t = create_audio_video_test ();
2562 const gchar *bundle[] = { "audio0", "video1", NULL };
2563 const gchar *bundle_only[] = { NULL };
2565 guint media_format_count[] = { 1, 1, };
2566 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2567 media_format_count, NULL);
2568 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2570 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &count);
2571 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2572 GUINT_TO_POINTER (2), &bundle_tag);
2573 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
2575 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2576 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2578 const gchar *expected_answer_setup[] = { "active", "active" };
2579 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2581 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2582 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2584 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2585 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2588 /* We set a max-compat policy on the offering webrtcbin,
2589 * this means that all the offered medias should be part
2590 * of the group:BUNDLE attribute, and they should *not* be marked
2593 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2595 /* We set a max-bundle policy on the answering webrtcbin,
2596 * this means that all the offered medias should be part
2597 * of the group:BUNDLE attribute, but need not be marked
2600 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2603 test_validate_sdp (t, &offer, &answer);
2605 test_webrtc_free (t);
2610 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2612 struct test_webrtc *t = create_audio_video_test ();
2613 const gchar *offer_mid[] = { "audio0", "video1", NULL };
2614 const gchar *offer_bundle_only[] = { "video1", NULL };
2615 const gchar *answer_mid[] = { NULL };
2616 const gchar *answer_bundle_only[] = { NULL };
2618 guint media_format_count[] = { 1, 1, };
2619 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2620 media_format_count, NULL);
2621 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2623 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2624 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2625 GUINT_TO_POINTER (1), &payloads);
2626 VAL_SDP_INIT (offer_bundle_tag, _check_bundle_tag, offer_mid,
2628 VAL_SDP_INIT (answer_bundle_tag, _check_bundle_tag, answer_mid,
2630 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2632 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2633 &answer_bundle_tag);
2634 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2635 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2637 const gchar *expected_answer_setup[] = { "active", "active" };
2638 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2640 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2641 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2643 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2644 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2647 /* We set a max-bundle policy on the offering webrtcbin,
2648 * this means that all the offered medias should be part
2649 * of the group:BUNDLE attribute, and they should be marked
2652 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2654 /* We set a none policy on the answering webrtcbin,
2655 * this means that the answer should contain no bundled
2656 * medias, and as the bundle-policy of the offering webrtcbin
2657 * is set to max-bundle, only one media should be active.
2659 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2661 test_validate_sdp (t, &offer, &answer);
2663 test_webrtc_free (t);
2668 GST_START_TEST (test_bundle_audio_video_data)
2670 struct test_webrtc *t = create_audio_video_test ();
2671 const gchar *mids[] = { "audio0", "video1", "application2", NULL };
2672 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2673 const gchar *answer_bundle_only[] = { NULL };
2674 GObject *channel = NULL;
2676 guint media_format_count[] = { 1, 1, 1 };
2677 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2678 media_format_count, NULL);
2679 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (3),
2681 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2682 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, mids, &payloads);
2683 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2684 GUINT_TO_POINTER (1), &bundle_tag);
2685 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2686 GUINT_TO_POINTER (3), &bundle_tag);
2687 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2689 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2690 &answer_non_reject);
2691 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2692 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2694 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2695 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2697 const gchar *expected_offer_direction[] =
2698 { "sendrecv", "sendrecv", "sendrecv" };
2699 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2701 const gchar *expected_answer_direction[] =
2702 { "recvonly", "recvonly", "recvonly" };
2703 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2706 /* We set a max-bundle policy on the offering webrtcbin,
2707 * this means that all the offered medias should be part
2708 * of the group:BUNDLE attribute, and they should be marked
2711 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2713 /* We also set a max-bundle policy on the answering webrtcbin,
2714 * this means that all the offered medias should be part
2715 * of the group:BUNDLE attribute, but need not be marked
2718 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2721 fail_if (gst_element_set_state (t->webrtc1,
2722 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2723 fail_if (gst_element_set_state (t->webrtc2,
2724 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2726 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2729 test_validate_sdp (t, &offer, &answer);
2731 g_object_unref (channel);
2732 test_webrtc_free (t);
2737 GST_START_TEST (test_duplicate_nego)
2739 struct test_webrtc *t = create_audio_video_test ();
2740 guint media_format_count[] = { 1, 1, };
2741 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2742 media_format_count, NULL);
2743 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2745 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2746 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2747 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2749 const gchar *expected_answer_setup[] = { "active", "active" };
2750 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2752 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2753 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2755 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2756 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2759 guint negotiation_flag = 0;
2761 /* check that negotiating twice succeeds */
2763 t->on_negotiation_needed = on_negotiation_needed_hit;
2764 t->negotiation_data = &negotiation_flag;
2766 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2767 add_fake_audio_src_harness (h, 96);
2768 t->harnesses = g_list_prepend (t->harnesses, h);
2770 test_validate_sdp (t, &offer, &answer);
2771 fail_unless (negotiation_flag & (1 << 2));
2773 test_webrtc_reset_negotiation (t);
2774 test_validate_sdp (t, &offer, &answer);
2776 test_webrtc_free (t);
2781 GST_START_TEST (test_dual_audio)
2783 struct test_webrtc *t = create_audio_test ();
2784 guint media_format_count[] = { 1, 1, };
2785 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2786 media_format_count, NULL);
2787 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2789 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2790 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2791 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2793 const gchar *expected_answer_setup[] = { "active", "active" };
2794 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2796 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2797 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2799 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2800 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2803 GstWebRTCRTPTransceiver *trans;
2804 GArray *transceivers;
2807 /* test that each mline gets a unique transceiver even with the same caps */
2809 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
2810 add_fake_audio_src_harness (h, 96);
2811 t->harnesses = g_list_prepend (t->harnesses, h);
2813 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2814 add_fake_audio_src_harness (h, 96);
2815 t->harnesses = g_list_prepend (t->harnesses, h);
2817 t->on_negotiation_needed = NULL;
2818 test_validate_sdp (t, &offer, &answer);
2820 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
2821 fail_unless (transceivers != NULL);
2822 fail_unless_equals_int (2, transceivers->len);
2824 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
2825 fail_unless (trans != NULL);
2826 g_object_get (trans, "mlineindex", &mline, NULL);
2827 fail_unless_equals_int (mline, 0);
2829 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
2830 fail_unless (trans != NULL);
2831 g_object_get (trans, "mlineindex", &mline, NULL);
2832 fail_unless_equals_int (mline, 1);
2834 g_array_unref (transceivers);
2835 test_webrtc_free (t);
2841 sdp_increasing_session_version (struct test_webrtc *t, GstElement * element,
2842 GstWebRTCSessionDescription * desc, gpointer user_data)
2844 GstWebRTCSessionDescription *previous;
2845 const GstSDPOrigin *our_origin, *previous_origin;
2847 guint64 our_v, previous_v;
2850 TEST_SDP_IS_LOCAL (t, element,
2851 desc) ? "current-local-description" : "current-remote-description";
2852 g_object_get (element, prop, &previous, NULL);
2854 our_origin = gst_sdp_message_get_origin (desc->sdp);
2855 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2857 our_v = g_ascii_strtoull (our_origin->sess_version, NULL, 10);
2858 previous_v = g_ascii_strtoull (previous_origin->sess_version, NULL, 10);
2860 ck_assert_int_lt (previous_v, our_v);
2862 gst_webrtc_session_description_free (previous);
2866 sdp_equal_session_id (struct test_webrtc *t, GstElement * element,
2867 GstWebRTCSessionDescription * desc, gpointer user_data)
2869 GstWebRTCSessionDescription *previous;
2870 const GstSDPOrigin *our_origin, *previous_origin;
2874 TEST_SDP_IS_LOCAL (t, element,
2875 desc) ? "current-local-description" : "current-remote-description";
2876 g_object_get (element, prop, &previous, NULL);
2878 our_origin = gst_sdp_message_get_origin (desc->sdp);
2879 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2881 fail_unless_equals_string (previous_origin->sess_id, our_origin->sess_id);
2882 gst_webrtc_session_description_free (previous);
2886 sdp_media_equal_attribute (struct test_webrtc *t, GstElement * element,
2887 GstWebRTCSessionDescription * desc, GstWebRTCSessionDescription * previous,
2892 n = MIN (gst_sdp_message_medias_len (previous->sdp),
2893 gst_sdp_message_medias_len (desc->sdp));
2895 for (i = 0; i < n; i++) {
2896 const GstSDPMedia *our_media, *other_media;
2897 const gchar *our_mid, *other_mid;
2899 our_media = gst_sdp_message_get_media (desc->sdp, i);
2900 other_media = gst_sdp_message_get_media (previous->sdp, i);
2902 our_mid = gst_sdp_media_get_attribute_val (our_media, attr);
2903 other_mid = gst_sdp_media_get_attribute_val (other_media, attr);
2905 fail_unless_equals_string (our_mid, other_mid);
2910 sdp_media_equal_mid (struct test_webrtc *t, GstElement * element,
2911 GstWebRTCSessionDescription * desc, gpointer user_data)
2913 GstWebRTCSessionDescription *previous;
2917 TEST_SDP_IS_LOCAL (t, element,
2918 desc) ? "current-local-description" : "current-remote-description";
2919 g_object_get (element, prop, &previous, NULL);
2921 sdp_media_equal_attribute (t, element, desc, previous, "mid");
2923 gst_webrtc_session_description_free (previous);
2927 sdp_media_equal_ice_params (struct test_webrtc *t, GstElement * element,
2928 GstWebRTCSessionDescription * desc, gpointer user_data)
2930 GstWebRTCSessionDescription *previous;
2934 TEST_SDP_IS_LOCAL (t, element,
2935 desc) ? "current-local-description" : "current-remote-description";
2936 g_object_get (element, prop, &previous, NULL);
2938 sdp_media_equal_attribute (t, element, desc, previous, "ice-ufrag");
2939 sdp_media_equal_attribute (t, element, desc, previous, "ice-pwd");
2941 gst_webrtc_session_description_free (previous);
2945 sdp_media_equal_fingerprint (struct test_webrtc *t, GstElement * element,
2946 GstWebRTCSessionDescription * desc, gpointer user_data)
2948 GstWebRTCSessionDescription *previous;
2952 TEST_SDP_IS_LOCAL (t, element,
2953 desc) ? "current-local-description" : "current-remote-description";
2954 g_object_get (element, prop, &previous, NULL);
2956 sdp_media_equal_attribute (t, element, desc, previous, "fingerprint");
2958 gst_webrtc_session_description_free (previous);
2961 GST_START_TEST (test_renego_add_stream)
2963 struct test_webrtc *t = create_audio_video_test ();
2964 guint media_format_count[] = { 1, 1, 1 };
2965 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2966 media_format_count, NULL);
2967 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2969 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2970 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2971 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2973 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2974 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2976 const gchar *expected_offer_direction[] =
2977 { "sendrecv", "sendrecv", "sendrecv" };
2978 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2980 const gchar *expected_answer_direction[] =
2981 { "sendrecv", "recvonly", "recvonly" };
2982 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2984 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
2985 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
2987 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
2988 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
2990 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
2994 /* negotiate an AV stream and then renegotiate an extra stream */
2995 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2996 add_fake_audio_src_harness (h, 96);
2997 t->harnesses = g_list_prepend (t->harnesses, h);
2999 test_validate_sdp (t, &offer, &answer);
3001 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3002 add_fake_audio_src_harness (h, 98);
3003 t->harnesses = g_list_prepend (t->harnesses, h);
3005 media_formats.next = &renego_fingerprint;
3006 count.user_data = GUINT_TO_POINTER (3);
3009 test_webrtc_reset_negotiation (t);
3010 test_validate_sdp (t, &offer, &answer);
3012 test_webrtc_free (t);
3017 GST_START_TEST (test_renego_stream_add_data_channel)
3019 struct test_webrtc *t = create_audio_video_test ();
3021 guint media_format_count[] = { 1, 1, 1 };
3022 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3023 media_format_count, NULL);
3024 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3026 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3027 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3028 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3030 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3031 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3033 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv", NULL };
3034 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3036 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly", NULL };
3037 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3039 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3040 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3042 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3043 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3045 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3050 /* negotiate an AV stream and then renegotiate a data channel */
3051 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3052 add_fake_audio_src_harness (h, 96);
3053 t->harnesses = g_list_prepend (t->harnesses, h);
3055 test_validate_sdp (t, &offer, &answer);
3057 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3060 media_formats.next = &renego_fingerprint;
3061 count.user_data = GUINT_TO_POINTER (3);
3064 test_webrtc_reset_negotiation (t);
3065 test_validate_sdp (t, &offer, &answer);
3067 g_object_unref (channel);
3068 test_webrtc_free (t);
3073 GST_START_TEST (test_renego_data_channel_add_stream)
3075 struct test_webrtc *t = test_webrtc_new ();
3076 guint media_format_count[] = { 1, 1, 1 };
3077 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3078 media_format_count, NULL);
3079 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3081 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3082 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3083 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3085 const gchar *expected_answer_setup[] = { "active", "active" };
3086 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3088 const gchar *expected_offer_direction[] = { NULL, "sendrecv" };
3089 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3091 const gchar *expected_answer_direction[] = { NULL, "recvonly" };
3092 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3094 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3095 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3097 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3098 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3100 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3105 /* negotiate an data channel and then renegotiate to add a av stream */
3106 t->on_negotiation_needed = NULL;
3107 t->on_ice_candidate = NULL;
3108 t->on_data_channel = NULL;
3109 t->on_pad_added = _pad_added_fakesink;
3111 fail_if (gst_element_set_state (t->webrtc1,
3112 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3113 fail_if (gst_element_set_state (t->webrtc2,
3114 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3116 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3119 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3121 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3122 add_fake_audio_src_harness (h, 97);
3123 t->harnesses = g_list_prepend (t->harnesses, h);
3125 media_formats.next = &renego_fingerprint;
3126 count.user_data = GUINT_TO_POINTER (2);
3129 test_webrtc_reset_negotiation (t);
3130 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3132 g_object_unref (channel);
3133 test_webrtc_free (t);
3139 GST_START_TEST (test_renego_stream_data_channel_add_stream)
3141 struct test_webrtc *t = test_webrtc_new ();
3142 guint media_format_count[] = { 1, 1, 1 };
3143 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3144 media_format_count, NULL);
3145 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3147 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3148 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3149 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3151 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3152 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3154 const gchar *expected_offer_direction[] = { "sendrecv", NULL, "sendrecv" };
3155 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3157 const gchar *expected_answer_direction[] = { "recvonly", NULL, "recvonly" };
3158 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3160 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3161 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3163 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3164 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3166 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3171 /* Negotiate a stream and a data channel, then renogotiate with a new stream */
3172 t->on_negotiation_needed = NULL;
3173 t->on_ice_candidate = NULL;
3174 t->on_data_channel = NULL;
3175 t->on_pad_added = _pad_added_fakesink;
3177 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3178 add_fake_audio_src_harness (h, 97);
3179 t->harnesses = g_list_prepend (t->harnesses, h);
3181 fail_if (gst_element_set_state (t->webrtc1,
3182 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3183 fail_if (gst_element_set_state (t->webrtc2,
3184 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3186 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3189 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3191 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3192 add_fake_audio_src_harness (h, 97);
3193 t->harnesses = g_list_prepend (t->harnesses, h);
3195 media_formats.next = &renego_fingerprint;
3196 count.user_data = GUINT_TO_POINTER (3);
3199 test_webrtc_reset_negotiation (t);
3200 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3202 g_object_unref (channel);
3203 test_webrtc_free (t);
3208 GST_START_TEST (test_bundle_renego_add_stream)
3210 struct test_webrtc *t = create_audio_video_test ();
3211 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3212 const gchar *offer_bundle_only[] = { "video1", "audio2", NULL };
3213 const gchar *answer_bundle_only[] = { NULL };
3214 guint media_format_count[] = { 1, 1, 1 };
3215 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3216 media_format_count, NULL);
3217 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3219 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3220 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3221 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3223 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3224 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3226 const gchar *expected_offer_direction[] =
3227 { "sendrecv", "sendrecv", "sendrecv" };
3228 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3230 const gchar *expected_answer_direction[] =
3231 { "sendrecv", "recvonly", "recvonly" };
3232 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3235 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, &payloads);
3236 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3238 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3239 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3241 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3243 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3244 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
3245 GUINT_TO_POINTER (1), &bundle_tag);
3246 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
3247 GUINT_TO_POINTER (3), &bundle_tag);
3248 VAL_SDP_INIT (offer_bundle_only_sdp, _check_bundle_only_media,
3249 &offer_bundle_only, &offer_non_reject);
3250 VAL_SDP_INIT (answer_bundle_only_sdp, _check_bundle_only_media,
3251 &answer_bundle_only, &answer_non_reject);
3254 /* We set a max-bundle policy on the offering webrtcbin,
3255 * this means that all the offered medias should be part
3256 * of the group:BUNDLE attribute, and they should be marked
3259 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3261 /* We also set a max-bundle policy on the answering webrtcbin,
3262 * this means that all the offered medias should be part
3263 * of the group:BUNDLE attribute, but need not be marked
3266 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3269 /* negotiate an AV stream and then renegotiate an extra stream */
3270 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3271 add_fake_audio_src_harness (h, 96);
3272 t->harnesses = g_list_prepend (t->harnesses, h);
3274 test_validate_sdp (t, &offer, &answer);
3276 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3277 add_fake_audio_src_harness (h, 98);
3278 t->harnesses = g_list_prepend (t->harnesses, h);
3280 offer_setup.next = &offer_bundle_only_sdp;
3281 answer_setup.next = &answer_bundle_only_sdp;
3282 count.user_data = GUINT_TO_POINTER (3);
3285 test_webrtc_reset_negotiation (t);
3286 test_validate_sdp (t, &offer, &answer);
3288 test_webrtc_free (t);
3293 GST_START_TEST (test_bundle_max_compat_max_bundle_renego_add_stream)
3295 struct test_webrtc *t = create_audio_video_test ();
3296 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3297 const gchar *bundle_only[] = { NULL };
3298 guint media_format_count[] = { 1, 1, 1 };
3299 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3300 media_format_count, NULL);
3301 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3303 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3304 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3305 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3307 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3308 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3310 const gchar *expected_offer_direction[] =
3311 { "sendrecv", "sendrecv", "sendrecv" };
3312 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3314 const gchar *expected_answer_direction[] =
3315 { "sendrecv", "recvonly", "recvonly" };
3316 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3319 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3320 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3322 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3323 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3325 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3327 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3328 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
3329 GUINT_TO_POINTER (3), &bundle_tag);
3330 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
3334 /* We set a max-compat policy on the offering webrtcbin,
3335 * this means that all the offered medias should be part
3336 * of the group:BUNDLE attribute, and they should *not* be marked
3339 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3341 /* We set a max-bundle policy on the answering webrtcbin,
3342 * this means that all the offered medias should be part
3343 * of the group:BUNDLE attribute, but need not be marked
3346 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3349 /* negotiate an AV stream and then renegotiate an extra stream */
3350 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3351 add_fake_audio_src_harness (h, 96);
3352 t->harnesses = g_list_prepend (t->harnesses, h);
3354 test_validate_sdp (t, &offer, &answer);
3356 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3357 add_fake_audio_src_harness (h, 98);
3358 t->harnesses = g_list_prepend (t->harnesses, h);
3360 media_formats.next = &bundle_sdp;
3361 count.user_data = GUINT_TO_POINTER (3);
3364 test_webrtc_reset_negotiation (t);
3365 test_validate_sdp (t, &offer, &answer);
3367 test_webrtc_free (t);
3372 GST_START_TEST (test_renego_transceiver_set_direction)
3374 struct test_webrtc *t = create_audio_test ();
3375 guint media_format_count[] = { 1, };
3376 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3377 media_format_count, NULL);
3378 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3380 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3381 const gchar *expected_offer_setup[] = { "actpass", };
3382 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3384 const gchar *expected_answer_setup[] = { "active", };
3385 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3387 const gchar *expected_offer_direction[] = { "sendrecv", };
3388 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3390 const gchar *expected_answer_direction[] = { "sendrecv", };
3391 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3393 GstWebRTCRTPTransceiver *transceiver;
3397 /* negotiate an AV stream and then change the transceiver direction */
3398 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3399 add_fake_audio_src_harness (h, 96);
3400 t->harnesses = g_list_prepend (t->harnesses, h);
3402 test_validate_sdp (t, &offer, &answer);
3404 /* renegotiate an inactive transceiver! */
3405 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
3406 g_object_get (pad, "transceiver", &transceiver, NULL);
3407 fail_unless (transceiver != NULL);
3408 g_object_set (transceiver, "direction",
3409 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE, NULL);
3410 expected_offer_direction[0] = "inactive";
3411 expected_answer_direction[0] = "inactive";
3413 /* TODO: also validate EOS events from the inactive change */
3415 test_webrtc_reset_negotiation (t);
3416 test_validate_sdp (t, &offer, &answer);
3418 gst_object_unref (pad);
3419 gst_object_unref (transceiver);
3420 test_webrtc_free (t);
3426 offer_remove_last_media (struct test_webrtc *t, GstElement * element,
3427 GstPromise * promise, gpointer user_data)
3430 GstSDPMessage *new, *old;
3431 const GstSDPOrigin *origin;
3432 const GstSDPConnection *conn;
3434 old = t->offer_desc->sdp;
3435 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_new (&new));
3437 origin = gst_sdp_message_get_origin (old);
3438 conn = gst_sdp_message_get_connection (old);
3439 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_version (new,
3440 gst_sdp_message_get_version (old)));
3441 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_origin (new,
3442 origin->username, origin->sess_id, origin->sess_version,
3443 origin->nettype, origin->addrtype, origin->addr));
3444 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_session_name (new,
3445 gst_sdp_message_get_session_name (old)));
3446 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_information (new,
3447 gst_sdp_message_get_information (old)));
3448 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_uri (new,
3449 gst_sdp_message_get_uri (old)));
3450 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_connection (new,
3451 conn->nettype, conn->addrtype, conn->address, conn->ttl,
3452 conn->addr_number));
3454 n = gst_sdp_message_attributes_len (old);
3455 for (i = 0; i < n; i++) {
3456 const GstSDPAttribute *a = gst_sdp_message_get_attribute (old, i);
3457 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_attribute (new,
3461 n = gst_sdp_message_medias_len (old);
3462 fail_unless (n > 0);
3463 for (i = 0; i < n - 1; i++) {
3464 const GstSDPMedia *m = gst_sdp_message_get_media (old, i);
3467 fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_copy (m, &new_m));
3468 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_media (new, new_m));
3469 gst_sdp_media_init (new_m);
3470 gst_sdp_media_free (new_m);
3473 gst_webrtc_session_description_free (t->offer_desc);
3474 t->offer_desc = gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_OFFER,
3479 offer_set_produced_error (struct test_webrtc *t, GstElement * element,
3480 GstPromise * promise, gpointer user_data)
3482 const GstStructure *reply;
3483 GError *error = NULL;
3485 reply = gst_promise_get_reply (promise);
3486 fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
3487 GST_INFO ("error produced: %s", error->message);
3488 g_clear_error (&error);
3490 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
3493 GST_START_TEST (test_renego_lose_media_fails)
3495 struct test_webrtc *t = create_audio_video_test ();
3496 VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3497 VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3499 /* check that removing an m=line will produce an error */
3501 test_validate_sdp (t, &offer, &answer);
3503 test_webrtc_reset_negotiation (t);
3505 t->on_offer_created = offer_remove_last_media;
3506 t->on_offer_set = offer_set_produced_error;
3507 t->on_answer_created = NULL;
3509 test_webrtc_create_offer (t);
3510 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
3512 test_webrtc_free (t);
3517 GST_START_TEST (test_bundle_codec_preferences_rtx_no_duplicate_payloads)
3519 struct test_webrtc *t = test_webrtc_new ();
3520 GstWebRTCRTPTransceiverDirection direction;
3521 GstWebRTCRTPTransceiver *trans;
3522 guint offer_media_format_count[] = { 2, };
3523 guint answer_media_format_count[] = { 1, };
3524 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3525 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3526 offer_media_format_count, &payloads);
3527 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3528 answer_media_format_count, &payloads);
3529 const gchar *expected_offer_setup[] = { "actpass", };
3530 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3531 &offer_media_formats);
3532 const gchar *expected_answer_setup[] = { "active", };
3533 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3534 &answer_media_formats);
3535 const gchar *expected_offer_direction[] = { "recvonly", };
3536 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3538 const gchar *expected_answer_direction[] = { "sendonly", };
3539 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3544 /* add a transceiver that will only receive an opus stream and check that
3545 * the created offer is marked as recvonly */
3546 t->on_negotiation_needed = NULL;
3547 t->on_ice_candidate = NULL;
3548 t->on_pad_added = _pad_added_fakesink;
3550 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3552 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3555 /* setup recvonly transceiver */
3556 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3557 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3558 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3560 g_object_set (GST_OBJECT (trans), "do-nack", TRUE, NULL);
3561 gst_caps_unref (caps);
3562 fail_unless (trans != NULL);
3563 gst_object_unref (trans);
3565 /* setup sendonly peer */
3566 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3567 add_fake_video_src_harness (h, 96);
3568 t->harnesses = g_list_prepend (t->harnesses, h);
3569 test_validate_sdp (t, &offer, &answer);
3571 test_webrtc_free (t);
3576 GST_START_TEST (test_reject_request_pad)
3578 struct test_webrtc *t = test_webrtc_new ();
3579 GstWebRTCRTPTransceiverDirection direction;
3580 GstWebRTCRTPTransceiver *trans, *trans2;
3581 guint offer_media_format_count[] = { 1, };
3582 guint answer_media_format_count[] = { 1, };
3583 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3584 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3585 offer_media_format_count, &payloads);
3586 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3587 answer_media_format_count, &payloads);
3588 const gchar *expected_offer_setup[] = { "actpass", };
3589 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3590 &offer_media_formats);
3591 const gchar *expected_answer_setup[] = { "active", };
3592 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3593 &answer_media_formats);
3594 const gchar *expected_offer_direction[] = { "recvonly", };
3595 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3597 const gchar *expected_answer_direction[] = { "sendonly", };
3598 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3603 GstPadTemplate *templ;
3605 t->on_negotiation_needed = NULL;
3606 t->on_ice_candidate = NULL;
3607 t->on_pad_added = _pad_added_fakesink;
3609 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3611 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3614 /* setup recvonly transceiver */
3615 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3616 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3617 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3619 gst_caps_unref (caps);
3620 fail_unless (trans != NULL);
3622 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3623 add_fake_video_src_harness (h, 96);
3624 t->harnesses = g_list_prepend (t->harnesses, h);
3626 test_validate_sdp (t, &offer, &answer);
3628 /* This should fail because the direction is wrong */
3629 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3630 fail_unless (pad == NULL);
3632 g_object_set (trans, "direction",
3633 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV, NULL);
3635 templ = gst_element_get_pad_template (t->webrtc1, "sink_%u");
3636 fail_unless (templ != NULL);
3638 /* This should fail because the caps are wrong */
3639 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
3640 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3641 fail_unless (pad == NULL);
3643 g_object_set (trans, "codec-preferences", NULL, NULL);
3645 /* This should fail because the kind doesn't match */
3646 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3647 fail_unless (pad == NULL);
3648 gst_caps_unref (caps);
3650 /* This should succeed and give us sink_0 */
3651 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3652 fail_unless (pad != NULL);
3654 g_object_get (pad, "transceiver", &trans2, NULL);
3656 fail_unless (trans == trans2);
3658 gst_object_unref (pad);
3659 gst_object_unref (trans);
3660 gst_object_unref (trans2);
3662 test_webrtc_free (t);
3668 _verify_media_types (struct test_webrtc *t, GstElement * element,
3669 GstWebRTCSessionDescription * desc, gpointer user_data)
3671 gchar **media_types = user_data;
3674 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
3675 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
3677 fail_unless_equals_string (gst_sdp_media_get_media (media), media_types[i]);
3681 GST_START_TEST (test_reject_create_offer)
3683 struct test_webrtc *t = test_webrtc_new ();
3685 GstPromise *promise;
3686 GstPromiseResult res;
3687 const GstStructure *s;
3688 GError *error = NULL;
3690 const gchar *media_types[] = { "video", "audio" };
3691 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3692 guint media_format_count[] = { 1, 1 };
3693 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3694 media_format_count, &media_type);
3695 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3697 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3698 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3699 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3701 const gchar *expected_answer_setup[] = { "active", "active" };
3702 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3704 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
3705 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3707 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
3708 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3711 t->on_negotiation_needed = NULL;
3712 t->on_ice_candidate = NULL;
3713 t->on_pad_added = _pad_added_fakesink;
3715 /* setup sendonly peer */
3716 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3717 add_fake_audio_src_harness (h, 96);
3718 t->harnesses = g_list_prepend (t->harnesses, h);
3720 /* Check that if there is no 0, we can't create an offer with a hole */
3721 promise = gst_promise_new ();
3722 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3723 res = gst_promise_wait (promise);
3724 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3725 s = gst_promise_get_reply (promise);
3726 fail_unless (s != NULL);
3727 fail_unless (gst_structure_has_name (s, "application/x-gstwebrtcbin-error"));
3728 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3729 fail_unless (g_error_matches (error, GST_WEBRTC_BIN_ERROR,
3730 GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION));
3731 g_clear_error (&error);
3732 gst_promise_unref (promise);
3734 h = gst_harness_new_with_element (t->webrtc1, "sink_%u", NULL);
3735 add_fake_video_src_harness (h, 97);
3736 t->harnesses = g_list_prepend (t->harnesses, h);
3738 /* Adding a second sink, which will fill m-line 0, should fix it */
3739 test_validate_sdp (t, &offer, &answer);
3741 test_webrtc_free (t);
3746 GST_START_TEST (test_reject_set_description)
3748 struct test_webrtc *t = test_webrtc_new ();
3750 GstPromise *promise;
3751 GstPromiseResult res;
3752 const GstStructure *s;
3753 GError *error = NULL;
3754 GstWebRTCSessionDescription *desc = NULL;
3755 GstPadTemplate *templ;
3759 t->on_negotiation_needed = NULL;
3760 t->on_ice_candidate = NULL;
3761 t->on_pad_added = _pad_added_fakesink;
3764 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3765 add_fake_audio_src_harness (h, 96);
3766 t->harnesses = g_list_prepend (t->harnesses, h);
3768 /* Create a second side with specific video caps */
3769 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
3770 fail_unless (templ != NULL);
3771 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
3772 pad = gst_element_request_pad (t->webrtc2, templ, "sink_0", caps);
3773 fail_unless (pad != NULL);
3774 gst_caps_unref (caps);
3775 gst_object_unref (pad);
3777 /* Create an offer */
3778 promise = gst_promise_new ();
3779 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3780 res = gst_promise_wait (promise);
3781 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3782 s = gst_promise_get_reply (promise);
3783 fail_unless (s != NULL);
3784 fail_unless (gst_structure_has_name (s, "application/x-gst-promise"));
3785 gst_structure_get (s, "offer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &desc,
3787 fail_unless (desc != NULL);
3788 gst_promise_unref (promise);
3790 fail_if (gst_element_set_state (t->webrtc2,
3791 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
3793 /* Verify that setting an offer where there is a forced m-line with
3794 a different kind fails. */
3795 promise = gst_promise_new ();
3796 g_signal_emit_by_name (t->webrtc2, "set-remote-description", desc, promise);
3797 res = gst_promise_wait (promise);
3798 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3799 s = gst_promise_get_reply (promise);
3800 fail_unless (gst_structure_has_name (s, "application/x-gstwebrtcbin-error"));
3801 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3802 fail_unless (g_error_matches (error, GST_WEBRTC_BIN_ERROR,
3803 GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION));
3804 g_clear_error (&error);
3805 fail_unless (s != NULL);
3806 gst_promise_unref (promise);
3807 gst_webrtc_session_description_free (desc);
3809 test_webrtc_free (t);
3814 GST_START_TEST (test_force_second_media)
3816 struct test_webrtc *t = test_webrtc_new ();
3817 const gchar *media_types[] = { "audio" };
3818 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3819 guint media_format_count[] = { 1, };
3820 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3821 media_format_count, &media_type);
3822 const gchar *expected_offer_setup[] = { "actpass", };
3823 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3825 const gchar *expected_answer_setup[] = { "active", };
3826 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3828 const gchar *expected_offer_direction[] = { "sendrecv", };
3829 VAL_SDP_INIT (offer_direction, on_sdp_media_direction,
3830 expected_offer_direction, &offer_setup);
3831 const gchar *expected_answer_direction[] = { "recvonly", };
3832 VAL_SDP_INIT (answer_direction, on_sdp_media_direction,
3833 expected_answer_direction, &answer_setup);
3834 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3836 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3839 const gchar *second_media_types[] = { "audio", "video" };
3840 VAL_SDP_INIT (second_media_type, _verify_media_types, &second_media_types,
3842 guint second_media_format_count[] = { 1, 1 };
3843 VAL_SDP_INIT (second_media_formats, on_sdp_media_count_formats,
3844 second_media_format_count, &second_media_type);
3845 const gchar *second_expected_offer_setup[] = { "active", "actpass" };
3846 VAL_SDP_INIT (second_offer_setup, on_sdp_media_setup,
3847 second_expected_offer_setup, &second_media_formats);
3848 const gchar *second_expected_answer_setup[] = { "passive", "active" };
3849 VAL_SDP_INIT (second_answer_setup, on_sdp_media_setup,
3850 second_expected_answer_setup, &second_media_formats);
3851 const gchar *second_expected_answer_direction[] = { "sendonly", "recvonly" };
3852 VAL_SDP_INIT (second_answer_direction, on_sdp_media_direction,
3853 second_expected_answer_direction, &second_answer_setup);
3854 const gchar *second_expected_offer_direction[] = { "recvonly", "sendrecv" };
3855 VAL_SDP_INIT (second_offer_direction, on_sdp_media_direction,
3856 second_expected_offer_direction, &second_offer_setup);
3857 VAL_SDP_INIT (second_answer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3858 &second_answer_direction);
3859 VAL_SDP_INIT (second_offer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3860 &second_offer_direction);
3863 guint negotiation_flag = 0;
3864 GstPadTemplate *templ;
3868 /* add a transceiver that will only receive an opus stream and check that
3869 * the created offer is marked as recvonly */
3870 t->on_negotiation_needed = on_negotiation_needed_hit;
3871 t->negotiation_data = &negotiation_flag;
3872 t->on_ice_candidate = NULL;
3873 t->on_pad_added = _pad_added_fakesink;
3876 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3877 add_fake_audio_src_harness (h, 96);
3878 t->harnesses = g_list_prepend (t->harnesses, h);
3880 /* Create a second side with specific video caps */
3881 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
3882 fail_unless (templ != NULL);
3883 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
3884 pad = gst_element_request_pad (t->webrtc2, templ, NULL, caps);
3885 gst_caps_unref (caps);
3886 fail_unless (pad != NULL);
3887 h = gst_harness_new_with_element (t->webrtc2, GST_PAD_NAME (pad), NULL);
3888 gst_object_unref (pad);
3889 add_fake_video_src_harness (h, 97);
3890 t->harnesses = g_list_prepend (t->harnesses, h);
3892 test_validate_sdp (t, &offer_count, &answer_count);
3893 fail_unless (negotiation_flag & 1 << 2);
3895 test_webrtc_reset_negotiation (t);
3898 test_validate_sdp (t, &second_offer_count, &second_answer_count);
3900 test_webrtc_free (t);
3905 GST_START_TEST (test_codec_preferences_caps)
3909 GstWebRTCRTPTransceiver *trans;
3910 GstCaps *caps, *caps2;
3912 h = gst_harness_new_with_padnames ("webrtcbin", "sink_0", NULL);
3913 pad = gst_element_get_static_pad (h->element, "sink_0");
3915 g_object_get (pad, "transceiver", &trans, NULL);
3917 caps = gst_caps_from_string ("application/x-rtp, media=video,"
3918 "encoding-name=VP8, payload=115; application/x-rtp, media=video,"
3919 " encoding-name=H264, payload=104");
3920 g_object_set (trans, "codec-preferences", caps, NULL);
3922 caps2 = gst_pad_query_caps (pad, NULL);
3923 fail_unless (gst_caps_is_equal (caps, caps2));
3924 gst_caps_unref (caps2);
3925 gst_caps_unref (caps);
3927 caps = gst_caps_from_string (VP8_RTP_CAPS (115));
3928 fail_unless (gst_pad_query_accept_caps (pad, caps));
3929 gst_harness_set_src_caps (h, g_steal_pointer (&caps));
3931 caps = gst_caps_from_string (VP8_RTP_CAPS (99));
3932 fail_unless (!gst_pad_query_accept_caps (pad, caps));
3933 gst_caps_unref (caps);
3935 gst_object_unref (pad);
3936 gst_object_unref (trans);
3937 gst_harness_teardown (h);
3942 GST_START_TEST (test_codec_preferences_negotiation_sinkpad)
3944 struct test_webrtc *t = test_webrtc_new ();
3945 guint media_format_count[] = { 1, };
3946 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3947 media_format_count, NULL);
3948 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3950 VAL_SDP_INIT (payloads2, on_sdp_media_payload_types, GUINT_TO_POINTER (0),
3952 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &payloads2);
3953 const gchar *expected_offer_setup[] = { "actpass", };
3954 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3956 const gchar *expected_answer_setup[] = { "active", };
3957 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3959 const gchar *expected_offer_direction[] = { "sendrecv", };
3960 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3962 const gchar *expected_answer_direction[] = { "recvonly", };
3963 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3967 GstWebRTCRTPTransceiver *transceiver;
3970 GstPromise *promise;
3971 GstPromiseResult res;
3972 const GstStructure *s;
3973 GError *error = NULL;
3975 t->on_negotiation_needed = NULL;
3976 t->on_ice_candidate = NULL;
3977 t->on_pad_added = _pad_added_fakesink;
3979 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3980 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
3981 g_object_get (pad, "transceiver", &transceiver, NULL);
3982 caps = gst_caps_from_string (VP8_RTP_CAPS (115) ";" VP8_RTP_CAPS (97));
3983 g_object_set (transceiver, "codec-preferences", caps, NULL);
3984 gst_caps_unref (caps);
3985 gst_object_unref (transceiver);
3986 gst_object_unref (pad);
3988 add_fake_video_src_harness (h, 96);
3989 t->harnesses = g_list_prepend (t->harnesses, h);
3991 promise = gst_promise_new ();
3992 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3993 res = gst_promise_wait (promise);
3994 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3995 s = gst_promise_get_reply (promise);
3996 fail_unless (s != NULL);
3997 fail_unless (gst_structure_has_name (s, "application/x-gstwebrtcbin-error"));
3998 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3999 fail_unless (g_error_matches (error, GST_WEBRTC_BIN_ERROR,
4000 GST_WEBRTC_BIN_ERROR_CAPS_NEGOTIATION_FAILED));
4001 g_clear_error (&error);
4002 gst_promise_unref (promise);
4004 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
4005 gst_harness_set_src_caps (h, caps);
4007 test_validate_sdp (t, &offer, &answer);
4009 test_webrtc_free (t);
4016 add_audio_test_src_harness (GstHarness * h)
4018 #define L16_CAPS "application/x-rtp, payload=11, media=audio," \
4019 " encoding-name=L16, clock-rate=44100, ssrc=(uint)3484078952"
4020 GstCaps *caps = gst_caps_from_string (L16_CAPS);
4021 gst_harness_set_src_caps (h, caps);
4022 gst_harness_add_src_parse (h, "audiotestsrc is-live=true ! rtpL16pay ! "
4023 L16_CAPS " ! identity", TRUE);
4027 _pad_added_harness (struct test_webrtc *t, GstElement * element,
4028 GstPad * pad, gpointer user_data)
4031 GstHarness **sink_harness = user_data;
4033 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
4036 h = gst_harness_new_with_element (element, NULL, GST_OBJECT_NAME (pad));
4037 t->harnesses = g_list_prepend (t->harnesses, h);
4041 g_cond_broadcast (&t->cond);
4046 new_jitterbuffer_set_fast_start (GstElement * rtpbin,
4047 GstElement * rtpjitterbuffer, guint session_id, guint ssrc,
4050 g_object_set (rtpjitterbuffer, "faststart-min-packets", 1, NULL);
4053 GST_START_TEST (test_codec_preferences_negotiation_srcpad)
4055 struct test_webrtc *t = test_webrtc_new ();
4056 guint media_format_count[] = { 1, };
4057 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4058 media_format_count, NULL);
4059 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4061 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
4062 const gchar *expected_offer_setup[] = { "actpass", };
4063 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4065 const gchar *expected_answer_setup[] = { "active", };
4066 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4068 const gchar *expected_offer_direction[] = { "sendrecv", };
4069 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4071 const gchar *expected_answer_direction[] = { "recvonly", };
4072 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4074 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
4075 GUINT_TO_POINTER (0), &count);
4077 GstHarness *sink_harness = NULL;
4079 GstElement *rtpbin2;
4082 t->on_negotiation_needed = NULL;
4083 t->on_ice_candidate = NULL;
4084 t->on_pad_added = _pad_added_harness;
4085 t->pad_added_data = &sink_harness;
4087 rtpbin2 = gst_bin_get_by_name (GST_BIN (t->webrtc2), "rtpbin");
4088 fail_unless (rtpbin2 != NULL);
4089 g_signal_connect (rtpbin2, "new-jitterbuffer",
4090 G_CALLBACK (new_jitterbuffer_set_fast_start), NULL);
4091 g_object_unref (rtpbin2);
4093 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4094 add_audio_test_src_harness (h);
4095 t->harnesses = g_list_prepend (t->harnesses, h);
4097 test_validate_sdp (t, &offer, &answer);
4099 fail_if (gst_element_set_state (t->webrtc1,
4100 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4101 fail_if (gst_element_set_state (t->webrtc2,
4102 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4104 for (i = 0; i < 10; i++)
4105 gst_harness_push_from_src (h);
4107 g_mutex_lock (&t->lock);
4108 while (sink_harness == NULL) {
4109 gst_harness_push_from_src (h);
4110 g_cond_wait_until (&t->cond, &t->lock, g_get_monotonic_time () + 5000);
4112 g_mutex_unlock (&t->lock);
4113 fail_unless (sink_harness->element == t->webrtc2);
4115 /* Get one buffer out, this makes sure the capsfilter is primed and
4118 buf = gst_harness_pull (sink_harness);
4119 fail_unless (buf != NULL);
4120 gst_buffer_unref (buf);
4122 gst_harness_set_sink_caps_str (sink_harness, OPUS_RTP_CAPS (100));
4124 test_webrtc_reset_negotiation (t);
4125 test_validate_sdp_full (t, &offer, &answer_non_reject, 0, FALSE);
4127 test_webrtc_free (t);
4133 _on_new_transceiver_codec_preferences_h264 (GstElement * webrtcbin,
4134 GstWebRTCRTPTransceiver * trans, gpointer * user_data)
4138 caps = gst_caps_from_string ("application/x-rtp,encoding-name=(string)H264");
4139 g_object_set (trans, "codec-preferences", caps, NULL);
4140 gst_caps_unref (caps);
4144 on_sdp_media_payload_types_only_h264 (struct test_webrtc *t,
4145 GstElement * element, GstWebRTCSessionDescription * desc,
4148 const GstSDPMedia *vmedia;
4149 guint video_mline = GPOINTER_TO_UINT (user_data);
4152 vmedia = gst_sdp_message_get_media (desc->sdp, video_mline);
4154 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
4155 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
4157 if (!g_strcmp0 (attr->key, "rtpmap")) {
4158 fail_unless_equals_string (attr->value, "101 H264/90000");
4164 GST_START_TEST (test_codec_preferences_in_on_new_transceiver)
4166 struct test_webrtc *t = test_webrtc_new ();
4167 GstWebRTCRTPTransceiverDirection direction;
4168 GstWebRTCRTPTransceiver *trans;
4169 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4171 guint offer_media_format_count[] = { 2 };
4172 guint answer_media_format_count[] = { 1 };
4173 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
4174 offer_media_format_count, &no_duplicate_payloads);
4175 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
4176 answer_media_format_count, &no_duplicate_payloads);
4177 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4178 &offer_media_formats);
4179 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4180 &answer_media_formats);
4181 VAL_SDP_INIT (offer_payloads, on_sdp_media_payload_types,
4182 GUINT_TO_POINTER (0), &offer_count);
4183 VAL_SDP_INIT (answer_payloads, on_sdp_media_payload_types_only_h264,
4184 GUINT_TO_POINTER (0), &answer_count);
4185 const gchar *expected_offer_setup[] = { "actpass", };
4186 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4188 const gchar *expected_answer_setup[] = { "active", };
4189 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4191 const gchar *expected_offer_direction[] = { "sendonly", };
4192 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4194 const gchar *expected_answer_direction[] = { "recvonly", };
4195 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4200 t->on_negotiation_needed = NULL;
4201 t->on_ice_candidate = NULL;
4202 t->on_pad_added = _pad_added_fakesink;
4204 /* setup sendonly transceiver with VP8 and H264 */
4205 caps = gst_caps_from_string (VP8_RTP_CAPS (97) ";" H264_RTP_CAPS (101));
4206 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
4207 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
4209 gst_caps_unref (caps);
4210 fail_unless (trans != NULL);
4211 gst_object_unref (trans);
4213 /* setup recvonly peer */
4214 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
4215 add_fake_video_src_harness (h, 101);
4216 t->harnesses = g_list_prepend (t->harnesses, h);
4218 /* connect to "on-new-transceiver" to set codec-preferences to H264 */
4219 g_signal_connect (t->webrtc2, "on-new-transceiver",
4220 G_CALLBACK (_on_new_transceiver_codec_preferences_h264), NULL);
4222 /* Answer SDP should now have H264 only. Without the codec-preferences it
4223 * would only have VP8 because that comes first in the SDP */
4225 test_validate_sdp (t, &offer, &answer);
4226 test_webrtc_free (t);
4232 webrtcbin_suite (void)
4234 Suite *s = suite_create ("webrtcbin");
4235 TCase *tc = tcase_create ("general");
4236 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
4237 GstPluginFeature *sctpenc, *sctpdec;
4238 GstRegistry *registry;
4240 registry = gst_registry_get ();
4241 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
4242 nicesink = gst_registry_lookup_feature (registry, "nicesink");
4243 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
4244 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
4245 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
4246 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
4248 tcase_add_test (tc, test_no_nice_elements_request_pad);
4249 tcase_add_test (tc, test_no_nice_elements_state_change);
4250 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
4251 tcase_add_test (tc, test_sdp_no_media);
4252 tcase_add_test (tc, test_session_stats);
4253 tcase_add_test (tc, test_audio);
4254 tcase_add_test (tc, test_ice_port_restriction);
4255 tcase_add_test (tc, test_audio_video);
4256 tcase_add_test (tc, test_media_direction);
4257 tcase_add_test (tc, test_add_transceiver);
4258 tcase_add_test (tc, test_get_transceivers);
4259 tcase_add_test (tc, test_add_recvonly_transceiver);
4260 tcase_add_test (tc, test_recvonly_sendonly);
4261 tcase_add_test (tc, test_payload_types);
4262 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
4263 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
4264 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
4265 tcase_add_test (tc, test_dual_audio);
4266 tcase_add_test (tc, test_duplicate_nego);
4267 tcase_add_test (tc, test_renego_add_stream);
4268 tcase_add_test (tc, test_bundle_renego_add_stream);
4269 tcase_add_test (tc, test_bundle_max_compat_max_bundle_renego_add_stream);
4270 tcase_add_test (tc, test_renego_transceiver_set_direction);
4271 tcase_add_test (tc, test_renego_lose_media_fails);
4273 test_bundle_codec_preferences_rtx_no_duplicate_payloads);
4274 tcase_add_test (tc, test_reject_request_pad);
4275 tcase_add_test (tc, test_reject_create_offer);
4276 tcase_add_test (tc, test_reject_set_description);
4277 tcase_add_test (tc, test_force_second_media);
4278 tcase_add_test (tc, test_codec_preferences_caps);
4279 tcase_add_test (tc, test_codec_preferences_negotiation_sinkpad);
4280 tcase_add_test (tc, test_codec_preferences_negotiation_srcpad);
4281 tcase_add_test (tc, test_codec_preferences_in_on_new_transceiver);
4282 if (sctpenc && sctpdec) {
4283 tcase_add_test (tc, test_data_channel_create);
4284 tcase_add_test (tc, test_data_channel_remote_notify);
4285 tcase_add_test (tc, test_data_channel_transfer_string);
4286 tcase_add_test (tc, test_data_channel_transfer_data);
4287 tcase_add_test (tc, test_data_channel_create_after_negotiate);
4288 tcase_add_test (tc, test_data_channel_close);
4289 tcase_add_test (tc, test_data_channel_low_threshold);
4290 tcase_add_test (tc, test_data_channel_max_message_size);
4291 tcase_add_test (tc, test_data_channel_pre_negotiated);
4292 tcase_add_test (tc, test_bundle_audio_video_data);
4293 tcase_add_test (tc, test_renego_stream_add_data_channel);
4294 tcase_add_test (tc, test_renego_data_channel_add_stream);
4295 tcase_add_test (tc, test_renego_stream_data_channel_add_stream);
4297 GST_WARNING ("Some required elements were not found. "
4298 "All datachannel tests are disabled. sctpenc %p, sctpdec %p", sctpenc,
4302 GST_WARNING ("Some required elements were not found. "
4303 "All media tests are disabled. nicesrc %p, nicesink %p, "
4304 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
4309 gst_object_unref (nicesrc);
4311 gst_object_unref (nicesink);
4313 gst_object_unref (dtlssrtpdec);
4315 gst_object_unref (dtlssrtpenc);
4317 gst_object_unref (sctpenc);
4319 gst_object_unref (sctpdec);
4321 suite_add_tcase (s, tc);
4326 GST_CHECK_MAIN (webrtcbin);