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);
1632 on_sdp_media_check_mid (struct test_webrtc *t, GstElement * element,
1633 GstWebRTCSessionDescription * desc, gpointer user_data)
1635 const char **mid = user_data;
1638 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1639 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
1640 gboolean seen_mid = FALSE;
1643 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
1644 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
1646 if (g_strcmp0 (attr->key, "mid") == 0) {
1647 fail_unless (!seen_mid);
1649 fail_unless_equals_string (attr->value, mid[i]);
1655 GST_START_TEST (test_add_recvonly_transceiver)
1657 struct test_webrtc *t = test_webrtc_new ();
1658 GstWebRTCRTPTransceiverDirection direction;
1659 GstWebRTCRTPTransceiver *trans;
1660 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1662 guint media_format_count[] = { 1, 1, };
1663 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1664 media_format_count, &no_duplicate_payloads);
1665 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
1667 const char *expected_mid[] = { "gst", };
1668 VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
1669 const gchar *expected_offer_setup[] = { "actpass", };
1670 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
1671 const gchar *expected_answer_setup[] = { "active", };
1672 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
1673 const gchar *expected_offer_direction[] = { "recvonly", };
1674 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1676 const gchar *expected_answer_direction[] = { "sendonly", };
1677 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1682 /* add a transceiver that will only receive an opus stream and check that
1683 * the created offer is marked as recvonly */
1684 t->on_negotiation_needed = NULL;
1685 t->on_ice_candidate = NULL;
1686 t->on_pad_added = _pad_added_fakesink;
1688 /* setup recvonly transceiver */
1689 caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
1690 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1691 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1693 gst_caps_unref (caps);
1694 fail_unless (trans != NULL);
1695 gst_object_unref (trans);
1697 /* setup sendonly peer */
1698 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1699 add_fake_audio_src_harness (h, 96);
1700 t->harnesses = g_list_prepend (t->harnesses, h);
1701 test_validate_sdp (t, &offer, &answer);
1703 test_webrtc_free (t);
1708 GST_START_TEST (test_recvonly_sendonly)
1710 struct test_webrtc *t = test_webrtc_new ();
1711 GstWebRTCRTPTransceiverDirection direction;
1712 GstWebRTCRTPTransceiver *trans;
1713 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1715 guint media_format_count[] = { 1, 1, };
1716 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1717 media_format_count, &no_duplicate_payloads);
1718 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1720 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1721 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1722 const gchar *expected_answer_setup[] = { "active", "active" };
1723 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1725 const gchar *expected_offer_direction[] = { "recvonly", "sendonly" };
1726 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1728 const gchar *expected_answer_direction[] = { "sendonly", "recvonly" };
1729 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1733 GArray *transceivers;
1735 /* add a transceiver that will only receive an opus stream and check that
1736 * the created offer is marked as recvonly */
1737 t->on_negotiation_needed = NULL;
1738 t->on_ice_candidate = NULL;
1739 t->on_pad_added = _pad_added_fakesink;
1741 /* setup recvonly transceiver */
1742 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1743 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1744 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1746 gst_caps_unref (caps);
1747 fail_unless (trans != NULL);
1748 gst_object_unref (trans);
1750 /* setup sendonly stream */
1751 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1752 add_fake_audio_src_harness (h, 96);
1753 t->harnesses = g_list_prepend (t->harnesses, h);
1754 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1755 fail_unless (transceivers != NULL);
1756 fail_unless_equals_int (transceivers->len, 2);
1757 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1758 g_object_set (trans, "direction",
1759 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, NULL);
1761 g_array_unref (transceivers);
1763 /* setup sendonly peer */
1764 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1765 add_fake_audio_src_harness (h, 96);
1766 t->harnesses = g_list_prepend (t->harnesses, h);
1768 test_validate_sdp (t, &offer, &answer);
1770 test_webrtc_free (t);
1776 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1777 GstWebRTCSessionDescription * desc, gpointer user_data)
1779 gboolean have_data_channel = FALSE;
1782 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1783 if (_message_media_is_datachannel (desc->sdp, i)) {
1784 /* there should only be one data channel m= section */
1785 fail_unless_equals_int (FALSE, have_data_channel);
1786 have_data_channel = TRUE;
1790 fail_unless_equals_int (TRUE, have_data_channel);
1794 on_channel_error_not_reached (GObject * channel, GError * error,
1797 g_assert_not_reached ();
1800 GST_START_TEST (test_data_channel_create)
1802 struct test_webrtc *t = test_webrtc_new ();
1803 GObject *channel = NULL;
1804 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1805 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1808 t->on_negotiation_needed = NULL;
1809 t->on_ice_candidate = NULL;
1811 fail_if (gst_element_set_state (t->webrtc1,
1812 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1813 fail_if (gst_element_set_state (t->webrtc2,
1814 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1816 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1818 g_assert_nonnull (channel);
1819 g_object_get (channel, "label", &label, NULL);
1820 g_assert_cmpstr (label, ==, "label");
1821 g_signal_connect (channel, "on-error",
1822 G_CALLBACK (on_channel_error_not_reached), NULL);
1824 test_validate_sdp (t, &offer, &offer);
1826 g_object_unref (channel);
1828 test_webrtc_free (t);
1834 have_data_channel (struct test_webrtc *t, GstElement * element,
1835 GObject * our, gpointer user_data)
1837 GObject *other = user_data;
1838 gchar *our_label, *other_label;
1840 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1843 g_object_get (our, "label", &our_label, NULL);
1844 g_object_get (other, "label", &other_label, NULL);
1846 g_assert_cmpstr (our_label, ==, other_label);
1849 g_free (other_label);
1851 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1854 GST_START_TEST (test_data_channel_remote_notify)
1856 struct test_webrtc *t = test_webrtc_new ();
1857 GObject *channel = NULL;
1858 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1859 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1861 t->on_negotiation_needed = NULL;
1862 t->on_ice_candidate = NULL;
1863 t->on_data_channel = have_data_channel;
1865 fail_if (gst_element_set_state (t->webrtc1,
1866 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1867 fail_if (gst_element_set_state (t->webrtc2,
1868 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1870 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1872 g_assert_nonnull (channel);
1873 t->data_channel_data = channel;
1874 g_signal_connect (channel, "on-error",
1875 G_CALLBACK (on_channel_error_not_reached), NULL);
1877 fail_if (gst_element_set_state (t->webrtc1,
1878 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1879 fail_if (gst_element_set_state (t->webrtc2,
1880 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1882 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1884 g_object_unref (channel);
1885 test_webrtc_free (t);
1890 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1893 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1895 GstWebRTCDataChannelState state;
1898 g_object_get (channel, "ready-state", &state, NULL);
1899 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1901 expected = g_object_steal_data (channel, "expected");
1902 g_assert_cmpstr (expected, ==, str);
1905 test_webrtc_signal_state (t, STATE_CUSTOM);
1909 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1910 GObject * our, gpointer user_data)
1912 GObject *other = user_data;
1913 GstWebRTCDataChannelState state;
1915 g_object_get (our, "ready-state", &state, NULL);
1916 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1918 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1919 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1922 g_signal_connect (other, "on-error",
1923 G_CALLBACK (on_channel_error_not_reached), NULL);
1924 g_signal_emit_by_name (other, "send-string", test_string);
1927 GST_START_TEST (test_data_channel_transfer_string)
1929 struct test_webrtc *t = test_webrtc_new ();
1930 GObject *channel = NULL;
1931 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1932 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1934 t->on_negotiation_needed = NULL;
1935 t->on_ice_candidate = NULL;
1936 t->on_data_channel = have_data_channel_transfer_string;
1938 fail_if (gst_element_set_state (t->webrtc1,
1939 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1940 fail_if (gst_element_set_state (t->webrtc2,
1941 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1943 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1945 g_assert_nonnull (channel);
1946 t->data_channel_data = channel;
1947 g_signal_connect (channel, "on-error",
1948 G_CALLBACK (on_channel_error_not_reached), NULL);
1950 fail_if (gst_element_set_state (t->webrtc1,
1951 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1952 fail_if (gst_element_set_state (t->webrtc2,
1953 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1955 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1957 g_object_unref (channel);
1958 test_webrtc_free (t);
1963 #define g_assert_cmpbytes(b1, b2) \
1966 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1967 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1968 g_assert_cmpmem (d1, l1, d2, l2); \
1972 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1974 GstWebRTCDataChannelState state;
1977 g_object_get (channel, "ready-state", &state, NULL);
1978 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1980 expected = g_object_steal_data (channel, "expected");
1981 g_assert_cmpbytes (data, expected);
1982 g_bytes_unref (expected);
1984 test_webrtc_signal_state (t, STATE_CUSTOM);
1988 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1989 GObject * our, gpointer user_data)
1991 GObject *other = user_data;
1992 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1993 GstWebRTCDataChannelState state;
1995 g_object_get (our, "ready-state", &state, NULL);
1996 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1998 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1999 (GDestroyNotify) g_bytes_unref);
2000 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
2002 g_signal_connect (other, "on-error",
2003 G_CALLBACK (on_channel_error_not_reached), NULL);
2004 g_signal_emit_by_name (other, "send-data", data);
2005 g_bytes_unref (data);
2008 GST_START_TEST (test_data_channel_transfer_data)
2010 struct test_webrtc *t = test_webrtc_new ();
2011 GObject *channel = NULL;
2012 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2013 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2015 t->on_negotiation_needed = NULL;
2016 t->on_ice_candidate = NULL;
2017 t->on_data_channel = have_data_channel_transfer_data;
2019 fail_if (gst_element_set_state (t->webrtc1,
2020 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2021 fail_if (gst_element_set_state (t->webrtc2,
2022 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2024 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2026 g_assert_nonnull (channel);
2027 t->data_channel_data = channel;
2028 g_signal_connect (channel, "on-error",
2029 G_CALLBACK (on_channel_error_not_reached), NULL);
2031 fail_if (gst_element_set_state (t->webrtc1,
2032 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2033 fail_if (gst_element_set_state (t->webrtc2,
2034 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2036 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2038 g_object_unref (channel);
2039 test_webrtc_free (t);
2045 have_data_channel_create_data_channel (struct test_webrtc *t,
2046 GstElement * element, GObject * our, gpointer user_data)
2050 t->on_data_channel = have_data_channel_transfer_string;
2052 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2054 g_assert_nonnull (another);
2055 t->data_channel_data = another;
2056 t->data_channel_notify = (GDestroyNotify) g_object_unref;
2057 g_signal_connect (another, "on-error",
2058 G_CALLBACK (on_channel_error_not_reached), NULL);
2061 GST_START_TEST (test_data_channel_create_after_negotiate)
2063 struct test_webrtc *t = test_webrtc_new ();
2064 GObject *channel = NULL;
2065 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2066 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2068 t->on_negotiation_needed = NULL;
2069 t->on_ice_candidate = NULL;
2070 t->on_data_channel = have_data_channel_create_data_channel;
2072 fail_if (gst_element_set_state (t->webrtc1,
2073 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2074 fail_if (gst_element_set_state (t->webrtc2,
2075 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2077 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
2079 g_assert_nonnull (channel);
2080 t->data_channel_data = channel;
2081 g_signal_connect (channel, "on-error",
2082 G_CALLBACK (on_channel_error_not_reached), NULL);
2084 fail_if (gst_element_set_state (t->webrtc1,
2085 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2086 fail_if (gst_element_set_state (t->webrtc2,
2087 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2089 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2091 g_object_unref (channel);
2092 test_webrtc_free (t);
2097 struct test_data_channel
2107 have_data_channel_mark_open (struct test_webrtc *t,
2108 GstElement * element, GObject * our, gpointer user_data)
2110 struct test_data_channel *tdc = t->data_channel_data;
2113 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2114 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
2119 is_data_channel_open (GObject * channel)
2121 GstWebRTCDataChannelState ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
2124 g_object_get (channel, "ready-state", &ready_state, NULL);
2127 return ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
2131 on_data_channel_open (GObject * channel, GParamSpec * pspec,
2132 struct test_webrtc *t)
2134 struct test_data_channel *tdc = t->data_channel_data;
2136 if (is_data_channel_open (channel)) {
2137 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2138 test_webrtc_signal_state (t, STATE_CUSTOM);
2144 on_data_channel_close (GObject * channel, GParamSpec * pspec,
2145 struct test_webrtc *t)
2147 struct test_data_channel *tdc = t->data_channel_data;
2148 GstWebRTCDataChannelState ready_state;
2150 g_object_get (channel, "ready-state", &ready_state, NULL);
2152 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
2153 g_atomic_int_add (&tdc->n_closed, 1);
2158 on_data_channel_destroyed (gpointer data, GObject * where_the_object_was)
2160 struct test_webrtc *t = data;
2161 struct test_data_channel *tdc = t->data_channel_data;
2163 if (where_the_object_was == tdc->dc1) {
2165 } else if (where_the_object_was == tdc->dc2) {
2169 if (g_atomic_int_add (&tdc->n_destroyed, 1) == 1) {
2170 test_webrtc_signal_state (t, STATE_CUSTOM);
2174 GST_START_TEST (test_data_channel_close)
2176 #define NUM_CHANNELS 3
2177 struct test_webrtc *t = test_webrtc_new ();
2178 struct test_data_channel tdc = { NULL, NULL, 0, 0, 0 };
2179 guint channel_id[NUM_CHANNELS] = { 0, 1, 2 };
2182 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2183 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2185 t->on_negotiation_needed = NULL;
2186 t->on_ice_candidate = NULL;
2187 t->on_data_channel = have_data_channel_mark_open;
2188 t->data_channel_data = &tdc;
2190 fail_if (gst_element_set_state (t->webrtc1,
2191 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2192 fail_if (gst_element_set_state (t->webrtc2,
2193 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2195 /* open and close NUM_CHANNELS data channels to verify that we can reuse the
2196 * stream id of a previously closed data channel and that we have the same
2197 * behaviour no matter if we create the channel in READY or PLAYING state */
2198 for (i = 0; i < NUM_CHANNELS; i++) {
2201 tdc.n_destroyed = 0;
2203 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2205 g_assert_nonnull (tdc.dc1);
2206 g_object_unref (tdc.dc1); /* webrtcbin should still hold a ref */
2207 g_object_weak_ref (tdc.dc1, on_data_channel_destroyed, t);
2208 g_signal_connect (tdc.dc1, "on-error",
2209 G_CALLBACK (on_channel_error_not_reached), NULL);
2210 sigid = g_signal_connect (tdc.dc1, "notify::ready-state",
2211 G_CALLBACK (on_data_channel_open), t);
2214 fail_if (gst_element_set_state (t->webrtc1,
2215 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2216 fail_if (gst_element_set_state (t->webrtc2,
2217 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2219 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2221 /* FIXME: Creating a data channel may result in "on-open" being sent
2222 * before we even had a chance to register the signal. For this test we
2223 * want to make sure that the channel is actually open before we try to
2224 * close it. So if we didn't receive the signal we fall back to a 1s
2225 * timeout where we explicitly check if both channels are open. */
2226 gint64 timeout = g_get_monotonic_time () + 1 * G_TIME_SPAN_SECOND;
2227 g_mutex_lock (&t->lock);
2228 while (((1 << t->state) & STATE_CUSTOM) == 0) {
2229 if (!g_cond_wait_until (&t->cond, &t->lock, timeout)) {
2230 g_assert (is_data_channel_open (tdc.dc1)
2231 && is_data_channel_open (tdc.dc2));
2235 g_mutex_unlock (&t->lock);
2238 g_object_get (tdc.dc1, "id", &channel_id[i], NULL);
2240 g_signal_handler_disconnect (tdc.dc1, sigid);
2241 g_object_weak_ref (tdc.dc2, on_data_channel_destroyed, t);
2242 g_signal_connect (tdc.dc1, "notify::ready-state",
2243 G_CALLBACK (on_data_channel_close), t);
2244 g_signal_connect (tdc.dc2, "notify::ready-state",
2245 G_CALLBACK (on_data_channel_close), t);
2246 test_webrtc_signal_state (t, STATE_NEW);
2248 /* currently we assume there is no renegotiation if the last data channel is
2249 * removed but if it changes this test could be extended to verify both
2250 * the behaviour of removing the last channel as well as the behaviour when
2251 * there are still data channels remaining */
2252 t->on_negotiation_needed = _negotiation_not_reached;
2253 g_signal_emit_by_name (tdc.dc1, "close");
2255 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2257 assert_equals_int (g_atomic_int_get (&tdc.n_closed), 2);
2258 assert_equals_pointer (tdc.dc1, NULL);
2259 assert_equals_pointer (tdc.dc2, NULL);
2261 test_webrtc_signal_state (t, STATE_NEW);
2264 /* verify the same stream id has been reused for each data channel */
2265 assert_equals_int (channel_id[0], channel_id[1]);
2266 assert_equals_int (channel_id[0], channel_id[2]);
2268 test_webrtc_free (t);
2275 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
2277 test_webrtc_signal_state (t, STATE_CUSTOM);
2281 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
2282 GstElement * element, GObject * our, gpointer user_data)
2284 g_signal_connect (our, "on-buffered-amount-low",
2285 G_CALLBACK (on_buffered_amount_low_emitted), t);
2286 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
2288 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
2290 g_signal_emit_by_name (our, "send-string", "A");
2293 GST_START_TEST (test_data_channel_low_threshold)
2295 struct test_webrtc *t = test_webrtc_new ();
2296 GObject *channel = NULL;
2297 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2298 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2300 t->on_negotiation_needed = NULL;
2301 t->on_ice_candidate = NULL;
2302 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
2304 fail_if (gst_element_set_state (t->webrtc1,
2305 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2306 fail_if (gst_element_set_state (t->webrtc2,
2307 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2309 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2311 g_assert_nonnull (channel);
2312 t->data_channel_data = channel;
2313 g_signal_connect (channel, "on-error",
2314 G_CALLBACK (on_channel_error_not_reached), NULL);
2316 fail_if (gst_element_set_state (t->webrtc1,
2317 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2318 fail_if (gst_element_set_state (t->webrtc2,
2319 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2321 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2323 g_object_unref (channel);
2324 test_webrtc_free (t);
2330 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
2332 g_assert_nonnull (error);
2334 test_webrtc_signal_state (t, STATE_CUSTOM);
2338 have_data_channel_transfer_large_data (struct test_webrtc *t,
2339 GstElement * element, GObject * our, gpointer user_data)
2341 GObject *other = user_data;
2342 const gsize size = 1024 * 1024;
2343 guint8 *random_data = g_new (guint8, size);
2347 for (i = 0; i < size; i++)
2348 random_data[i] = (guint8) (i & 0xff);
2350 data = g_bytes_new_with_free_func (random_data, size,
2351 (GDestroyNotify) g_free, random_data);
2353 g_object_set_data_full (our, "expected", g_bytes_ref (data),
2354 (GDestroyNotify) g_bytes_unref);
2355 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
2357 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
2358 g_signal_emit_by_name (other, "send-data", data);
2359 g_bytes_unref (data);
2362 GST_START_TEST (test_data_channel_max_message_size)
2364 struct test_webrtc *t = test_webrtc_new ();
2365 GObject *channel = NULL;
2366 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2367 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2369 t->on_negotiation_needed = NULL;
2370 t->on_ice_candidate = NULL;
2371 t->on_data_channel = have_data_channel_transfer_large_data;
2373 fail_if (gst_element_set_state (t->webrtc1,
2374 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2375 fail_if (gst_element_set_state (t->webrtc2,
2376 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2378 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2380 g_assert_nonnull (channel);
2381 t->data_channel_data = channel;
2383 fail_if (gst_element_set_state (t->webrtc1,
2384 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2385 fail_if (gst_element_set_state (t->webrtc2,
2386 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2388 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2390 g_object_unref (channel);
2391 test_webrtc_free (t);
2397 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
2398 struct test_webrtc *t)
2400 gint *n_ready = t->data_channel_data;
2401 GstWebRTCDataChannelState ready_state;
2403 g_object_get (channel, "ready-state", &ready_state, NULL);
2405 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
2406 if (g_atomic_int_add (n_ready, 1) >= 1) {
2407 test_webrtc_signal_state (t, STATE_CUSTOM);
2412 GST_START_TEST (test_data_channel_pre_negotiated)
2414 struct test_webrtc *t = test_webrtc_new ();
2415 GObject *channel1 = NULL, *channel2 = NULL;
2416 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2417 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2421 t->on_negotiation_needed = NULL;
2422 t->on_ice_candidate = NULL;
2424 fail_if (gst_element_set_state (t->webrtc1,
2425 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2426 fail_if (gst_element_set_state (t->webrtc2,
2427 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2429 s = gst_structure_new ("application/data-channel", "negotiated",
2430 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
2432 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
2434 g_assert_nonnull (channel1);
2435 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
2437 g_assert_nonnull (channel2);
2439 fail_if (gst_element_set_state (t->webrtc1,
2440 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2441 fail_if (gst_element_set_state (t->webrtc2,
2442 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2444 test_validate_sdp_full (t, &offer, &offer, 0, FALSE);
2446 t->data_channel_data = &n_ready;
2448 g_signal_connect (channel1, "notify::ready-state",
2449 G_CALLBACK (_on_ready_state_notify), t);
2450 g_signal_connect (channel2, "notify::ready-state",
2451 G_CALLBACK (_on_ready_state_notify), t);
2453 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2454 test_webrtc_signal_state (t, STATE_NEW);
2456 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
2458 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2460 g_object_unref (channel1);
2461 g_object_unref (channel2);
2462 gst_structure_free (s);
2463 test_webrtc_free (t);
2469 _count_non_rejected_media (struct test_webrtc *t, GstElement * element,
2470 GstWebRTCSessionDescription * sd, gpointer user_data)
2472 guint expected = GPOINTER_TO_UINT (user_data);
2473 guint non_rejected_media;
2476 non_rejected_media = 0;
2478 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2479 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2481 if (gst_sdp_media_get_port (media) != 0)
2482 non_rejected_media += 1;
2485 fail_unless_equals_int (non_rejected_media, expected);
2489 _check_bundle_tag (struct test_webrtc *t, GstElement * element,
2490 GstWebRTCSessionDescription * sd, gpointer user_data)
2492 gchar **bundled = NULL;
2493 GStrv expected = user_data;
2496 fail_unless (_parse_bundle (sd->sdp, &bundled, NULL));
2499 fail_unless_equals_int (g_strv_length (expected), 0);
2501 fail_unless_equals_int (g_strv_length (bundled), g_strv_length (expected));
2504 for (i = 0; i < g_strv_length (expected); i++) {
2505 fail_unless (g_strv_contains ((const gchar **) bundled, expected[i]));
2508 g_strfreev (bundled);
2512 _check_bundle_only_media (struct test_webrtc *t, GstElement * element,
2513 GstWebRTCSessionDescription * sd, gpointer user_data)
2515 gchar **expected_bundle_only = user_data;
2518 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2519 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2520 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2522 if (g_strv_contains ((const gchar **) expected_bundle_only, mid))
2523 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2527 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2529 struct test_webrtc *t = create_audio_video_test ();
2530 const gchar *bundle[] = { "audio0", "video1", NULL };
2531 const gchar *offer_bundle_only[] = { "video1", NULL };
2532 const gchar *answer_bundle_only[] = { NULL };
2534 guint media_format_count[] = { 1, 1, };
2535 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2536 media_format_count, NULL);
2537 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2539 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2540 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &payloads);
2541 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2542 GUINT_TO_POINTER (1), &bundle_tag);
2543 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2544 GUINT_TO_POINTER (2), &bundle_tag);
2545 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2547 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2548 &answer_non_reject);
2549 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2550 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2552 const gchar *expected_answer_setup[] = { "active", "active" };
2553 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2555 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2556 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2558 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2559 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2562 /* We set a max-bundle policy on the offering webrtcbin,
2563 * this means that all the offered medias should be part
2564 * of the group:BUNDLE attribute, and they should be marked
2567 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2569 /* We also set a max-bundle policy on the answering webrtcbin,
2570 * this means that all the offered medias should be part
2571 * of the group:BUNDLE attribute, but need not be marked
2574 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2577 test_validate_sdp (t, &offer, &answer);
2579 test_webrtc_free (t);
2584 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2586 struct test_webrtc *t = create_audio_video_test ();
2587 const gchar *bundle[] = { "audio0", "video1", NULL };
2588 const gchar *bundle_only[] = { NULL };
2590 guint media_format_count[] = { 1, 1, };
2591 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2592 media_format_count, NULL);
2593 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2595 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &count);
2596 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2597 GUINT_TO_POINTER (2), &bundle_tag);
2598 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
2600 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2601 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2603 const gchar *expected_answer_setup[] = { "active", "active" };
2604 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2606 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2607 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2609 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2610 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2613 /* We set a max-compat policy on the offering webrtcbin,
2614 * this means that all the offered medias should be part
2615 * of the group:BUNDLE attribute, and they should *not* be marked
2618 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2620 /* We set a max-bundle policy on the answering webrtcbin,
2621 * this means that all the offered medias should be part
2622 * of the group:BUNDLE attribute, but need not be marked
2625 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2628 test_validate_sdp (t, &offer, &answer);
2630 test_webrtc_free (t);
2635 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2637 struct test_webrtc *t = create_audio_video_test ();
2638 const gchar *offer_mid[] = { "audio0", "video1", NULL };
2639 const gchar *offer_bundle_only[] = { "video1", NULL };
2640 const gchar *answer_mid[] = { NULL };
2641 const gchar *answer_bundle_only[] = { NULL };
2643 guint media_format_count[] = { 1, 1, };
2644 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2645 media_format_count, NULL);
2646 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2648 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2649 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2650 GUINT_TO_POINTER (1), &payloads);
2651 VAL_SDP_INIT (offer_bundle_tag, _check_bundle_tag, offer_mid,
2653 VAL_SDP_INIT (answer_bundle_tag, _check_bundle_tag, answer_mid,
2655 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2657 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2658 &answer_bundle_tag);
2659 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2660 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2662 const gchar *expected_answer_setup[] = { "active", "active" };
2663 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2665 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2666 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2668 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2669 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2672 /* We set a max-bundle policy on the offering webrtcbin,
2673 * this means that all the offered medias should be part
2674 * of the group:BUNDLE attribute, and they should be marked
2677 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2679 /* We set a none policy on the answering webrtcbin,
2680 * this means that the answer should contain no bundled
2681 * medias, and as the bundle-policy of the offering webrtcbin
2682 * is set to max-bundle, only one media should be active.
2684 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2686 test_validate_sdp (t, &offer, &answer);
2688 test_webrtc_free (t);
2693 GST_START_TEST (test_bundle_audio_video_data)
2695 struct test_webrtc *t = create_audio_video_test ();
2696 const gchar *mids[] = { "audio0", "video1", "application2", NULL };
2697 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2698 const gchar *answer_bundle_only[] = { NULL };
2699 GObject *channel = NULL;
2701 guint media_format_count[] = { 1, 1, 1 };
2702 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2703 media_format_count, NULL);
2704 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (3),
2706 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2707 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, mids, &payloads);
2708 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2709 GUINT_TO_POINTER (1), &bundle_tag);
2710 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2711 GUINT_TO_POINTER (3), &bundle_tag);
2712 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2714 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2715 &answer_non_reject);
2716 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2717 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2719 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2720 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2722 const gchar *expected_offer_direction[] =
2723 { "sendrecv", "sendrecv", "sendrecv" };
2724 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2726 const gchar *expected_answer_direction[] =
2727 { "recvonly", "recvonly", "recvonly" };
2728 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2731 /* We set a max-bundle policy on the offering webrtcbin,
2732 * this means that all the offered medias should be part
2733 * of the group:BUNDLE attribute, and they should be marked
2736 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2738 /* We also set a max-bundle policy on the answering webrtcbin,
2739 * this means that all the offered medias should be part
2740 * of the group:BUNDLE attribute, but need not be marked
2743 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2746 fail_if (gst_element_set_state (t->webrtc1,
2747 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2748 fail_if (gst_element_set_state (t->webrtc2,
2749 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2751 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2754 test_validate_sdp (t, &offer, &answer);
2756 g_object_unref (channel);
2757 test_webrtc_free (t);
2762 GST_START_TEST (test_duplicate_nego)
2764 struct test_webrtc *t = create_audio_video_test ();
2765 guint media_format_count[] = { 1, 1, };
2766 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2767 media_format_count, NULL);
2768 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2770 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2771 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2772 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2774 const gchar *expected_answer_setup[] = { "active", "active" };
2775 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2777 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2778 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2780 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2781 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2784 guint negotiation_flag = 0;
2786 /* check that negotiating twice succeeds */
2788 t->on_negotiation_needed = on_negotiation_needed_hit;
2789 t->negotiation_data = &negotiation_flag;
2791 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2792 add_fake_audio_src_harness (h, 96);
2793 t->harnesses = g_list_prepend (t->harnesses, h);
2795 test_validate_sdp (t, &offer, &answer);
2796 fail_unless (negotiation_flag & (1 << 2));
2798 test_webrtc_reset_negotiation (t);
2799 test_validate_sdp (t, &offer, &answer);
2801 test_webrtc_free (t);
2806 GST_START_TEST (test_dual_audio)
2808 struct test_webrtc *t = create_audio_test ();
2809 guint media_format_count[] = { 1, 1, };
2810 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2811 media_format_count, NULL);
2812 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2814 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2815 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2816 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2818 const gchar *expected_answer_setup[] = { "active", "active" };
2819 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2821 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2822 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2824 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2825 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2828 GstWebRTCRTPTransceiver *trans;
2829 GArray *transceivers;
2832 /* test that each mline gets a unique transceiver even with the same caps */
2834 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
2835 add_fake_audio_src_harness (h, 96);
2836 t->harnesses = g_list_prepend (t->harnesses, h);
2838 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2839 add_fake_audio_src_harness (h, 96);
2840 t->harnesses = g_list_prepend (t->harnesses, h);
2842 t->on_negotiation_needed = NULL;
2843 test_validate_sdp (t, &offer, &answer);
2845 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
2846 fail_unless (transceivers != NULL);
2847 fail_unless_equals_int (2, transceivers->len);
2849 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
2850 fail_unless (trans != NULL);
2851 g_object_get (trans, "mlineindex", &mline, NULL);
2852 fail_unless_equals_int (mline, 0);
2854 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
2855 fail_unless (trans != NULL);
2856 g_object_get (trans, "mlineindex", &mline, NULL);
2857 fail_unless_equals_int (mline, 1);
2859 g_array_unref (transceivers);
2860 test_webrtc_free (t);
2866 sdp_increasing_session_version (struct test_webrtc *t, GstElement * element,
2867 GstWebRTCSessionDescription * desc, gpointer user_data)
2869 GstWebRTCSessionDescription *previous;
2870 const GstSDPOrigin *our_origin, *previous_origin;
2872 guint64 our_v, previous_v;
2875 TEST_SDP_IS_LOCAL (t, element,
2876 desc) ? "current-local-description" : "current-remote-description";
2877 g_object_get (element, prop, &previous, NULL);
2879 our_origin = gst_sdp_message_get_origin (desc->sdp);
2880 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2882 our_v = g_ascii_strtoull (our_origin->sess_version, NULL, 10);
2883 previous_v = g_ascii_strtoull (previous_origin->sess_version, NULL, 10);
2885 ck_assert_int_lt (previous_v, our_v);
2887 gst_webrtc_session_description_free (previous);
2891 sdp_equal_session_id (struct test_webrtc *t, GstElement * element,
2892 GstWebRTCSessionDescription * desc, gpointer user_data)
2894 GstWebRTCSessionDescription *previous;
2895 const GstSDPOrigin *our_origin, *previous_origin;
2899 TEST_SDP_IS_LOCAL (t, element,
2900 desc) ? "current-local-description" : "current-remote-description";
2901 g_object_get (element, prop, &previous, NULL);
2903 our_origin = gst_sdp_message_get_origin (desc->sdp);
2904 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2906 fail_unless_equals_string (previous_origin->sess_id, our_origin->sess_id);
2907 gst_webrtc_session_description_free (previous);
2911 sdp_media_equal_attribute (struct test_webrtc *t, GstElement * element,
2912 GstWebRTCSessionDescription * desc, GstWebRTCSessionDescription * previous,
2917 n = MIN (gst_sdp_message_medias_len (previous->sdp),
2918 gst_sdp_message_medias_len (desc->sdp));
2920 for (i = 0; i < n; i++) {
2921 const GstSDPMedia *our_media, *other_media;
2922 const gchar *our_mid, *other_mid;
2924 our_media = gst_sdp_message_get_media (desc->sdp, i);
2925 other_media = gst_sdp_message_get_media (previous->sdp, i);
2927 our_mid = gst_sdp_media_get_attribute_val (our_media, attr);
2928 other_mid = gst_sdp_media_get_attribute_val (other_media, attr);
2930 fail_unless_equals_string (our_mid, other_mid);
2935 sdp_media_equal_mid (struct test_webrtc *t, GstElement * element,
2936 GstWebRTCSessionDescription * desc, gpointer user_data)
2938 GstWebRTCSessionDescription *previous;
2942 TEST_SDP_IS_LOCAL (t, element,
2943 desc) ? "current-local-description" : "current-remote-description";
2944 g_object_get (element, prop, &previous, NULL);
2946 sdp_media_equal_attribute (t, element, desc, previous, "mid");
2948 gst_webrtc_session_description_free (previous);
2952 sdp_media_equal_ice_params (struct test_webrtc *t, GstElement * element,
2953 GstWebRTCSessionDescription * desc, gpointer user_data)
2955 GstWebRTCSessionDescription *previous;
2959 TEST_SDP_IS_LOCAL (t, element,
2960 desc) ? "current-local-description" : "current-remote-description";
2961 g_object_get (element, prop, &previous, NULL);
2963 sdp_media_equal_attribute (t, element, desc, previous, "ice-ufrag");
2964 sdp_media_equal_attribute (t, element, desc, previous, "ice-pwd");
2966 gst_webrtc_session_description_free (previous);
2970 sdp_media_equal_fingerprint (struct test_webrtc *t, GstElement * element,
2971 GstWebRTCSessionDescription * desc, gpointer user_data)
2973 GstWebRTCSessionDescription *previous;
2977 TEST_SDP_IS_LOCAL (t, element,
2978 desc) ? "current-local-description" : "current-remote-description";
2979 g_object_get (element, prop, &previous, NULL);
2981 sdp_media_equal_attribute (t, element, desc, previous, "fingerprint");
2983 gst_webrtc_session_description_free (previous);
2986 GST_START_TEST (test_renego_add_stream)
2988 struct test_webrtc *t = create_audio_video_test ();
2989 guint media_format_count[] = { 1, 1, 1 };
2990 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2991 media_format_count, NULL);
2992 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2994 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2995 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2996 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2998 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2999 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3001 const gchar *expected_offer_direction[] =
3002 { "sendrecv", "sendrecv", "sendrecv" };
3003 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3005 const gchar *expected_answer_direction[] =
3006 { "sendrecv", "recvonly", "recvonly" };
3007 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3009 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3010 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3012 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3013 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3015 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3019 /* negotiate an AV stream and then renegotiate an extra stream */
3020 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3021 add_fake_audio_src_harness (h, 96);
3022 t->harnesses = g_list_prepend (t->harnesses, h);
3024 test_validate_sdp (t, &offer, &answer);
3026 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3027 add_fake_audio_src_harness (h, 98);
3028 t->harnesses = g_list_prepend (t->harnesses, h);
3030 media_formats.next = &renego_fingerprint;
3031 count.user_data = GUINT_TO_POINTER (3);
3034 test_webrtc_reset_negotiation (t);
3035 test_validate_sdp (t, &offer, &answer);
3037 test_webrtc_free (t);
3042 GST_START_TEST (test_renego_stream_add_data_channel)
3044 struct test_webrtc *t = create_audio_video_test ();
3046 guint media_format_count[] = { 1, 1, 1 };
3047 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3048 media_format_count, NULL);
3049 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3051 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3052 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3053 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3055 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3056 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3058 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv", NULL };
3059 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3061 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly", NULL };
3062 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3064 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3065 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3067 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3068 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3070 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3075 /* negotiate an AV stream and then renegotiate a data channel */
3076 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3077 add_fake_audio_src_harness (h, 96);
3078 t->harnesses = g_list_prepend (t->harnesses, h);
3080 test_validate_sdp (t, &offer, &answer);
3082 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3085 media_formats.next = &renego_fingerprint;
3086 count.user_data = GUINT_TO_POINTER (3);
3089 test_webrtc_reset_negotiation (t);
3090 test_validate_sdp (t, &offer, &answer);
3092 g_object_unref (channel);
3093 test_webrtc_free (t);
3098 GST_START_TEST (test_renego_data_channel_add_stream)
3100 struct test_webrtc *t = test_webrtc_new ();
3101 guint media_format_count[] = { 1, 1, 1 };
3102 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3103 media_format_count, NULL);
3104 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3106 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3107 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3108 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3110 const gchar *expected_answer_setup[] = { "active", "active" };
3111 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3113 const gchar *expected_offer_direction[] = { NULL, "sendrecv" };
3114 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3116 const gchar *expected_answer_direction[] = { NULL, "recvonly" };
3117 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3119 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3120 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3122 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3123 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3125 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3130 /* negotiate an data channel and then renegotiate to add a av stream */
3131 t->on_negotiation_needed = NULL;
3132 t->on_ice_candidate = NULL;
3133 t->on_data_channel = NULL;
3134 t->on_pad_added = _pad_added_fakesink;
3136 fail_if (gst_element_set_state (t->webrtc1,
3137 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3138 fail_if (gst_element_set_state (t->webrtc2,
3139 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3141 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3144 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3146 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3147 add_fake_audio_src_harness (h, 97);
3148 t->harnesses = g_list_prepend (t->harnesses, h);
3150 media_formats.next = &renego_fingerprint;
3151 count.user_data = GUINT_TO_POINTER (2);
3154 test_webrtc_reset_negotiation (t);
3155 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3157 g_object_unref (channel);
3158 test_webrtc_free (t);
3164 GST_START_TEST (test_renego_stream_data_channel_add_stream)
3166 struct test_webrtc *t = test_webrtc_new ();
3167 guint media_format_count[] = { 1, 1, 1 };
3168 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3169 media_format_count, NULL);
3170 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3172 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3173 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3174 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3176 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3177 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3179 const gchar *expected_offer_direction[] = { "sendrecv", NULL, "sendrecv" };
3180 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3182 const gchar *expected_answer_direction[] = { "recvonly", NULL, "recvonly" };
3183 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3185 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3186 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3188 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3189 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3191 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3196 /* Negotiate a stream and a data channel, then renogotiate with a new stream */
3197 t->on_negotiation_needed = NULL;
3198 t->on_ice_candidate = NULL;
3199 t->on_data_channel = NULL;
3200 t->on_pad_added = _pad_added_fakesink;
3202 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3203 add_fake_audio_src_harness (h, 97);
3204 t->harnesses = g_list_prepend (t->harnesses, h);
3206 fail_if (gst_element_set_state (t->webrtc1,
3207 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3208 fail_if (gst_element_set_state (t->webrtc2,
3209 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3211 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3214 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3216 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3217 add_fake_audio_src_harness (h, 97);
3218 t->harnesses = g_list_prepend (t->harnesses, h);
3220 media_formats.next = &renego_fingerprint;
3221 count.user_data = GUINT_TO_POINTER (3);
3224 test_webrtc_reset_negotiation (t);
3225 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3227 g_object_unref (channel);
3228 test_webrtc_free (t);
3233 GST_START_TEST (test_bundle_renego_add_stream)
3235 struct test_webrtc *t = create_audio_video_test ();
3236 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3237 const gchar *offer_bundle_only[] = { "video1", "audio2", NULL };
3238 const gchar *answer_bundle_only[] = { NULL };
3239 guint media_format_count[] = { 1, 1, 1 };
3240 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3241 media_format_count, NULL);
3242 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3244 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3245 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3246 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3248 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3249 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3251 const gchar *expected_offer_direction[] =
3252 { "sendrecv", "sendrecv", "sendrecv" };
3253 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3255 const gchar *expected_answer_direction[] =
3256 { "sendrecv", "recvonly", "recvonly" };
3257 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3260 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, &payloads);
3261 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3263 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3264 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3266 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3268 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3269 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
3270 GUINT_TO_POINTER (1), &bundle_tag);
3271 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
3272 GUINT_TO_POINTER (3), &bundle_tag);
3273 VAL_SDP_INIT (offer_bundle_only_sdp, _check_bundle_only_media,
3274 &offer_bundle_only, &offer_non_reject);
3275 VAL_SDP_INIT (answer_bundle_only_sdp, _check_bundle_only_media,
3276 &answer_bundle_only, &answer_non_reject);
3279 /* We set a max-bundle policy on the offering webrtcbin,
3280 * this means that all the offered medias should be part
3281 * of the group:BUNDLE attribute, and they should be marked
3284 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3286 /* We also set a max-bundle policy on the answering webrtcbin,
3287 * this means that all the offered medias should be part
3288 * of the group:BUNDLE attribute, but need not be marked
3291 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3294 /* negotiate an AV stream and then renegotiate an extra stream */
3295 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3296 add_fake_audio_src_harness (h, 96);
3297 t->harnesses = g_list_prepend (t->harnesses, h);
3299 test_validate_sdp (t, &offer, &answer);
3301 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3302 add_fake_audio_src_harness (h, 98);
3303 t->harnesses = g_list_prepend (t->harnesses, h);
3305 offer_setup.next = &offer_bundle_only_sdp;
3306 answer_setup.next = &answer_bundle_only_sdp;
3307 count.user_data = GUINT_TO_POINTER (3);
3310 test_webrtc_reset_negotiation (t);
3311 test_validate_sdp (t, &offer, &answer);
3313 test_webrtc_free (t);
3318 GST_START_TEST (test_bundle_max_compat_max_bundle_renego_add_stream)
3320 struct test_webrtc *t = create_audio_video_test ();
3321 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3322 const gchar *bundle_only[] = { NULL };
3323 guint media_format_count[] = { 1, 1, 1 };
3324 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3325 media_format_count, NULL);
3326 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3328 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3329 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3330 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3332 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3333 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3335 const gchar *expected_offer_direction[] =
3336 { "sendrecv", "sendrecv", "sendrecv" };
3337 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3339 const gchar *expected_answer_direction[] =
3340 { "sendrecv", "recvonly", "recvonly" };
3341 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3344 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3345 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3347 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3348 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3350 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3352 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3353 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
3354 GUINT_TO_POINTER (3), &bundle_tag);
3355 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
3359 /* We set a max-compat policy on the offering webrtcbin,
3360 * this means that all the offered medias should be part
3361 * of the group:BUNDLE attribute, and they should *not* be marked
3364 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3366 /* We set a max-bundle policy on the answering webrtcbin,
3367 * this means that all the offered medias should be part
3368 * of the group:BUNDLE attribute, but need not be marked
3371 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3374 /* negotiate an AV stream and then renegotiate an extra stream */
3375 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3376 add_fake_audio_src_harness (h, 96);
3377 t->harnesses = g_list_prepend (t->harnesses, h);
3379 test_validate_sdp (t, &offer, &answer);
3381 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3382 add_fake_audio_src_harness (h, 98);
3383 t->harnesses = g_list_prepend (t->harnesses, h);
3385 media_formats.next = &bundle_sdp;
3386 count.user_data = GUINT_TO_POINTER (3);
3389 test_webrtc_reset_negotiation (t);
3390 test_validate_sdp (t, &offer, &answer);
3392 test_webrtc_free (t);
3397 GST_START_TEST (test_renego_transceiver_set_direction)
3399 struct test_webrtc *t = create_audio_test ();
3400 guint media_format_count[] = { 1, };
3401 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3402 media_format_count, NULL);
3403 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3405 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3406 const gchar *expected_offer_setup[] = { "actpass", };
3407 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3409 const gchar *expected_answer_setup[] = { "active", };
3410 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3412 const gchar *expected_offer_direction[] = { "sendrecv", };
3413 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3415 const gchar *expected_answer_direction[] = { "sendrecv", };
3416 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3418 GstWebRTCRTPTransceiver *transceiver;
3422 /* negotiate an AV stream and then change the transceiver direction */
3423 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3424 add_fake_audio_src_harness (h, 96);
3425 t->harnesses = g_list_prepend (t->harnesses, h);
3427 test_validate_sdp (t, &offer, &answer);
3429 /* renegotiate an inactive transceiver! */
3430 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
3431 g_object_get (pad, "transceiver", &transceiver, NULL);
3432 fail_unless (transceiver != NULL);
3433 g_object_set (transceiver, "direction",
3434 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE, NULL);
3435 expected_offer_direction[0] = "inactive";
3436 expected_answer_direction[0] = "inactive";
3438 /* TODO: also validate EOS events from the inactive change */
3440 test_webrtc_reset_negotiation (t);
3441 test_validate_sdp (t, &offer, &answer);
3443 gst_object_unref (pad);
3444 gst_object_unref (transceiver);
3445 test_webrtc_free (t);
3451 offer_remove_last_media (struct test_webrtc *t, GstElement * element,
3452 GstPromise * promise, gpointer user_data)
3455 GstSDPMessage *new, *old;
3456 const GstSDPOrigin *origin;
3457 const GstSDPConnection *conn;
3459 old = t->offer_desc->sdp;
3460 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_new (&new));
3462 origin = gst_sdp_message_get_origin (old);
3463 conn = gst_sdp_message_get_connection (old);
3464 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_version (new,
3465 gst_sdp_message_get_version (old)));
3466 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_origin (new,
3467 origin->username, origin->sess_id, origin->sess_version,
3468 origin->nettype, origin->addrtype, origin->addr));
3469 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_session_name (new,
3470 gst_sdp_message_get_session_name (old)));
3471 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_information (new,
3472 gst_sdp_message_get_information (old)));
3473 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_uri (new,
3474 gst_sdp_message_get_uri (old)));
3475 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_connection (new,
3476 conn->nettype, conn->addrtype, conn->address, conn->ttl,
3477 conn->addr_number));
3479 n = gst_sdp_message_attributes_len (old);
3480 for (i = 0; i < n; i++) {
3481 const GstSDPAttribute *a = gst_sdp_message_get_attribute (old, i);
3482 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_attribute (new,
3486 n = gst_sdp_message_medias_len (old);
3487 fail_unless (n > 0);
3488 for (i = 0; i < n - 1; i++) {
3489 const GstSDPMedia *m = gst_sdp_message_get_media (old, i);
3492 fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_copy (m, &new_m));
3493 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_media (new, new_m));
3494 gst_sdp_media_init (new_m);
3495 gst_sdp_media_free (new_m);
3498 gst_webrtc_session_description_free (t->offer_desc);
3499 t->offer_desc = gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_OFFER,
3504 offer_set_produced_error (struct test_webrtc *t, GstElement * element,
3505 GstPromise * promise, gpointer user_data)
3507 const GstStructure *reply;
3508 GError *error = NULL;
3510 reply = gst_promise_get_reply (promise);
3511 fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
3512 GST_INFO ("error produced: %s", error->message);
3513 g_clear_error (&error);
3515 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
3519 offer_created_produced_error (struct test_webrtc *t, GstElement * element,
3520 GstPromise * promise, gpointer user_data)
3522 const GstStructure *reply;
3523 GError *error = NULL;
3525 reply = gst_promise_get_reply (promise);
3526 fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
3527 GST_INFO ("error produced: %s", error->message);
3528 g_clear_error (&error);
3531 GST_START_TEST (test_renego_lose_media_fails)
3533 struct test_webrtc *t = create_audio_video_test ();
3534 VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3535 VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3537 /* check that removing an m=line will produce an error */
3539 test_validate_sdp (t, &offer, &answer);
3541 test_webrtc_reset_negotiation (t);
3543 t->on_offer_created = offer_remove_last_media;
3544 t->on_offer_set = offer_set_produced_error;
3545 t->on_answer_created = NULL;
3547 test_webrtc_create_offer (t);
3548 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
3550 test_webrtc_free (t);
3555 GST_START_TEST (test_bundle_codec_preferences_rtx_no_duplicate_payloads)
3557 struct test_webrtc *t = test_webrtc_new ();
3558 GstWebRTCRTPTransceiverDirection direction;
3559 GstWebRTCRTPTransceiver *trans;
3560 guint offer_media_format_count[] = { 2, };
3561 guint answer_media_format_count[] = { 1, };
3562 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3563 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3564 offer_media_format_count, &payloads);
3565 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3566 answer_media_format_count, &payloads);
3567 const gchar *expected_offer_setup[] = { "actpass", };
3568 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3569 &offer_media_formats);
3570 const gchar *expected_answer_setup[] = { "active", };
3571 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3572 &answer_media_formats);
3573 const gchar *expected_offer_direction[] = { "recvonly", };
3574 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3576 const gchar *expected_answer_direction[] = { "sendonly", };
3577 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3582 /* add a transceiver that will only receive an opus stream and check that
3583 * the created offer is marked as recvonly */
3584 t->on_negotiation_needed = NULL;
3585 t->on_ice_candidate = NULL;
3586 t->on_pad_added = _pad_added_fakesink;
3588 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3590 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3593 /* setup recvonly transceiver */
3594 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3595 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3596 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3598 g_object_set (GST_OBJECT (trans), "do-nack", TRUE, NULL);
3599 gst_caps_unref (caps);
3600 fail_unless (trans != NULL);
3601 gst_object_unref (trans);
3603 /* setup sendonly peer */
3604 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3605 add_fake_video_src_harness (h, 96);
3606 t->harnesses = g_list_prepend (t->harnesses, h);
3607 test_validate_sdp (t, &offer, &answer);
3609 test_webrtc_free (t);
3615 on_sdp_media_no_duplicate_extmaps (struct test_webrtc *t, GstElement * element,
3616 GstWebRTCSessionDescription * desc, gpointer user_data)
3618 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, 0);
3620 fail_unless (media != NULL);
3622 fail_unless_equals_string (gst_sdp_media_get_attribute_val_n (media, "extmap",
3625 fail_unless (gst_sdp_media_get_attribute_val_n (media, "extmap", 1) == NULL);
3628 /* In this test, we validate that identical extmaps for multiple formats
3629 * in the caps of a single transceiver are deduplicated. This is necessary
3630 * because Firefox will complain about duplicate extmap ids and fail negotiation
3632 GST_START_TEST (test_codec_preferences_no_duplicate_extmaps)
3634 struct test_webrtc *t = test_webrtc_new ();
3635 GstWebRTCRTPTransceiver *trans;
3636 GstWebRTCRTPTransceiverDirection direction;
3637 VAL_SDP_INIT (extmaps, on_sdp_media_no_duplicate_extmaps, NULL, NULL);
3641 caps = gst_caps_new_empty ();
3643 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3644 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3645 gst_caps_append_structure (caps, s);
3646 s = gst_structure_from_string (H264_RTP_CAPS (97), NULL);
3647 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3648 gst_caps_append_structure (caps, s);
3650 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3651 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3653 gst_caps_unref (caps);
3654 fail_unless (trans != NULL);
3656 t->on_negotiation_needed = NULL;
3657 t->on_pad_added = NULL;
3658 t->on_ice_candidate = NULL;
3660 test_validate_sdp (t, &extmaps, NULL);
3662 test_webrtc_free (t);
3667 /* In this test, we validate that trying to use different values
3668 * for the same extmap id in multiple formats in the caps of a
3669 * single transceiver errors out when creating the offer. */
3670 GST_START_TEST (test_codec_preferences_incompatible_extmaps)
3672 struct test_webrtc *t = test_webrtc_new ();
3673 GstWebRTCRTPTransceiver *trans;
3674 GstWebRTCRTPTransceiverDirection direction;
3678 caps = gst_caps_new_empty ();
3680 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3681 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3682 gst_caps_append_structure (caps, s);
3683 s = gst_structure_from_string (H264_RTP_CAPS (97), NULL);
3684 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobaz", NULL);
3685 gst_caps_append_structure (caps, s);
3687 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3688 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3690 gst_caps_unref (caps);
3691 fail_unless (trans != NULL);
3693 t->on_negotiation_needed = NULL;
3694 t->on_pad_added = NULL;
3695 t->on_ice_candidate = NULL;
3696 t->on_offer_created = offer_created_produced_error;
3698 test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
3700 test_webrtc_free (t);
3705 /* In this test, we validate that extmap values must be of the correct type */
3706 GST_START_TEST (test_codec_preferences_invalid_extmap)
3708 struct test_webrtc *t = test_webrtc_new ();
3709 GstWebRTCRTPTransceiver *trans;
3710 GstWebRTCRTPTransceiverDirection direction;
3714 caps = gst_caps_new_empty ();
3716 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3717 gst_structure_set (s, "extmap-1", G_TYPE_INT, 42, NULL);
3718 gst_caps_append_structure (caps, s);
3720 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3721 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3723 gst_caps_unref (caps);
3724 fail_unless (trans != NULL);
3726 t->on_negotiation_needed = NULL;
3727 t->on_pad_added = NULL;
3728 t->on_ice_candidate = NULL;
3729 t->on_offer_created = offer_created_produced_error;
3731 test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
3733 test_webrtc_free (t);
3738 GST_START_TEST (test_reject_request_pad)
3740 struct test_webrtc *t = test_webrtc_new ();
3741 GstWebRTCRTPTransceiverDirection direction;
3742 GstWebRTCRTPTransceiver *trans, *trans2;
3743 guint offer_media_format_count[] = { 1, };
3744 guint answer_media_format_count[] = { 1, };
3745 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3746 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3747 offer_media_format_count, &payloads);
3748 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3749 answer_media_format_count, &payloads);
3750 const gchar *expected_offer_setup[] = { "actpass", };
3751 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3752 &offer_media_formats);
3753 const gchar *expected_answer_setup[] = { "active", };
3754 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3755 &answer_media_formats);
3756 const gchar *expected_offer_direction[] = { "recvonly", };
3757 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3759 const gchar *expected_answer_direction[] = { "sendonly", };
3760 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3765 GstPadTemplate *templ;
3767 t->on_negotiation_needed = NULL;
3768 t->on_ice_candidate = NULL;
3769 t->on_pad_added = _pad_added_fakesink;
3771 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3773 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3776 /* setup recvonly transceiver */
3777 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3778 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3779 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3781 gst_caps_unref (caps);
3782 fail_unless (trans != NULL);
3784 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3785 add_fake_video_src_harness (h, 96);
3786 t->harnesses = g_list_prepend (t->harnesses, h);
3788 test_validate_sdp (t, &offer, &answer);
3790 /* This should fail because the direction is wrong */
3791 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3792 fail_unless (pad == NULL);
3794 g_object_set (trans, "direction",
3795 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV, NULL);
3797 templ = gst_element_get_pad_template (t->webrtc1, "sink_%u");
3798 fail_unless (templ != NULL);
3800 /* This should fail because the caps are wrong */
3801 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
3802 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3803 fail_unless (pad == NULL);
3805 g_object_set (trans, "codec-preferences", NULL, NULL);
3807 /* This should fail because the kind doesn't match */
3808 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3809 fail_unless (pad == NULL);
3810 gst_caps_unref (caps);
3812 /* This should succeed and give us sink_0 */
3813 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3814 fail_unless (pad != NULL);
3816 g_object_get (pad, "transceiver", &trans2, NULL);
3818 fail_unless (trans == trans2);
3820 gst_object_unref (pad);
3821 gst_object_unref (trans);
3822 gst_object_unref (trans2);
3824 test_webrtc_free (t);
3830 _verify_media_types (struct test_webrtc *t, GstElement * element,
3831 GstWebRTCSessionDescription * desc, gpointer user_data)
3833 gchar **media_types = user_data;
3836 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
3837 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
3839 fail_unless_equals_string (gst_sdp_media_get_media (media), media_types[i]);
3843 GST_START_TEST (test_reject_create_offer)
3845 struct test_webrtc *t = test_webrtc_new ();
3847 GstPromise *promise;
3848 GstPromiseResult res;
3849 const GstStructure *s;
3850 GError *error = NULL;
3852 const gchar *media_types[] = { "video", "audio" };
3853 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3854 guint media_format_count[] = { 1, 1 };
3855 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3856 media_format_count, &media_type);
3857 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3859 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3860 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3861 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3863 const gchar *expected_answer_setup[] = { "active", "active" };
3864 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3866 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
3867 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3869 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
3870 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3873 t->on_negotiation_needed = NULL;
3874 t->on_ice_candidate = NULL;
3875 t->on_pad_added = _pad_added_fakesink;
3877 /* setup sendonly peer */
3878 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3879 add_fake_audio_src_harness (h, 96);
3880 t->harnesses = g_list_prepend (t->harnesses, h);
3882 /* Check that if there is no 0, we can't create an offer with a hole */
3883 promise = gst_promise_new ();
3884 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3885 res = gst_promise_wait (promise);
3886 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3887 s = gst_promise_get_reply (promise);
3888 fail_unless (s != NULL);
3889 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3890 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
3891 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
3892 fail_unless (g_str_match_string
3893 ("has locked mline 1 but the whole offer only has 0 sections",
3894 error->message, FALSE));
3895 g_clear_error (&error);
3896 gst_promise_unref (promise);
3898 h = gst_harness_new_with_element (t->webrtc1, "sink_%u", NULL);
3899 add_fake_video_src_harness (h, 97);
3900 t->harnesses = g_list_prepend (t->harnesses, h);
3902 /* Adding a second sink, which will fill m-line 0, should fix it */
3903 test_validate_sdp (t, &offer, &answer);
3905 test_webrtc_free (t);
3910 GST_START_TEST (test_reject_set_description)
3912 struct test_webrtc *t = test_webrtc_new ();
3914 GstPromise *promise;
3915 GstPromiseResult res;
3916 const GstStructure *s;
3917 GError *error = NULL;
3918 GstWebRTCSessionDescription *desc = NULL;
3919 GstPadTemplate *templ;
3923 t->on_negotiation_needed = NULL;
3924 t->on_ice_candidate = NULL;
3925 t->on_pad_added = _pad_added_fakesink;
3928 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3929 add_fake_audio_src_harness (h, 96);
3930 t->harnesses = g_list_prepend (t->harnesses, h);
3932 /* Create a second side with specific video caps */
3933 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
3934 fail_unless (templ != NULL);
3935 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
3936 pad = gst_element_request_pad (t->webrtc2, templ, "sink_0", caps);
3937 fail_unless (pad != NULL);
3938 gst_caps_unref (caps);
3939 gst_object_unref (pad);
3941 /* Create an offer */
3942 promise = gst_promise_new ();
3943 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3944 res = gst_promise_wait (promise);
3945 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3946 s = gst_promise_get_reply (promise);
3947 fail_unless (s != NULL);
3948 gst_structure_get (s, "offer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &desc,
3950 fail_unless (desc != NULL);
3951 gst_promise_unref (promise);
3953 fail_if (gst_element_set_state (t->webrtc2,
3954 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
3956 /* Verify that setting an offer where there is a forced m-line with
3957 a different kind fails. */
3958 promise = gst_promise_new ();
3959 g_signal_emit_by_name (t->webrtc2, "set-remote-description", desc, promise);
3960 res = gst_promise_wait (promise);
3961 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3962 s = gst_promise_get_reply (promise);
3963 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3964 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
3965 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
3966 fail_unless (g_str_match_string
3967 ("m-line 0 was locked to audio, but SDP has audio media", error->message,
3970 g_clear_error (&error);
3971 fail_unless (s != NULL);
3972 gst_promise_unref (promise);
3973 gst_webrtc_session_description_free (desc);
3975 test_webrtc_free (t);
3980 GST_START_TEST (test_force_second_media)
3982 struct test_webrtc *t = test_webrtc_new ();
3983 const gchar *media_types[] = { "audio" };
3984 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3985 guint media_format_count[] = { 1, };
3986 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3987 media_format_count, &media_type);
3988 const gchar *expected_offer_setup[] = { "actpass", };
3989 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3991 const gchar *expected_answer_setup[] = { "active", };
3992 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3994 const gchar *expected_offer_direction[] = { "sendrecv", };
3995 VAL_SDP_INIT (offer_direction, on_sdp_media_direction,
3996 expected_offer_direction, &offer_setup);
3997 const gchar *expected_answer_direction[] = { "recvonly", };
3998 VAL_SDP_INIT (answer_direction, on_sdp_media_direction,
3999 expected_answer_direction, &answer_setup);
4000 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4002 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4005 const gchar *second_media_types[] = { "audio", "video" };
4006 VAL_SDP_INIT (second_media_type, _verify_media_types, &second_media_types,
4008 guint second_media_format_count[] = { 1, 1 };
4009 VAL_SDP_INIT (second_media_formats, on_sdp_media_count_formats,
4010 second_media_format_count, &second_media_type);
4011 const gchar *second_expected_offer_setup[] = { "active", "actpass" };
4012 VAL_SDP_INIT (second_offer_setup, on_sdp_media_setup,
4013 second_expected_offer_setup, &second_media_formats);
4014 const gchar *second_expected_answer_setup[] = { "passive", "active" };
4015 VAL_SDP_INIT (second_answer_setup, on_sdp_media_setup,
4016 second_expected_answer_setup, &second_media_formats);
4017 const gchar *second_expected_answer_direction[] = { "sendonly", "recvonly" };
4018 VAL_SDP_INIT (second_answer_direction, on_sdp_media_direction,
4019 second_expected_answer_direction, &second_answer_setup);
4020 const gchar *second_expected_offer_direction[] = { "recvonly", "sendrecv" };
4021 VAL_SDP_INIT (second_offer_direction, on_sdp_media_direction,
4022 second_expected_offer_direction, &second_offer_setup);
4023 VAL_SDP_INIT (second_answer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
4024 &second_answer_direction);
4025 VAL_SDP_INIT (second_offer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
4026 &second_offer_direction);
4029 guint negotiation_flag = 0;
4030 GstPadTemplate *templ;
4034 /* add a transceiver that will only receive an opus stream and check that
4035 * the created offer is marked as recvonly */
4036 t->on_negotiation_needed = on_negotiation_needed_hit;
4037 t->negotiation_data = &negotiation_flag;
4038 t->on_ice_candidate = NULL;
4039 t->on_pad_added = _pad_added_fakesink;
4042 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4043 add_fake_audio_src_harness (h, 96);
4044 t->harnesses = g_list_prepend (t->harnesses, h);
4046 /* Create a second side with specific video caps */
4047 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
4048 fail_unless (templ != NULL);
4049 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
4050 pad = gst_element_request_pad (t->webrtc2, templ, NULL, caps);
4051 gst_caps_unref (caps);
4052 fail_unless (pad != NULL);
4053 h = gst_harness_new_with_element (t->webrtc2, GST_PAD_NAME (pad), NULL);
4054 gst_object_unref (pad);
4055 add_fake_video_src_harness (h, 97);
4056 t->harnesses = g_list_prepend (t->harnesses, h);
4058 test_validate_sdp (t, &offer_count, &answer_count);
4059 fail_unless (negotiation_flag & 1 << 2);
4061 test_webrtc_reset_negotiation (t);
4064 test_validate_sdp (t, &second_offer_count, &second_answer_count);
4066 test_webrtc_free (t);
4071 GST_START_TEST (test_codec_preferences_caps)
4075 GstWebRTCRTPTransceiver *trans;
4076 GstCaps *caps, *caps2;
4078 h = gst_harness_new_with_padnames ("webrtcbin", "sink_0", NULL);
4079 pad = gst_element_get_static_pad (h->element, "sink_0");
4081 g_object_get (pad, "transceiver", &trans, NULL);
4083 caps = gst_caps_from_string ("application/x-rtp, media=video,"
4084 "encoding-name=VP8, payload=115; application/x-rtp, media=video,"
4085 " encoding-name=H264, payload=104");
4086 g_object_set (trans, "codec-preferences", caps, NULL);
4088 caps2 = gst_pad_query_caps (pad, NULL);
4089 fail_unless (gst_caps_is_equal (caps, caps2));
4090 gst_caps_unref (caps2);
4091 gst_caps_unref (caps);
4093 caps = gst_caps_from_string (VP8_RTP_CAPS (115));
4094 fail_unless (gst_pad_query_accept_caps (pad, caps));
4095 gst_harness_set_src_caps (h, g_steal_pointer (&caps));
4097 caps = gst_caps_from_string (VP8_RTP_CAPS (99));
4098 fail_unless (!gst_pad_query_accept_caps (pad, caps));
4099 gst_caps_unref (caps);
4101 gst_object_unref (pad);
4102 gst_object_unref (trans);
4103 gst_harness_teardown (h);
4108 GST_START_TEST (test_codec_preferences_negotiation_sinkpad)
4110 struct test_webrtc *t = test_webrtc_new ();
4111 guint media_format_count[] = { 1, };
4112 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4113 media_format_count, NULL);
4114 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4116 VAL_SDP_INIT (payloads2, on_sdp_media_payload_types, GUINT_TO_POINTER (0),
4118 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &payloads2);
4119 const gchar *expected_offer_setup[] = { "actpass", };
4120 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4122 const gchar *expected_answer_setup[] = { "active", };
4123 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4125 const gchar *expected_offer_direction[] = { "sendrecv", };
4126 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4128 const gchar *expected_answer_direction[] = { "recvonly", };
4129 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4133 GstWebRTCRTPTransceiver *transceiver;
4136 GstPromise *promise;
4137 GstPromiseResult res;
4138 const GstStructure *s;
4139 GError *error = NULL;
4141 t->on_negotiation_needed = NULL;
4142 t->on_ice_candidate = NULL;
4143 t->on_pad_added = _pad_added_fakesink;
4145 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4146 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
4147 g_object_get (pad, "transceiver", &transceiver, NULL);
4148 caps = gst_caps_from_string (VP8_RTP_CAPS (115) ";" VP8_RTP_CAPS (97));
4149 g_object_set (transceiver, "codec-preferences", caps, NULL);
4150 gst_caps_unref (caps);
4151 gst_object_unref (transceiver);
4152 gst_object_unref (pad);
4154 add_fake_video_src_harness (h, 96);
4155 t->harnesses = g_list_prepend (t->harnesses, h);
4157 promise = gst_promise_new ();
4158 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
4159 res = gst_promise_wait (promise);
4160 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
4161 s = gst_promise_get_reply (promise);
4162 fail_unless (s != NULL);
4163 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
4164 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
4165 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
4166 fail_unless (g_str_match_string
4167 ("Caps negotiation on pad sink_0 failed against codec preferences",
4168 error->message, FALSE));
4169 g_clear_error (&error);
4170 gst_promise_unref (promise);
4172 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
4173 gst_harness_set_src_caps (h, caps);
4175 test_validate_sdp (t, &offer, &answer);
4177 test_webrtc_free (t);
4184 add_audio_test_src_harness (GstHarness * h)
4186 #define L16_CAPS "application/x-rtp, payload=11, media=audio," \
4187 " encoding-name=L16, clock-rate=44100, ssrc=(uint)3484078952"
4188 GstCaps *caps = gst_caps_from_string (L16_CAPS);
4189 gst_harness_set_src_caps (h, caps);
4190 gst_harness_add_src_parse (h, "audiotestsrc is-live=true ! rtpL16pay ! "
4191 L16_CAPS " ! identity", TRUE);
4195 _pad_added_harness (struct test_webrtc *t, GstElement * element,
4196 GstPad * pad, gpointer user_data)
4199 GstHarness **sink_harness = user_data;
4201 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
4204 h = gst_harness_new_with_element (element, NULL, GST_OBJECT_NAME (pad));
4205 t->harnesses = g_list_prepend (t->harnesses, h);
4209 g_cond_broadcast (&t->cond);
4214 new_jitterbuffer_set_fast_start (GstElement * rtpbin,
4215 GstElement * rtpjitterbuffer, guint session_id, guint ssrc,
4218 g_object_set (rtpjitterbuffer, "faststart-min-packets", 1, NULL);
4221 GST_START_TEST (test_codec_preferences_negotiation_srcpad)
4223 struct test_webrtc *t = test_webrtc_new ();
4224 guint media_format_count[] = { 1, };
4225 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4226 media_format_count, NULL);
4227 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4229 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
4230 const gchar *expected_offer_setup[] = { "actpass", };
4231 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4233 const gchar *expected_answer_setup[] = { "active", };
4234 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4236 const gchar *expected_offer_direction[] = { "sendrecv", };
4237 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4239 const gchar *expected_answer_direction[] = { "recvonly", };
4240 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4242 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
4243 GUINT_TO_POINTER (0), &count);
4245 GstHarness *sink_harness = NULL;
4247 GstElement *rtpbin2;
4250 t->on_negotiation_needed = NULL;
4251 t->on_ice_candidate = NULL;
4252 t->on_pad_added = _pad_added_harness;
4253 t->pad_added_data = &sink_harness;
4255 rtpbin2 = gst_bin_get_by_name (GST_BIN (t->webrtc2), "rtpbin");
4256 fail_unless (rtpbin2 != NULL);
4257 g_signal_connect (rtpbin2, "new-jitterbuffer",
4258 G_CALLBACK (new_jitterbuffer_set_fast_start), NULL);
4259 g_object_unref (rtpbin2);
4261 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4262 add_audio_test_src_harness (h);
4263 t->harnesses = g_list_prepend (t->harnesses, h);
4265 test_validate_sdp (t, &offer, &answer);
4267 fail_if (gst_element_set_state (t->webrtc1,
4268 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4269 fail_if (gst_element_set_state (t->webrtc2,
4270 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4272 for (i = 0; i < 10; i++)
4273 gst_harness_push_from_src (h);
4275 g_mutex_lock (&t->lock);
4276 while (sink_harness == NULL) {
4277 gst_harness_push_from_src (h);
4278 g_cond_wait_until (&t->cond, &t->lock, g_get_monotonic_time () + 5000);
4280 g_mutex_unlock (&t->lock);
4281 fail_unless (sink_harness->element == t->webrtc2);
4283 /* Get one buffer out, this makes sure the capsfilter is primed and
4286 buf = gst_harness_pull (sink_harness);
4287 fail_unless (buf != NULL);
4288 gst_buffer_unref (buf);
4290 gst_harness_set_sink_caps_str (sink_harness, OPUS_RTP_CAPS (100));
4292 test_webrtc_reset_negotiation (t);
4293 test_validate_sdp_full (t, &offer, &answer_non_reject, 0, FALSE);
4295 test_webrtc_free (t);
4301 _on_new_transceiver_codec_preferences_h264 (GstElement * webrtcbin,
4302 GstWebRTCRTPTransceiver * trans, gpointer * user_data)
4306 caps = gst_caps_from_string ("application/x-rtp,encoding-name=(string)H264");
4307 g_object_set (trans, "codec-preferences", caps, NULL);
4308 gst_caps_unref (caps);
4312 on_sdp_media_payload_types_only_h264 (struct test_webrtc *t,
4313 GstElement * element, GstWebRTCSessionDescription * desc,
4316 const GstSDPMedia *vmedia;
4317 guint video_mline = GPOINTER_TO_UINT (user_data);
4320 vmedia = gst_sdp_message_get_media (desc->sdp, video_mline);
4322 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
4323 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
4325 if (!g_strcmp0 (attr->key, "rtpmap")) {
4326 fail_unless_equals_string (attr->value, "101 H264/90000");
4332 GST_START_TEST (test_codec_preferences_in_on_new_transceiver)
4334 struct test_webrtc *t = test_webrtc_new ();
4335 GstWebRTCRTPTransceiverDirection direction;
4336 GstWebRTCRTPTransceiver *trans;
4337 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4339 guint offer_media_format_count[] = { 2 };
4340 guint answer_media_format_count[] = { 1 };
4341 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
4342 offer_media_format_count, &no_duplicate_payloads);
4343 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
4344 answer_media_format_count, &no_duplicate_payloads);
4345 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4346 &offer_media_formats);
4347 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4348 &answer_media_formats);
4349 VAL_SDP_INIT (offer_payloads, on_sdp_media_payload_types,
4350 GUINT_TO_POINTER (0), &offer_count);
4351 VAL_SDP_INIT (answer_payloads, on_sdp_media_payload_types_only_h264,
4352 GUINT_TO_POINTER (0), &answer_count);
4353 const gchar *expected_offer_setup[] = { "actpass", };
4354 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4356 const gchar *expected_answer_setup[] = { "active", };
4357 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4359 const gchar *expected_offer_direction[] = { "sendonly", };
4360 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4362 const gchar *expected_answer_direction[] = { "recvonly", };
4363 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4368 t->on_negotiation_needed = NULL;
4369 t->on_ice_candidate = NULL;
4370 t->on_pad_added = _pad_added_fakesink;
4372 /* setup sendonly transceiver with VP8 and H264 */
4373 caps = gst_caps_from_string (VP8_RTP_CAPS (97) ";" H264_RTP_CAPS (101));
4374 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
4375 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
4377 gst_caps_unref (caps);
4378 fail_unless (trans != NULL);
4379 gst_object_unref (trans);
4381 /* setup recvonly peer */
4382 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
4383 add_fake_video_src_harness (h, 101);
4384 t->harnesses = g_list_prepend (t->harnesses, h);
4386 /* connect to "on-new-transceiver" to set codec-preferences to H264 */
4387 g_signal_connect (t->webrtc2, "on-new-transceiver",
4388 G_CALLBACK (_on_new_transceiver_codec_preferences_h264), NULL);
4390 /* Answer SDP should now have H264 only. Without the codec-preferences it
4391 * would only have VP8 because that comes first in the SDP */
4393 test_validate_sdp (t, &offer, &answer);
4394 test_webrtc_free (t);
4399 GST_START_TEST (test_renego_rtx)
4401 struct test_webrtc *t = create_audio_video_test ();
4402 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4404 guint media_format_count[] = { 1, 1 };
4405 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4406 media_format_count, &no_duplicate_payloads);
4407 VAL_SDP_INIT (count_media, _count_num_sdp_media, GUINT_TO_POINTER (2),
4409 VAL_SDP_INIT (payloads, on_sdp_media_payload_types,
4410 GUINT_TO_POINTER (1), &count_media);
4411 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv", };
4412 VAL_SDP_INIT (offer_direction, on_sdp_media_direction,
4413 expected_offer_direction, &payloads);
4414 const gchar *expected_answer_direction[] = { "recvonly", "recvonly", };
4415 VAL_SDP_INIT (answer_direction, on_sdp_media_direction,
4416 expected_answer_direction, &payloads);
4417 const gchar *expected_offer_setup[] = { "actpass", "actpass", };
4418 VAL_SDP_INIT (offer, on_sdp_media_setup, expected_offer_setup,
4420 const gchar *expected_answer_setup[] = { "active", "active", };
4421 VAL_SDP_INIT (answer, on_sdp_media_setup, expected_answer_setup,
4423 GstWebRTCRTPTransceiver *trans;
4425 t->on_negotiation_needed = NULL;
4426 t->on_ice_candidate = NULL;
4427 t->on_pad_added = _pad_added_fakesink;
4429 test_validate_sdp (t, &offer, &answer);
4431 test_webrtc_reset_negotiation (t);
4433 g_signal_emit_by_name (t->webrtc1, "get-transceiver", 1, &trans);
4434 g_object_set (trans, "do-nack", TRUE, "fec-type",
4435 GST_WEBRTC_FEC_TYPE_ULP_RED, NULL);
4436 g_clear_object (&trans);
4438 g_signal_emit_by_name (t->webrtc2, "get-transceiver", 1, &trans);
4439 g_object_set (trans, "do-nack", TRUE, "fec-type",
4440 GST_WEBRTC_FEC_TYPE_ULP_RED, NULL);
4441 g_clear_object (&trans);
4443 /* adding RTX/RED/FEC increases the number of media formats */
4444 media_format_count[1] = 5;
4446 test_validate_sdp (t, &offer, &answer);
4448 test_webrtc_free (t);
4453 GST_START_TEST (test_bundle_mid_header_extension)
4455 struct test_webrtc *t = test_webrtc_new ();
4456 GstWebRTCRTPTransceiverDirection direction;
4457 GstWebRTCRTPTransceiver *trans;
4458 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4460 guint media_format_count[] = { 1, 1, };
4461 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4462 media_format_count, &no_duplicate_payloads);
4463 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4465 const char *expected_mid[] = { "gst", };
4466 VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
4467 const gchar *expected_offer_setup[] = { "actpass", };
4468 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
4469 const gchar *expected_answer_setup[] = { "active", };
4470 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
4471 const gchar *expected_offer_direction[] = { "recvonly", };
4472 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4474 const gchar *expected_answer_direction[] = { "sendonly", };
4475 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4482 /* add a transceiver that will only receive an opus stream and check that
4483 * the created offer is marked as recvonly */
4484 t->on_negotiation_needed = NULL;
4485 t->on_ice_candidate = NULL;
4486 t->on_pad_added = _pad_added_fakesink;
4488 /* setup recvonly transceiver */
4489 caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
4490 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
4491 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
4493 gst_caps_unref (caps);
4494 fail_unless (trans != NULL);
4495 g_object_get (trans, "mlineindex", &mline, NULL);
4496 fail_unless_equals_int (mline, -1);
4498 /* setup sendonly peer */
4499 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
4500 add_fake_audio_src_harness (h, 96);
4501 t->harnesses = g_list_prepend (t->harnesses, h);
4503 test_validate_sdp (t, &offer, &answer);
4505 g_object_get (trans, "mlineindex", &mline, "mid", &trans_mid, NULL);
4506 fail_unless_equals_int (mline, 0);
4507 fail_unless_equals_string (trans_mid, "gst");
4508 g_clear_pointer (&trans_mid, g_free);
4509 gst_object_unref (trans);
4511 test_webrtc_free (t);
4517 webrtcbin_suite (void)
4519 Suite *s = suite_create ("webrtcbin");
4520 TCase *tc = tcase_create ("general");
4521 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
4522 GstPluginFeature *sctpenc, *sctpdec;
4523 GstRegistry *registry;
4525 registry = gst_registry_get ();
4526 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
4527 nicesink = gst_registry_lookup_feature (registry, "nicesink");
4528 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
4529 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
4530 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
4531 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
4533 tcase_add_test (tc, test_no_nice_elements_request_pad);
4534 tcase_add_test (tc, test_no_nice_elements_state_change);
4535 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
4536 tcase_add_test (tc, test_sdp_no_media);
4537 tcase_add_test (tc, test_session_stats);
4538 tcase_add_test (tc, test_audio);
4539 tcase_add_test (tc, test_ice_port_restriction);
4540 tcase_add_test (tc, test_audio_video);
4541 tcase_add_test (tc, test_media_direction);
4542 tcase_add_test (tc, test_add_transceiver);
4543 tcase_add_test (tc, test_get_transceivers);
4544 tcase_add_test (tc, test_add_recvonly_transceiver);
4545 tcase_add_test (tc, test_recvonly_sendonly);
4546 tcase_add_test (tc, test_payload_types);
4547 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
4548 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
4549 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
4550 tcase_add_test (tc, test_dual_audio);
4551 tcase_add_test (tc, test_duplicate_nego);
4552 tcase_add_test (tc, test_renego_add_stream);
4553 tcase_add_test (tc, test_bundle_renego_add_stream);
4554 tcase_add_test (tc, test_bundle_max_compat_max_bundle_renego_add_stream);
4555 tcase_add_test (tc, test_renego_transceiver_set_direction);
4556 tcase_add_test (tc, test_renego_lose_media_fails);
4558 test_bundle_codec_preferences_rtx_no_duplicate_payloads);
4559 tcase_add_test (tc, test_reject_request_pad);
4560 tcase_add_test (tc, test_reject_create_offer);
4561 tcase_add_test (tc, test_reject_set_description);
4562 tcase_add_test (tc, test_force_second_media);
4563 tcase_add_test (tc, test_codec_preferences_caps);
4564 tcase_add_test (tc, test_codec_preferences_negotiation_sinkpad);
4565 tcase_add_test (tc, test_codec_preferences_negotiation_srcpad);
4566 tcase_add_test (tc, test_codec_preferences_in_on_new_transceiver);
4567 tcase_add_test (tc, test_codec_preferences_no_duplicate_extmaps);
4568 tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
4569 tcase_add_test (tc, test_codec_preferences_invalid_extmap);
4570 tcase_add_test (tc, test_renego_rtx);
4571 tcase_add_test (tc, test_bundle_mid_header_extension);
4572 if (sctpenc && sctpdec) {
4573 tcase_add_test (tc, test_data_channel_create);
4574 tcase_add_test (tc, test_data_channel_remote_notify);
4575 tcase_add_test (tc, test_data_channel_transfer_string);
4576 tcase_add_test (tc, test_data_channel_transfer_data);
4577 tcase_add_test (tc, test_data_channel_create_after_negotiate);
4578 tcase_add_test (tc, test_data_channel_close);
4579 tcase_add_test (tc, test_data_channel_low_threshold);
4580 tcase_add_test (tc, test_data_channel_max_message_size);
4581 tcase_add_test (tc, test_data_channel_pre_negotiated);
4582 tcase_add_test (tc, test_bundle_audio_video_data);
4583 tcase_add_test (tc, test_renego_stream_add_data_channel);
4584 tcase_add_test (tc, test_renego_data_channel_add_stream);
4585 tcase_add_test (tc, test_renego_stream_data_channel_add_stream);
4587 GST_WARNING ("Some required elements were not found. "
4588 "All datachannel tests are disabled. sctpenc %p, sctpdec %p", sctpenc,
4592 GST_WARNING ("Some required elements were not found. "
4593 "All media tests are disabled. nicesrc %p, nicesink %p, "
4594 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
4599 gst_object_unref (nicesrc);
4601 gst_object_unref (nicesink);
4603 gst_object_unref (dtlssrtpdec);
4605 gst_object_unref (dtlssrtpenc);
4607 gst_object_unref (sctpenc);
4609 gst_object_unref (sctpdec);
4611 suite_add_tcase (s, tc);
4616 GST_CHECK_MAIN (webrtcbin);