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"
40 #define TEST_IS_OFFER_ELEMENT(t, e) ((t)->offerror == 1 && (e) == (t)->webrtc1 ? TRUE : FALSE)
41 #define TEST_GET_OFFEROR(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc1 : t->webrtc2)
42 #define TEST_GET_ANSWERER(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc2 : t->webrtc1)
47 STATE_NEGOTIATION_NEEDED,
55 /* basic premise of this is that webrtc1 and webrtc2 are attempting to connect
56 * to each other in various configurations */
72 GDestroyNotify data_notify;
74 void (*on_negotiation_needed) (struct test_webrtc * t,
77 gpointer negotiation_data;
78 GDestroyNotify negotiation_notify;
79 void (*on_ice_candidate) (struct test_webrtc * t,
85 gpointer ice_candidate_data;
86 GDestroyNotify ice_candidate_notify;
87 GstWebRTCSessionDescription * (*on_offer_created) (struct test_webrtc * t,
92 GDestroyNotify offer_notify;
93 GstWebRTCSessionDescription * (*on_answer_created) (struct test_webrtc * t,
97 gpointer data_channel_data;
98 GDestroyNotify data_channel_notify;
99 void (*on_data_channel) (struct test_webrtc * t,
100 GstElement * element,
101 GObject *data_channel,
103 gpointer answer_data;
104 GDestroyNotify answer_notify;
105 void (*on_pad_added) (struct test_webrtc * t,
106 GstElement * element,
109 gpointer pad_added_data;
110 GDestroyNotify pad_added_notify;
111 void (*bus_message) (struct test_webrtc * t,
116 GDestroyNotify bus_notify;
121 _on_answer_received (GstPromise * promise, gpointer user_data)
123 struct test_webrtc *t = user_data;
124 GstElement *offeror = TEST_GET_OFFEROR (t);
125 GstElement *answerer = TEST_GET_ANSWERER (t);
126 const GstStructure *reply;
127 GstWebRTCSessionDescription *answer = NULL;
130 reply = gst_promise_get_reply (promise);
131 gst_structure_get (reply, "answer",
132 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
133 desc = gst_sdp_message_as_text (answer->sdp);
134 GST_INFO ("Created Answer: %s", desc);
137 g_mutex_lock (&t->lock);
138 if (t->on_answer_created) {
139 gst_webrtc_session_description_free (answer);
140 answer = t->on_answer_created (t, answerer, promise, t->answer_data);
142 gst_promise_unref (promise);
144 g_signal_emit_by_name (answerer, "set-local-description", answer, NULL);
145 g_signal_emit_by_name (offeror, "set-remote-description", answer, NULL);
147 t->state = STATE_ANSWER_CREATED;
148 g_cond_broadcast (&t->cond);
149 g_mutex_unlock (&t->lock);
151 gst_webrtc_session_description_free (answer);
155 _on_offer_received (GstPromise * promise, gpointer user_data)
157 struct test_webrtc *t = user_data;
158 GstElement *offeror = TEST_GET_OFFEROR (t);
159 GstElement *answerer = TEST_GET_ANSWERER (t);
160 const GstStructure *reply;
161 GstWebRTCSessionDescription *offer = NULL;
164 reply = gst_promise_get_reply (promise);
165 gst_structure_get (reply, "offer",
166 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
167 desc = gst_sdp_message_as_text (offer->sdp);
168 GST_INFO ("Created offer: %s", desc);
171 g_mutex_lock (&t->lock);
172 if (t->on_offer_created) {
173 gst_webrtc_session_description_free (offer);
174 offer = t->on_offer_created (t, offeror, promise, t->offer_data);
176 gst_promise_unref (promise);
178 g_signal_emit_by_name (offeror, "set-local-description", offer, NULL);
179 g_signal_emit_by_name (answerer, "set-remote-description", offer, NULL);
181 promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
182 g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
184 t->state = STATE_OFFER_CREATED;
185 g_cond_broadcast (&t->cond);
186 g_mutex_unlock (&t->lock);
188 gst_webrtc_session_description_free (offer);
192 _bus_watch (GstBus * bus, GstMessage * msg, struct test_webrtc *t)
194 g_mutex_lock (&t->lock);
195 switch (GST_MESSAGE_TYPE (msg)) {
196 case GST_MESSAGE_STATE_CHANGED:
197 if (GST_ELEMENT (msg->src) == t->webrtc1
198 || GST_ELEMENT (msg->src) == t->webrtc2) {
199 GstState old, new, pending;
201 gst_message_parse_state_changed (msg, &old, &new, &pending);
204 gchar *dump_name = g_strconcat ("%s-state_changed-",
205 GST_OBJECT_NAME (msg->src), gst_element_state_get_name (old), "_",
206 gst_element_state_get_name (new), NULL);
207 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
208 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
213 case GST_MESSAGE_ERROR:{
215 gchar *dbg_info = NULL;
220 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc1), NULL);
221 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
222 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
225 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc2), NULL);
226 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
227 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
231 gst_message_parse_error (msg, &err, &dbg_info);
232 GST_WARNING ("ERROR from element %s: %s\n",
233 GST_OBJECT_NAME (msg->src), err->message);
234 GST_WARNING ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
237 t->state = STATE_ERROR;
238 g_cond_broadcast (&t->cond);
241 case GST_MESSAGE_EOS:{
244 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc1), NULL);
245 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
246 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
248 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc2), NULL);
249 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
250 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
253 GST_INFO ("EOS received\n");
254 t->state = STATE_EOS;
255 g_cond_broadcast (&t->cond);
263 t->bus_message (t, bus, msg, t->bus_data);
264 g_mutex_unlock (&t->lock);
270 _on_negotiation_needed (GstElement * webrtc, struct test_webrtc *t)
272 g_mutex_lock (&t->lock);
273 if (t->on_negotiation_needed)
274 t->on_negotiation_needed (t, webrtc, t->negotiation_data);
275 if (t->state == STATE_NEW)
276 t->state = STATE_NEGOTIATION_NEEDED;
277 g_cond_broadcast (&t->cond);
278 g_mutex_unlock (&t->lock);
282 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
283 struct test_webrtc *t)
287 g_mutex_lock (&t->lock);
288 other = webrtc == t->webrtc1 ? t->webrtc2 : t->webrtc1;
290 if (t->on_ice_candidate)
291 t->on_ice_candidate (t, webrtc, mlineindex, candidate, other,
292 t->ice_candidate_data);
294 g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
295 g_mutex_unlock (&t->lock);
299 _on_pad_added (GstElement * webrtc, GstPad * new_pad, struct test_webrtc *t)
301 g_mutex_lock (&t->lock);
303 t->on_pad_added (t, webrtc, new_pad, t->pad_added_data);
304 g_mutex_unlock (&t->lock);
308 _on_data_channel (GstElement * webrtc, GObject * data_channel,
309 struct test_webrtc *t)
311 g_mutex_lock (&t->lock);
312 if (t->on_data_channel)
313 t->on_data_channel (t, webrtc, data_channel, t->data_channel_data);
314 g_mutex_unlock (&t->lock);
318 _pad_added_not_reached (struct test_webrtc *t, GstElement * element,
319 GstPad * pad, gpointer user_data)
321 g_assert_not_reached ();
325 _ice_candidate_not_reached (struct test_webrtc *t, GstElement * element,
326 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
328 g_assert_not_reached ();
332 _negotiation_not_reached (struct test_webrtc *t, GstElement * element,
335 g_assert_not_reached ();
339 _bus_no_errors (struct test_webrtc *t, GstBus * bus, GstMessage * msg,
342 switch (GST_MESSAGE_TYPE (msg)) {
343 case GST_MESSAGE_ERROR:{
344 g_assert_not_reached ();
352 static GstWebRTCSessionDescription *
353 _offer_answer_not_reached (struct test_webrtc *t, GstElement * element,
354 GstPromise * promise, gpointer user_data)
356 g_assert_not_reached ();
360 _on_data_channel_not_reached (struct test_webrtc *t, GstElement * element,
361 GObject * data_channel, gpointer user_data)
363 g_assert_not_reached ();
367 _broadcast (struct test_webrtc *t)
369 g_mutex_lock (&t->lock);
370 g_cond_broadcast (&t->cond);
371 g_mutex_unlock (&t->lock);
375 _unlock_create_thread (GMutex * lock)
377 g_mutex_unlock (lock);
378 return G_SOURCE_REMOVE;
382 _bus_thread (struct test_webrtc *t)
384 g_mutex_lock (&t->lock);
385 t->loop = g_main_loop_new (NULL, FALSE);
386 g_idle_add ((GSourceFunc) _unlock_create_thread, &t->lock);
387 g_cond_broadcast (&t->cond);
389 g_main_loop_run (t->loop);
391 g_mutex_lock (&t->lock);
392 g_main_loop_unref (t->loop);
394 g_cond_broadcast (&t->cond);
395 g_mutex_unlock (&t->lock);
401 element_added_disable_sync (GstBin * bin, GstBin * sub_bin,
402 GstElement * element, gpointer user_data)
404 GObjectClass *class = G_OBJECT_GET_CLASS (element);
405 if (g_object_class_find_property (class, "async"))
406 g_object_set (element, "async", FALSE, NULL);
407 if (g_object_class_find_property (class, "sync"))
408 g_object_set (element, "sync", FALSE, NULL);
411 static struct test_webrtc *
412 test_webrtc_new (void)
414 struct test_webrtc *ret = g_new0 (struct test_webrtc, 1);
416 ret->on_negotiation_needed = _negotiation_not_reached;
417 ret->on_ice_candidate = _ice_candidate_not_reached;
418 ret->on_pad_added = _pad_added_not_reached;
419 ret->on_offer_created = _offer_answer_not_reached;
420 ret->on_answer_created = _offer_answer_not_reached;
421 ret->on_data_channel = _on_data_channel_not_reached;
422 ret->bus_message = _bus_no_errors;
424 g_mutex_init (&ret->lock);
425 g_cond_init (&ret->cond);
427 ret->bus1 = gst_bus_new ();
428 ret->bus2 = gst_bus_new ();
429 gst_bus_add_watch (ret->bus1, (GstBusFunc) _bus_watch, ret);
430 gst_bus_add_watch (ret->bus2, (GstBusFunc) _bus_watch, ret);
431 ret->webrtc1 = gst_element_factory_make ("webrtcbin", NULL);
432 ret->webrtc2 = gst_element_factory_make ("webrtcbin", NULL);
433 fail_unless (ret->webrtc1 != NULL && ret->webrtc2 != NULL);
435 gst_element_set_bus (ret->webrtc1, ret->bus1);
436 gst_element_set_bus (ret->webrtc2, ret->bus2);
438 g_signal_connect (ret->webrtc1, "deep-element-added",
439 G_CALLBACK (element_added_disable_sync), NULL);
440 g_signal_connect (ret->webrtc2, "deep-element-added",
441 G_CALLBACK (element_added_disable_sync), NULL);
442 g_signal_connect (ret->webrtc1, "on-negotiation-needed",
443 G_CALLBACK (_on_negotiation_needed), ret);
444 g_signal_connect (ret->webrtc2, "on-negotiation-needed",
445 G_CALLBACK (_on_negotiation_needed), ret);
446 g_signal_connect (ret->webrtc1, "on-ice-candidate",
447 G_CALLBACK (_on_ice_candidate), ret);
448 g_signal_connect (ret->webrtc2, "on-ice-candidate",
449 G_CALLBACK (_on_ice_candidate), ret);
450 g_signal_connect (ret->webrtc1, "on-data-channel",
451 G_CALLBACK (_on_data_channel), ret);
452 g_signal_connect (ret->webrtc2, "on-data-channel",
453 G_CALLBACK (_on_data_channel), ret);
454 g_signal_connect (ret->webrtc1, "pad-added", G_CALLBACK (_on_pad_added), ret);
455 g_signal_connect (ret->webrtc2, "pad-added", G_CALLBACK (_on_pad_added), ret);
456 g_signal_connect_swapped (ret->webrtc1, "notify::ice-gathering-state",
457 G_CALLBACK (_broadcast), ret);
458 g_signal_connect_swapped (ret->webrtc2, "notify::ice-gathering-state",
459 G_CALLBACK (_broadcast), ret);
460 g_signal_connect_swapped (ret->webrtc1, "notify::ice-connection-state",
461 G_CALLBACK (_broadcast), ret);
462 g_signal_connect_swapped (ret->webrtc2, "notify::ice-connection-state",
463 G_CALLBACK (_broadcast), ret);
465 ret->thread = g_thread_new ("test-webrtc", (GThreadFunc) _bus_thread, ret);
467 g_mutex_lock (&ret->lock);
469 g_cond_wait (&ret->cond, &ret->lock);
470 g_mutex_unlock (&ret->lock);
476 test_webrtc_free (struct test_webrtc *t)
478 /* Otherwise while one webrtcbin is being destroyed, the other could
479 * generate a signal that calls into the destroyed webrtcbin */
480 g_signal_handlers_disconnect_by_data (t->webrtc1, t);
481 g_signal_handlers_disconnect_by_data (t->webrtc2, t);
483 g_main_loop_quit (t->loop);
484 g_mutex_lock (&t->lock);
486 g_cond_wait (&t->cond, &t->lock);
487 g_mutex_unlock (&t->lock);
489 g_thread_join (t->thread);
491 gst_bus_remove_watch (t->bus1);
492 gst_bus_remove_watch (t->bus2);
494 gst_bus_set_flushing (t->bus1, TRUE);
495 gst_bus_set_flushing (t->bus2, TRUE);
497 gst_object_unref (t->bus1);
498 gst_object_unref (t->bus2);
500 g_list_free_full (t->harnesses, (GDestroyNotify) gst_harness_teardown);
503 t->data_notify (t->user_data);
504 if (t->negotiation_notify)
505 t->negotiation_notify (t->negotiation_data);
506 if (t->ice_candidate_notify)
507 t->ice_candidate_notify (t->ice_candidate_data);
509 t->offer_notify (t->offer_data);
510 if (t->answer_notify)
511 t->answer_notify (t->answer_data);
512 if (t->pad_added_notify)
513 t->pad_added_notify (t->pad_added_data);
514 if (t->data_channel_notify)
515 t->data_channel_notify (t->data_channel_data);
517 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
518 gst_element_set_state (t->webrtc1, GST_STATE_NULL));
519 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
520 gst_element_set_state (t->webrtc2, GST_STATE_NULL));
522 gst_object_unref (t->webrtc1);
523 gst_object_unref (t->webrtc2);
525 g_mutex_clear (&t->lock);
526 g_cond_clear (&t->cond);
532 test_webrtc_create_offer (struct test_webrtc *t, GstElement * webrtc)
536 t->offerror = webrtc == t->webrtc1 ? 1 : 2;
537 promise = gst_promise_new_with_change_func (_on_offer_received, t, NULL);
538 g_signal_emit_by_name (webrtc, "create-offer", NULL, promise);
542 test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
544 g_mutex_lock (&t->lock);
545 while (((1 << t->state) & state) == 0) {
546 GST_INFO ("test state 0x%x, current 0x%x", state, (1 << t->state));
547 g_cond_wait (&t->cond, &t->lock);
549 GST_INFO ("have test state 0x%x, current 0x%x", state, 1 << t->state);
550 g_mutex_unlock (&t->lock);
554 test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t)
556 TestState states = 0;
557 states |= (1 << STATE_ANSWER_CREATED);
558 states |= (1 << STATE_EOS);
559 states |= (1 << STATE_ERROR);
560 test_webrtc_wait_for_state_mask (t, states);
564 test_webrtc_signal_state_unlocked (struct test_webrtc *t, TestState state)
567 g_cond_broadcast (&t->cond);
571 test_webrtc_signal_state (struct test_webrtc *t, TestState state)
573 g_mutex_lock (&t->lock);
574 test_webrtc_signal_state_unlocked (t, state);
575 g_mutex_unlock (&t->lock);
580 test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
582 GstWebRTCICEGatheringState ice_state1, ice_state2;
583 g_mutex_lock (&t->lock);
584 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
585 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
586 while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE &&
587 ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
588 g_cond_wait (&t->cond, &t->lock);
589 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
590 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
592 g_mutex_unlock (&t->lock);
596 test_webrtc_wait_for_ice_connection (struct test_webrtc *t,
597 GstWebRTCICEConnectionState states)
599 GstWebRTCICEConnectionState ice_state1, ice_state2, current;
600 g_mutex_lock (&t->lock);
601 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
602 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
603 current = (1 << ice_state1) | (1 << ice_state2);
604 while ((current & states) == 0 || (current & ~states)) {
605 g_cond_wait (&t->cond, &t->lock);
606 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
607 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
608 current = (1 << ice_state1) | (1 << ice_state2);
610 g_mutex_unlock (&t->lock);
614 _pad_added_fakesink (struct test_webrtc *t, GstElement * element,
615 GstPad * pad, gpointer user_data)
619 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
622 h = gst_harness_new_with_element (element, NULL, "src_%u");
623 gst_harness_add_sink_parse (h, "fakesink async=false sync=false");
625 t->harnesses = g_list_prepend (t->harnesses, h);
629 _count_num_sdp_media (struct test_webrtc *t, GstElement * element,
630 GstWebRTCSessionDescription * desc, gpointer user_data)
632 guint expected = GPOINTER_TO_UINT (user_data);
634 fail_unless_equals_int (gst_sdp_message_medias_len (desc->sdp), expected);
637 typedef void (*ValidateSDPFunc) (struct test_webrtc * t, GstElement * element,
638 GstWebRTCSessionDescription * desc, gpointer user_data);
643 ValidateSDPFunc validate;
645 struct validate_sdp *next;
648 static GstWebRTCSessionDescription *
649 _check_validate_sdp (struct test_webrtc *t, GstElement * element,
650 GstPromise * promise, gpointer user_data)
652 struct validate_sdp *validate = user_data;
653 GstWebRTCSessionDescription *offer = NULL;
654 const GstStructure *reply;
657 field = t->offerror == 1 && t->webrtc1 == element ? "offer" : "answer";
659 reply = gst_promise_get_reply (promise);
660 gst_structure_get (reply, field,
661 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
664 validate->validate (t, element, offer, validate->user_data);
665 validate = validate->next;
672 test_validate_sdp (struct test_webrtc *t, struct validate_sdp *offer,
673 struct validate_sdp *answer)
676 t->offer_data = offer;
677 t->on_offer_created = _check_validate_sdp;
679 t->offer_data = NULL;
680 t->on_offer_created = NULL;
683 t->answer_data = answer;
684 t->on_answer_created = _check_validate_sdp;
686 t->answer_data = NULL;
687 t->on_answer_created = NULL;
690 fail_if (gst_element_set_state (t->webrtc1,
691 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
692 fail_if (gst_element_set_state (t->webrtc2,
693 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
695 test_webrtc_create_offer (t, t->webrtc1);
697 test_webrtc_wait_for_answer_error_eos (t);
698 fail_unless (t->state == STATE_ANSWER_CREATED);
701 GST_START_TEST (test_sdp_no_media)
703 struct test_webrtc *t = test_webrtc_new ();
704 struct validate_sdp offer =
705 { _count_num_sdp_media, GUINT_TO_POINTER (0), NULL };
706 struct validate_sdp answer =
707 { _count_num_sdp_media, GUINT_TO_POINTER (0), NULL };
709 /* check that a no stream connection creates 0 media sections */
711 t->on_negotiation_needed = NULL;
712 test_validate_sdp (t, &offer, &answer);
714 test_webrtc_free (t);
720 add_fake_audio_src_harness (GstHarness * h, gint pt)
722 GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
723 GstStructure *s = gst_caps_get_structure (caps, 0);
724 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
725 gst_harness_set_src_caps (h, caps);
726 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
730 add_fake_video_src_harness (GstHarness * h, gint pt)
732 GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
733 GstStructure *s = gst_caps_get_structure (caps, 0);
734 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
735 gst_harness_set_src_caps (h, caps);
736 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
739 static struct test_webrtc *
740 create_audio_test (void)
742 struct test_webrtc *t = test_webrtc_new ();
745 t->on_negotiation_needed = NULL;
746 t->on_ice_candidate = NULL;
747 t->on_pad_added = _pad_added_fakesink;
749 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
750 add_fake_audio_src_harness (h, 96);
751 t->harnesses = g_list_prepend (t->harnesses, h);
756 GST_START_TEST (test_audio)
758 struct test_webrtc *t = create_audio_test ();
759 struct validate_sdp offer =
760 { _count_num_sdp_media, GUINT_TO_POINTER (1), NULL };
761 struct validate_sdp answer =
762 { _count_num_sdp_media, GUINT_TO_POINTER (1), NULL };
764 /* check that a single stream connection creates the associated number
765 * of media sections */
767 test_validate_sdp (t, &offer, &answer);
768 test_webrtc_free (t);
773 static struct test_webrtc *
774 create_audio_video_test (void)
776 struct test_webrtc *t = create_audio_test ();
779 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
780 add_fake_video_src_harness (h, 97);
781 t->harnesses = g_list_prepend (t->harnesses, h);
786 GST_START_TEST (test_audio_video)
788 struct test_webrtc *t = create_audio_video_test ();
789 struct validate_sdp offer =
790 { _count_num_sdp_media, GUINT_TO_POINTER (2), NULL };
791 struct validate_sdp answer =
792 { _count_num_sdp_media, GUINT_TO_POINTER (2), NULL };
794 /* check that a dual stream connection creates the associated number
795 * of media sections */
797 test_validate_sdp (t, &offer, &answer);
798 test_webrtc_free (t);
804 on_sdp_media_direction (struct test_webrtc *t, GstElement * element,
805 GstWebRTCSessionDescription * desc, gpointer user_data)
807 gchar **expected_directions = user_data;
810 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
811 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
813 if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0
814 || g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) {
815 gboolean have_direction = FALSE;
818 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
819 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
821 if (g_strcmp0 (attr->key, "inactive") == 0) {
822 fail_unless (have_direction == FALSE,
823 "duplicate/multiple directions for media %u", j);
824 have_direction = TRUE;
825 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
826 } else if (g_strcmp0 (attr->key, "sendonly") == 0) {
827 fail_unless (have_direction == FALSE,
828 "duplicate/multiple directions for media %u", j);
829 have_direction = TRUE;
830 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
831 } else if (g_strcmp0 (attr->key, "recvonly") == 0) {
832 fail_unless (have_direction == FALSE,
833 "duplicate/multiple directions for media %u", j);
834 have_direction = TRUE;
835 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
836 } else if (g_strcmp0 (attr->key, "sendrecv") == 0) {
837 fail_unless (have_direction == FALSE,
838 "duplicate/multiple directions for media %u", j);
839 have_direction = TRUE;
840 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
843 fail_unless (have_direction, "no direction attribute in media %u", j);
848 GST_START_TEST (test_media_direction)
850 struct test_webrtc *t = create_audio_video_test ();
851 const gchar *expected_offer[] = { "sendrecv", "sendrecv" };
852 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
853 struct validate_sdp offer_direction =
854 { on_sdp_media_direction, expected_offer, NULL };
855 struct validate_sdp offer =
856 { _count_num_sdp_media, GUINT_TO_POINTER (2), &offer_direction };
857 struct validate_sdp answer_direction =
858 { on_sdp_media_direction, expected_answer, NULL };
859 struct validate_sdp answer =
860 { _count_num_sdp_media, GUINT_TO_POINTER (2), &answer_direction };
863 /* check the default media directions for transceivers */
865 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
866 add_fake_audio_src_harness (h, 96);
867 t->harnesses = g_list_prepend (t->harnesses, h);
869 test_validate_sdp (t, &offer, &answer);
870 test_webrtc_free (t);
876 on_sdp_media_payload_types (struct test_webrtc *t, GstElement * element,
877 GstWebRTCSessionDescription * desc, gpointer user_data)
879 const GstSDPMedia *vmedia;
882 vmedia = gst_sdp_message_get_media (desc->sdp, 1);
884 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
885 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
887 if (!g_strcmp0 (attr->key, "rtpmap")) {
888 if (g_str_has_prefix (attr->value, "97")) {
889 fail_unless_equals_string (attr->value, "97 VP8/90000");
890 } else if (g_str_has_prefix (attr->value, "96")) {
891 fail_unless_equals_string (attr->value, "96 red/90000");
892 } else if (g_str_has_prefix (attr->value, "98")) {
893 fail_unless_equals_string (attr->value, "98 ulpfec/90000");
894 } else if (g_str_has_prefix (attr->value, "99")) {
895 fail_unless_equals_string (attr->value, "99 rtx/90000");
896 } else if (g_str_has_prefix (attr->value, "100")) {
897 fail_unless_equals_string (attr->value, "100 rtx/90000");
903 /* In this test we verify that webrtcbin will pick available payload
904 * types when it needs to, in that example for RTX and FEC */
905 GST_START_TEST (test_payload_types)
907 struct test_webrtc *t = create_audio_video_test ();
908 struct validate_sdp payloads = { on_sdp_media_payload_types, NULL, NULL };
909 struct validate_sdp offer =
910 { _count_num_sdp_media, GUINT_TO_POINTER (2), &payloads };
911 GstWebRTCRTPTransceiver *trans;
912 GArray *transceivers;
914 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
915 fail_unless_equals_int (transceivers->len, 2);
916 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
917 g_object_set (trans, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, "do-nack", TRUE,
919 g_array_unref (transceivers);
921 /* We don't really care about the answer here */
922 test_validate_sdp (t, &offer, NULL);
923 test_webrtc_free (t);
929 on_sdp_media_setup (struct test_webrtc *t, GstElement * element,
930 GstWebRTCSessionDescription * desc, gpointer user_data)
932 gchar **expected_setup = user_data;
935 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
936 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
937 gboolean have_setup = FALSE;
940 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
941 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
943 if (g_strcmp0 (attr->key, "setup") == 0) {
944 fail_unless (have_setup == FALSE,
945 "duplicate/multiple setup for media %u", j);
947 fail_unless (g_strcmp0 (attr->value, expected_setup[i]) == 0);
950 fail_unless (have_setup, "no setup attribute in media %u", j);
954 GST_START_TEST (test_media_setup)
956 struct test_webrtc *t = create_audio_test ();
957 const gchar *expected_offer[] = { "actpass" };
958 const gchar *expected_answer[] = { "active" };
959 struct validate_sdp offer = { on_sdp_media_setup, expected_offer, NULL };
960 struct validate_sdp answer = { on_sdp_media_setup, expected_answer, NULL };
962 /* check the default dtls setup negotiation values */
963 test_validate_sdp (t, &offer, &answer);
964 test_webrtc_free (t);
969 GST_START_TEST (test_no_nice_elements_request_pad)
971 struct test_webrtc *t = test_webrtc_new ();
972 GstPluginFeature *nicesrc, *nicesink;
973 GstRegistry *registry;
976 /* check that the absence of libnice elements posts an error on the bus
977 * when requesting a pad */
979 registry = gst_registry_get ();
980 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
981 nicesink = gst_registry_lookup_feature (registry, "nicesink");
984 gst_registry_remove_feature (registry, nicesrc);
986 gst_registry_remove_feature (registry, nicesink);
988 t->bus_message = NULL;
990 pad = gst_element_get_request_pad (t->webrtc1, "sink_0");
991 fail_unless (pad == NULL);
993 test_webrtc_wait_for_answer_error_eos (t);
994 fail_unless_equals_int (STATE_ERROR, t->state);
995 test_webrtc_free (t);
998 gst_registry_add_feature (registry, nicesrc);
1000 gst_registry_add_feature (registry, nicesink);
1005 GST_START_TEST (test_no_nice_elements_state_change)
1007 struct test_webrtc *t = test_webrtc_new ();
1008 GstPluginFeature *nicesrc, *nicesink;
1009 GstRegistry *registry;
1011 /* check that the absence of libnice elements posts an error on the bus */
1013 registry = gst_registry_get ();
1014 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1015 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1018 gst_registry_remove_feature (registry, nicesrc);
1020 gst_registry_remove_feature (registry, nicesink);
1022 t->bus_message = NULL;
1023 gst_element_set_state (t->webrtc1, GST_STATE_READY);
1025 test_webrtc_wait_for_answer_error_eos (t);
1026 fail_unless_equals_int (STATE_ERROR, t->state);
1027 test_webrtc_free (t);
1030 gst_registry_add_feature (registry, nicesrc);
1032 gst_registry_add_feature (registry, nicesink);
1038 validate_rtc_stats (const GstStructure * s)
1040 GstWebRTCStatsType type = 0;
1044 fail_unless (gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type,
1046 fail_unless (gst_structure_get (s, "id", G_TYPE_STRING, &id, NULL));
1047 fail_unless (gst_structure_get (s, "timestamp", G_TYPE_DOUBLE, &ts, NULL));
1048 fail_unless (type != 0);
1049 fail_unless (ts != 0.);
1050 fail_unless (id != NULL);
1056 validate_codec_stats (const GstStructure * s)
1058 guint pt = 0, clock_rate = 0;
1060 fail_unless (gst_structure_get (s, "payload-type", G_TYPE_UINT, &pt, NULL));
1061 fail_unless (gst_structure_get (s, "clock-rate", G_TYPE_UINT, &clock_rate,
1063 fail_unless (pt >= 0 && pt <= 127);
1064 fail_unless (clock_rate >= 0);
1068 validate_rtc_stream_stats (const GstStructure * s, const GstStructure * stats)
1070 gchar *codec_id, *transport_id;
1071 GstStructure *codec, *transport;
1073 fail_unless (gst_structure_get (s, "codec-id", G_TYPE_STRING, &codec_id,
1075 fail_unless (gst_structure_get (s, "transport-id", G_TYPE_STRING,
1076 &transport_id, NULL));
1078 fail_unless (gst_structure_get (stats, codec_id, GST_TYPE_STRUCTURE, &codec,
1080 fail_unless (gst_structure_get (stats, transport_id, GST_TYPE_STRUCTURE,
1083 fail_unless (codec != NULL);
1084 fail_unless (transport != NULL);
1086 gst_structure_free (transport);
1087 gst_structure_free (codec);
1090 g_free (transport_id);
1094 validate_inbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1096 guint ssrc, fir, pli, nack;
1098 guint64 packets_received, bytes_received;
1101 GstStructure *remote;
1103 validate_rtc_stream_stats (s, stats);
1105 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1106 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1107 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1108 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1109 fail_unless (gst_structure_get (s, "packets-received", G_TYPE_UINT64,
1110 &packets_received, NULL));
1111 fail_unless (gst_structure_get (s, "bytes-received", G_TYPE_UINT64,
1112 &bytes_received, NULL));
1113 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1114 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1116 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1118 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1120 fail_unless (remote != NULL);
1122 gst_structure_free (remote);
1127 validate_remote_inbound_rtp_stats (const GstStructure * s,
1128 const GstStructure * stats)
1134 GstStructure *local;
1136 validate_rtc_stream_stats (s, stats);
1138 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1139 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1140 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1142 fail_unless (gst_structure_get (s, "round-trip-time", G_TYPE_DOUBLE, &rtt,
1144 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1146 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1148 fail_unless (local != NULL);
1150 gst_structure_free (local);
1155 validate_outbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1157 guint ssrc, fir, pli, nack;
1158 guint64 packets_sent, bytes_sent;
1160 GstStructure *remote;
1162 validate_rtc_stream_stats (s, stats);
1164 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1165 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1166 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1167 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1168 fail_unless (gst_structure_get (s, "packets-sent", G_TYPE_UINT64,
1169 &packets_sent, NULL));
1170 fail_unless (gst_structure_get (s, "bytes-sent", G_TYPE_UINT64, &bytes_sent,
1172 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1174 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1176 fail_unless (remote != NULL);
1178 gst_structure_free (remote);
1183 validate_remote_outbound_rtp_stats (const GstStructure * s,
1184 const GstStructure * stats)
1188 GstStructure *local;
1190 validate_rtc_stream_stats (s, stats);
1192 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1193 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1195 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1197 fail_unless (local != NULL);
1199 gst_structure_free (local);
1204 validate_stats_foreach (GQuark field_id, const GValue * value,
1205 const GstStructure * stats)
1207 const gchar *field = g_quark_to_string (field_id);
1208 GstWebRTCStatsType type;
1209 const GstStructure *s;
1211 fail_unless (GST_VALUE_HOLDS_STRUCTURE (value));
1213 s = gst_value_get_structure (value);
1215 GST_INFO ("validating field %s %" GST_PTR_FORMAT, field, s);
1217 validate_rtc_stats (s);
1218 gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type, NULL);
1219 if (type == GST_WEBRTC_STATS_CODEC) {
1220 validate_codec_stats (s);
1221 } else if (type == GST_WEBRTC_STATS_INBOUND_RTP) {
1222 validate_inbound_rtp_stats (s, stats);
1223 } else if (type == GST_WEBRTC_STATS_OUTBOUND_RTP) {
1224 validate_outbound_rtp_stats (s, stats);
1225 } else if (type == GST_WEBRTC_STATS_REMOTE_INBOUND_RTP) {
1226 validate_remote_inbound_rtp_stats (s, stats);
1227 } else if (type == GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP) {
1228 validate_remote_outbound_rtp_stats (s, stats);
1229 } else if (type == GST_WEBRTC_STATS_CSRC) {
1230 } else if (type == GST_WEBRTC_STATS_PEER_CONNECTION) {
1231 } else if (type == GST_WEBRTC_STATS_DATA_CHANNEL) {
1232 } else if (type == GST_WEBRTC_STATS_STREAM) {
1233 } else if (type == GST_WEBRTC_STATS_TRANSPORT) {
1234 } else if (type == GST_WEBRTC_STATS_CANDIDATE_PAIR) {
1235 } else if (type == GST_WEBRTC_STATS_LOCAL_CANDIDATE) {
1236 } else if (type == GST_WEBRTC_STATS_REMOTE_CANDIDATE) {
1237 } else if (type == GST_WEBRTC_STATS_CERTIFICATE) {
1239 g_assert_not_reached ();
1246 validate_stats (const GstStructure * stats)
1248 gst_structure_foreach (stats,
1249 (GstStructureForeachFunc) validate_stats_foreach, (gpointer) stats);
1253 _on_stats (GstPromise * promise, gpointer user_data)
1255 struct test_webrtc *t = user_data;
1256 const GstStructure *reply = gst_promise_get_reply (promise);
1259 validate_stats (reply);
1260 i = GPOINTER_TO_INT (t->user_data);
1262 t->user_data = GINT_TO_POINTER (i);
1264 test_webrtc_signal_state (t, STATE_CUSTOM);
1266 gst_promise_unref (promise);
1269 GST_START_TEST (test_session_stats)
1271 struct test_webrtc *t = test_webrtc_new ();
1274 /* test that the stats generated without any streams are sane */
1275 t->on_negotiation_needed = NULL;
1276 test_validate_sdp (t, NULL, NULL);
1278 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1279 g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p);
1280 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1281 g_signal_emit_by_name (t->webrtc2, "get-stats", NULL, p);
1283 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1285 test_webrtc_free (t);
1290 GST_START_TEST (test_add_transceiver)
1292 struct test_webrtc *t = test_webrtc_new ();
1293 GstWebRTCRTPTransceiverDirection direction;
1294 GstWebRTCRTPTransceiver *trans;
1296 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
1297 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, NULL,
1299 fail_unless (trans != NULL);
1300 fail_unless_equals_int (direction, trans->direction);
1302 gst_object_unref (trans);
1304 test_webrtc_free (t);
1309 GST_START_TEST (test_get_transceivers)
1311 struct test_webrtc *t = create_audio_test ();
1312 GstWebRTCRTPTransceiver *trans;
1313 GArray *transceivers;
1315 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1316 fail_unless (transceivers != NULL);
1317 fail_unless_equals_int (1, transceivers->len);
1319 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
1320 fail_unless (trans != NULL);
1322 g_array_unref (transceivers);
1324 test_webrtc_free (t);
1329 GST_START_TEST (test_add_recvonly_transceiver)
1331 struct test_webrtc *t = test_webrtc_new ();
1332 GstWebRTCRTPTransceiverDirection direction;
1333 GstWebRTCRTPTransceiver *trans;
1334 const gchar *expected_offer[] = { "recvonly" };
1335 const gchar *expected_answer[] = { "sendonly" };
1336 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
1337 struct validate_sdp answer =
1338 { on_sdp_media_direction, expected_answer, NULL };
1342 /* add a transceiver that will only receive an opus stream and check that
1343 * the created offer is marked as recvonly */
1344 t->on_negotiation_needed = NULL;
1345 t->on_ice_candidate = NULL;
1346 t->on_pad_added = _pad_added_fakesink;
1348 /* setup recvonly transceiver */
1349 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1350 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1351 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1353 gst_caps_unref (caps);
1354 fail_unless (trans != NULL);
1355 gst_object_unref (trans);
1357 /* setup sendonly peer */
1358 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1359 add_fake_audio_src_harness (h, 96);
1360 t->harnesses = g_list_prepend (t->harnesses, h);
1361 test_validate_sdp (t, &offer, &answer);
1363 test_webrtc_free (t);
1368 GST_START_TEST (test_recvonly_sendonly)
1370 struct test_webrtc *t = test_webrtc_new ();
1371 GstWebRTCRTPTransceiverDirection direction;
1372 GstWebRTCRTPTransceiver *trans;
1373 const gchar *expected_offer[] = { "recvonly", "sendonly" };
1374 const gchar *expected_answer[] = { "sendonly", "recvonly" };
1375 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
1376 struct validate_sdp answer =
1377 { on_sdp_media_direction, expected_answer, NULL };
1380 GArray *transceivers;
1382 /* add a transceiver that will only receive an opus stream and check that
1383 * the created offer is marked as recvonly */
1384 t->on_negotiation_needed = NULL;
1385 t->on_ice_candidate = NULL;
1386 t->on_pad_added = _pad_added_fakesink;
1388 /* setup recvonly transceiver */
1389 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1390 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1391 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1393 gst_caps_unref (caps);
1394 fail_unless (trans != NULL);
1395 gst_object_unref (trans);
1397 /* setup sendonly stream */
1398 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1399 add_fake_audio_src_harness (h, 96);
1400 t->harnesses = g_list_prepend (t->harnesses, h);
1401 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1402 fail_unless (transceivers != NULL);
1403 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1404 trans->direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
1406 g_array_unref (transceivers);
1408 /* setup sendonly peer */
1409 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1410 add_fake_audio_src_harness (h, 96);
1411 t->harnesses = g_list_prepend (t->harnesses, h);
1413 test_validate_sdp (t, &offer, &answer);
1415 test_webrtc_free (t);
1421 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1422 GstWebRTCSessionDescription * desc, gpointer user_data)
1424 gboolean have_data_channel = FALSE;
1427 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1428 if (_message_media_is_datachannel (desc->sdp, i)) {
1429 /* there should only be one data channel m= section */
1430 fail_unless_equals_int (FALSE, have_data_channel);
1431 have_data_channel = TRUE;
1435 fail_unless_equals_int (TRUE, have_data_channel);
1439 on_channel_error_not_reached (GObject * channel, GError * error,
1442 g_assert_not_reached ();
1445 GST_START_TEST (test_data_channel_create)
1447 struct test_webrtc *t = test_webrtc_new ();
1448 GObject *channel = NULL;
1449 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1450 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1453 t->on_negotiation_needed = NULL;
1454 t->on_ice_candidate = NULL;
1456 fail_if (gst_element_set_state (t->webrtc1,
1457 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1458 fail_if (gst_element_set_state (t->webrtc2,
1459 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1461 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1463 g_assert_nonnull (channel);
1464 g_object_get (channel, "label", &label, NULL);
1465 g_assert_cmpstr (label, ==, "label");
1466 g_signal_connect (channel, "on-error",
1467 G_CALLBACK (on_channel_error_not_reached), NULL);
1469 test_validate_sdp (t, &offer, &answer);
1471 g_object_unref (channel);
1473 test_webrtc_free (t);
1479 have_data_channel (struct test_webrtc *t, GstElement * element,
1480 GObject * our, gpointer user_data)
1482 GObject *other = user_data;
1483 gchar *our_label, *other_label;
1485 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1488 g_object_get (our, "label", &our_label, NULL);
1489 g_object_get (other, "label", &other_label, NULL);
1491 g_assert_cmpstr (our_label, ==, other_label);
1494 g_free (other_label);
1496 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1499 GST_START_TEST (test_data_channel_remote_notify)
1501 struct test_webrtc *t = test_webrtc_new ();
1502 GObject *channel = NULL;
1503 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1504 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1506 t->on_negotiation_needed = NULL;
1507 t->offer_data = &offer;
1508 t->on_offer_created = _check_validate_sdp;
1509 t->answer_data = &answer;
1510 t->on_answer_created = _check_validate_sdp;
1511 t->on_ice_candidate = NULL;
1512 t->on_data_channel = have_data_channel;
1514 fail_if (gst_element_set_state (t->webrtc1,
1515 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1516 fail_if (gst_element_set_state (t->webrtc2,
1517 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1519 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1521 g_assert_nonnull (channel);
1522 t->data_channel_data = channel;
1523 g_signal_connect (channel, "on-error",
1524 G_CALLBACK (on_channel_error_not_reached), NULL);
1526 fail_if (gst_element_set_state (t->webrtc1,
1527 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1528 fail_if (gst_element_set_state (t->webrtc2,
1529 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1531 test_webrtc_create_offer (t, t->webrtc1);
1533 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1535 g_object_unref (channel);
1536 test_webrtc_free (t);
1541 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1544 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1546 gchar *expected = g_object_steal_data (channel, "expected");
1547 g_assert_cmpstr (expected, ==, str);
1550 test_webrtc_signal_state (t, STATE_CUSTOM);
1554 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1555 GObject * our, gpointer user_data)
1557 GObject *other = user_data;
1558 GstWebRTCDataChannelState state;
1560 g_object_get (our, "ready-state", &state, NULL);
1561 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1562 g_object_get (other, "ready-state", &state, NULL);
1563 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1565 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1566 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1569 g_signal_connect (other, "on-error",
1570 G_CALLBACK (on_channel_error_not_reached), NULL);
1571 g_signal_emit_by_name (other, "send-string", test_string);
1574 GST_START_TEST (test_data_channel_transfer_string)
1576 struct test_webrtc *t = test_webrtc_new ();
1577 GObject *channel = NULL;
1578 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1579 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1581 t->on_negotiation_needed = NULL;
1582 t->offer_data = &offer;
1583 t->on_offer_created = _check_validate_sdp;
1584 t->answer_data = &answer;
1585 t->on_answer_created = _check_validate_sdp;
1586 t->on_ice_candidate = NULL;
1587 t->on_data_channel = have_data_channel_transfer_string;
1589 fail_if (gst_element_set_state (t->webrtc1,
1590 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1591 fail_if (gst_element_set_state (t->webrtc2,
1592 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1594 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1596 g_assert_nonnull (channel);
1597 t->data_channel_data = channel;
1598 g_signal_connect (channel, "on-error",
1599 G_CALLBACK (on_channel_error_not_reached), NULL);
1601 fail_if (gst_element_set_state (t->webrtc1,
1602 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1603 fail_if (gst_element_set_state (t->webrtc2,
1604 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1606 test_webrtc_create_offer (t, t->webrtc1);
1608 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1610 g_object_unref (channel);
1611 test_webrtc_free (t);
1616 #define g_assert_cmpbytes(b1, b2) \
1619 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1620 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1621 g_assert_cmpmem (d1, l1, d2, l2); \
1625 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1627 GBytes *expected = g_object_steal_data (channel, "expected");
1628 g_assert_cmpbytes (data, expected);
1629 g_bytes_unref (expected);
1631 test_webrtc_signal_state (t, STATE_CUSTOM);
1635 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1636 GObject * our, gpointer user_data)
1638 GObject *other = user_data;
1639 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1640 GstWebRTCDataChannelState state;
1642 g_object_get (our, "ready-state", &state, NULL);
1643 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1644 g_object_get (other, "ready-state", &state, NULL);
1645 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1647 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1648 (GDestroyNotify) g_bytes_unref);
1649 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1651 g_signal_connect (other, "on-error",
1652 G_CALLBACK (on_channel_error_not_reached), NULL);
1653 g_signal_emit_by_name (other, "send-data", data);
1656 GST_START_TEST (test_data_channel_transfer_data)
1658 struct test_webrtc *t = test_webrtc_new ();
1659 GObject *channel = NULL;
1660 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1661 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1663 t->on_negotiation_needed = NULL;
1664 t->offer_data = &offer;
1665 t->on_offer_created = _check_validate_sdp;
1666 t->answer_data = &answer;
1667 t->on_answer_created = _check_validate_sdp;
1668 t->on_ice_candidate = NULL;
1669 t->on_data_channel = have_data_channel_transfer_data;
1671 fail_if (gst_element_set_state (t->webrtc1,
1672 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1673 fail_if (gst_element_set_state (t->webrtc2,
1674 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1676 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1678 g_assert_nonnull (channel);
1679 t->data_channel_data = channel;
1680 g_signal_connect (channel, "on-error",
1681 G_CALLBACK (on_channel_error_not_reached), NULL);
1683 fail_if (gst_element_set_state (t->webrtc1,
1684 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1685 fail_if (gst_element_set_state (t->webrtc2,
1686 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1688 test_webrtc_create_offer (t, t->webrtc1);
1690 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1692 g_object_unref (channel);
1693 test_webrtc_free (t);
1699 have_data_channel_create_data_channel (struct test_webrtc *t,
1700 GstElement * element, GObject * our, gpointer user_data)
1704 t->on_data_channel = have_data_channel_transfer_string;
1706 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1708 g_assert_nonnull (another);
1709 t->data_channel_data = another;
1710 g_signal_connect (another, "on-error",
1711 G_CALLBACK (on_channel_error_not_reached), NULL);
1714 GST_START_TEST (test_data_channel_create_after_negotiate)
1716 struct test_webrtc *t = test_webrtc_new ();
1717 GObject *channel = NULL;
1718 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1719 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1721 t->on_negotiation_needed = NULL;
1722 t->offer_data = &offer;
1723 t->on_offer_created = _check_validate_sdp;
1724 t->answer_data = &answer;
1725 t->on_answer_created = _check_validate_sdp;
1726 t->on_ice_candidate = NULL;
1727 t->on_data_channel = have_data_channel_create_data_channel;
1729 fail_if (gst_element_set_state (t->webrtc1,
1730 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1731 fail_if (gst_element_set_state (t->webrtc2,
1732 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1734 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
1736 g_assert_nonnull (channel);
1737 t->data_channel_data = channel;
1738 g_signal_connect (channel, "on-error",
1739 G_CALLBACK (on_channel_error_not_reached), NULL);
1741 fail_if (gst_element_set_state (t->webrtc1,
1742 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1743 fail_if (gst_element_set_state (t->webrtc2,
1744 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1746 test_webrtc_create_offer (t, t->webrtc1);
1748 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1750 g_object_unref (channel);
1751 test_webrtc_free (t);
1757 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
1759 test_webrtc_signal_state (t, STATE_CUSTOM);
1763 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
1764 GstElement * element, GObject * our, gpointer user_data)
1766 g_signal_connect (our, "on-buffered-amount-low",
1767 G_CALLBACK (on_buffered_amount_low_emitted), t);
1768 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
1770 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1772 g_signal_emit_by_name (our, "send-string", "DATA");
1775 GST_START_TEST (test_data_channel_low_threshold)
1777 struct test_webrtc *t = test_webrtc_new ();
1778 GObject *channel = NULL;
1779 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1780 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1782 t->on_negotiation_needed = NULL;
1783 t->offer_data = &offer;
1784 t->on_offer_created = _check_validate_sdp;
1785 t->answer_data = &answer;
1786 t->on_answer_created = _check_validate_sdp;
1787 t->on_ice_candidate = NULL;
1788 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
1790 fail_if (gst_element_set_state (t->webrtc1,
1791 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1792 fail_if (gst_element_set_state (t->webrtc2,
1793 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1795 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1797 g_assert_nonnull (channel);
1798 t->data_channel_data = channel;
1799 g_signal_connect (channel, "on-error",
1800 G_CALLBACK (on_channel_error_not_reached), NULL);
1802 fail_if (gst_element_set_state (t->webrtc1,
1803 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1804 fail_if (gst_element_set_state (t->webrtc2,
1805 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1807 test_webrtc_create_offer (t, t->webrtc1);
1809 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1811 g_object_unref (channel);
1812 test_webrtc_free (t);
1818 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
1820 g_assert_nonnull (error);
1822 test_webrtc_signal_state (t, STATE_CUSTOM);
1826 have_data_channel_transfer_large_data (struct test_webrtc *t,
1827 GstElement * element, GObject * our, gpointer user_data)
1829 GObject *other = user_data;
1830 const gsize size = 1024 * 1024;
1831 guint8 *random_data = g_new (guint8, size);
1835 for (i = 0; i < size; i++)
1836 random_data[i] = (guint8) (i & 0xff);
1838 data = g_bytes_new_static (random_data, size);
1840 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1841 (GDestroyNotify) g_bytes_unref);
1842 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1844 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
1845 g_signal_emit_by_name (other, "send-data", data);
1848 GST_START_TEST (test_data_channel_max_message_size)
1850 struct test_webrtc *t = test_webrtc_new ();
1851 GObject *channel = NULL;
1852 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1853 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1855 t->on_negotiation_needed = NULL;
1856 t->offer_data = &offer;
1857 t->on_offer_created = _check_validate_sdp;
1858 t->answer_data = &answer;
1859 t->on_answer_created = _check_validate_sdp;
1860 t->on_ice_candidate = NULL;
1861 t->on_data_channel = have_data_channel_transfer_large_data;
1863 fail_if (gst_element_set_state (t->webrtc1,
1864 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1865 fail_if (gst_element_set_state (t->webrtc2,
1866 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1868 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1870 g_assert_nonnull (channel);
1871 t->data_channel_data = channel;
1873 fail_if (gst_element_set_state (t->webrtc1,
1874 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1875 fail_if (gst_element_set_state (t->webrtc2,
1876 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1878 test_webrtc_create_offer (t, t->webrtc1);
1880 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1882 g_object_unref (channel);
1883 test_webrtc_free (t);
1889 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
1890 struct test_webrtc *t)
1892 gint *n_ready = t->data_channel_data;
1893 GstWebRTCDataChannelState ready_state;
1895 g_object_get (channel, "ready-state", &ready_state, NULL);
1897 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
1898 if (++(*n_ready) >= 2)
1899 test_webrtc_signal_state (t, STATE_CUSTOM);
1903 GST_START_TEST (test_data_channel_pre_negotiated)
1905 struct test_webrtc *t = test_webrtc_new ();
1906 GObject *channel1 = NULL, *channel2 = NULL;
1907 struct validate_sdp offer = { on_sdp_has_datachannel, NULL, NULL };
1908 struct validate_sdp answer = { on_sdp_has_datachannel, NULL, NULL };
1912 t->on_negotiation_needed = NULL;
1913 t->offer_data = &offer;
1914 t->on_offer_created = _check_validate_sdp;
1915 t->answer_data = &answer;
1916 t->on_answer_created = _check_validate_sdp;
1917 t->on_ice_candidate = NULL;
1919 fail_if (gst_element_set_state (t->webrtc1,
1920 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1921 fail_if (gst_element_set_state (t->webrtc2,
1922 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1924 s = gst_structure_new ("application/data-channel", "negotiated",
1925 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
1927 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
1929 g_assert_nonnull (channel1);
1930 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
1932 g_assert_nonnull (channel2);
1934 fail_if (gst_element_set_state (t->webrtc1,
1935 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1936 fail_if (gst_element_set_state (t->webrtc2,
1937 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1939 test_webrtc_create_offer (t, t->webrtc1);
1940 test_webrtc_wait_for_answer_error_eos (t);
1941 fail_unless (t->state == STATE_ANSWER_CREATED);
1943 t->data_channel_data = &n_ready;
1945 g_signal_connect (channel1, "notify::ready-state",
1946 G_CALLBACK (_on_ready_state_notify), t);
1947 g_signal_connect (channel2, "notify::ready-state",
1948 G_CALLBACK (_on_ready_state_notify), t);
1950 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1951 test_webrtc_signal_state (t, STATE_NEW);
1953 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
1955 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1957 g_object_unref (channel1);
1958 g_object_unref (channel2);
1959 gst_structure_free (s);
1960 test_webrtc_free (t);
1968 guint num_active_media;
1969 const gchar **bundled;
1970 const gchar **bundled_only;
1974 _check_bundled_sdp_media (struct test_webrtc *t, GstElement * element,
1975 GstWebRTCSessionDescription * sd, gpointer user_data)
1977 gchar **bundled = NULL;
1978 BundleCheckData *data = (BundleCheckData *) user_data;
1982 fail_unless_equals_int (gst_sdp_message_medias_len (sd->sdp),
1985 fail_unless (_parse_bundle (sd->sdp, &bundled));
1988 fail_unless_equals_int (g_strv_length ((GStrv) data->bundled), 0);
1990 fail_unless_equals_int (g_strv_length (bundled),
1991 g_strv_length ((GStrv) data->bundled));
1994 for (i = 0; data->bundled[i]; i++) {
1995 fail_unless (g_strv_contains ((const gchar **) bundled, data->bundled[i]));
2000 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2001 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2002 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2004 if (g_strv_contains ((const gchar **) data->bundled_only, mid))
2005 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2007 if (gst_sdp_media_get_port (media) != 0)
2011 fail_unless_equals_int (active_media, data->num_active_media);
2014 g_strfreev (bundled);
2017 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2019 struct test_webrtc *t = create_audio_video_test ();
2020 const gchar *bundle[] = { "audio0", "video1", NULL };
2021 const gchar *offer_bundle_only[] = { "video1", NULL };
2022 const gchar *answer_bundle_only[] = { NULL };
2023 /* We set a max-bundle policy on the offering webrtcbin,
2024 * this means that all the offered medias should be part
2025 * of the group:BUNDLE attribute, and they should be marked
2028 BundleCheckData offer_data = {
2034 /* We also set a max-bundle policy on the answering webrtcbin,
2035 * this means that all the offered medias should be part
2036 * of the group:BUNDLE attribute, but need not be marked
2039 BundleCheckData answer_data = {
2045 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2046 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2048 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2050 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2053 test_validate_sdp (t, &offer, &answer);
2055 test_webrtc_free (t);
2060 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2062 struct test_webrtc *t = create_audio_video_test ();
2063 const gchar *bundle[] = { "audio0", "video1", NULL };
2064 const gchar *bundle_only[] = { NULL };
2065 /* We set a max-compat policy on the offering webrtcbin,
2066 * this means that all the offered medias should be part
2067 * of the group:BUNDLE attribute, and they should *not* be marked
2070 BundleCheckData offer_data = {
2076 /* We set a max-bundle policy on the answering webrtcbin,
2077 * this means that all the offered medias should be part
2078 * of the group:BUNDLE attribute, but need not be marked
2081 BundleCheckData answer_data = {
2087 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2088 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2090 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2092 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2095 test_validate_sdp (t, &offer, &answer);
2097 test_webrtc_free (t);
2102 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2104 struct test_webrtc *t = create_audio_video_test ();
2105 const gchar *offer_bundle[] = { "audio0", "video1", NULL };
2106 const gchar *offer_bundle_only[] = { "video1", NULL };
2107 const gchar *answer_bundle[] = { NULL };
2108 const gchar *answer_bundle_only[] = { NULL };
2109 /* We set a max-bundle policy on the offering webrtcbin,
2110 * this means that all the offered medias should be part
2111 * of the group:BUNDLE attribute, and they should be marked
2114 BundleCheckData offer_data = {
2120 /* We set a none policy on the answering webrtcbin,
2121 * this means that the answer should contain no bundled
2122 * medias, and as the bundle-policy of the offering webrtcbin
2123 * is set to max-bundle, only one media should be active.
2125 BundleCheckData answer_data = {
2131 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2132 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2134 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2136 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2138 test_validate_sdp (t, &offer, &answer);
2140 test_webrtc_free (t);
2145 GST_START_TEST (test_bundle_audio_video_data)
2147 struct test_webrtc *t = create_audio_video_test ();
2148 const gchar *bundle[] = { "audio0", "video1", "application2", NULL };
2149 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2150 const gchar *answer_bundle_only[] = { NULL };
2151 GObject *channel = NULL;
2152 /* We set a max-bundle policy on the offering webrtcbin,
2153 * this means that all the offered medias should be part
2154 * of the group:BUNDLE attribute, and they should be marked
2157 BundleCheckData offer_data = {
2163 /* We also set a max-bundle policy on the answering webrtcbin,
2164 * this means that all the offered medias should be part
2165 * of the group:BUNDLE attribute, but need not be marked
2168 BundleCheckData answer_data = {
2174 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data, NULL };
2175 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data, NULL };
2177 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2179 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2182 fail_if (gst_element_set_state (t->webrtc1,
2183 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2184 fail_if (gst_element_set_state (t->webrtc2,
2185 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2187 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2190 test_validate_sdp (t, &offer, &answer);
2192 g_object_unref (channel);
2193 test_webrtc_free (t);
2198 GST_START_TEST (test_duplicate_nego)
2200 struct test_webrtc *t = create_audio_video_test ();
2201 const gchar *expected_offer[] = { "sendrecv", "sendrecv" };
2202 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
2203 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
2204 struct validate_sdp answer =
2205 { on_sdp_media_direction, expected_answer, NULL };
2208 /* check that negotiating twice succeeds */
2210 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2211 add_fake_audio_src_harness (h, 96);
2212 t->harnesses = g_list_prepend (t->harnesses, h);
2214 t->on_negotiation_needed = NULL;
2215 test_validate_sdp (t, &offer, &answer);
2216 test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED);
2217 test_validate_sdp (t, &offer, &answer);
2219 test_webrtc_free (t);
2224 GST_START_TEST (test_dual_audio)
2226 struct test_webrtc *t = create_audio_test ();
2227 const gchar *expected_offer[] = { "sendrecv", "sendrecv", };
2228 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
2229 struct validate_sdp offer = { on_sdp_media_direction, expected_offer, NULL };
2230 struct validate_sdp answer =
2231 { on_sdp_media_direction, expected_answer, NULL };
2233 GstWebRTCRTPTransceiver *trans;
2234 GArray *transceivers;
2236 /* test that each mline gets a unique transceiver even with the same caps */
2238 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
2239 add_fake_audio_src_harness (h, 96);
2240 t->harnesses = g_list_prepend (t->harnesses, h);
2242 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2243 add_fake_audio_src_harness (h, 96);
2244 t->harnesses = g_list_prepend (t->harnesses, h);
2246 t->on_negotiation_needed = NULL;
2247 test_validate_sdp (t, &offer, &answer);
2249 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
2250 fail_unless (transceivers != NULL);
2251 fail_unless_equals_int (2, transceivers->len);
2253 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
2254 fail_unless (trans != NULL);
2255 fail_unless_equals_int (trans->mline, 0);
2257 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
2258 fail_unless (trans != NULL);
2259 fail_unless_equals_int (trans->mline, 1);
2261 g_array_unref (transceivers);
2262 test_webrtc_free (t);
2266 webrtcbin_suite (void)
2268 Suite *s = suite_create ("webrtcbin");
2269 TCase *tc = tcase_create ("general");
2270 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
2271 GstPluginFeature *sctpenc, *sctpdec;
2272 GstRegistry *registry;
2274 registry = gst_registry_get ();
2275 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
2276 nicesink = gst_registry_lookup_feature (registry, "nicesink");
2277 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
2278 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
2279 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
2280 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
2282 tcase_add_test (tc, test_no_nice_elements_request_pad);
2283 tcase_add_test (tc, test_no_nice_elements_state_change);
2284 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
2285 tcase_add_test (tc, test_sdp_no_media);
2286 tcase_add_test (tc, test_session_stats);
2287 tcase_add_test (tc, test_audio);
2288 tcase_add_test (tc, test_audio_video);
2289 tcase_add_test (tc, test_media_direction);
2290 tcase_add_test (tc, test_media_setup);
2291 tcase_add_test (tc, test_add_transceiver);
2292 tcase_add_test (tc, test_get_transceivers);
2293 tcase_add_test (tc, test_add_recvonly_transceiver);
2294 tcase_add_test (tc, test_recvonly_sendonly);
2295 tcase_add_test (tc, test_payload_types);
2296 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
2297 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
2298 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
2299 tcase_add_test (tc, test_dual_audio);
2300 tcase_add_test (tc, test_duplicate_nego);
2301 if (sctpenc && sctpdec) {
2302 tcase_add_test (tc, test_data_channel_create);
2303 tcase_add_test (tc, test_data_channel_remote_notify);
2304 tcase_add_test (tc, test_data_channel_transfer_string);
2305 tcase_add_test (tc, test_data_channel_transfer_data);
2306 tcase_add_test (tc, test_data_channel_create_after_negotiate);
2307 tcase_add_test (tc, test_data_channel_low_threshold);
2308 tcase_add_test (tc, test_data_channel_max_message_size);
2309 tcase_add_test (tc, test_data_channel_pre_negotiated);
2310 tcase_add_test (tc, test_bundle_audio_video_data);
2312 GST_WARNING ("Some required elements were not found. "
2313 "All datachannel are disabled. sctpenc %p, sctpdec %p", sctpenc,
2317 GST_WARNING ("Some required elements were not found. "
2318 "All media tests are disabled. nicesrc %p, nicesink %p, "
2319 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
2324 gst_object_unref (nicesrc);
2326 gst_object_unref (nicesink);
2328 gst_object_unref (dtlssrtpdec);
2330 gst_object_unref (dtlssrtpenc);
2332 gst_object_unref (sctpenc);
2334 gst_object_unref (sctpdec);
2336 suite_add_tcase (s, tc);
2341 GST_CHECK_MAIN (webrtcbin);