1 /* GStreamer
2 *
3 * Unit tests for webrtcbin
4 *
5 * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
6 *
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.
11 *
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.
16 *
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.
21 */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/gst.h>
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"
36
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
40 typedef enum
41 {
42 STATE_NEW,
43 STATE_NEGOTATION_NEEDED,
44 STATE_OFFER_CREATED,
45 STATE_ANSWER_CREATED,
46 STATE_EOS,
47 STATE_ERROR,
48 STATE_CUSTOM,
49 } TestState;
50
51 /* basic premise of this is that webrtc1 and webrtc2 are attempting to connect
52 * to each other in various configurations */
53 struct test_webrtc;
54 struct test_webrtc
55 {
56 GList *harnesses;
57 GThread *thread;
58 GMainLoop *loop;
59 GstBus *bus1;
60 GstBus *bus2;
61 GstElement *webrtc1;
62 GstElement *webrtc2;
63 GMutex lock;
64 GCond cond;
65 TestState state;
66 guint offerror;
67 gpointer user_data;
68 GDestroyNotify data_notify;
69 /* *INDENT-OFF* */
70 void (*on_negotiation_needed) (struct test_webrtc * t,
71 GstElement * element,
72 gpointer user_data);
73 gpointer negotiation_data;
74 GDestroyNotify negotiation_notify;
75 void (*on_ice_candidate) (struct test_webrtc * t,
76 GstElement * element,
77 guint mlineindex,
78 gchar * candidate,
79 GstElement * other,
80 gpointer user_data);
81 gpointer ice_candidate_data;
82 GDestroyNotify ice_candidate_notify;
83 GstWebRTCSessionDescription * (*on_offer_created) (struct test_webrtc * t,
84 GstElement * element,
85 GstPromise * promise,
86 gpointer user_data);
87 gpointer offer_data;
88 GDestroyNotify offer_notify;
89 GstWebRTCSessionDescription * (*on_answer_created) (struct test_webrtc * t,
90 GstElement * element,
91 GstPromise * promise,
92 gpointer user_data);
93 gpointer data_channel_data;
94 GDestroyNotify data_channel_notify;
95 void (*on_data_channel) (struct test_webrtc * t,
96 GstElement * element,
97 GObject *data_channel,
98 gpointer user_data);
99 gpointer answer_data;
100 GDestroyNotify answer_notify;
101 void (*on_pad_added) (struct test_webrtc * t,
102 GstElement * element,
103 GstPad * pad,
104 gpointer user_data);
105 gpointer pad_added_data;
106 GDestroyNotify pad_added_notify;
107 void (*bus_message) (struct test_webrtc * t,
108 GstBus * bus,
109 GstMessage * msg,
110 gpointer user_data);
111 gpointer bus_data;
112 GDestroyNotify bus_notify;
113 /* *INDENT-ON* */
114 };
115
116 static void
_on_answer_received(GstPromise * promise,gpointer user_data)117 _on_answer_received (GstPromise * promise, gpointer user_data)
118 {
119 struct test_webrtc *t = user_data;
120 GstElement *offeror = t->offerror == 1 ? t->webrtc1 : t->webrtc2;
121 GstElement *answerer = t->offerror == 2 ? t->webrtc1 : t->webrtc2;
122 const GstStructure *reply;
123 GstWebRTCSessionDescription *answer = NULL;
124 gchar *desc;
125
126 reply = gst_promise_get_reply (promise);
127 gst_structure_get (reply, "answer",
128 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
129 desc = gst_sdp_message_as_text (answer->sdp);
130 GST_INFO ("Created Answer: %s", desc);
131 g_free (desc);
132
133 g_mutex_lock (&t->lock);
134 if (t->on_answer_created) {
135 gst_webrtc_session_description_free (answer);
136 answer = t->on_answer_created (t, answerer, promise, t->answer_data);
137 }
138 gst_promise_unref (promise);
139
140 g_signal_emit_by_name (answerer, "set-local-description", answer, NULL);
141 g_signal_emit_by_name (offeror, "set-remote-description", answer, NULL);
142
143 t->state = STATE_ANSWER_CREATED;
144 g_cond_broadcast (&t->cond);
145 g_mutex_unlock (&t->lock);
146
147 gst_webrtc_session_description_free (answer);
148 }
149
150 static void
_on_offer_received(GstPromise * promise,gpointer user_data)151 _on_offer_received (GstPromise * promise, gpointer user_data)
152 {
153 struct test_webrtc *t = user_data;
154 GstElement *offeror = t->offerror == 1 ? t->webrtc1 : t->webrtc2;
155 GstElement *answerer = t->offerror == 2 ? t->webrtc1 : t->webrtc2;
156 const GstStructure *reply;
157 GstWebRTCSessionDescription *offer = NULL;
158 gchar *desc;
159
160 reply = gst_promise_get_reply (promise);
161 gst_structure_get (reply, "offer",
162 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
163 desc = gst_sdp_message_as_text (offer->sdp);
164 GST_INFO ("Created offer: %s", desc);
165 g_free (desc);
166
167 g_mutex_lock (&t->lock);
168 if (t->on_offer_created) {
169 gst_webrtc_session_description_free (offer);
170 offer = t->on_offer_created (t, offeror, promise, t->offer_data);
171 }
172 gst_promise_unref (promise);
173
174 g_signal_emit_by_name (offeror, "set-local-description", offer, NULL);
175 g_signal_emit_by_name (answerer, "set-remote-description", offer, NULL);
176
177 promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
178 g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
179
180 t->state = STATE_OFFER_CREATED;
181 g_cond_broadcast (&t->cond);
182 g_mutex_unlock (&t->lock);
183
184 gst_webrtc_session_description_free (offer);
185 }
186
187 static gboolean
_bus_watch(GstBus * bus,GstMessage * msg,struct test_webrtc * t)188 _bus_watch (GstBus * bus, GstMessage * msg, struct test_webrtc *t)
189 {
190 g_mutex_lock (&t->lock);
191 switch (GST_MESSAGE_TYPE (msg)) {
192 case GST_MESSAGE_STATE_CHANGED:
193 if (GST_ELEMENT (msg->src) == t->webrtc1
194 || GST_ELEMENT (msg->src) == t->webrtc2) {
195 GstState old, new, pending;
196
197 gst_message_parse_state_changed (msg, &old, &new, &pending);
198
199 {
200 gchar *dump_name = g_strconcat ("%s-state_changed-",
201 GST_OBJECT_NAME (msg->src), gst_element_state_get_name (old), "_",
202 gst_element_state_get_name (new), NULL);
203 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
204 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
205 g_free (dump_name);
206 }
207 }
208 break;
209 case GST_MESSAGE_ERROR:{
210 GError *err = NULL;
211 gchar *dbg_info = NULL;
212
213 {
214 gchar *dump_name;
215 dump_name =
216 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc1), NULL);
217 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
218 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
219 g_free (dump_name);
220 dump_name =
221 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc2), NULL);
222 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
223 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
224 g_free (dump_name);
225 }
226
227 gst_message_parse_error (msg, &err, &dbg_info);
228 GST_WARNING ("ERROR from element %s: %s\n",
229 GST_OBJECT_NAME (msg->src), err->message);
230 GST_WARNING ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
231 g_error_free (err);
232 g_free (dbg_info);
233 t->state = STATE_ERROR;
234 g_cond_broadcast (&t->cond);
235 break;
236 }
237 case GST_MESSAGE_EOS:{
238 {
239 gchar *dump_name;
240 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc1), NULL);
241 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
242 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
243 g_free (dump_name);
244 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc2), NULL);
245 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
246 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
247 g_free (dump_name);
248 }
249 GST_INFO ("EOS received\n");
250 t->state = STATE_EOS;
251 g_cond_broadcast (&t->cond);
252 break;
253 }
254 default:
255 break;
256 }
257
258 if (t->bus_message)
259 t->bus_message (t, bus, msg, t->bus_data);
260 g_mutex_unlock (&t->lock);
261
262 return TRUE;
263 }
264
265 static void
_on_negotiation_needed(GstElement * webrtc,struct test_webrtc * t)266 _on_negotiation_needed (GstElement * webrtc, struct test_webrtc *t)
267 {
268 g_mutex_lock (&t->lock);
269 if (t->on_negotiation_needed)
270 t->on_negotiation_needed (t, webrtc, t->negotiation_data);
271 if (t->state == STATE_NEW)
272 t->state = STATE_NEGOTATION_NEEDED;
273 g_cond_broadcast (&t->cond);
274 g_mutex_unlock (&t->lock);
275 }
276
277 static void
_on_ice_candidate(GstElement * webrtc,guint mlineindex,gchar * candidate,struct test_webrtc * t)278 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
279 struct test_webrtc *t)
280 {
281 GstElement *other;
282
283 g_mutex_lock (&t->lock);
284 other = webrtc == t->webrtc1 ? t->webrtc2 : t->webrtc1;
285
286 if (t->on_ice_candidate)
287 t->on_ice_candidate (t, webrtc, mlineindex, candidate, other,
288 t->ice_candidate_data);
289
290 g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
291 g_mutex_unlock (&t->lock);
292 }
293
294 static void
_on_pad_added(GstElement * webrtc,GstPad * new_pad,struct test_webrtc * t)295 _on_pad_added (GstElement * webrtc, GstPad * new_pad, struct test_webrtc *t)
296 {
297 g_mutex_lock (&t->lock);
298 if (t->on_pad_added)
299 t->on_pad_added (t, webrtc, new_pad, t->pad_added_data);
300 g_mutex_unlock (&t->lock);
301 }
302
303 static void
_on_data_channel(GstElement * webrtc,GObject * data_channel,struct test_webrtc * t)304 _on_data_channel (GstElement * webrtc, GObject * data_channel,
305 struct test_webrtc *t)
306 {
307 g_mutex_lock (&t->lock);
308 if (t->on_data_channel)
309 t->on_data_channel (t, webrtc, data_channel, t->data_channel_data);
310 g_mutex_unlock (&t->lock);
311 }
312
313 static void
_pad_added_not_reached(struct test_webrtc * t,GstElement * element,GstPad * pad,gpointer user_data)314 _pad_added_not_reached (struct test_webrtc *t, GstElement * element,
315 GstPad * pad, gpointer user_data)
316 {
317 g_assert_not_reached ();
318 }
319
320 static void
_ice_candidate_not_reached(struct test_webrtc * t,GstElement * element,guint mlineindex,gchar * candidate,GstElement * other,gpointer user_data)321 _ice_candidate_not_reached (struct test_webrtc *t, GstElement * element,
322 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
323 {
324 g_assert_not_reached ();
325 }
326
327 static void
_negotiation_not_reached(struct test_webrtc * t,GstElement * element,gpointer user_data)328 _negotiation_not_reached (struct test_webrtc *t, GstElement * element,
329 gpointer user_data)
330 {
331 g_assert_not_reached ();
332 }
333
334 static void
_bus_no_errors(struct test_webrtc * t,GstBus * bus,GstMessage * msg,gpointer user_data)335 _bus_no_errors (struct test_webrtc *t, GstBus * bus, GstMessage * msg,
336 gpointer user_data)
337 {
338 switch (GST_MESSAGE_TYPE (msg)) {
339 case GST_MESSAGE_ERROR:{
340 g_assert_not_reached ();
341 break;
342 }
343 default:
344 break;
345 }
346 }
347
348 static GstWebRTCSessionDescription *
_offer_answer_not_reached(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)349 _offer_answer_not_reached (struct test_webrtc *t, GstElement * element,
350 GstPromise * promise, gpointer user_data)
351 {
352 g_assert_not_reached ();
353 }
354
355 static void
_on_data_channel_not_reached(struct test_webrtc * t,GstElement * element,GObject * data_channel,gpointer user_data)356 _on_data_channel_not_reached (struct test_webrtc *t, GstElement * element,
357 GObject * data_channel, gpointer user_data)
358 {
359 g_assert_not_reached ();
360 }
361
362 static void
_broadcast(struct test_webrtc * t)363 _broadcast (struct test_webrtc *t)
364 {
365 g_mutex_lock (&t->lock);
366 g_cond_broadcast (&t->cond);
367 g_mutex_unlock (&t->lock);
368 }
369
370 static gboolean
_unlock_create_thread(GMutex * lock)371 _unlock_create_thread (GMutex * lock)
372 {
373 g_mutex_unlock (lock);
374 return G_SOURCE_REMOVE;
375 }
376
377 static gpointer
_bus_thread(struct test_webrtc * t)378 _bus_thread (struct test_webrtc *t)
379 {
380 g_mutex_lock (&t->lock);
381 t->loop = g_main_loop_new (NULL, FALSE);
382 g_idle_add ((GSourceFunc) _unlock_create_thread, &t->lock);
383 g_cond_broadcast (&t->cond);
384
385 g_main_loop_run (t->loop);
386
387 g_mutex_lock (&t->lock);
388 g_main_loop_unref (t->loop);
389 t->loop = NULL;
390 g_cond_broadcast (&t->cond);
391 g_mutex_unlock (&t->lock);
392
393 return NULL;
394 }
395
396 static void
element_added_disable_sync(GstBin * bin,GstBin * sub_bin,GstElement * element,gpointer user_data)397 element_added_disable_sync (GstBin * bin, GstBin * sub_bin,
398 GstElement * element, gpointer user_data)
399 {
400 GObjectClass *class = G_OBJECT_GET_CLASS (element);
401 if (g_object_class_find_property (class, "async"))
402 g_object_set (element, "async", FALSE, NULL);
403 if (g_object_class_find_property (class, "sync"))
404 g_object_set (element, "sync", FALSE, NULL);
405 }
406
407 static struct test_webrtc *
test_webrtc_new(void)408 test_webrtc_new (void)
409 {
410 struct test_webrtc *ret = g_new0 (struct test_webrtc, 1);
411
412 ret->on_negotiation_needed = _negotiation_not_reached;
413 ret->on_ice_candidate = _ice_candidate_not_reached;
414 ret->on_pad_added = _pad_added_not_reached;
415 ret->on_offer_created = _offer_answer_not_reached;
416 ret->on_answer_created = _offer_answer_not_reached;
417 ret->on_data_channel = _on_data_channel_not_reached;
418 ret->bus_message = _bus_no_errors;
419
420 g_mutex_init (&ret->lock);
421 g_cond_init (&ret->cond);
422
423 ret->bus1 = gst_bus_new ();
424 ret->bus2 = gst_bus_new ();
425 gst_bus_add_watch (ret->bus1, (GstBusFunc) _bus_watch, ret);
426 gst_bus_add_watch (ret->bus2, (GstBusFunc) _bus_watch, ret);
427 ret->webrtc1 = gst_element_factory_make ("webrtcbin", NULL);
428 ret->webrtc2 = gst_element_factory_make ("webrtcbin", NULL);
429 fail_unless (ret->webrtc1 != NULL && ret->webrtc2 != NULL);
430
431 gst_element_set_bus (ret->webrtc1, ret->bus1);
432 gst_element_set_bus (ret->webrtc2, ret->bus2);
433
434 g_signal_connect (ret->webrtc1, "deep-element-added",
435 G_CALLBACK (element_added_disable_sync), NULL);
436 g_signal_connect (ret->webrtc2, "deep-element-added",
437 G_CALLBACK (element_added_disable_sync), NULL);
438 g_signal_connect (ret->webrtc1, "on-negotiation-needed",
439 G_CALLBACK (_on_negotiation_needed), ret);
440 g_signal_connect (ret->webrtc2, "on-negotiation-needed",
441 G_CALLBACK (_on_negotiation_needed), ret);
442 g_signal_connect (ret->webrtc1, "on-ice-candidate",
443 G_CALLBACK (_on_ice_candidate), ret);
444 g_signal_connect (ret->webrtc2, "on-ice-candidate",
445 G_CALLBACK (_on_ice_candidate), ret);
446 g_signal_connect (ret->webrtc1, "on-data-channel",
447 G_CALLBACK (_on_data_channel), ret);
448 g_signal_connect (ret->webrtc2, "on-data-channel",
449 G_CALLBACK (_on_data_channel), ret);
450 g_signal_connect (ret->webrtc1, "pad-added", G_CALLBACK (_on_pad_added), ret);
451 g_signal_connect (ret->webrtc2, "pad-added", G_CALLBACK (_on_pad_added), ret);
452 g_signal_connect_swapped (ret->webrtc1, "notify::ice-gathering-state",
453 G_CALLBACK (_broadcast), ret);
454 g_signal_connect_swapped (ret->webrtc2, "notify::ice-gathering-state",
455 G_CALLBACK (_broadcast), ret);
456 g_signal_connect_swapped (ret->webrtc1, "notify::ice-connection-state",
457 G_CALLBACK (_broadcast), ret);
458 g_signal_connect_swapped (ret->webrtc2, "notify::ice-connection-state",
459 G_CALLBACK (_broadcast), ret);
460
461 ret->thread = g_thread_new ("test-webrtc", (GThreadFunc) _bus_thread, ret);
462
463 g_mutex_lock (&ret->lock);
464 while (!ret->loop)
465 g_cond_wait (&ret->cond, &ret->lock);
466 g_mutex_unlock (&ret->lock);
467
468 return ret;
469 }
470
471 static void
test_webrtc_free(struct test_webrtc * t)472 test_webrtc_free (struct test_webrtc *t)
473 {
474 /* Otherwise while one webrtcbin is being destroyed, the other could
475 * generate a signal that calls into the destroyed webrtcbin */
476 g_signal_handlers_disconnect_by_data (t->webrtc1, t);
477 g_signal_handlers_disconnect_by_data (t->webrtc2, t);
478
479 g_main_loop_quit (t->loop);
480 g_mutex_lock (&t->lock);
481 while (t->loop)
482 g_cond_wait (&t->cond, &t->lock);
483 g_mutex_unlock (&t->lock);
484
485 g_thread_join (t->thread);
486
487 gst_bus_remove_watch (t->bus1);
488 gst_bus_remove_watch (t->bus2);
489
490 gst_bus_set_flushing (t->bus1, TRUE);
491 gst_bus_set_flushing (t->bus2, TRUE);
492
493 gst_object_unref (t->bus1);
494 gst_object_unref (t->bus2);
495
496 g_list_free_full (t->harnesses, (GDestroyNotify) gst_harness_teardown);
497
498 if (t->data_notify)
499 t->data_notify (t->user_data);
500 if (t->negotiation_notify)
501 t->negotiation_notify (t->negotiation_data);
502 if (t->ice_candidate_notify)
503 t->ice_candidate_notify (t->ice_candidate_data);
504 if (t->offer_notify)
505 t->offer_notify (t->offer_data);
506 if (t->answer_notify)
507 t->answer_notify (t->answer_data);
508 if (t->pad_added_notify)
509 t->pad_added_notify (t->pad_added_data);
510 if (t->data_channel_notify)
511 t->data_channel_notify (t->data_channel_data);
512
513 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
514 gst_element_set_state (t->webrtc1, GST_STATE_NULL));
515 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
516 gst_element_set_state (t->webrtc2, GST_STATE_NULL));
517
518 gst_object_unref (t->webrtc1);
519 gst_object_unref (t->webrtc2);
520
521 g_mutex_clear (&t->lock);
522 g_cond_clear (&t->cond);
523
524 g_free (t);
525 }
526
527 static void
test_webrtc_create_offer(struct test_webrtc * t,GstElement * webrtc)528 test_webrtc_create_offer (struct test_webrtc *t, GstElement * webrtc)
529 {
530 GstPromise *promise;
531
532 t->offerror = webrtc == t->webrtc1 ? 1 : 2;
533 promise = gst_promise_new_with_change_func (_on_offer_received, t, NULL);
534 g_signal_emit_by_name (webrtc, "create-offer", NULL, promise);
535 }
536
537 static void
test_webrtc_wait_for_state_mask(struct test_webrtc * t,TestState state)538 test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
539 {
540 g_mutex_lock (&t->lock);
541 while (((1 << t->state) & state) == 0) {
542 GST_INFO ("test state 0x%x, current 0x%x", state, (1 << t->state));
543 g_cond_wait (&t->cond, &t->lock);
544 }
545 GST_INFO ("have test state 0x%x, current 0x%x", state, 1 << t->state);
546 g_mutex_unlock (&t->lock);
547 }
548
549 static void
test_webrtc_wait_for_answer_error_eos(struct test_webrtc * t)550 test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t)
551 {
552 TestState states = 0;
553 states |= (1 << STATE_ANSWER_CREATED);
554 states |= (1 << STATE_EOS);
555 states |= (1 << STATE_ERROR);
556 test_webrtc_wait_for_state_mask (t, states);
557 }
558
559 static void
test_webrtc_signal_state_unlocked(struct test_webrtc * t,TestState state)560 test_webrtc_signal_state_unlocked (struct test_webrtc *t, TestState state)
561 {
562 t->state = state;
563 g_cond_broadcast (&t->cond);
564 }
565
566 static void
test_webrtc_signal_state(struct test_webrtc * t,TestState state)567 test_webrtc_signal_state (struct test_webrtc *t, TestState state)
568 {
569 g_mutex_lock (&t->lock);
570 test_webrtc_signal_state_unlocked (t, state);
571 g_mutex_unlock (&t->lock);
572 }
573
574 #if 0
575 static void
576 test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
577 {
578 GstWebRTCICEGatheringState ice_state1, ice_state2;
579 g_mutex_lock (&t->lock);
580 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
581 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
582 while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE &&
583 ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
584 g_cond_wait (&t->cond, &t->lock);
585 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
586 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
587 }
588 g_mutex_unlock (&t->lock);
589 }
590
591 static void
592 test_webrtc_wait_for_ice_connection (struct test_webrtc *t,
593 GstWebRTCICEConnectionState states)
594 {
595 GstWebRTCICEConnectionState ice_state1, ice_state2, current;
596 g_mutex_lock (&t->lock);
597 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
598 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
599 current = (1 << ice_state1) | (1 << ice_state2);
600 while ((current & states) == 0 || (current & ~states)) {
601 g_cond_wait (&t->cond, &t->lock);
602 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
603 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
604 current = (1 << ice_state1) | (1 << ice_state2);
605 }
606 g_mutex_unlock (&t->lock);
607 }
608 #endif
609 static void
_pad_added_fakesink(struct test_webrtc * t,GstElement * element,GstPad * pad,gpointer user_data)610 _pad_added_fakesink (struct test_webrtc *t, GstElement * element,
611 GstPad * pad, gpointer user_data)
612 {
613 GstHarness *h;
614
615 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
616 return;
617
618 h = gst_harness_new_with_element (element, NULL, "src_%u");
619 gst_harness_add_sink_parse (h, "fakesink async=false sync=false");
620
621 t->harnesses = g_list_prepend (t->harnesses, h);
622 }
623
624 static GstWebRTCSessionDescription *
_count_num_sdp_media(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)625 _count_num_sdp_media (struct test_webrtc *t, GstElement * element,
626 GstPromise * promise, gpointer user_data)
627 {
628 GstWebRTCSessionDescription *offer = NULL;
629 guint expected = GPOINTER_TO_UINT (user_data);
630 const GstStructure *reply;
631 const gchar *field;
632
633 field = t->offerror == 1 && t->webrtc1 == element ? "offer" : "answer";
634
635 reply = gst_promise_get_reply (promise);
636 gst_structure_get (reply, field,
637 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
638
639 fail_unless_equals_int (gst_sdp_message_medias_len (offer->sdp), expected);
640
641 return offer;
642 }
643
GST_START_TEST(test_sdp_no_media)644 GST_START_TEST (test_sdp_no_media)
645 {
646 struct test_webrtc *t = test_webrtc_new ();
647
648 /* check that a no stream connection creates 0 media sections */
649
650 t->on_negotiation_needed = NULL;
651 t->offer_data = GUINT_TO_POINTER (0);
652 t->on_offer_created = _count_num_sdp_media;
653 t->answer_data = GUINT_TO_POINTER (0);
654 t->on_answer_created = _count_num_sdp_media;
655
656 fail_if (gst_element_set_state (t->webrtc1,
657 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
658 fail_if (gst_element_set_state (t->webrtc2,
659 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
660
661 test_webrtc_create_offer (t, t->webrtc1);
662
663 test_webrtc_wait_for_answer_error_eos (t);
664 fail_unless (t->state == STATE_ANSWER_CREATED);
665 test_webrtc_free (t);
666 }
667
668 GST_END_TEST;
669
670 static void
add_fake_audio_src_harness(GstHarness * h,gint pt)671 add_fake_audio_src_harness (GstHarness * h, gint pt)
672 {
673 GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
674 GstStructure *s = gst_caps_get_structure (caps, 0);
675 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
676 gst_harness_set_src_caps (h, caps);
677 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
678 }
679
680 static void
add_fake_video_src_harness(GstHarness * h,gint pt)681 add_fake_video_src_harness (GstHarness * h, gint pt)
682 {
683 GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
684 GstStructure *s = gst_caps_get_structure (caps, 0);
685 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
686 gst_harness_set_src_caps (h, caps);
687 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
688 }
689
690 static struct test_webrtc *
create_audio_test(void)691 create_audio_test (void)
692 {
693 struct test_webrtc *t = test_webrtc_new ();
694 GstHarness *h;
695
696 t->on_negotiation_needed = NULL;
697 t->on_pad_added = _pad_added_fakesink;
698
699 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
700 add_fake_audio_src_harness (h, 96);
701 t->harnesses = g_list_prepend (t->harnesses, h);
702
703 return t;
704 }
705
GST_START_TEST(test_audio)706 GST_START_TEST (test_audio)
707 {
708 struct test_webrtc *t = create_audio_test ();
709
710 /* check that a single stream connection creates the associated number
711 * of media sections */
712
713 t->on_negotiation_needed = NULL;
714 t->offer_data = GUINT_TO_POINTER (1);
715 t->on_offer_created = _count_num_sdp_media;
716 t->answer_data = GUINT_TO_POINTER (1);
717 t->on_answer_created = _count_num_sdp_media;
718 t->on_ice_candidate = NULL;
719
720 fail_if (gst_element_set_state (t->webrtc1,
721 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
722 fail_if (gst_element_set_state (t->webrtc2,
723 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
724
725 test_webrtc_create_offer (t, t->webrtc1);
726
727 test_webrtc_wait_for_answer_error_eos (t);
728 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
729 test_webrtc_free (t);
730 }
731
732 GST_END_TEST;
733
734 static struct test_webrtc *
create_audio_video_test(void)735 create_audio_video_test (void)
736 {
737 struct test_webrtc *t = test_webrtc_new ();
738 GstHarness *h;
739
740 t->on_negotiation_needed = NULL;
741 t->on_pad_added = _pad_added_fakesink;
742
743 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
744 add_fake_audio_src_harness (h, 96);
745 t->harnesses = g_list_prepend (t->harnesses, h);
746
747 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
748 add_fake_video_src_harness (h, 97);
749 t->harnesses = g_list_prepend (t->harnesses, h);
750
751 return t;
752 }
753
GST_START_TEST(test_audio_video)754 GST_START_TEST (test_audio_video)
755 {
756 struct test_webrtc *t = create_audio_video_test ();
757
758 /* check that a dual stream connection creates the associated number
759 * of media sections */
760
761 t->on_negotiation_needed = NULL;
762 t->offer_data = GUINT_TO_POINTER (2);
763 t->on_offer_created = _count_num_sdp_media;
764 t->answer_data = GUINT_TO_POINTER (2);
765 t->on_answer_created = _count_num_sdp_media;
766 t->on_ice_candidate = NULL;
767
768 fail_if (gst_element_set_state (t->webrtc1,
769 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
770 fail_if (gst_element_set_state (t->webrtc2,
771 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
772
773 test_webrtc_create_offer (t, t->webrtc1);
774
775 test_webrtc_wait_for_answer_error_eos (t);
776 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
777 test_webrtc_free (t);
778 }
779
780 GST_END_TEST;
781
782 typedef void (*ValidateSDPFunc) (struct test_webrtc * t, GstElement * element,
783 GstWebRTCSessionDescription * desc, gpointer user_data);
784
785 struct validate_sdp
786 {
787 ValidateSDPFunc validate;
788 gpointer user_data;
789 };
790
791 static GstWebRTCSessionDescription *
_check_validate_sdp(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)792 _check_validate_sdp (struct test_webrtc *t, GstElement * element,
793 GstPromise * promise, gpointer user_data)
794 {
795 struct validate_sdp *validate = user_data;
796 GstWebRTCSessionDescription *offer = NULL;
797 const GstStructure *reply;
798 const gchar *field;
799
800 field = t->offerror == 1 && t->webrtc1 == element ? "offer" : "answer";
801
802 reply = gst_promise_get_reply (promise);
803 gst_structure_get (reply, field,
804 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
805
806 validate->validate (t, element, offer, validate->user_data);
807
808 return offer;
809 }
810
811 static void
on_sdp_media_direction(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)812 on_sdp_media_direction (struct test_webrtc *t, GstElement * element,
813 GstWebRTCSessionDescription * desc, gpointer user_data)
814 {
815 gchar **expected_directions = user_data;
816 int i;
817
818 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
819 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
820 gboolean have_direction = FALSE;
821 int j;
822
823 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
824 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
825
826 if (g_strcmp0 (attr->key, "inactive") == 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, "sendonly") == 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, "recvonly") == 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);
841 } else if (g_strcmp0 (attr->key, "sendrecv") == 0) {
842 fail_unless (have_direction == FALSE,
843 "duplicate/multiple directions for media %u", j);
844 have_direction = TRUE;
845 fail_unless (g_strcmp0 (attr->key, expected_directions[i]) == 0);
846 }
847 }
848 fail_unless (have_direction, "no direction attribute in media %u", j);
849 }
850 }
851
GST_START_TEST(test_media_direction)852 GST_START_TEST (test_media_direction)
853 {
854 struct test_webrtc *t = create_audio_video_test ();
855 const gchar *expected_offer[] = { "sendrecv", "sendrecv" };
856 const gchar *expected_answer[] = { "sendrecv", "recvonly" };
857 struct validate_sdp offer = { on_sdp_media_direction, expected_offer };
858 struct validate_sdp answer = { on_sdp_media_direction, expected_answer };
859 GstHarness *h;
860
861 /* check the default media directions for transceivers */
862
863 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
864 add_fake_audio_src_harness (h, 96);
865 t->harnesses = g_list_prepend (t->harnesses, h);
866
867 t->on_negotiation_needed = NULL;
868 t->offer_data = &offer;
869 t->on_offer_created = _check_validate_sdp;
870 t->answer_data = &answer;
871 t->on_answer_created = _check_validate_sdp;
872 t->on_ice_candidate = NULL;
873
874 fail_if (gst_element_set_state (t->webrtc1,
875 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
876 fail_if (gst_element_set_state (t->webrtc2,
877 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
878
879 test_webrtc_create_offer (t, t->webrtc1);
880
881 test_webrtc_wait_for_answer_error_eos (t);
882 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
883 test_webrtc_free (t);
884 }
885
886 GST_END_TEST;
887
888 static void
on_sdp_media_payload_types(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)889 on_sdp_media_payload_types (struct test_webrtc *t, GstElement * element,
890 GstWebRTCSessionDescription * desc, gpointer user_data)
891 {
892 const GstSDPMedia *vmedia;
893 guint j;
894
895 fail_unless_equals_int (gst_sdp_message_medias_len (desc->sdp), 2);
896
897 vmedia = gst_sdp_message_get_media (desc->sdp, 1);
898
899 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
900 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
901
902 if (!g_strcmp0 (attr->key, "rtpmap")) {
903 if (g_str_has_prefix (attr->value, "97")) {
904 fail_unless_equals_string (attr->value, "97 VP8/90000");
905 } else if (g_str_has_prefix (attr->value, "96")) {
906 fail_unless_equals_string (attr->value, "96 red/90000");
907 } else if (g_str_has_prefix (attr->value, "98")) {
908 fail_unless_equals_string (attr->value, "98 ulpfec/90000");
909 } else if (g_str_has_prefix (attr->value, "99")) {
910 fail_unless_equals_string (attr->value, "99 rtx/90000");
911 } else if (g_str_has_prefix (attr->value, "100")) {
912 fail_unless_equals_string (attr->value, "100 rtx/90000");
913 }
914 }
915 }
916 }
917
918 /* In this test we verify that webrtcbin will pick available payload
919 * types when it needs to, in that example for RTX and FEC */
GST_START_TEST(test_payload_types)920 GST_START_TEST (test_payload_types)
921 {
922 struct test_webrtc *t = create_audio_video_test ();
923 struct validate_sdp offer = { on_sdp_media_payload_types, NULL };
924 GstWebRTCRTPTransceiver *trans;
925 GArray *transceivers;
926
927 t->on_negotiation_needed = NULL;
928 t->offer_data = &offer;
929 t->on_offer_created = _check_validate_sdp;
930 t->on_ice_candidate = NULL;
931 /* We don't really care about the answer here */
932 t->on_answer_created = NULL;
933
934 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
935 fail_unless_equals_int (transceivers->len, 2);
936 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
937 g_object_set (trans, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, "do-nack", TRUE,
938 NULL);
939 g_array_unref (transceivers);
940
941 fail_if (gst_element_set_state (t->webrtc1,
942 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
943 fail_if (gst_element_set_state (t->webrtc2,
944 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
945
946 test_webrtc_create_offer (t, t->webrtc1);
947
948 test_webrtc_wait_for_answer_error_eos (t);
949 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
950 test_webrtc_free (t);
951 }
952
953 GST_END_TEST;
954
955 static void
on_sdp_media_setup(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)956 on_sdp_media_setup (struct test_webrtc *t, GstElement * element,
957 GstWebRTCSessionDescription * desc, gpointer user_data)
958 {
959 gchar **expected_setup = user_data;
960 int i;
961
962 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
963 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
964 gboolean have_setup = FALSE;
965 int j;
966
967 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
968 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
969
970 if (g_strcmp0 (attr->key, "setup") == 0) {
971 fail_unless (have_setup == FALSE,
972 "duplicate/multiple setup for media %u", j);
973 have_setup = TRUE;
974 fail_unless (g_strcmp0 (attr->value, expected_setup[i]) == 0);
975 }
976 }
977 fail_unless (have_setup, "no setup attribute in media %u", j);
978 }
979 }
980
GST_START_TEST(test_media_setup)981 GST_START_TEST (test_media_setup)
982 {
983 struct test_webrtc *t = create_audio_test ();
984 const gchar *expected_offer[] = { "actpass" };
985 const gchar *expected_answer[] = { "active" };
986 struct validate_sdp offer = { on_sdp_media_setup, expected_offer };
987 struct validate_sdp answer = { on_sdp_media_setup, expected_answer };
988
989 /* check the default dtls setup negotiation values */
990
991 t->on_negotiation_needed = NULL;
992 t->offer_data = &offer;
993 t->on_offer_created = _check_validate_sdp;
994 t->answer_data = &answer;
995 t->on_answer_created = _check_validate_sdp;
996 t->on_ice_candidate = NULL;
997
998 fail_if (gst_element_set_state (t->webrtc1,
999 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1000 fail_if (gst_element_set_state (t->webrtc2,
1001 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1002
1003 test_webrtc_create_offer (t, t->webrtc1);
1004
1005 test_webrtc_wait_for_answer_error_eos (t);
1006 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
1007 test_webrtc_free (t);
1008 }
1009
1010 GST_END_TEST;
1011
GST_START_TEST(test_no_nice_elements_request_pad)1012 GST_START_TEST (test_no_nice_elements_request_pad)
1013 {
1014 struct test_webrtc *t = test_webrtc_new ();
1015 GstPluginFeature *nicesrc, *nicesink;
1016 GstRegistry *registry;
1017 GstPad *pad;
1018
1019 /* check that the absence of libnice elements posts an error on the bus
1020 * when requesting a pad */
1021
1022 registry = gst_registry_get ();
1023 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1024 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1025
1026 if (nicesrc)
1027 gst_registry_remove_feature (registry, nicesrc);
1028 if (nicesink)
1029 gst_registry_remove_feature (registry, nicesink);
1030
1031 t->bus_message = NULL;
1032
1033 pad = gst_element_get_request_pad (t->webrtc1, "sink_0");
1034 fail_unless (pad == NULL);
1035
1036 test_webrtc_wait_for_answer_error_eos (t);
1037 fail_unless_equals_int (STATE_ERROR, t->state);
1038 test_webrtc_free (t);
1039
1040 if (nicesrc)
1041 gst_registry_add_feature (registry, nicesrc);
1042 if (nicesink)
1043 gst_registry_add_feature (registry, nicesink);
1044 }
1045
1046 GST_END_TEST;
1047
GST_START_TEST(test_no_nice_elements_state_change)1048 GST_START_TEST (test_no_nice_elements_state_change)
1049 {
1050 struct test_webrtc *t = test_webrtc_new ();
1051 GstPluginFeature *nicesrc, *nicesink;
1052 GstRegistry *registry;
1053
1054 /* check that the absence of libnice elements posts an error on the bus */
1055
1056 registry = gst_registry_get ();
1057 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1058 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1059
1060 if (nicesrc)
1061 gst_registry_remove_feature (registry, nicesrc);
1062 if (nicesink)
1063 gst_registry_remove_feature (registry, nicesink);
1064
1065 t->bus_message = NULL;
1066 gst_element_set_state (t->webrtc1, GST_STATE_READY);
1067
1068 test_webrtc_wait_for_answer_error_eos (t);
1069 fail_unless_equals_int (STATE_ERROR, t->state);
1070 test_webrtc_free (t);
1071
1072 if (nicesrc)
1073 gst_registry_add_feature (registry, nicesrc);
1074 if (nicesink)
1075 gst_registry_add_feature (registry, nicesink);
1076 }
1077
1078 GST_END_TEST;
1079
1080 static void
validate_rtc_stats(const GstStructure * s)1081 validate_rtc_stats (const GstStructure * s)
1082 {
1083 GstWebRTCStatsType type = 0;
1084 double ts = 0.;
1085 gchar *id = NULL;
1086
1087 fail_unless (gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type,
1088 NULL));
1089 fail_unless (gst_structure_get (s, "id", G_TYPE_STRING, &id, NULL));
1090 fail_unless (gst_structure_get (s, "timestamp", G_TYPE_DOUBLE, &ts, NULL));
1091 fail_unless (type != 0);
1092 fail_unless (ts != 0.);
1093 fail_unless (id != NULL);
1094
1095 g_free (id);
1096 }
1097
1098 static void
validate_codec_stats(const GstStructure * s)1099 validate_codec_stats (const GstStructure * s)
1100 {
1101 guint pt = 0, clock_rate = 0;
1102
1103 fail_unless (gst_structure_get (s, "payload-type", G_TYPE_UINT, &pt, NULL));
1104 fail_unless (gst_structure_get (s, "clock-rate", G_TYPE_UINT, &clock_rate,
1105 NULL));
1106 fail_unless (pt >= 0 && pt <= 127);
1107 fail_unless (clock_rate >= 0);
1108 }
1109
1110 static void
validate_rtc_stream_stats(const GstStructure * s,const GstStructure * stats)1111 validate_rtc_stream_stats (const GstStructure * s, const GstStructure * stats)
1112 {
1113 gchar *codec_id, *transport_id;
1114 GstStructure *codec, *transport;
1115
1116 fail_unless (gst_structure_get (s, "codec-id", G_TYPE_STRING, &codec_id,
1117 NULL));
1118 fail_unless (gst_structure_get (s, "transport-id", G_TYPE_STRING,
1119 &transport_id, NULL));
1120
1121 fail_unless (gst_structure_get (stats, codec_id, GST_TYPE_STRUCTURE, &codec,
1122 NULL));
1123 fail_unless (gst_structure_get (stats, transport_id, GST_TYPE_STRUCTURE,
1124 &transport, NULL));
1125
1126 fail_unless (codec != NULL);
1127 fail_unless (transport != NULL);
1128
1129 gst_structure_free (transport);
1130 gst_structure_free (codec);
1131
1132 g_free (codec_id);
1133 g_free (transport_id);
1134 }
1135
1136 static void
validate_inbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1137 validate_inbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1138 {
1139 guint ssrc, fir, pli, nack;
1140 gint packets_lost;
1141 guint64 packets_received, bytes_received;
1142 double jitter;
1143 gchar *remote_id;
1144 GstStructure *remote;
1145
1146 validate_rtc_stream_stats (s, stats);
1147
1148 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1149 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1150 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1151 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1152 fail_unless (gst_structure_get (s, "packets-received", G_TYPE_UINT64,
1153 &packets_received, NULL));
1154 fail_unless (gst_structure_get (s, "bytes-received", G_TYPE_UINT64,
1155 &bytes_received, NULL));
1156 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1157 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1158 NULL));
1159 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1160 NULL));
1161 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1162 NULL));
1163 fail_unless (remote != NULL);
1164
1165 gst_structure_free (remote);
1166 g_free (remote_id);
1167 }
1168
1169 static void
validate_remote_inbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1170 validate_remote_inbound_rtp_stats (const GstStructure * s,
1171 const GstStructure * stats)
1172 {
1173 guint ssrc;
1174 gint packets_lost;
1175 double jitter, rtt;
1176 gchar *local_id;
1177 GstStructure *local;
1178
1179 validate_rtc_stream_stats (s, stats);
1180
1181 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1182 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1183 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1184 NULL));
1185 fail_unless (gst_structure_get (s, "round-trip-time", G_TYPE_DOUBLE, &rtt,
1186 NULL));
1187 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1188 NULL));
1189 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1190 NULL));
1191 fail_unless (local != NULL);
1192
1193 gst_structure_free (local);
1194 g_free (local_id);
1195 }
1196
1197 static void
validate_outbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1198 validate_outbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1199 {
1200 guint ssrc, fir, pli, nack;
1201 guint64 packets_sent, bytes_sent;
1202 gchar *remote_id;
1203 GstStructure *remote;
1204
1205 validate_rtc_stream_stats (s, stats);
1206
1207 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1208 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1209 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1210 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1211 fail_unless (gst_structure_get (s, "packets-sent", G_TYPE_UINT64,
1212 &packets_sent, NULL));
1213 fail_unless (gst_structure_get (s, "bytes-sent", G_TYPE_UINT64, &bytes_sent,
1214 NULL));
1215 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1216 NULL));
1217 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1218 NULL));
1219 fail_unless (remote != NULL);
1220
1221 gst_structure_free (remote);
1222 g_free (remote_id);
1223 }
1224
1225 static void
validate_remote_outbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1226 validate_remote_outbound_rtp_stats (const GstStructure * s,
1227 const GstStructure * stats)
1228 {
1229 guint ssrc;
1230 gchar *local_id;
1231 GstStructure *local;
1232
1233 validate_rtc_stream_stats (s, stats);
1234
1235 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1236 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1237 NULL));
1238 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1239 NULL));
1240 fail_unless (local != NULL);
1241
1242 gst_structure_free (local);
1243 g_free (local_id);
1244 }
1245
1246 static gboolean
validate_stats_foreach(GQuark field_id,const GValue * value,const GstStructure * stats)1247 validate_stats_foreach (GQuark field_id, const GValue * value,
1248 const GstStructure * stats)
1249 {
1250 const gchar *field = g_quark_to_string (field_id);
1251 GstWebRTCStatsType type;
1252 const GstStructure *s;
1253
1254 fail_unless (GST_VALUE_HOLDS_STRUCTURE (value));
1255
1256 s = gst_value_get_structure (value);
1257
1258 GST_INFO ("validating field %s %" GST_PTR_FORMAT, field, s);
1259
1260 validate_rtc_stats (s);
1261 gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type, NULL);
1262 if (type == GST_WEBRTC_STATS_CODEC) {
1263 validate_codec_stats (s);
1264 } else if (type == GST_WEBRTC_STATS_INBOUND_RTP) {
1265 validate_inbound_rtp_stats (s, stats);
1266 } else if (type == GST_WEBRTC_STATS_OUTBOUND_RTP) {
1267 validate_outbound_rtp_stats (s, stats);
1268 } else if (type == GST_WEBRTC_STATS_REMOTE_INBOUND_RTP) {
1269 validate_remote_inbound_rtp_stats (s, stats);
1270 } else if (type == GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP) {
1271 validate_remote_outbound_rtp_stats (s, stats);
1272 } else if (type == GST_WEBRTC_STATS_CSRC) {
1273 } else if (type == GST_WEBRTC_STATS_PEER_CONNECTION) {
1274 } else if (type == GST_WEBRTC_STATS_DATA_CHANNEL) {
1275 } else if (type == GST_WEBRTC_STATS_STREAM) {
1276 } else if (type == GST_WEBRTC_STATS_TRANSPORT) {
1277 } else if (type == GST_WEBRTC_STATS_CANDIDATE_PAIR) {
1278 } else if (type == GST_WEBRTC_STATS_LOCAL_CANDIDATE) {
1279 } else if (type == GST_WEBRTC_STATS_REMOTE_CANDIDATE) {
1280 } else if (type == GST_WEBRTC_STATS_CERTIFICATE) {
1281 } else {
1282 g_assert_not_reached ();
1283 }
1284
1285 return TRUE;
1286 }
1287
1288 static void
validate_stats(const GstStructure * stats)1289 validate_stats (const GstStructure * stats)
1290 {
1291 gst_structure_foreach (stats,
1292 (GstStructureForeachFunc) validate_stats_foreach, (gpointer) stats);
1293 }
1294
1295 static void
_on_stats(GstPromise * promise,gpointer user_data)1296 _on_stats (GstPromise * promise, gpointer user_data)
1297 {
1298 struct test_webrtc *t = user_data;
1299 const GstStructure *reply = gst_promise_get_reply (promise);
1300 int i;
1301
1302 validate_stats (reply);
1303 i = GPOINTER_TO_INT (t->user_data);
1304 i++;
1305 t->user_data = GINT_TO_POINTER (i);
1306 if (i >= 2)
1307 test_webrtc_signal_state (t, STATE_CUSTOM);
1308
1309 gst_promise_unref (promise);
1310 }
1311
GST_START_TEST(test_session_stats)1312 GST_START_TEST (test_session_stats)
1313 {
1314 struct test_webrtc *t = test_webrtc_new ();
1315 GstPromise *p;
1316
1317 /* test that the stats generated without any streams are sane */
1318
1319 t->on_negotiation_needed = NULL;
1320 t->on_offer_created = NULL;
1321 t->on_answer_created = NULL;
1322
1323 fail_if (gst_element_set_state (t->webrtc1,
1324 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1325 fail_if (gst_element_set_state (t->webrtc2,
1326 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1327
1328 test_webrtc_create_offer (t, t->webrtc1);
1329
1330 test_webrtc_wait_for_answer_error_eos (t);
1331 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
1332
1333 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1334 g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p);
1335 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1336 g_signal_emit_by_name (t->webrtc2, "get-stats", NULL, p);
1337
1338 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1339
1340 test_webrtc_free (t);
1341 }
1342
1343 GST_END_TEST;
1344
GST_START_TEST(test_add_transceiver)1345 GST_START_TEST (test_add_transceiver)
1346 {
1347 struct test_webrtc *t = test_webrtc_new ();
1348 GstWebRTCRTPTransceiverDirection direction;
1349 GstWebRTCRTPTransceiver *trans;
1350
1351 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
1352 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, NULL,
1353 &trans);
1354 fail_unless (trans != NULL);
1355 fail_unless_equals_int (direction, trans->direction);
1356
1357 gst_object_unref (trans);
1358
1359 test_webrtc_free (t);
1360 }
1361
1362 GST_END_TEST;
1363
GST_START_TEST(test_get_transceivers)1364 GST_START_TEST (test_get_transceivers)
1365 {
1366 struct test_webrtc *t = create_audio_test ();
1367 GstWebRTCRTPTransceiver *trans;
1368 GArray *transceivers;
1369
1370 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1371 fail_unless (transceivers != NULL);
1372 fail_unless_equals_int (1, transceivers->len);
1373
1374 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
1375 fail_unless (trans != NULL);
1376
1377 g_array_unref (transceivers);
1378
1379 test_webrtc_free (t);
1380 }
1381
1382 GST_END_TEST;
1383
GST_START_TEST(test_add_recvonly_transceiver)1384 GST_START_TEST (test_add_recvonly_transceiver)
1385 {
1386 struct test_webrtc *t = test_webrtc_new ();
1387 GstWebRTCRTPTransceiverDirection direction;
1388 GstWebRTCRTPTransceiver *trans;
1389 const gchar *expected_offer[] = { "recvonly" };
1390 const gchar *expected_answer[] = { "sendonly" };
1391 struct validate_sdp offer = { on_sdp_media_direction, expected_offer };
1392 struct validate_sdp answer = { on_sdp_media_direction, expected_answer };
1393 GstCaps *caps;
1394 GstHarness *h;
1395
1396 /* add a transceiver that will only receive an opus stream and check that
1397 * the created offer is marked as recvonly */
1398
1399 t->on_negotiation_needed = NULL;
1400 t->on_pad_added = _pad_added_fakesink;
1401 t->on_negotiation_needed = NULL;
1402 t->offer_data = &offer;
1403 t->on_offer_created = _check_validate_sdp;
1404 t->answer_data = &answer;
1405 t->on_answer_created = _check_validate_sdp;
1406 t->on_ice_candidate = NULL;
1407
1408 /* setup recvonly transceiver */
1409 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1410 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1411 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1412 &trans);
1413 gst_caps_unref (caps);
1414 fail_unless (trans != NULL);
1415 gst_object_unref (trans);
1416
1417 /* setup sendonly peer */
1418 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1419 add_fake_audio_src_harness (h, 96);
1420 t->harnesses = g_list_prepend (t->harnesses, h);
1421
1422 fail_if (gst_element_set_state (t->webrtc1,
1423 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1424 fail_if (gst_element_set_state (t->webrtc2,
1425 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1426
1427 test_webrtc_create_offer (t, t->webrtc1);
1428
1429 test_webrtc_wait_for_answer_error_eos (t);
1430 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
1431 test_webrtc_free (t);
1432 }
1433
1434 GST_END_TEST;
1435
GST_START_TEST(test_recvonly_sendonly)1436 GST_START_TEST (test_recvonly_sendonly)
1437 {
1438 struct test_webrtc *t = test_webrtc_new ();
1439 GstWebRTCRTPTransceiverDirection direction;
1440 GstWebRTCRTPTransceiver *trans;
1441 const gchar *expected_offer[] = { "recvonly", "sendonly" };
1442 const gchar *expected_answer[] = { "sendonly", "recvonly" };
1443 struct validate_sdp offer = { on_sdp_media_direction, expected_offer };
1444 struct validate_sdp answer = { on_sdp_media_direction, expected_answer };
1445 GstCaps *caps;
1446 GstHarness *h;
1447 GArray *transceivers;
1448
1449 /* add a transceiver that will only receive an opus stream and check that
1450 * the created offer is marked as recvonly */
1451
1452 t->on_negotiation_needed = NULL;
1453 t->on_pad_added = _pad_added_fakesink;
1454 t->on_negotiation_needed = NULL;
1455 t->offer_data = &offer;
1456 t->on_offer_created = _check_validate_sdp;
1457 t->answer_data = &answer;
1458 t->on_answer_created = _check_validate_sdp;
1459 t->on_ice_candidate = NULL;
1460
1461 /* setup recvonly transceiver */
1462 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1463 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1464 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1465 &trans);
1466 gst_caps_unref (caps);
1467 fail_unless (trans != NULL);
1468 gst_object_unref (trans);
1469
1470 /* setup sendonly stream */
1471 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1472 add_fake_audio_src_harness (h, 96);
1473 t->harnesses = g_list_prepend (t->harnesses, h);
1474 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1475 fail_unless (transceivers != NULL);
1476 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1477 trans->direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
1478
1479 g_array_unref (transceivers);
1480
1481 /* setup sendonly peer */
1482 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1483 add_fake_audio_src_harness (h, 96);
1484 t->harnesses = g_list_prepend (t->harnesses, h);
1485
1486 fail_if (gst_element_set_state (t->webrtc1,
1487 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1488 fail_if (gst_element_set_state (t->webrtc2,
1489 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1490
1491 test_webrtc_create_offer (t, t->webrtc1);
1492
1493 test_webrtc_wait_for_answer_error_eos (t);
1494 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
1495 test_webrtc_free (t);
1496 }
1497
1498 GST_END_TEST;
1499
1500 static void
on_sdp_has_datachannel(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)1501 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1502 GstWebRTCSessionDescription * desc, gpointer user_data)
1503 {
1504 gboolean have_data_channel = FALSE;
1505 int i;
1506
1507 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1508 if (_message_media_is_datachannel (desc->sdp, i)) {
1509 /* there should only be one data channel m= section */
1510 fail_unless_equals_int (FALSE, have_data_channel);
1511 have_data_channel = TRUE;
1512 }
1513 }
1514
1515 fail_unless_equals_int (TRUE, have_data_channel);
1516 }
1517
1518 static void
on_channel_error_not_reached(GObject * channel,GError * error,gpointer user_data)1519 on_channel_error_not_reached (GObject * channel, GError * error,
1520 gpointer user_data)
1521 {
1522 g_assert_not_reached ();
1523 }
1524
GST_START_TEST(test_data_channel_create)1525 GST_START_TEST (test_data_channel_create)
1526 {
1527 struct test_webrtc *t = test_webrtc_new ();
1528 GObject *channel = NULL;
1529 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1530 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1531 gchar *label;
1532
1533 t->on_negotiation_needed = NULL;
1534 t->offer_data = &offer;
1535 t->on_offer_created = _check_validate_sdp;
1536 t->answer_data = &answer;
1537 t->on_answer_created = _check_validate_sdp;
1538 t->on_ice_candidate = NULL;
1539
1540 fail_if (gst_element_set_state (t->webrtc1,
1541 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1542 fail_if (gst_element_set_state (t->webrtc2,
1543 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1544
1545 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1546 &channel);
1547 g_assert_nonnull (channel);
1548 g_object_get (channel, "label", &label, NULL);
1549 g_assert_cmpstr (label, ==, "label");
1550 g_signal_connect (channel, "on-error",
1551 G_CALLBACK (on_channel_error_not_reached), NULL);
1552
1553 test_webrtc_create_offer (t, t->webrtc1);
1554
1555 test_webrtc_wait_for_answer_error_eos (t);
1556 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
1557 g_object_unref (channel);
1558 g_free (label);
1559 test_webrtc_free (t);
1560 }
1561
1562 GST_END_TEST;
1563
1564 static void
have_data_channel(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1565 have_data_channel (struct test_webrtc *t, GstElement * element,
1566 GObject * our, gpointer user_data)
1567 {
1568 GObject *other = user_data;
1569 gchar *our_label, *other_label;
1570
1571 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1572 NULL);
1573
1574 g_object_get (our, "label", &our_label, NULL);
1575 g_object_get (other, "label", &other_label, NULL);
1576
1577 g_assert_cmpstr (our_label, ==, other_label);
1578
1579 g_free (our_label);
1580 g_free (other_label);
1581
1582 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1583 }
1584
GST_START_TEST(test_data_channel_remote_notify)1585 GST_START_TEST (test_data_channel_remote_notify)
1586 {
1587 struct test_webrtc *t = test_webrtc_new ();
1588 GObject *channel = NULL;
1589 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1590 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1591
1592 t->on_negotiation_needed = NULL;
1593 t->offer_data = &offer;
1594 t->on_offer_created = _check_validate_sdp;
1595 t->answer_data = &answer;
1596 t->on_answer_created = _check_validate_sdp;
1597 t->on_ice_candidate = NULL;
1598 t->on_data_channel = have_data_channel;
1599
1600 fail_if (gst_element_set_state (t->webrtc1,
1601 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1602 fail_if (gst_element_set_state (t->webrtc2,
1603 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1604
1605 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1606 &channel);
1607 g_assert_nonnull (channel);
1608 t->data_channel_data = channel;
1609 g_signal_connect (channel, "on-error",
1610 G_CALLBACK (on_channel_error_not_reached), NULL);
1611
1612 fail_if (gst_element_set_state (t->webrtc1,
1613 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1614 fail_if (gst_element_set_state (t->webrtc2,
1615 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1616
1617 test_webrtc_create_offer (t, t->webrtc1);
1618
1619 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1620
1621 g_object_unref (channel);
1622 test_webrtc_free (t);
1623 }
1624
1625 GST_END_TEST;
1626
1627 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1628
1629 static void
on_message_string(GObject * channel,const gchar * str,struct test_webrtc * t)1630 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1631 {
1632 gchar *expected = g_object_steal_data (channel, "expected");
1633 g_assert_cmpstr (expected, ==, str);
1634 g_free (expected);
1635
1636 test_webrtc_signal_state (t, STATE_CUSTOM);
1637 }
1638
1639 static void
have_data_channel_transfer_string(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1640 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1641 GObject * our, gpointer user_data)
1642 {
1643 GObject *other = user_data;
1644 GstWebRTCDataChannelState state;
1645
1646 g_object_get (our, "ready-state", &state, NULL);
1647 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1648 g_object_get (other, "ready-state", &state, NULL);
1649 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1650
1651 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1652 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1653 t);
1654
1655 g_signal_connect (other, "on-error",
1656 G_CALLBACK (on_channel_error_not_reached), NULL);
1657 g_signal_emit_by_name (other, "send-string", test_string);
1658 }
1659
GST_START_TEST(test_data_channel_transfer_string)1660 GST_START_TEST (test_data_channel_transfer_string)
1661 {
1662 struct test_webrtc *t = test_webrtc_new ();
1663 GObject *channel = NULL;
1664 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1665 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1666
1667 t->on_negotiation_needed = NULL;
1668 t->offer_data = &offer;
1669 t->on_offer_created = _check_validate_sdp;
1670 t->answer_data = &answer;
1671 t->on_answer_created = _check_validate_sdp;
1672 t->on_ice_candidate = NULL;
1673 t->on_data_channel = have_data_channel_transfer_string;
1674
1675 fail_if (gst_element_set_state (t->webrtc1,
1676 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1677 fail_if (gst_element_set_state (t->webrtc2,
1678 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1679
1680 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1681 &channel);
1682 g_assert_nonnull (channel);
1683 t->data_channel_data = channel;
1684 g_signal_connect (channel, "on-error",
1685 G_CALLBACK (on_channel_error_not_reached), NULL);
1686
1687 fail_if (gst_element_set_state (t->webrtc1,
1688 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1689 fail_if (gst_element_set_state (t->webrtc2,
1690 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1691
1692 test_webrtc_create_offer (t, t->webrtc1);
1693
1694 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1695
1696 g_object_unref (channel);
1697 test_webrtc_free (t);
1698 }
1699
1700 GST_END_TEST;
1701
1702 #define g_assert_cmpbytes(b1, b2) \
1703 G_STMT_START { \
1704 gsize l1, l2; \
1705 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1706 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1707 g_assert_cmpmem (d1, l1, d2, l2); \
1708 } G_STMT_END;
1709
1710 static void
on_message_data(GObject * channel,GBytes * data,struct test_webrtc * t)1711 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1712 {
1713 GBytes *expected = g_object_steal_data (channel, "expected");
1714 g_assert_cmpbytes (data, expected);
1715 g_bytes_unref (expected);
1716
1717 test_webrtc_signal_state (t, STATE_CUSTOM);
1718 }
1719
1720 static void
have_data_channel_transfer_data(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1721 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1722 GObject * our, gpointer user_data)
1723 {
1724 GObject *other = user_data;
1725 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1726 GstWebRTCDataChannelState state;
1727
1728 g_object_get (our, "ready-state", &state, NULL);
1729 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1730 g_object_get (other, "ready-state", &state, NULL);
1731 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1732
1733 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1734 (GDestroyNotify) g_bytes_unref);
1735 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1736
1737 g_signal_connect (other, "on-error",
1738 G_CALLBACK (on_channel_error_not_reached), NULL);
1739 g_signal_emit_by_name (other, "send-data", data);
1740 }
1741
GST_START_TEST(test_data_channel_transfer_data)1742 GST_START_TEST (test_data_channel_transfer_data)
1743 {
1744 struct test_webrtc *t = test_webrtc_new ();
1745 GObject *channel = NULL;
1746 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1747 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1748
1749 t->on_negotiation_needed = NULL;
1750 t->offer_data = &offer;
1751 t->on_offer_created = _check_validate_sdp;
1752 t->answer_data = &answer;
1753 t->on_answer_created = _check_validate_sdp;
1754 t->on_ice_candidate = NULL;
1755 t->on_data_channel = have_data_channel_transfer_data;
1756
1757 fail_if (gst_element_set_state (t->webrtc1,
1758 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1759 fail_if (gst_element_set_state (t->webrtc2,
1760 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1761
1762 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1763 &channel);
1764 g_assert_nonnull (channel);
1765 t->data_channel_data = channel;
1766 g_signal_connect (channel, "on-error",
1767 G_CALLBACK (on_channel_error_not_reached), NULL);
1768
1769 fail_if (gst_element_set_state (t->webrtc1,
1770 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1771 fail_if (gst_element_set_state (t->webrtc2,
1772 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1773
1774 test_webrtc_create_offer (t, t->webrtc1);
1775
1776 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1777
1778 g_object_unref (channel);
1779 test_webrtc_free (t);
1780 }
1781
1782 GST_END_TEST;
1783
1784 static void
have_data_channel_create_data_channel(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1785 have_data_channel_create_data_channel (struct test_webrtc *t,
1786 GstElement * element, GObject * our, gpointer user_data)
1787 {
1788 GObject *another;
1789
1790 t->on_data_channel = have_data_channel_transfer_string;
1791
1792 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1793 &another);
1794 g_assert_nonnull (another);
1795 t->data_channel_data = another;
1796 g_signal_connect (another, "on-error",
1797 G_CALLBACK (on_channel_error_not_reached), NULL);
1798 }
1799
GST_START_TEST(test_data_channel_create_after_negotiate)1800 GST_START_TEST (test_data_channel_create_after_negotiate)
1801 {
1802 struct test_webrtc *t = test_webrtc_new ();
1803 GObject *channel = NULL;
1804 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1805 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1806
1807 t->on_negotiation_needed = NULL;
1808 t->offer_data = &offer;
1809 t->on_offer_created = _check_validate_sdp;
1810 t->answer_data = &answer;
1811 t->on_answer_created = _check_validate_sdp;
1812 t->on_ice_candidate = NULL;
1813 t->on_data_channel = have_data_channel_create_data_channel;
1814
1815 fail_if (gst_element_set_state (t->webrtc1,
1816 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1817 fail_if (gst_element_set_state (t->webrtc2,
1818 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1819
1820 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
1821 &channel);
1822 g_assert_nonnull (channel);
1823 t->data_channel_data = channel;
1824 g_signal_connect (channel, "on-error",
1825 G_CALLBACK (on_channel_error_not_reached), NULL);
1826
1827 fail_if (gst_element_set_state (t->webrtc1,
1828 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1829 fail_if (gst_element_set_state (t->webrtc2,
1830 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1831
1832 test_webrtc_create_offer (t, t->webrtc1);
1833
1834 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1835
1836 g_object_unref (channel);
1837 test_webrtc_free (t);
1838 }
1839
1840 GST_END_TEST;
1841
1842 static void
on_buffered_amount_low_emitted(GObject * channel,struct test_webrtc * t)1843 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
1844 {
1845 test_webrtc_signal_state (t, STATE_CUSTOM);
1846 }
1847
1848 static void
have_data_channel_check_low_threshold_emitted(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1849 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
1850 GstElement * element, GObject * our, gpointer user_data)
1851 {
1852 g_signal_connect (our, "on-buffered-amount-low",
1853 G_CALLBACK (on_buffered_amount_low_emitted), t);
1854 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
1855
1856 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1857 NULL);
1858 g_signal_emit_by_name (our, "send-string", "DATA");
1859 }
1860
GST_START_TEST(test_data_channel_low_threshold)1861 GST_START_TEST (test_data_channel_low_threshold)
1862 {
1863 struct test_webrtc *t = test_webrtc_new ();
1864 GObject *channel = NULL;
1865 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1866 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1867
1868 t->on_negotiation_needed = NULL;
1869 t->offer_data = &offer;
1870 t->on_offer_created = _check_validate_sdp;
1871 t->answer_data = &answer;
1872 t->on_answer_created = _check_validate_sdp;
1873 t->on_ice_candidate = NULL;
1874 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
1875
1876 fail_if (gst_element_set_state (t->webrtc1,
1877 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1878 fail_if (gst_element_set_state (t->webrtc2,
1879 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1880
1881 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1882 &channel);
1883 g_assert_nonnull (channel);
1884 t->data_channel_data = channel;
1885 g_signal_connect (channel, "on-error",
1886 G_CALLBACK (on_channel_error_not_reached), NULL);
1887
1888 fail_if (gst_element_set_state (t->webrtc1,
1889 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1890 fail_if (gst_element_set_state (t->webrtc2,
1891 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1892
1893 test_webrtc_create_offer (t, t->webrtc1);
1894
1895 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1896
1897 g_object_unref (channel);
1898 test_webrtc_free (t);
1899 }
1900
1901 GST_END_TEST;
1902
1903 static void
on_channel_error(GObject * channel,GError * error,struct test_webrtc * t)1904 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
1905 {
1906 g_assert_nonnull (error);
1907
1908 test_webrtc_signal_state (t, STATE_CUSTOM);
1909 }
1910
1911 static void
have_data_channel_transfer_large_data(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1912 have_data_channel_transfer_large_data (struct test_webrtc *t,
1913 GstElement * element, GObject * our, gpointer user_data)
1914 {
1915 GObject *other = user_data;
1916 const gsize size = 1024 * 1024;
1917 guint8 *random_data = g_new (guint8, size);
1918 GBytes *data;
1919 gsize i;
1920
1921 for (i = 0; i < size; i++)
1922 random_data[i] = (guint8) (i & 0xff);
1923
1924 data = g_bytes_new_static (random_data, size);
1925
1926 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1927 (GDestroyNotify) g_bytes_unref);
1928 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1929
1930 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
1931 g_signal_emit_by_name (other, "send-data", data);
1932 }
1933
GST_START_TEST(test_data_channel_max_message_size)1934 GST_START_TEST (test_data_channel_max_message_size)
1935 {
1936 struct test_webrtc *t = test_webrtc_new ();
1937 GObject *channel = NULL;
1938 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1939 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1940
1941 t->on_negotiation_needed = NULL;
1942 t->offer_data = &offer;
1943 t->on_offer_created = _check_validate_sdp;
1944 t->answer_data = &answer;
1945 t->on_answer_created = _check_validate_sdp;
1946 t->on_ice_candidate = NULL;
1947 t->on_data_channel = have_data_channel_transfer_large_data;
1948
1949 fail_if (gst_element_set_state (t->webrtc1,
1950 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1951 fail_if (gst_element_set_state (t->webrtc2,
1952 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1953
1954 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1955 &channel);
1956 g_assert_nonnull (channel);
1957 t->data_channel_data = channel;
1958
1959 fail_if (gst_element_set_state (t->webrtc1,
1960 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1961 fail_if (gst_element_set_state (t->webrtc2,
1962 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1963
1964 test_webrtc_create_offer (t, t->webrtc1);
1965
1966 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1967
1968 g_object_unref (channel);
1969 test_webrtc_free (t);
1970 }
1971
1972 GST_END_TEST;
1973
1974 static void
_on_ready_state_notify(GObject * channel,GParamSpec * pspec,struct test_webrtc * t)1975 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
1976 struct test_webrtc *t)
1977 {
1978 gint *n_ready = t->data_channel_data;
1979 GstWebRTCDataChannelState ready_state;
1980
1981 g_object_get (channel, "ready-state", &ready_state, NULL);
1982
1983 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
1984 if (++(*n_ready) >= 2)
1985 test_webrtc_signal_state (t, STATE_CUSTOM);
1986 }
1987 }
1988
GST_START_TEST(test_data_channel_pre_negotiated)1989 GST_START_TEST (test_data_channel_pre_negotiated)
1990 {
1991 struct test_webrtc *t = test_webrtc_new ();
1992 GObject *channel1 = NULL, *channel2 = NULL;
1993 struct validate_sdp offer = { on_sdp_has_datachannel, NULL };
1994 struct validate_sdp answer = { on_sdp_has_datachannel, NULL };
1995 GstStructure *s;
1996 gint n_ready = 0;
1997
1998 t->on_negotiation_needed = NULL;
1999 t->offer_data = &offer;
2000 t->on_offer_created = _check_validate_sdp;
2001 t->answer_data = &answer;
2002 t->on_answer_created = _check_validate_sdp;
2003 t->on_ice_candidate = NULL;
2004
2005 fail_if (gst_element_set_state (t->webrtc1,
2006 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2007 fail_if (gst_element_set_state (t->webrtc2,
2008 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2009
2010 s = gst_structure_new ("application/data-channel", "negotiated",
2011 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
2012
2013 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
2014 &channel1);
2015 g_assert_nonnull (channel1);
2016 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
2017 &channel2);
2018 g_assert_nonnull (channel2);
2019
2020 fail_if (gst_element_set_state (t->webrtc1,
2021 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2022 fail_if (gst_element_set_state (t->webrtc2,
2023 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2024
2025 test_webrtc_create_offer (t, t->webrtc1);
2026 test_webrtc_wait_for_answer_error_eos (t);
2027 fail_unless (t->state == STATE_ANSWER_CREATED);
2028
2029 t->data_channel_data = &n_ready;
2030
2031 g_signal_connect (channel1, "notify::ready-state",
2032 G_CALLBACK (_on_ready_state_notify), t);
2033 g_signal_connect (channel2, "notify::ready-state",
2034 G_CALLBACK (_on_ready_state_notify), t);
2035
2036 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2037 test_webrtc_signal_state (t, STATE_NEW);
2038
2039 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
2040
2041 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2042
2043 g_object_unref (channel1);
2044 g_object_unref (channel2);
2045 gst_structure_free (s);
2046 test_webrtc_free (t);
2047 }
2048
2049 GST_END_TEST;
2050
2051 typedef struct
2052 {
2053 guint num_media;
2054 guint num_active_media;
2055 const gchar **bundled;
2056 const gchar **bundled_only;
2057 } BundleCheckData;
2058
2059 static void
_check_bundled_sdp_media(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * sd,gpointer user_data)2060 _check_bundled_sdp_media (struct test_webrtc *t, GstElement * element,
2061 GstWebRTCSessionDescription * sd, gpointer user_data)
2062 {
2063 gchar **bundled = NULL;
2064 BundleCheckData *data = (BundleCheckData *) user_data;
2065 guint i;
2066 guint active_media;
2067
2068 fail_unless_equals_int (gst_sdp_message_medias_len (sd->sdp),
2069 data->num_media);
2070
2071 fail_unless (_parse_bundle (sd->sdp, &bundled));
2072
2073 if (!bundled) {
2074 fail_unless_equals_int (g_strv_length ((GStrv) data->bundled), 0);
2075 } else {
2076 fail_unless_equals_int (g_strv_length (bundled),
2077 g_strv_length ((GStrv) data->bundled));
2078 }
2079
2080 for (i = 0; data->bundled[i]; i++) {
2081 fail_unless (g_strv_contains ((const gchar **) bundled, data->bundled[i]));
2082 }
2083
2084 active_media = 0;
2085
2086 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2087 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2088 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2089
2090 if (g_strv_contains ((const gchar **) data->bundled_only, mid))
2091 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2092
2093 if (gst_sdp_media_get_port (media) != 0)
2094 active_media += 1;
2095 }
2096
2097 fail_unless_equals_int (active_media, data->num_active_media);
2098
2099 if (bundled)
2100 g_strfreev (bundled);
2101 }
2102
GST_START_TEST(test_bundle_audio_video_max_bundle_max_bundle)2103 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2104 {
2105 struct test_webrtc *t = create_audio_video_test ();
2106 const gchar *bundle[] = { "audio0", "video1", NULL };
2107 const gchar *offer_bundle_only[] = { "video1", 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
2112 * as bundle-only
2113 */
2114 BundleCheckData offer_data = {
2115 2,
2116 1,
2117 bundle,
2118 offer_bundle_only,
2119 };
2120 /* We also set a max-bundle policy on the answering webrtcbin,
2121 * this means that all the offered medias should be part
2122 * of the group:BUNDLE attribute, but need not be marked
2123 * as bundle-only.
2124 */
2125 BundleCheckData answer_data = {
2126 2,
2127 2,
2128 bundle,
2129 answer_bundle_only,
2130 };
2131 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data };
2132 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data };
2133
2134 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2135 "max-bundle");
2136 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2137 "max-bundle");
2138
2139 t->on_negotiation_needed = NULL;
2140 t->offer_data = &offer;
2141 t->on_offer_created = _check_validate_sdp;
2142 t->answer_data = &answer;
2143 t->on_answer_created = _check_validate_sdp;
2144 t->on_ice_candidate = NULL;
2145
2146 fail_if (gst_element_set_state (t->webrtc1,
2147 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2148 fail_if (gst_element_set_state (t->webrtc2,
2149 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2150
2151 test_webrtc_create_offer (t, t->webrtc1);
2152
2153 test_webrtc_wait_for_answer_error_eos (t);
2154 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
2155
2156 test_webrtc_free (t);
2157 }
2158
2159 GST_END_TEST;
2160
GST_START_TEST(test_bundle_audio_video_max_compat_max_bundle)2161 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2162 {
2163 struct test_webrtc *t = create_audio_video_test ();
2164 const gchar *bundle[] = { "audio0", "video1", NULL };
2165 const gchar *bundle_only[] = { NULL };
2166 /* We set a max-compat policy on the offering webrtcbin,
2167 * this means that all the offered medias should be part
2168 * of the group:BUNDLE attribute, and they should *not* be marked
2169 * as bundle-only
2170 */
2171 BundleCheckData offer_data = {
2172 2,
2173 2,
2174 bundle,
2175 bundle_only,
2176 };
2177 /* We set a max-bundle policy on the answering webrtcbin,
2178 * this means that all the offered medias should be part
2179 * of the group:BUNDLE attribute, but need not be marked
2180 * as bundle-only.
2181 */
2182 BundleCheckData answer_data = {
2183 2,
2184 2,
2185 bundle,
2186 bundle_only,
2187 };
2188 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data };
2189 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data };
2190
2191 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2192 "max-compat");
2193 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2194 "max-bundle");
2195
2196 t->on_negotiation_needed = NULL;
2197 t->offer_data = &offer;
2198 t->on_offer_created = _check_validate_sdp;
2199 t->answer_data = &answer;
2200 t->on_answer_created = _check_validate_sdp;
2201 t->on_ice_candidate = NULL;
2202
2203 fail_if (gst_element_set_state (t->webrtc1,
2204 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2205 fail_if (gst_element_set_state (t->webrtc2,
2206 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2207
2208 test_webrtc_create_offer (t, t->webrtc1);
2209
2210 test_webrtc_wait_for_answer_error_eos (t);
2211 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
2212
2213 test_webrtc_free (t);
2214 }
2215
2216 GST_END_TEST;
2217
GST_START_TEST(test_bundle_audio_video_max_bundle_none)2218 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2219 {
2220 struct test_webrtc *t = create_audio_video_test ();
2221 const gchar *offer_bundle[] = { "audio0", "video1", NULL };
2222 const gchar *offer_bundle_only[] = { "video1", NULL };
2223 const gchar *answer_bundle[] = { NULL };
2224 const gchar *answer_bundle_only[] = { NULL };
2225 /* We set a max-bundle policy on the offering webrtcbin,
2226 * this means that all the offered medias should be part
2227 * of the group:BUNDLE attribute, and they should be marked
2228 * as bundle-only
2229 */
2230 BundleCheckData offer_data = {
2231 2,
2232 1,
2233 offer_bundle,
2234 offer_bundle_only,
2235 };
2236 /* We set a none policy on the answering webrtcbin,
2237 * this means that the answer should contain no bundled
2238 * medias, and as the bundle-policy of the offering webrtcbin
2239 * is set to max-bundle, only one media should be active.
2240 */
2241 BundleCheckData answer_data = {
2242 2,
2243 1,
2244 answer_bundle,
2245 answer_bundle_only,
2246 };
2247 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data };
2248 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data };
2249
2250 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2251 "max-bundle");
2252 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2253
2254 t->on_negotiation_needed = NULL;
2255 t->offer_data = &offer;
2256 t->on_offer_created = _check_validate_sdp;
2257 t->answer_data = &answer;
2258 t->on_answer_created = _check_validate_sdp;
2259 t->on_ice_candidate = NULL;
2260
2261 fail_if (gst_element_set_state (t->webrtc1,
2262 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2263 fail_if (gst_element_set_state (t->webrtc2,
2264 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2265
2266 test_webrtc_create_offer (t, t->webrtc1);
2267
2268 test_webrtc_wait_for_answer_error_eos (t);
2269 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
2270
2271 test_webrtc_free (t);
2272 }
2273
2274 GST_END_TEST;
2275
GST_START_TEST(test_bundle_audio_video_data)2276 GST_START_TEST (test_bundle_audio_video_data)
2277 {
2278 struct test_webrtc *t = create_audio_video_test ();
2279 const gchar *bundle[] = { "audio0", "video1", "application2", NULL };
2280 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2281 const gchar *answer_bundle_only[] = { NULL };
2282 GObject *channel = NULL;
2283 /* We set a max-bundle policy on the offering webrtcbin,
2284 * this means that all the offered medias should be part
2285 * of the group:BUNDLE attribute, and they should be marked
2286 * as bundle-only
2287 */
2288 BundleCheckData offer_data = {
2289 3,
2290 1,
2291 bundle,
2292 offer_bundle_only,
2293 };
2294 /* We also set a max-bundle policy on the answering webrtcbin,
2295 * this means that all the offered medias should be part
2296 * of the group:BUNDLE attribute, but need not be marked
2297 * as bundle-only.
2298 */
2299 BundleCheckData answer_data = {
2300 3,
2301 3,
2302 bundle,
2303 answer_bundle_only,
2304 };
2305 struct validate_sdp offer = { _check_bundled_sdp_media, &offer_data };
2306 struct validate_sdp answer = { _check_bundled_sdp_media, &answer_data };
2307
2308 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2309 "max-bundle");
2310 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2311 "max-bundle");
2312
2313 t->on_negotiation_needed = NULL;
2314 t->offer_data = &offer;
2315 t->on_offer_created = _check_validate_sdp;
2316 t->answer_data = &answer;
2317 t->on_answer_created = _check_validate_sdp;
2318 t->on_ice_candidate = NULL;
2319
2320 fail_if (gst_element_set_state (t->webrtc1,
2321 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2322 fail_if (gst_element_set_state (t->webrtc2,
2323 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2324
2325 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2326 &channel);
2327
2328 test_webrtc_create_offer (t, t->webrtc1);
2329
2330 test_webrtc_wait_for_answer_error_eos (t);
2331 fail_unless_equals_int (STATE_ANSWER_CREATED, t->state);
2332
2333 g_object_unref (channel);
2334 test_webrtc_free (t);
2335 }
2336
2337 GST_END_TEST;
2338
2339 static Suite *
webrtcbin_suite(void)2340 webrtcbin_suite (void)
2341 {
2342 Suite *s = suite_create ("webrtcbin");
2343 TCase *tc = tcase_create ("general");
2344 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
2345 GstPluginFeature *sctpenc, *sctpdec;
2346 GstRegistry *registry;
2347
2348 registry = gst_registry_get ();
2349 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
2350 nicesink = gst_registry_lookup_feature (registry, "nicesink");
2351 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
2352 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
2353 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
2354 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
2355
2356 tcase_add_test (tc, test_no_nice_elements_request_pad);
2357 tcase_add_test (tc, test_no_nice_elements_state_change);
2358 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
2359 tcase_add_test (tc, test_sdp_no_media);
2360 tcase_add_test (tc, test_session_stats);
2361 tcase_add_test (tc, test_audio);
2362 tcase_add_test (tc, test_audio_video);
2363 tcase_add_test (tc, test_media_direction);
2364 tcase_add_test (tc, test_media_setup);
2365 tcase_add_test (tc, test_add_transceiver);
2366 tcase_add_test (tc, test_get_transceivers);
2367 tcase_add_test (tc, test_add_recvonly_transceiver);
2368 tcase_add_test (tc, test_recvonly_sendonly);
2369 tcase_add_test (tc, test_payload_types);
2370 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
2371 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
2372 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
2373 if (sctpenc && sctpdec) {
2374 tcase_add_test (tc, test_data_channel_create);
2375 tcase_add_test (tc, test_data_channel_remote_notify);
2376 tcase_add_test (tc, test_data_channel_transfer_string);
2377 tcase_add_test (tc, test_data_channel_transfer_data);
2378 tcase_add_test (tc, test_data_channel_create_after_negotiate);
2379 tcase_add_test (tc, test_data_channel_low_threshold);
2380 tcase_add_test (tc, test_data_channel_max_message_size);
2381 tcase_add_test (tc, test_data_channel_pre_negotiated);
2382 tcase_add_test (tc, test_bundle_audio_video_data);
2383 } else {
2384 GST_WARNING ("Some required elements were not found. "
2385 "All datachannel are disabled. sctpenc %p, sctpdec %p", sctpenc,
2386 sctpdec);
2387 }
2388 } else {
2389 GST_WARNING ("Some required elements were not found. "
2390 "All media tests are disabled. nicesrc %p, nicesink %p, "
2391 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
2392 dtlssrtpdec);
2393 }
2394
2395 if (nicesrc)
2396 gst_object_unref (nicesrc);
2397 if (nicesink)
2398 gst_object_unref (nicesink);
2399 if (dtlssrtpdec)
2400 gst_object_unref (dtlssrtpdec);
2401 if (dtlssrtpenc)
2402 gst_object_unref (dtlssrtpenc);
2403 if (sctpenc)
2404 gst_object_unref (sctpenc);
2405 if (sctpdec)
2406 gst_object_unref (sctpdec);
2407
2408 suite_add_tcase (s, tc);
2409
2410 return s;
2411 }
2412
2413 GST_CHECK_MAIN (webrtcbin);
2414