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 #define H264_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=H264,media=video,clock-rate=90000,ssrc=(uint)3484078951"
40
41 #define TEST_IS_OFFER_ELEMENT(t, e) ((((t)->offerror == 1 && (e) == (t)->webrtc1) || ((t)->offerror == 2 && (e) == (t)->webrtc2)) ? TRUE : FALSE)
42 #define TEST_GET_OFFEROR(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc1 : t->webrtc2)
43 #define TEST_GET_ANSWERER(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc2 : t->webrtc1)
44
45 #define TEST_SDP_IS_LOCAL(t, e, d) ((TEST_IS_OFFER_ELEMENT (t, e) ^ ((d)->type == GST_WEBRTC_SDP_TYPE_OFFER)) == 0)
46
47 typedef enum
48 {
49 STATE_NEW,
50 STATE_NEGOTIATION_NEEDED,
51 STATE_OFFER_CREATED,
52 STATE_OFFER_SET,
53 STATE_ANSWER_CREATED,
54 STATE_ANSWER_SET,
55 STATE_EOS,
56 STATE_ERROR,
57 STATE_CUSTOM,
58 } TestState;
59
60 /* basic premise of this is that webrtc1 and webrtc2 are attempting to connect
61 * to each other in various configurations */
62 struct test_webrtc;
63 struct test_webrtc
64 {
65 GList *harnesses;
66 GstTestClock *test_clock;
67 GThread *thread;
68 GMainLoop *loop;
69 GstBus *bus1;
70 GstBus *bus2;
71 GstElement *webrtc1;
72 GstElement *webrtc2;
73 GMutex lock;
74 GCond cond;
75 TestState state;
76 guint offerror;
77 gpointer user_data;
78 GDestroyNotify data_notify;
79 /* *INDENT-OFF* */
80 void (*on_negotiation_needed) (struct test_webrtc * t,
81 GstElement * element,
82 gpointer user_data);
83 gpointer negotiation_data;
84 GDestroyNotify negotiation_notify;
85 void (*on_ice_candidate) (struct test_webrtc * t,
86 GstElement * element,
87 guint mlineindex,
88 gchar * candidate,
89 GstElement * other,
90 gpointer user_data);
91 gpointer ice_candidate_data;
92 GDestroyNotify ice_candidate_notify;
93 void (*on_offer_created) (struct test_webrtc * t,
94 GstElement * element,
95 GstPromise * promise,
96 gpointer user_data);
97 GstWebRTCSessionDescription *offer_desc;
98 guint offer_set_count;
99 gpointer offer_data;
100 GDestroyNotify offer_notify;
101 void (*on_offer_set) (struct test_webrtc * t,
102 GstElement * element,
103 GstPromise * promise,
104 gpointer user_data);
105 gpointer offer_set_data;
106 GDestroyNotify offer_set_notify;
107 void (*on_answer_created) (struct test_webrtc * t,
108 GstElement * element,
109 GstPromise * promise,
110 gpointer user_data);
111 GstWebRTCSessionDescription *answer_desc;
112 guint answer_set_count;
113 gpointer answer_data;
114 GDestroyNotify answer_notify;
115 void (*on_answer_set) (struct test_webrtc * t,
116 GstElement * element,
117 GstPromise * promise,
118 gpointer user_data);
119 gpointer answer_set_data;
120 GDestroyNotify answer_set_notify;
121 void (*on_data_channel) (struct test_webrtc * t,
122 GstElement * element,
123 GObject *data_channel,
124 gpointer user_data);
125 gpointer data_channel_data;
126 GDestroyNotify data_channel_notify;
127 void (*on_pad_added) (struct test_webrtc * t,
128 GstElement * element,
129 GstPad * pad,
130 gpointer user_data);
131 gpointer pad_added_data;
132 GDestroyNotify pad_added_notify;
133 void (*bus_message) (struct test_webrtc * t,
134 GstBus * bus,
135 GstMessage * msg,
136 gpointer user_data);
137 gpointer bus_data;
138 GDestroyNotify bus_notify;
139 /* *INDENT-ON* */
140 };
141
142 static void
test_webrtc_signal_state_unlocked(struct test_webrtc * t,TestState state)143 test_webrtc_signal_state_unlocked (struct test_webrtc *t, TestState state)
144 {
145 t->state = state;
146 g_cond_broadcast (&t->cond);
147 }
148
149 static void
test_webrtc_signal_state(struct test_webrtc * t,TestState state)150 test_webrtc_signal_state (struct test_webrtc *t, TestState state)
151 {
152 g_mutex_lock (&t->lock);
153 test_webrtc_signal_state_unlocked (t, state);
154 g_mutex_unlock (&t->lock);
155 }
156
157 static void
_on_answer_set(GstPromise * promise,gpointer user_data)158 _on_answer_set (GstPromise * promise, gpointer user_data)
159 {
160 struct test_webrtc *t = user_data;
161 GstElement *answerer = TEST_GET_ANSWERER (t);
162
163 g_mutex_lock (&t->lock);
164 if (++t->answer_set_count >= 2) {
165 if (t->on_answer_set)
166 t->on_answer_set (t, answerer, promise, t->answer_set_data);
167 if (t->state == STATE_ANSWER_CREATED)
168 t->state = STATE_ANSWER_SET;
169 g_cond_broadcast (&t->cond);
170 }
171 gst_promise_unref (promise);
172 g_mutex_unlock (&t->lock);
173 }
174
175 static void
_on_answer_received(GstPromise * promise,gpointer user_data)176 _on_answer_received (GstPromise * promise, gpointer user_data)
177 {
178 struct test_webrtc *t = user_data;
179 GstElement *offeror = TEST_GET_OFFEROR (t);
180 GstElement *answerer = TEST_GET_ANSWERER (t);
181 const GstStructure *reply;
182 GstWebRTCSessionDescription *answer = NULL;
183 GError *error = NULL;
184
185 reply = gst_promise_get_reply (promise);
186 if (gst_structure_get (reply, "answer",
187 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL)) {
188 gchar *desc = gst_sdp_message_as_text (answer->sdp);
189 GST_INFO ("Created Answer: %s", desc);
190 g_free (desc);
191 } else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
192 GST_INFO ("Creating answer resulted in error: %s", error->message);
193 } else {
194 g_assert_not_reached ();
195 }
196
197 g_mutex_lock (&t->lock);
198
199 g_assert (t->answer_desc == NULL);
200 t->answer_desc = answer;
201
202 if (t->on_answer_created) {
203 t->on_answer_created (t, answerer, promise, t->answer_data);
204 }
205 gst_promise_unref (promise);
206
207 if (error)
208 goto error;
209
210 if (t->answer_desc) {
211 promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
212 g_signal_emit_by_name (answerer, "set-local-description", t->answer_desc,
213 promise);
214 promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
215 g_signal_emit_by_name (offeror, "set-remote-description", t->answer_desc,
216 promise);
217 }
218
219 test_webrtc_signal_state_unlocked (t, STATE_ANSWER_CREATED);
220 g_mutex_unlock (&t->lock);
221 return;
222
223 error:
224 g_clear_error (&error);
225 if (t->state < STATE_ERROR)
226 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
227 g_mutex_unlock (&t->lock);
228 return;
229 }
230
231 static void
_on_offer_set(GstPromise * promise,gpointer user_data)232 _on_offer_set (GstPromise * promise, gpointer user_data)
233 {
234 struct test_webrtc *t = user_data;
235 GstElement *offeror = TEST_GET_OFFEROR (t);
236
237 g_mutex_lock (&t->lock);
238 if (++t->offer_set_count >= 2) {
239 if (t->on_offer_set)
240 t->on_offer_set (t, offeror, promise, t->offer_set_data);
241 if (t->state == STATE_OFFER_CREATED)
242 t->state = STATE_OFFER_SET;
243 g_cond_broadcast (&t->cond);
244 }
245 gst_promise_unref (promise);
246 g_mutex_unlock (&t->lock);
247 }
248
249 static void
_on_offer_received(GstPromise * promise,gpointer user_data)250 _on_offer_received (GstPromise * promise, gpointer user_data)
251 {
252 struct test_webrtc *t = user_data;
253 GstElement *offeror = TEST_GET_OFFEROR (t);
254 GstElement *answerer = TEST_GET_ANSWERER (t);
255 const GstStructure *reply;
256 GstWebRTCSessionDescription *offer = NULL;
257 GError *error = NULL;
258
259 reply = gst_promise_get_reply (promise);
260 if (gst_structure_get (reply, "offer",
261 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL)) {
262 gchar *desc = gst_sdp_message_as_text (offer->sdp);
263 GST_INFO ("Created offer: %s", desc);
264 g_free (desc);
265 } else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
266 GST_INFO ("Creating offer resulted in error: %s", error->message);
267 } else {
268 g_assert_not_reached ();
269 }
270
271 g_mutex_lock (&t->lock);
272
273 g_assert (t->offer_desc == NULL);
274 t->offer_desc = offer;
275
276 if (t->on_offer_created) {
277 t->on_offer_created (t, offeror, promise, t->offer_data);
278 }
279 gst_promise_unref (promise);
280
281 if (error)
282 goto error;
283
284 if (t->offer_desc) {
285 promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
286 g_signal_emit_by_name (offeror, "set-local-description", t->offer_desc,
287 promise);
288 promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
289 g_signal_emit_by_name (answerer, "set-remote-description", t->offer_desc,
290 promise);
291
292 promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
293 g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
294 }
295
296 test_webrtc_signal_state_unlocked (t, STATE_OFFER_CREATED);
297 g_mutex_unlock (&t->lock);
298 return;
299
300 error:
301 g_clear_error (&error);
302 if (t->state < STATE_ERROR)
303 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
304 g_mutex_unlock (&t->lock);
305 return;
306 }
307
308 static gboolean
_bus_watch(GstBus * bus,GstMessage * msg,struct test_webrtc * t)309 _bus_watch (GstBus * bus, GstMessage * msg, struct test_webrtc *t)
310 {
311 g_mutex_lock (&t->lock);
312 switch (GST_MESSAGE_TYPE (msg)) {
313 case GST_MESSAGE_STATE_CHANGED:
314 if (GST_ELEMENT (msg->src) == t->webrtc1
315 || GST_ELEMENT (msg->src) == t->webrtc2) {
316 GstState old, new, pending;
317
318 gst_message_parse_state_changed (msg, &old, &new, &pending);
319
320 {
321 gchar *dump_name = g_strconcat ("%s-state_changed-",
322 GST_OBJECT_NAME (msg->src), gst_element_state_get_name (old), "_",
323 gst_element_state_get_name (new), NULL);
324 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
325 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
326 g_free (dump_name);
327 }
328 }
329 break;
330 case GST_MESSAGE_ERROR:{
331 GError *err = NULL;
332 gchar *dbg_info = NULL;
333
334 {
335 gchar *dump_name;
336 dump_name =
337 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc1), NULL);
338 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
339 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
340 g_free (dump_name);
341 dump_name =
342 g_strconcat ("%s-error", GST_OBJECT_NAME (t->webrtc2), NULL);
343 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
344 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
345 g_free (dump_name);
346 }
347
348 gst_message_parse_error (msg, &err, &dbg_info);
349 GST_WARNING ("ERROR from element %s: %s",
350 GST_OBJECT_NAME (msg->src), err->message);
351 GST_WARNING ("Debugging info: %s", (dbg_info) ? dbg_info : "none");
352 g_error_free (err);
353 g_free (dbg_info);
354 test_webrtc_signal_state_unlocked (t, STATE_ERROR);
355 break;
356 }
357 case GST_MESSAGE_EOS:{
358 {
359 gchar *dump_name;
360 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc1), NULL);
361 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc1),
362 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
363 g_free (dump_name);
364 dump_name = g_strconcat ("%s-eos", GST_OBJECT_NAME (t->webrtc2), NULL);
365 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (t->webrtc2),
366 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
367 g_free (dump_name);
368 }
369 GST_INFO ("EOS received");
370 test_webrtc_signal_state_unlocked (t, STATE_EOS);
371 break;
372 }
373 default:
374 break;
375 }
376
377 if (t->bus_message)
378 t->bus_message (t, bus, msg, t->bus_data);
379 g_mutex_unlock (&t->lock);
380
381 return TRUE;
382 }
383
384 static void
_on_negotiation_needed(GstElement * webrtc,struct test_webrtc * t)385 _on_negotiation_needed (GstElement * webrtc, struct test_webrtc *t)
386 {
387 g_mutex_lock (&t->lock);
388 if (t->on_negotiation_needed)
389 t->on_negotiation_needed (t, webrtc, t->negotiation_data);
390 if (t->state == STATE_NEW)
391 t->state = STATE_NEGOTIATION_NEEDED;
392 g_cond_broadcast (&t->cond);
393 g_mutex_unlock (&t->lock);
394 }
395
396 static void
_on_ice_candidate(GstElement * webrtc,guint mlineindex,gchar * candidate,struct test_webrtc * t)397 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
398 struct test_webrtc *t)
399 {
400 GstElement *other;
401
402 g_mutex_lock (&t->lock);
403 other = webrtc == t->webrtc1 ? t->webrtc2 : t->webrtc1;
404
405 if (t->on_ice_candidate)
406 t->on_ice_candidate (t, webrtc, mlineindex, candidate, other,
407 t->ice_candidate_data);
408
409 g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
410 g_mutex_unlock (&t->lock);
411 }
412
413 static void
_on_pad_added(GstElement * webrtc,GstPad * new_pad,struct test_webrtc * t)414 _on_pad_added (GstElement * webrtc, GstPad * new_pad, struct test_webrtc *t)
415 {
416 g_mutex_lock (&t->lock);
417 if (t->on_pad_added)
418 t->on_pad_added (t, webrtc, new_pad, t->pad_added_data);
419 g_mutex_unlock (&t->lock);
420 }
421
422 static void
_on_data_channel(GstElement * webrtc,GObject * data_channel,struct test_webrtc * t)423 _on_data_channel (GstElement * webrtc, GObject * data_channel,
424 struct test_webrtc *t)
425 {
426 g_mutex_lock (&t->lock);
427 if (t->on_data_channel)
428 t->on_data_channel (t, webrtc, data_channel, t->data_channel_data);
429 g_mutex_unlock (&t->lock);
430 }
431
432 static void
_pad_added_not_reached(struct test_webrtc * t,GstElement * element,GstPad * pad,gpointer user_data)433 _pad_added_not_reached (struct test_webrtc *t, GstElement * element,
434 GstPad * pad, gpointer user_data)
435 {
436 g_assert_not_reached ();
437 }
438
439 static void
_ice_candidate_not_reached(struct test_webrtc * t,GstElement * element,guint mlineindex,gchar * candidate,GstElement * other,gpointer user_data)440 _ice_candidate_not_reached (struct test_webrtc *t, GstElement * element,
441 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
442 {
443 g_assert_not_reached ();
444 }
445
446 static void
_negotiation_not_reached(struct test_webrtc * t,GstElement * element,gpointer user_data)447 _negotiation_not_reached (struct test_webrtc *t, GstElement * element,
448 gpointer user_data)
449 {
450 g_assert_not_reached ();
451 }
452
453 static void
_bus_no_errors(struct test_webrtc * t,GstBus * bus,GstMessage * msg,gpointer user_data)454 _bus_no_errors (struct test_webrtc *t, GstBus * bus, GstMessage * msg,
455 gpointer user_data)
456 {
457 switch (GST_MESSAGE_TYPE (msg)) {
458 case GST_MESSAGE_ERROR:{
459 GError *err = NULL;
460 gchar *dbg = NULL;
461
462 gst_message_parse_error (msg, &err, &dbg);
463 g_error ("ERROR from element %s: %s (Debugging info: %s)",
464 GST_OBJECT_NAME (msg->src), err->message, (dbg) ? dbg : "none");
465 g_error_free (err);
466 g_free (dbg);
467 g_assert_not_reached ();
468 break;
469 }
470 default:
471 break;
472 }
473 }
474
475 static void
_offer_answer_not_reached(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)476 _offer_answer_not_reached (struct test_webrtc *t, GstElement * element,
477 GstPromise * promise, gpointer user_data)
478 {
479 g_assert_not_reached ();
480 }
481
482 static void
_on_data_channel_not_reached(struct test_webrtc * t,GstElement * element,GObject * data_channel,gpointer user_data)483 _on_data_channel_not_reached (struct test_webrtc *t, GstElement * element,
484 GObject * data_channel, gpointer user_data)
485 {
486 g_assert_not_reached ();
487 }
488
489 static void
_broadcast(struct test_webrtc * t)490 _broadcast (struct test_webrtc *t)
491 {
492 g_mutex_lock (&t->lock);
493 g_cond_broadcast (&t->cond);
494 g_mutex_unlock (&t->lock);
495 }
496
497 static gboolean
_unlock_create_thread(GMutex * lock)498 _unlock_create_thread (GMutex * lock)
499 {
500 g_mutex_unlock (lock);
501 return G_SOURCE_REMOVE;
502 }
503
504 static gpointer
_bus_thread(struct test_webrtc * t)505 _bus_thread (struct test_webrtc *t)
506 {
507 g_mutex_lock (&t->lock);
508 t->loop = g_main_loop_new (NULL, FALSE);
509 g_idle_add ((GSourceFunc) _unlock_create_thread, &t->lock);
510 g_cond_broadcast (&t->cond);
511
512 g_main_loop_run (t->loop);
513
514 g_mutex_lock (&t->lock);
515 g_main_loop_unref (t->loop);
516 t->loop = NULL;
517 g_cond_broadcast (&t->cond);
518 g_mutex_unlock (&t->lock);
519
520 return NULL;
521 }
522
523 static void
element_added_disable_sync(GstBin * bin,GstBin * sub_bin,GstElement * element,gpointer user_data)524 element_added_disable_sync (GstBin * bin, GstBin * sub_bin,
525 GstElement * element, gpointer user_data)
526 {
527 GObjectClass *class = G_OBJECT_GET_CLASS (element);
528 if (g_object_class_find_property (class, "async"))
529 g_object_set (element, "async", FALSE, NULL);
530 if (g_object_class_find_property (class, "sync"))
531 g_object_set (element, "sync", FALSE, NULL);
532 }
533
534 static struct test_webrtc *
test_webrtc_new(void)535 test_webrtc_new (void)
536 {
537 struct test_webrtc *ret = g_new0 (struct test_webrtc, 1);
538
539 ret->on_negotiation_needed = _negotiation_not_reached;
540 ret->on_ice_candidate = _ice_candidate_not_reached;
541 ret->on_pad_added = _pad_added_not_reached;
542 ret->on_offer_created = _offer_answer_not_reached;
543 ret->on_answer_created = _offer_answer_not_reached;
544 ret->on_data_channel = _on_data_channel_not_reached;
545 ret->bus_message = _bus_no_errors;
546 ret->offerror = 1;
547
548 g_mutex_init (&ret->lock);
549 g_cond_init (&ret->cond);
550
551 ret->test_clock = GST_TEST_CLOCK (gst_test_clock_new ());
552
553 ret->thread = g_thread_new ("test-webrtc", (GThreadFunc) _bus_thread, ret);
554
555 g_mutex_lock (&ret->lock);
556 while (!ret->loop)
557 g_cond_wait (&ret->cond, &ret->lock);
558 g_mutex_unlock (&ret->lock);
559
560 ret->bus1 = gst_bus_new ();
561 ret->bus2 = gst_bus_new ();
562 gst_bus_add_watch (ret->bus1, (GstBusFunc) _bus_watch, ret);
563 gst_bus_add_watch (ret->bus2, (GstBusFunc) _bus_watch, ret);
564 ret->webrtc1 = gst_element_factory_make ("webrtcbin", NULL);
565 ret->webrtc2 = gst_element_factory_make ("webrtcbin", NULL);
566 fail_unless (ret->webrtc1 != NULL && ret->webrtc2 != NULL);
567
568 gst_element_set_clock (ret->webrtc1, GST_CLOCK (ret->test_clock));
569 gst_element_set_clock (ret->webrtc2, GST_CLOCK (ret->test_clock));
570
571 gst_element_set_bus (ret->webrtc1, ret->bus1);
572 gst_element_set_bus (ret->webrtc2, ret->bus2);
573
574 g_signal_connect (ret->webrtc1, "deep-element-added",
575 G_CALLBACK (element_added_disable_sync), NULL);
576 g_signal_connect (ret->webrtc2, "deep-element-added",
577 G_CALLBACK (element_added_disable_sync), NULL);
578 g_signal_connect (ret->webrtc1, "on-negotiation-needed",
579 G_CALLBACK (_on_negotiation_needed), ret);
580 g_signal_connect (ret->webrtc2, "on-negotiation-needed",
581 G_CALLBACK (_on_negotiation_needed), ret);
582 g_signal_connect (ret->webrtc1, "on-ice-candidate",
583 G_CALLBACK (_on_ice_candidate), ret);
584 g_signal_connect (ret->webrtc2, "on-ice-candidate",
585 G_CALLBACK (_on_ice_candidate), ret);
586 g_signal_connect (ret->webrtc1, "on-data-channel",
587 G_CALLBACK (_on_data_channel), ret);
588 g_signal_connect (ret->webrtc2, "on-data-channel",
589 G_CALLBACK (_on_data_channel), ret);
590 g_signal_connect (ret->webrtc1, "pad-added", G_CALLBACK (_on_pad_added), ret);
591 g_signal_connect (ret->webrtc2, "pad-added", G_CALLBACK (_on_pad_added), ret);
592 g_signal_connect_swapped (ret->webrtc1, "notify::ice-gathering-state",
593 G_CALLBACK (_broadcast), ret);
594 g_signal_connect_swapped (ret->webrtc2, "notify::ice-gathering-state",
595 G_CALLBACK (_broadcast), ret);
596 g_signal_connect_swapped (ret->webrtc1, "notify::ice-connection-state",
597 G_CALLBACK (_broadcast), ret);
598 g_signal_connect_swapped (ret->webrtc2, "notify::ice-connection-state",
599 G_CALLBACK (_broadcast), ret);
600
601 return ret;
602 }
603
604 static void
test_webrtc_reset_negotiation(struct test_webrtc * t)605 test_webrtc_reset_negotiation (struct test_webrtc *t)
606 {
607 if (t->offer_desc)
608 gst_webrtc_session_description_free (t->offer_desc);
609 t->offer_desc = NULL;
610 t->offer_set_count = 0;
611 if (t->answer_desc)
612 gst_webrtc_session_description_free (t->answer_desc);
613 t->answer_desc = NULL;
614 t->answer_set_count = 0;
615
616 test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED);
617 }
618
619 static void
test_webrtc_free(struct test_webrtc * t)620 test_webrtc_free (struct test_webrtc *t)
621 {
622 /* Otherwise while one webrtcbin is being destroyed, the other could
623 * generate a signal that calls into the destroyed webrtcbin */
624 g_signal_handlers_disconnect_by_data (t->webrtc1, t);
625 g_signal_handlers_disconnect_by_data (t->webrtc2, t);
626
627 g_main_loop_quit (t->loop);
628 g_mutex_lock (&t->lock);
629 while (t->loop)
630 g_cond_wait (&t->cond, &t->lock);
631 g_mutex_unlock (&t->lock);
632
633 g_thread_join (t->thread);
634
635 g_object_unref (t->test_clock);
636
637 gst_bus_remove_watch (t->bus1);
638 gst_bus_remove_watch (t->bus2);
639
640 gst_bus_set_flushing (t->bus1, TRUE);
641 gst_bus_set_flushing (t->bus2, TRUE);
642
643 gst_object_unref (t->bus1);
644 gst_object_unref (t->bus2);
645
646 g_list_free_full (t->harnesses, (GDestroyNotify) gst_harness_teardown);
647
648 if (t->data_notify)
649 t->data_notify (t->user_data);
650 if (t->negotiation_notify)
651 t->negotiation_notify (t->negotiation_data);
652 if (t->ice_candidate_notify)
653 t->ice_candidate_notify (t->ice_candidate_data);
654 if (t->offer_notify)
655 t->offer_notify (t->offer_data);
656 if (t->offer_set_notify)
657 t->offer_set_notify (t->offer_set_data);
658 if (t->answer_notify)
659 t->answer_notify (t->answer_data);
660 if (t->answer_set_notify)
661 t->answer_set_notify (t->answer_set_data);
662 if (t->pad_added_notify)
663 t->pad_added_notify (t->pad_added_data);
664 if (t->data_channel_notify)
665 t->data_channel_notify (t->data_channel_data);
666
667 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
668 gst_element_set_state (t->webrtc1, GST_STATE_NULL));
669 fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
670 gst_element_set_state (t->webrtc2, GST_STATE_NULL));
671
672 test_webrtc_reset_negotiation (t);
673
674 gst_object_unref (t->webrtc1);
675 gst_object_unref (t->webrtc2);
676
677 g_mutex_clear (&t->lock);
678 g_cond_clear (&t->cond);
679
680 g_free (t);
681 }
682
683 static void
test_webrtc_create_offer(struct test_webrtc * t)684 test_webrtc_create_offer (struct test_webrtc *t)
685 {
686 GstPromise *promise;
687 GstElement *offeror = TEST_GET_OFFEROR (t);
688
689 promise = gst_promise_new_with_change_func (_on_offer_received, t, NULL);
690 g_signal_emit_by_name (offeror, "create-offer", NULL, promise);
691 }
692
693 static void
test_webrtc_wait_for_state_mask(struct test_webrtc * t,TestState state)694 test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
695 {
696 g_mutex_lock (&t->lock);
697 while (((1 << t->state) & state) == 0) {
698 GST_INFO ("test state 0x%x, current 0x%x", state, (1 << t->state));
699 g_cond_wait (&t->cond, &t->lock);
700 }
701 GST_INFO ("have test state 0x%x, current 0x%x", state, 1 << t->state);
702 g_mutex_unlock (&t->lock);
703 }
704
705 static void
test_webrtc_wait_for_answer_error_eos(struct test_webrtc * t)706 test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t)
707 {
708 TestState states = 0;
709 states |= (1 << STATE_ANSWER_SET);
710 states |= (1 << STATE_EOS);
711 states |= (1 << STATE_ERROR);
712 test_webrtc_wait_for_state_mask (t, states);
713 }
714
715 static void
test_webrtc_wait_for_ice_gathering_complete(struct test_webrtc * t)716 test_webrtc_wait_for_ice_gathering_complete (struct test_webrtc *t)
717 {
718 GstWebRTCICEGatheringState ice_state1, ice_state2;
719 g_mutex_lock (&t->lock);
720 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
721 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
722 while (ice_state1 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE &&
723 ice_state2 != GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
724 g_cond_wait (&t->cond, &t->lock);
725 g_object_get (t->webrtc1, "ice-gathering-state", &ice_state1, NULL);
726 g_object_get (t->webrtc2, "ice-gathering-state", &ice_state2, NULL);
727 }
728 g_mutex_unlock (&t->lock);
729 }
730
731 #if 0
732 static void
733 test_webrtc_wait_for_ice_connection (struct test_webrtc *t,
734 GstWebRTCICEConnectionState states)
735 {
736 GstWebRTCICEConnectionState ice_state1, ice_state2, current;
737 g_mutex_lock (&t->lock);
738 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
739 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
740 current = (1 << ice_state1) | (1 << ice_state2);
741 while ((current & states) == 0 || (current & ~states)) {
742 g_cond_wait (&t->cond, &t->lock);
743 g_object_get (t->webrtc1, "ice-connection-state", &ice_state1, NULL);
744 g_object_get (t->webrtc2, "ice-connection-state", &ice_state2, NULL);
745 current = (1 << ice_state1) | (1 << ice_state2);
746 }
747 g_mutex_unlock (&t->lock);
748 }
749 #endif
750
751 static void
_pad_added_fakesink(struct test_webrtc * t,GstElement * element,GstPad * pad,gpointer user_data)752 _pad_added_fakesink (struct test_webrtc *t, GstElement * element,
753 GstPad * pad, gpointer user_data)
754 {
755 GstHarness *h;
756
757 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
758 return;
759
760 h = gst_harness_new_with_element (element, NULL, "src_%u");
761 gst_harness_add_sink_parse (h, "fakesink async=false sync=false");
762
763 t->harnesses = g_list_prepend (t->harnesses, h);
764 }
765
766 static void
on_negotiation_needed_hit(struct test_webrtc * t,GstElement * element,gpointer user_data)767 on_negotiation_needed_hit (struct test_webrtc *t, GstElement * element,
768 gpointer user_data)
769 {
770 guint *flag = (guint *) user_data;
771
772 *flag |= 1 << ((element == t->webrtc1) ? 1 : 2);
773 }
774
775 typedef void (*ValidateSDPFunc) (struct test_webrtc * t, GstElement * element,
776 GstWebRTCSessionDescription * desc, gpointer user_data);
777
778 struct validate_sdp;
779 struct validate_sdp
780 {
781 ValidateSDPFunc validate;
782 gpointer user_data;
783 struct validate_sdp *next;
784 };
785
786 #define VAL_SDP_INIT(name,func,data,next) \
787 struct validate_sdp name = { func, data, next }
788
789 static void
_check_validate_sdp(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)790 _check_validate_sdp (struct test_webrtc *t, GstElement * element,
791 GstPromise * promise, gpointer user_data)
792 {
793 struct validate_sdp *validate = user_data;
794 GstWebRTCSessionDescription *desc = NULL;
795
796 if (TEST_IS_OFFER_ELEMENT (t, element))
797 desc = t->offer_desc;
798 else
799 desc = t->answer_desc;
800
801 while (validate) {
802 validate->validate (t, element, desc, validate->user_data);
803 validate = validate->next;
804 }
805 }
806
807 static void
test_validate_sdp_full(struct test_webrtc * t,struct validate_sdp * offer,struct validate_sdp * answer,TestState wait_mask,gboolean perform_state_change)808 test_validate_sdp_full (struct test_webrtc *t, struct validate_sdp *offer,
809 struct validate_sdp *answer, TestState wait_mask,
810 gboolean perform_state_change)
811 {
812 if (offer) {
813 t->offer_data = offer;
814 t->on_offer_created = _check_validate_sdp;
815 } else {
816 t->offer_data = NULL;
817 t->on_offer_created = NULL;
818 }
819 if (answer) {
820 t->answer_data = answer;
821 t->on_answer_created = _check_validate_sdp;
822 } else {
823 t->answer_data = NULL;
824 t->on_answer_created = NULL;
825 }
826
827 if (perform_state_change) {
828 fail_if (gst_element_set_state (t->webrtc1,
829 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
830 fail_if (gst_element_set_state (t->webrtc2,
831 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
832 }
833
834 test_webrtc_create_offer (t);
835
836 if (wait_mask == 0) {
837 test_webrtc_wait_for_answer_error_eos (t);
838 fail_unless (t->state == STATE_ANSWER_SET);
839 } else {
840 test_webrtc_wait_for_state_mask (t, wait_mask);
841 }
842 }
843
844 static void
test_validate_sdp(struct test_webrtc * t,struct validate_sdp * offer,struct validate_sdp * answer)845 test_validate_sdp (struct test_webrtc *t, struct validate_sdp *offer,
846 struct validate_sdp *answer)
847 {
848 test_validate_sdp_full (t, offer, answer, 0, TRUE);
849 }
850
851 static void
_count_num_sdp_media(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)852 _count_num_sdp_media (struct test_webrtc *t, GstElement * element,
853 GstWebRTCSessionDescription * desc, gpointer user_data)
854 {
855 guint expected = GPOINTER_TO_UINT (user_data);
856
857 fail_unless_equals_int (gst_sdp_message_medias_len (desc->sdp), expected);
858 }
859
GST_START_TEST(test_sdp_no_media)860 GST_START_TEST (test_sdp_no_media)
861 {
862 struct test_webrtc *t = test_webrtc_new ();
863 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (0), NULL);
864
865 /* check that a no stream connection creates 0 media sections */
866
867 t->on_negotiation_needed = NULL;
868 test_validate_sdp (t, &count, &count);
869
870 test_webrtc_free (t);
871 }
872
873 GST_END_TEST;
874
875 static void
on_sdp_media_direction(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)876 on_sdp_media_direction (struct test_webrtc *t, GstElement * element,
877 GstWebRTCSessionDescription * desc, gpointer user_data)
878 {
879 gchar **expected_directions = user_data;
880 int i;
881
882 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
883 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
884
885 if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0
886 || g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) {
887 gboolean have_direction = FALSE;
888 int j;
889
890 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
891 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
892
893 if (g_strcmp0 (attr->key, "inactive") == 0) {
894 fail_unless (have_direction == FALSE,
895 "duplicate/multiple directions for media %u", j);
896 have_direction = TRUE;
897 fail_unless_equals_string (attr->key, expected_directions[i]);
898 } else if (g_strcmp0 (attr->key, "sendonly") == 0) {
899 fail_unless (have_direction == FALSE,
900 "duplicate/multiple directions for media %u", j);
901 have_direction = TRUE;
902 fail_unless_equals_string (attr->key, expected_directions[i]);
903 } else if (g_strcmp0 (attr->key, "recvonly") == 0) {
904 fail_unless (have_direction == FALSE,
905 "duplicate/multiple directions for media %u", j);
906 have_direction = TRUE;
907 fail_unless_equals_string (attr->key, expected_directions[i]);
908 } else if (g_strcmp0 (attr->key, "sendrecv") == 0) {
909 fail_unless (have_direction == FALSE,
910 "duplicate/multiple directions for media %u", j);
911 have_direction = TRUE;
912 fail_unless_equals_string (attr->key, expected_directions[i]);
913 }
914 }
915 fail_unless (have_direction, "no direction attribute in media %u", i);
916 }
917 }
918 }
919
920 static void
on_sdp_media_no_duplicate_payloads(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)921 on_sdp_media_no_duplicate_payloads (struct test_webrtc *t, GstElement * element,
922 GstWebRTCSessionDescription * desc, gpointer user_data)
923 {
924 int i, j, k;
925
926 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
927 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
928
929 GArray *media_formats = g_array_new (FALSE, FALSE, sizeof (int));
930 for (j = 0; j < gst_sdp_media_formats_len (media); j++) {
931 int pt = atoi (gst_sdp_media_get_format (media, j));
932 for (k = 0; k < media_formats->len; k++) {
933 int val = g_array_index (media_formats, int, k);
934 if (pt == val)
935 fail ("found an unexpected duplicate payload type %u within media %u",
936 pt, i);
937 }
938 g_array_append_val (media_formats, pt);
939 }
940 g_array_free (media_formats, TRUE);
941 }
942 }
943
944 static void
on_sdp_media_count_formats(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)945 on_sdp_media_count_formats (struct test_webrtc *t, GstElement * element,
946 GstWebRTCSessionDescription * desc, gpointer user_data)
947 {
948 guint *expected_n_media_formats = user_data;
949 int i;
950
951 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
952 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
953 fail_unless_equals_int (gst_sdp_media_formats_len (media),
954 expected_n_media_formats[i]);
955 }
956 }
957
958 static void
on_sdp_media_setup(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)959 on_sdp_media_setup (struct test_webrtc *t, GstElement * element,
960 GstWebRTCSessionDescription * desc, gpointer user_data)
961 {
962 gchar **expected_setup = user_data;
963 int i;
964
965 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
966 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
967 gboolean have_setup = FALSE;
968 int j;
969
970 for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
971 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
972
973 if (g_strcmp0 (attr->key, "setup") == 0) {
974 fail_unless (have_setup == FALSE,
975 "duplicate/multiple setup for media %u", j);
976 have_setup = TRUE;
977 fail_unless_equals_string (attr->value, expected_setup[i]);
978 }
979 }
980 fail_unless (have_setup, "no setup attribute in media %u", i);
981 }
982 }
983
984 static void
add_fake_audio_src_harness(GstHarness * h,gint pt)985 add_fake_audio_src_harness (GstHarness * h, gint pt)
986 {
987 GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
988 GstStructure *s = gst_caps_get_structure (caps, 0);
989 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
990 gst_harness_set_src_caps (h, caps);
991 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
992 }
993
994 static void
add_fake_video_src_harness(GstHarness * h,gint pt)995 add_fake_video_src_harness (GstHarness * h, gint pt)
996 {
997 GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
998 GstStructure *s = gst_caps_get_structure (caps, 0);
999 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
1000 gst_harness_set_src_caps (h, caps);
1001 gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
1002 }
1003
1004 static struct test_webrtc *
create_audio_test(void)1005 create_audio_test (void)
1006 {
1007 struct test_webrtc *t = test_webrtc_new ();
1008 GstHarness *h;
1009
1010 t->on_negotiation_needed = NULL;
1011 t->on_ice_candidate = NULL;
1012 t->on_pad_added = _pad_added_fakesink;
1013
1014 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
1015 add_fake_audio_src_harness (h, 96);
1016 t->harnesses = g_list_prepend (t->harnesses, h);
1017
1018 return t;
1019 }
1020
GST_START_TEST(test_audio)1021 GST_START_TEST (test_audio)
1022 {
1023 struct test_webrtc *t = create_audio_test ();
1024 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1025 NULL, NULL);
1026 guint media_format_count[] = { 1 };
1027 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1028 media_format_count, &no_duplicate_payloads);
1029 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
1030 &media_formats);
1031 const gchar *expected_offer_setup[] = { "actpass", };
1032 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1033 const gchar *expected_answer_setup[] = { "active", };
1034 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1035 &count);
1036 const gchar *expected_offer_direction[] = { "sendrecv", };
1037 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1038 &offer_setup);
1039 const gchar *expected_answer_direction[] = { "recvonly", };
1040 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1041 &answer_setup);
1042
1043 /* check that a single stream connection creates the associated number
1044 * of media sections */
1045
1046 test_validate_sdp (t, &offer, &answer);
1047 test_webrtc_free (t);
1048 }
1049
1050 GST_END_TEST;
1051
1052 static void
_check_ice_port_restriction(struct test_webrtc * t,GstElement * element,guint mlineindex,gchar * candidate,GstElement * other,gpointer user_data)1053 _check_ice_port_restriction (struct test_webrtc *t, GstElement * element,
1054 guint mlineindex, gchar * candidate, GstElement * other, gpointer user_data)
1055 {
1056 GRegex *regex;
1057 GMatchInfo *match_info;
1058
1059 gchar *candidate_port;
1060 gchar *candidate_protocol;
1061 gchar *candidate_typ;
1062 guint port_as_int;
1063 guint peer_number;
1064
1065 regex =
1066 g_regex_new ("candidate:(\\d+) (1) (UDP|TCP) (\\d+) ([0-9.]+|[0-9a-f:]+)"
1067 " (\\d+) typ ([a-z]+)", 0, 0, NULL);
1068
1069 g_regex_match (regex, candidate, 0, &match_info);
1070 fail_unless (g_match_info_get_match_count (match_info) == 8, candidate);
1071
1072 candidate_protocol = g_match_info_fetch (match_info, 2);
1073 candidate_port = g_match_info_fetch (match_info, 6);
1074 candidate_typ = g_match_info_fetch (match_info, 7);
1075
1076 peer_number = t->webrtc1 == element ? 1 : 2;
1077
1078 port_as_int = atoi (candidate_port);
1079
1080 if (!g_strcmp0 (candidate_typ, "host") && port_as_int != 9) {
1081 guint expected_min = peer_number * 10000 + 1000;
1082 guint expected_max = expected_min + 999;
1083
1084 fail_unless (port_as_int >= expected_min);
1085 fail_unless (port_as_int <= expected_max);
1086 }
1087
1088 g_free (candidate_port);
1089 g_free (candidate_protocol);
1090 g_free (candidate_typ);
1091 g_match_info_free (match_info);
1092 g_regex_unref (regex);
1093 }
1094
GST_START_TEST(test_ice_port_restriction)1095 GST_START_TEST (test_ice_port_restriction)
1096 {
1097 struct test_webrtc *t = create_audio_test ();
1098 GObject *webrtcice;
1099
1100 VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1101 VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1102
1103 /*
1104 * Ports are defined as follows "{peer}{protocol}000"
1105 * - peer number: "1" for t->webrtc1, "2" for t->webrtc2
1106 */
1107 g_object_get (t->webrtc1, "ice-agent", &webrtcice, NULL);
1108 g_object_set (webrtcice, "min-rtp-port", 11000, "max-rtp-port", 11999, NULL);
1109 g_object_unref (webrtcice);
1110
1111 g_object_get (t->webrtc2, "ice-agent", &webrtcice, NULL);
1112 g_object_set (webrtcice, "min-rtp-port", 21000, "max-rtp-port", 21999, NULL);
1113 g_object_unref (webrtcice);
1114
1115 t->on_ice_candidate = _check_ice_port_restriction;
1116 test_validate_sdp (t, &offer, &answer);
1117
1118 test_webrtc_wait_for_ice_gathering_complete (t);
1119 test_webrtc_free (t);
1120 }
1121
1122 GST_END_TEST;
1123
1124 static struct test_webrtc *
create_audio_video_test(void)1125 create_audio_video_test (void)
1126 {
1127 struct test_webrtc *t = create_audio_test ();
1128 GstHarness *h;
1129
1130 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1131 add_fake_video_src_harness (h, 97);
1132 t->harnesses = g_list_prepend (t->harnesses, h);
1133
1134 return t;
1135 }
1136
GST_START_TEST(test_audio_video)1137 GST_START_TEST (test_audio_video)
1138 {
1139 struct test_webrtc *t = create_audio_video_test ();
1140 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1141 NULL, NULL);
1142 guint media_format_count[] = { 1, 1 };
1143 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1144 media_format_count, &no_duplicate_payloads);
1145 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1146 &media_formats);
1147 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1148 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1149 const gchar *expected_answer_setup[] = { "active", "active" };
1150 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1151 &count);
1152 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1153 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1154 &offer_setup);
1155 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
1156 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1157 &answer_setup);
1158
1159 /* check that a dual stream connection creates the associated number
1160 * of media sections */
1161
1162 test_validate_sdp (t, &offer, &answer);
1163 test_webrtc_free (t);
1164 }
1165
1166 GST_END_TEST;
1167
GST_START_TEST(test_media_direction)1168 GST_START_TEST (test_media_direction)
1169 {
1170 struct test_webrtc *t = create_audio_video_test ();
1171 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1172 NULL, NULL);
1173 guint media_format_count[] = { 1, 1 };
1174 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1175 media_format_count, &no_duplicate_payloads);
1176 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1177 &media_formats);
1178 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1179 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1180 const gchar *expected_answer_setup[] = { "active", "active" };
1181 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1182 &count);
1183
1184 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1185 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1186 &offer_setup);
1187 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
1188 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1189 &answer_setup);
1190 GstHarness *h;
1191
1192 /* check the default media directions for transceivers */
1193
1194 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1195 add_fake_audio_src_harness (h, 96);
1196 t->harnesses = g_list_prepend (t->harnesses, h);
1197
1198 test_validate_sdp (t, &offer, &answer);
1199 test_webrtc_free (t);
1200 }
1201
1202 GST_END_TEST;
1203
1204 static void
on_sdp_media_payload_types(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)1205 on_sdp_media_payload_types (struct test_webrtc *t, GstElement * element,
1206 GstWebRTCSessionDescription * desc, gpointer user_data)
1207 {
1208 const GstSDPMedia *vmedia;
1209 guint video_mline = GPOINTER_TO_UINT (user_data);
1210 guint j;
1211
1212 vmedia = gst_sdp_message_get_media (desc->sdp, video_mline);
1213
1214 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
1215 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
1216
1217 if (!g_strcmp0 (attr->key, "rtpmap")) {
1218 if (g_str_has_prefix (attr->value, "97")) {
1219 fail_unless_equals_string (attr->value, "97 VP8/90000");
1220 } else if (g_str_has_prefix (attr->value, "96")) {
1221 fail_unless_equals_string (attr->value, "96 red/90000");
1222 } else if (g_str_has_prefix (attr->value, "98")) {
1223 fail_unless_equals_string (attr->value, "98 ulpfec/90000");
1224 } else if (g_str_has_prefix (attr->value, "99")) {
1225 fail_unless_equals_string (attr->value, "99 rtx/90000");
1226 } else if (g_str_has_prefix (attr->value, "100")) {
1227 fail_unless_equals_string (attr->value, "100 rtx/90000");
1228 } else if (g_str_has_prefix (attr->value, "101")) {
1229 fail_unless_equals_string (attr->value, "101 H264/90000");
1230 }
1231 }
1232 }
1233 }
1234
1235 /* In this test we verify that webrtcbin will pick available payload
1236 * types when it needs to, in that example for RTX and FEC */
GST_START_TEST(test_payload_types)1237 GST_START_TEST (test_payload_types)
1238 {
1239 struct test_webrtc *t = create_audio_video_test ();
1240 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1241 NULL, NULL);
1242 guint media_format_count[] = { 1, 5, };
1243 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1244 media_format_count, &no_duplicate_payloads);
1245 VAL_SDP_INIT (payloads, on_sdp_media_payload_types, GUINT_TO_POINTER (1),
1246 &media_formats);
1247 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2), &payloads);
1248 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1249 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1250 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
1251 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1252 &offer_setup);
1253 GstWebRTCRTPTransceiver *trans;
1254 GArray *transceivers;
1255
1256 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1257 fail_unless_equals_int (transceivers->len, 2);
1258 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1259 g_object_set (trans, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, "do-nack", TRUE,
1260 NULL);
1261 g_array_unref (transceivers);
1262
1263 /* We don't really care about the answer here */
1264 test_validate_sdp (t, &offer, NULL);
1265 test_webrtc_free (t);
1266 }
1267
1268 GST_END_TEST;
1269
GST_START_TEST(test_no_nice_elements_request_pad)1270 GST_START_TEST (test_no_nice_elements_request_pad)
1271 {
1272 struct test_webrtc *t = test_webrtc_new ();
1273 GstPluginFeature *nicesrc, *nicesink;
1274 GstRegistry *registry;
1275 GstPad *pad;
1276
1277 /* check that the absence of libnice elements posts an error on the bus
1278 * when requesting a pad */
1279
1280 registry = gst_registry_get ();
1281 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1282 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1283
1284 if (nicesrc)
1285 gst_registry_remove_feature (registry, nicesrc);
1286 if (nicesink)
1287 gst_registry_remove_feature (registry, nicesink);
1288
1289 t->bus_message = NULL;
1290
1291 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
1292 fail_unless (pad == NULL);
1293
1294 test_webrtc_wait_for_answer_error_eos (t);
1295 fail_unless_equals_int (STATE_ERROR, t->state);
1296 test_webrtc_free (t);
1297
1298 if (nicesrc)
1299 gst_registry_add_feature (registry, nicesrc);
1300 if (nicesink)
1301 gst_registry_add_feature (registry, nicesink);
1302 }
1303
1304 GST_END_TEST;
1305
GST_START_TEST(test_no_nice_elements_state_change)1306 GST_START_TEST (test_no_nice_elements_state_change)
1307 {
1308 struct test_webrtc *t = test_webrtc_new ();
1309 GstPluginFeature *nicesrc, *nicesink;
1310 GstRegistry *registry;
1311
1312 /* check that the absence of libnice elements posts an error on the bus */
1313
1314 registry = gst_registry_get ();
1315 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
1316 nicesink = gst_registry_lookup_feature (registry, "nicesink");
1317
1318 if (nicesrc)
1319 gst_registry_remove_feature (registry, nicesrc);
1320 if (nicesink)
1321 gst_registry_remove_feature (registry, nicesink);
1322
1323 t->bus_message = NULL;
1324 gst_element_set_state (t->webrtc1, GST_STATE_READY);
1325
1326 test_webrtc_wait_for_answer_error_eos (t);
1327 fail_unless_equals_int (STATE_ERROR, t->state);
1328 test_webrtc_free (t);
1329
1330 if (nicesrc)
1331 gst_registry_add_feature (registry, nicesrc);
1332 if (nicesink)
1333 gst_registry_add_feature (registry, nicesink);
1334 }
1335
1336 GST_END_TEST;
1337
1338 static void
validate_rtc_stats(const GstStructure * s)1339 validate_rtc_stats (const GstStructure * s)
1340 {
1341 GstWebRTCStatsType type = 0;
1342 double ts = 0.;
1343 gchar *id = NULL;
1344
1345 fail_unless (gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type,
1346 NULL));
1347 fail_unless (gst_structure_get (s, "id", G_TYPE_STRING, &id, NULL));
1348 fail_unless (gst_structure_get (s, "timestamp", G_TYPE_DOUBLE, &ts, NULL));
1349 fail_unless (type != 0);
1350 fail_unless (ts != 0.);
1351 fail_unless (id != NULL);
1352
1353 g_free (id);
1354 }
1355
1356 static void
validate_codec_stats(const GstStructure * s)1357 validate_codec_stats (const GstStructure * s)
1358 {
1359 guint pt = 0, clock_rate = 0;
1360
1361 fail_unless (gst_structure_get (s, "payload-type", G_TYPE_UINT, &pt, NULL));
1362 fail_unless (gst_structure_get (s, "clock-rate", G_TYPE_UINT, &clock_rate,
1363 NULL));
1364 fail_unless (pt >= 0 && pt <= 127);
1365 fail_unless (clock_rate >= 0);
1366 }
1367
1368 static void
validate_rtc_stream_stats(const GstStructure * s,const GstStructure * stats)1369 validate_rtc_stream_stats (const GstStructure * s, const GstStructure * stats)
1370 {
1371 gchar *codec_id, *transport_id;
1372 GstStructure *codec, *transport;
1373
1374 fail_unless (gst_structure_get (s, "codec-id", G_TYPE_STRING, &codec_id,
1375 NULL));
1376 fail_unless (gst_structure_get (s, "transport-id", G_TYPE_STRING,
1377 &transport_id, NULL));
1378
1379 fail_unless (gst_structure_get (stats, codec_id, GST_TYPE_STRUCTURE, &codec,
1380 NULL));
1381 fail_unless (gst_structure_get (stats, transport_id, GST_TYPE_STRUCTURE,
1382 &transport, NULL));
1383
1384 fail_unless (codec != NULL);
1385 fail_unless (transport != NULL);
1386
1387 gst_structure_free (transport);
1388 gst_structure_free (codec);
1389
1390 g_free (codec_id);
1391 g_free (transport_id);
1392 }
1393
1394 static void
validate_inbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1395 validate_inbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1396 {
1397 guint ssrc, fir, pli, nack;
1398 gint packets_lost;
1399 guint64 packets_received, bytes_received;
1400 double jitter;
1401 gchar *remote_id;
1402 GstStructure *remote;
1403
1404 validate_rtc_stream_stats (s, stats);
1405
1406 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1407 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1408 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1409 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1410 fail_unless (gst_structure_get (s, "packets-received", G_TYPE_UINT64,
1411 &packets_received, NULL));
1412 fail_unless (gst_structure_get (s, "bytes-received", G_TYPE_UINT64,
1413 &bytes_received, NULL));
1414 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1415 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1416 NULL));
1417 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1418 NULL));
1419 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1420 NULL));
1421 fail_unless (remote != NULL);
1422
1423 gst_structure_free (remote);
1424 g_free (remote_id);
1425 }
1426
1427 static void
validate_remote_inbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1428 validate_remote_inbound_rtp_stats (const GstStructure * s,
1429 const GstStructure * stats)
1430 {
1431 guint ssrc;
1432 gint packets_lost;
1433 double jitter, rtt;
1434 gchar *local_id;
1435 GstStructure *local;
1436
1437 validate_rtc_stream_stats (s, stats);
1438
1439 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1440 fail_unless (gst_structure_get (s, "jitter", G_TYPE_DOUBLE, &jitter, NULL));
1441 fail_unless (gst_structure_get (s, "packets-lost", G_TYPE_INT, &packets_lost,
1442 NULL));
1443 fail_unless (gst_structure_get (s, "round-trip-time", G_TYPE_DOUBLE, &rtt,
1444 NULL));
1445 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1446 NULL));
1447 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1448 NULL));
1449 fail_unless (local != NULL);
1450
1451 gst_structure_free (local);
1452 g_free (local_id);
1453 }
1454
1455 static void
validate_outbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1456 validate_outbound_rtp_stats (const GstStructure * s, const GstStructure * stats)
1457 {
1458 guint ssrc, fir, pli, nack;
1459 guint64 packets_sent, bytes_sent;
1460 gchar *remote_id;
1461 GstStructure *remote;
1462
1463 validate_rtc_stream_stats (s, stats);
1464
1465 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1466 fail_unless (gst_structure_get (s, "fir-count", G_TYPE_UINT, &fir, NULL));
1467 fail_unless (gst_structure_get (s, "pli-count", G_TYPE_UINT, &pli, NULL));
1468 fail_unless (gst_structure_get (s, "nack-count", G_TYPE_UINT, &nack, NULL));
1469 fail_unless (gst_structure_get (s, "packets-sent", G_TYPE_UINT64,
1470 &packets_sent, NULL));
1471 fail_unless (gst_structure_get (s, "bytes-sent", G_TYPE_UINT64, &bytes_sent,
1472 NULL));
1473 fail_unless (gst_structure_get (s, "remote-id", G_TYPE_STRING, &remote_id,
1474 NULL));
1475 fail_unless (gst_structure_get (stats, remote_id, GST_TYPE_STRUCTURE, &remote,
1476 NULL));
1477 fail_unless (remote != NULL);
1478
1479 gst_structure_free (remote);
1480 g_free (remote_id);
1481 }
1482
1483 static void
validate_remote_outbound_rtp_stats(const GstStructure * s,const GstStructure * stats)1484 validate_remote_outbound_rtp_stats (const GstStructure * s,
1485 const GstStructure * stats)
1486 {
1487 guint ssrc;
1488 gchar *local_id;
1489 GstStructure *local;
1490
1491 validate_rtc_stream_stats (s, stats);
1492
1493 fail_unless (gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL));
1494 fail_unless (gst_structure_get (s, "local-id", G_TYPE_STRING, &local_id,
1495 NULL));
1496 fail_unless (gst_structure_get (stats, local_id, GST_TYPE_STRUCTURE, &local,
1497 NULL));
1498 fail_unless (local != NULL);
1499
1500 gst_structure_free (local);
1501 g_free (local_id);
1502 }
1503
1504 static gboolean
validate_stats_foreach(GQuark field_id,const GValue * value,const GstStructure * stats)1505 validate_stats_foreach (GQuark field_id, const GValue * value,
1506 const GstStructure * stats)
1507 {
1508 const gchar *field = g_quark_to_string (field_id);
1509 GstWebRTCStatsType type;
1510 const GstStructure *s;
1511
1512 fail_unless (GST_VALUE_HOLDS_STRUCTURE (value));
1513
1514 s = gst_value_get_structure (value);
1515
1516 GST_INFO ("validating field %s %" GST_PTR_FORMAT, field, s);
1517
1518 validate_rtc_stats (s);
1519 gst_structure_get (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, &type, NULL);
1520 if (type == GST_WEBRTC_STATS_CODEC) {
1521 validate_codec_stats (s);
1522 } else if (type == GST_WEBRTC_STATS_INBOUND_RTP) {
1523 validate_inbound_rtp_stats (s, stats);
1524 } else if (type == GST_WEBRTC_STATS_OUTBOUND_RTP) {
1525 validate_outbound_rtp_stats (s, stats);
1526 } else if (type == GST_WEBRTC_STATS_REMOTE_INBOUND_RTP) {
1527 validate_remote_inbound_rtp_stats (s, stats);
1528 } else if (type == GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP) {
1529 validate_remote_outbound_rtp_stats (s, stats);
1530 } else if (type == GST_WEBRTC_STATS_CSRC) {
1531 } else if (type == GST_WEBRTC_STATS_PEER_CONNECTION) {
1532 } else if (type == GST_WEBRTC_STATS_DATA_CHANNEL) {
1533 } else if (type == GST_WEBRTC_STATS_STREAM) {
1534 } else if (type == GST_WEBRTC_STATS_TRANSPORT) {
1535 } else if (type == GST_WEBRTC_STATS_CANDIDATE_PAIR) {
1536 } else if (type == GST_WEBRTC_STATS_LOCAL_CANDIDATE) {
1537 } else if (type == GST_WEBRTC_STATS_REMOTE_CANDIDATE) {
1538 } else if (type == GST_WEBRTC_STATS_CERTIFICATE) {
1539 } else {
1540 g_assert_not_reached ();
1541 }
1542
1543 return TRUE;
1544 }
1545
1546 static void
validate_stats(const GstStructure * stats)1547 validate_stats (const GstStructure * stats)
1548 {
1549 gst_structure_foreach (stats,
1550 (GstStructureForeachFunc) validate_stats_foreach, (gpointer) stats);
1551 }
1552
1553 static void
_on_stats(GstPromise * promise,gpointer user_data)1554 _on_stats (GstPromise * promise, gpointer user_data)
1555 {
1556 struct test_webrtc *t = user_data;
1557 const GstStructure *reply = gst_promise_get_reply (promise);
1558 int i;
1559
1560 validate_stats (reply);
1561 i = GPOINTER_TO_INT (t->user_data);
1562 i++;
1563 t->user_data = GINT_TO_POINTER (i);
1564 if (i >= 2)
1565 test_webrtc_signal_state (t, STATE_CUSTOM);
1566
1567 gst_promise_unref (promise);
1568 }
1569
GST_START_TEST(test_session_stats)1570 GST_START_TEST (test_session_stats)
1571 {
1572 struct test_webrtc *t = test_webrtc_new ();
1573 GstPromise *p;
1574
1575 /* test that the stats generated without any streams are sane */
1576 t->on_negotiation_needed = NULL;
1577 test_validate_sdp (t, NULL, NULL);
1578
1579 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1580 g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p);
1581 p = gst_promise_new_with_change_func (_on_stats, t, NULL);
1582 g_signal_emit_by_name (t->webrtc2, "get-stats", NULL, p);
1583
1584 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
1585
1586 test_webrtc_free (t);
1587 }
1588
1589 GST_END_TEST;
1590
GST_START_TEST(test_add_transceiver)1591 GST_START_TEST (test_add_transceiver)
1592 {
1593 struct test_webrtc *t = test_webrtc_new ();
1594 GstWebRTCRTPTransceiverDirection direction, trans_direction;
1595 GstWebRTCRTPTransceiver *trans;
1596
1597 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
1598 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, NULL,
1599 &trans);
1600 fail_unless (trans != NULL);
1601 g_object_get (trans, "direction", &trans_direction, NULL);
1602 fail_unless_equals_int (direction, trans_direction);
1603
1604 gst_object_unref (trans);
1605
1606 test_webrtc_free (t);
1607 }
1608
1609 GST_END_TEST;
1610
GST_START_TEST(test_get_transceivers)1611 GST_START_TEST (test_get_transceivers)
1612 {
1613 struct test_webrtc *t = create_audio_test ();
1614 GstWebRTCRTPTransceiver *trans;
1615 GArray *transceivers;
1616
1617 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1618 fail_unless (transceivers != NULL);
1619 fail_unless_equals_int (1, transceivers->len);
1620
1621 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
1622 fail_unless (trans != NULL);
1623
1624 g_array_unref (transceivers);
1625
1626 test_webrtc_free (t);
1627 }
1628
1629 GST_END_TEST;
1630
GST_START_TEST(test_add_recvonly_transceiver)1631 GST_START_TEST (test_add_recvonly_transceiver)
1632 {
1633 struct test_webrtc *t = test_webrtc_new ();
1634 GstWebRTCRTPTransceiverDirection direction;
1635 GstWebRTCRTPTransceiver *trans;
1636 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1637 NULL, NULL);
1638 guint media_format_count[] = { 1, 1, };
1639 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1640 media_format_count, &no_duplicate_payloads);
1641 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
1642 &media_formats);
1643 const gchar *expected_offer_setup[] = { "actpass", };
1644 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1645 const gchar *expected_answer_setup[] = { "active", };
1646 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1647 &count);
1648 const gchar *expected_offer_direction[] = { "recvonly", };
1649 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1650 &offer_setup);
1651 const gchar *expected_answer_direction[] = { "sendonly", };
1652 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1653 &answer_setup);
1654 GstCaps *caps;
1655 GstHarness *h;
1656
1657 /* add a transceiver that will only receive an opus stream and check that
1658 * the created offer is marked as recvonly */
1659 t->on_negotiation_needed = NULL;
1660 t->on_ice_candidate = NULL;
1661 t->on_pad_added = _pad_added_fakesink;
1662
1663 /* setup recvonly transceiver */
1664 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1665 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1666 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1667 &trans);
1668 gst_caps_unref (caps);
1669 fail_unless (trans != NULL);
1670 gst_object_unref (trans);
1671
1672 /* setup sendonly peer */
1673 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1674 add_fake_audio_src_harness (h, 96);
1675 t->harnesses = g_list_prepend (t->harnesses, h);
1676 test_validate_sdp (t, &offer, &answer);
1677
1678 test_webrtc_free (t);
1679 }
1680
1681 GST_END_TEST;
1682
GST_START_TEST(test_recvonly_sendonly)1683 GST_START_TEST (test_recvonly_sendonly)
1684 {
1685 struct test_webrtc *t = test_webrtc_new ();
1686 GstWebRTCRTPTransceiverDirection direction;
1687 GstWebRTCRTPTransceiver *trans;
1688 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
1689 NULL, NULL);
1690 guint media_format_count[] = { 1, 1, };
1691 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
1692 media_format_count, &no_duplicate_payloads);
1693 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
1694 &media_formats);
1695 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
1696 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
1697 const gchar *expected_answer_setup[] = { "active", "active" };
1698 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
1699 &count);
1700 const gchar *expected_offer_direction[] = { "recvonly", "sendonly" };
1701 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
1702 &offer_setup);
1703 const gchar *expected_answer_direction[] = { "sendonly", "recvonly" };
1704 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
1705 &answer_setup);
1706 GstCaps *caps;
1707 GstHarness *h;
1708 GArray *transceivers;
1709
1710 /* add a transceiver that will only receive an opus stream and check that
1711 * the created offer is marked as recvonly */
1712 t->on_negotiation_needed = NULL;
1713 t->on_ice_candidate = NULL;
1714 t->on_pad_added = _pad_added_fakesink;
1715
1716 /* setup recvonly transceiver */
1717 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
1718 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
1719 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
1720 &trans);
1721 gst_caps_unref (caps);
1722 fail_unless (trans != NULL);
1723 gst_object_unref (trans);
1724
1725 /* setup sendonly stream */
1726 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
1727 add_fake_audio_src_harness (h, 96);
1728 t->harnesses = g_list_prepend (t->harnesses, h);
1729 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
1730 fail_unless (transceivers != NULL);
1731 fail_unless_equals_int (transceivers->len, 2);
1732 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
1733 g_object_set (trans, "direction",
1734 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, NULL);
1735
1736 g_array_unref (transceivers);
1737
1738 /* setup sendonly peer */
1739 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
1740 add_fake_audio_src_harness (h, 96);
1741 t->harnesses = g_list_prepend (t->harnesses, h);
1742
1743 test_validate_sdp (t, &offer, &answer);
1744
1745 test_webrtc_free (t);
1746 }
1747
1748 GST_END_TEST;
1749
1750 static void
on_sdp_has_datachannel(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)1751 on_sdp_has_datachannel (struct test_webrtc *t, GstElement * element,
1752 GstWebRTCSessionDescription * desc, gpointer user_data)
1753 {
1754 gboolean have_data_channel = FALSE;
1755 int i;
1756
1757 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
1758 if (_message_media_is_datachannel (desc->sdp, i)) {
1759 /* there should only be one data channel m= section */
1760 fail_unless_equals_int (FALSE, have_data_channel);
1761 have_data_channel = TRUE;
1762 }
1763 }
1764
1765 fail_unless_equals_int (TRUE, have_data_channel);
1766 }
1767
1768 static void
on_channel_error_not_reached(GObject * channel,GError * error,gpointer user_data)1769 on_channel_error_not_reached (GObject * channel, GError * error,
1770 gpointer user_data)
1771 {
1772 g_assert_not_reached ();
1773 }
1774
GST_START_TEST(test_data_channel_create)1775 GST_START_TEST (test_data_channel_create)
1776 {
1777 struct test_webrtc *t = test_webrtc_new ();
1778 GObject *channel = NULL;
1779 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1780 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1781 gchar *label;
1782
1783 t->on_negotiation_needed = NULL;
1784 t->on_ice_candidate = NULL;
1785
1786 fail_if (gst_element_set_state (t->webrtc1,
1787 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1788 fail_if (gst_element_set_state (t->webrtc2,
1789 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1790
1791 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1792 &channel);
1793 g_assert_nonnull (channel);
1794 g_object_get (channel, "label", &label, NULL);
1795 g_assert_cmpstr (label, ==, "label");
1796 g_signal_connect (channel, "on-error",
1797 G_CALLBACK (on_channel_error_not_reached), NULL);
1798
1799 test_validate_sdp (t, &offer, &offer);
1800
1801 g_object_unref (channel);
1802 g_free (label);
1803 test_webrtc_free (t);
1804 }
1805
1806 GST_END_TEST;
1807
1808 static void
have_data_channel(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1809 have_data_channel (struct test_webrtc *t, GstElement * element,
1810 GObject * our, gpointer user_data)
1811 {
1812 GObject *other = user_data;
1813 gchar *our_label, *other_label;
1814
1815 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
1816 NULL);
1817
1818 g_object_get (our, "label", &our_label, NULL);
1819 g_object_get (other, "label", &other_label, NULL);
1820
1821 g_assert_cmpstr (our_label, ==, other_label);
1822
1823 g_free (our_label);
1824 g_free (other_label);
1825
1826 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
1827 }
1828
GST_START_TEST(test_data_channel_remote_notify)1829 GST_START_TEST (test_data_channel_remote_notify)
1830 {
1831 struct test_webrtc *t = test_webrtc_new ();
1832 GObject *channel = NULL;
1833 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1834 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1835
1836 t->on_negotiation_needed = NULL;
1837 t->on_ice_candidate = NULL;
1838 t->on_data_channel = have_data_channel;
1839
1840 fail_if (gst_element_set_state (t->webrtc1,
1841 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1842 fail_if (gst_element_set_state (t->webrtc2,
1843 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1844
1845 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1846 &channel);
1847 g_assert_nonnull (channel);
1848 t->data_channel_data = channel;
1849 g_signal_connect (channel, "on-error",
1850 G_CALLBACK (on_channel_error_not_reached), NULL);
1851
1852 fail_if (gst_element_set_state (t->webrtc1,
1853 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1854 fail_if (gst_element_set_state (t->webrtc2,
1855 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1856
1857 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1858
1859 g_object_unref (channel);
1860 test_webrtc_free (t);
1861 }
1862
1863 GST_END_TEST;
1864
1865 static const gchar *test_string = "GStreamer WebRTC is awesome!";
1866
1867 static void
on_message_string(GObject * channel,const gchar * str,struct test_webrtc * t)1868 on_message_string (GObject * channel, const gchar * str, struct test_webrtc *t)
1869 {
1870 GstWebRTCDataChannelState state;
1871 gchar *expected;
1872
1873 g_object_get (channel, "ready-state", &state, NULL);
1874 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1875
1876 expected = g_object_steal_data (channel, "expected");
1877 g_assert_cmpstr (expected, ==, str);
1878 g_free (expected);
1879
1880 test_webrtc_signal_state (t, STATE_CUSTOM);
1881 }
1882
1883 static void
have_data_channel_transfer_string(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1884 have_data_channel_transfer_string (struct test_webrtc *t, GstElement * element,
1885 GObject * our, gpointer user_data)
1886 {
1887 GObject *other = user_data;
1888 GstWebRTCDataChannelState state;
1889
1890 g_object_get (our, "ready-state", &state, NULL);
1891 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1892
1893 g_object_set_data_full (our, "expected", g_strdup (test_string), g_free);
1894 g_signal_connect (our, "on-message-string", G_CALLBACK (on_message_string),
1895 t);
1896
1897 g_signal_connect (other, "on-error",
1898 G_CALLBACK (on_channel_error_not_reached), NULL);
1899 g_signal_emit_by_name (other, "send-string", test_string);
1900 }
1901
GST_START_TEST(test_data_channel_transfer_string)1902 GST_START_TEST (test_data_channel_transfer_string)
1903 {
1904 struct test_webrtc *t = test_webrtc_new ();
1905 GObject *channel = NULL;
1906 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1907 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1908
1909 t->on_negotiation_needed = NULL;
1910 t->on_ice_candidate = NULL;
1911 t->on_data_channel = have_data_channel_transfer_string;
1912
1913 fail_if (gst_element_set_state (t->webrtc1,
1914 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1915 fail_if (gst_element_set_state (t->webrtc2,
1916 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1917
1918 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
1919 &channel);
1920 g_assert_nonnull (channel);
1921 t->data_channel_data = channel;
1922 g_signal_connect (channel, "on-error",
1923 G_CALLBACK (on_channel_error_not_reached), NULL);
1924
1925 fail_if (gst_element_set_state (t->webrtc1,
1926 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1927 fail_if (gst_element_set_state (t->webrtc2,
1928 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
1929
1930 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
1931
1932 g_object_unref (channel);
1933 test_webrtc_free (t);
1934 }
1935
1936 GST_END_TEST;
1937
1938 #define g_assert_cmpbytes(b1, b2) \
1939 G_STMT_START { \
1940 gsize l1, l2; \
1941 const guint8 *d1 = g_bytes_get_data (b1, &l1); \
1942 const guint8 *d2 = g_bytes_get_data (b2, &l2); \
1943 g_assert_cmpmem (d1, l1, d2, l2); \
1944 } G_STMT_END;
1945
1946 static void
on_message_data(GObject * channel,GBytes * data,struct test_webrtc * t)1947 on_message_data (GObject * channel, GBytes * data, struct test_webrtc *t)
1948 {
1949 GstWebRTCDataChannelState state;
1950 GBytes *expected;
1951
1952 g_object_get (channel, "ready-state", &state, NULL);
1953 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1954
1955 expected = g_object_steal_data (channel, "expected");
1956 g_assert_cmpbytes (data, expected);
1957 g_bytes_unref (expected);
1958
1959 test_webrtc_signal_state (t, STATE_CUSTOM);
1960 }
1961
1962 static void
have_data_channel_transfer_data(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)1963 have_data_channel_transfer_data (struct test_webrtc *t, GstElement * element,
1964 GObject * our, gpointer user_data)
1965 {
1966 GObject *other = user_data;
1967 GBytes *data = g_bytes_new_static (test_string, strlen (test_string));
1968 GstWebRTCDataChannelState state;
1969
1970 g_object_get (our, "ready-state", &state, NULL);
1971 fail_unless_equals_int (GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, state);
1972
1973 g_object_set_data_full (our, "expected", g_bytes_ref (data),
1974 (GDestroyNotify) g_bytes_unref);
1975 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
1976
1977 g_signal_connect (other, "on-error",
1978 G_CALLBACK (on_channel_error_not_reached), NULL);
1979 g_signal_emit_by_name (other, "send-data", data);
1980 g_bytes_unref (data);
1981 }
1982
GST_START_TEST(test_data_channel_transfer_data)1983 GST_START_TEST (test_data_channel_transfer_data)
1984 {
1985 struct test_webrtc *t = test_webrtc_new ();
1986 GObject *channel = NULL;
1987 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
1988 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
1989
1990 t->on_negotiation_needed = NULL;
1991 t->on_ice_candidate = NULL;
1992 t->on_data_channel = have_data_channel_transfer_data;
1993
1994 fail_if (gst_element_set_state (t->webrtc1,
1995 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1996 fail_if (gst_element_set_state (t->webrtc2,
1997 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
1998
1999 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2000 &channel);
2001 g_assert_nonnull (channel);
2002 t->data_channel_data = channel;
2003 g_signal_connect (channel, "on-error",
2004 G_CALLBACK (on_channel_error_not_reached), NULL);
2005
2006 fail_if (gst_element_set_state (t->webrtc1,
2007 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2008 fail_if (gst_element_set_state (t->webrtc2,
2009 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2010
2011 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2012
2013 g_object_unref (channel);
2014 test_webrtc_free (t);
2015 }
2016
2017 GST_END_TEST;
2018
2019 static void
have_data_channel_create_data_channel(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)2020 have_data_channel_create_data_channel (struct test_webrtc *t,
2021 GstElement * element, GObject * our, gpointer user_data)
2022 {
2023 GObject *another;
2024
2025 t->on_data_channel = have_data_channel_transfer_string;
2026
2027 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2028 &another);
2029 g_assert_nonnull (another);
2030 t->data_channel_data = another;
2031 t->data_channel_notify = (GDestroyNotify) g_object_unref;
2032 g_signal_connect (another, "on-error",
2033 G_CALLBACK (on_channel_error_not_reached), NULL);
2034 }
2035
GST_START_TEST(test_data_channel_create_after_negotiate)2036 GST_START_TEST (test_data_channel_create_after_negotiate)
2037 {
2038 struct test_webrtc *t = test_webrtc_new ();
2039 GObject *channel = NULL;
2040 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2041 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2042
2043 t->on_negotiation_needed = NULL;
2044 t->on_ice_candidate = NULL;
2045 t->on_data_channel = have_data_channel_create_data_channel;
2046
2047 fail_if (gst_element_set_state (t->webrtc1,
2048 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2049 fail_if (gst_element_set_state (t->webrtc2,
2050 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2051
2052 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "prev-label", NULL,
2053 &channel);
2054 g_assert_nonnull (channel);
2055 t->data_channel_data = channel;
2056 g_signal_connect (channel, "on-error",
2057 G_CALLBACK (on_channel_error_not_reached), NULL);
2058
2059 fail_if (gst_element_set_state (t->webrtc1,
2060 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2061 fail_if (gst_element_set_state (t->webrtc2,
2062 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2063
2064 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2065
2066 g_object_unref (channel);
2067 test_webrtc_free (t);
2068 }
2069
2070 GST_END_TEST;
2071
2072 struct test_data_channel
2073 {
2074 GObject *dc1;
2075 GObject *dc2;
2076 gint n_open;
2077 gint n_closed;
2078 gint n_destroyed;
2079 };
2080
2081 static void
have_data_channel_mark_open(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)2082 have_data_channel_mark_open (struct test_webrtc *t,
2083 GstElement * element, GObject * our, gpointer user_data)
2084 {
2085 struct test_data_channel *tdc = t->data_channel_data;
2086
2087 tdc->dc2 = our;
2088 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2089 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
2090 }
2091 }
2092
2093 static gboolean
is_data_channel_open(GObject * channel)2094 is_data_channel_open (GObject * channel)
2095 {
2096 GstWebRTCDataChannelState ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
2097
2098 if (channel) {
2099 g_object_get (channel, "ready-state", &ready_state, NULL);
2100 }
2101
2102 return ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
2103 }
2104
2105 static void
on_data_channel_open(GObject * channel,GParamSpec * pspec,struct test_webrtc * t)2106 on_data_channel_open (GObject * channel, GParamSpec * pspec,
2107 struct test_webrtc *t)
2108 {
2109 struct test_data_channel *tdc = t->data_channel_data;
2110
2111 if (is_data_channel_open (channel)) {
2112 if (g_atomic_int_add (&tdc->n_open, 1) == 1) {
2113 test_webrtc_signal_state (t, STATE_CUSTOM);
2114 }
2115 }
2116 }
2117
2118 static void
on_data_channel_close(GObject * channel,GParamSpec * pspec,struct test_webrtc * t)2119 on_data_channel_close (GObject * channel, GParamSpec * pspec,
2120 struct test_webrtc *t)
2121 {
2122 struct test_data_channel *tdc = t->data_channel_data;
2123 GstWebRTCDataChannelState ready_state;
2124
2125 g_object_get (channel, "ready-state", &ready_state, NULL);
2126
2127 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
2128 g_atomic_int_add (&tdc->n_closed, 1);
2129 }
2130 }
2131
2132 static void
on_data_channel_destroyed(gpointer data,GObject * where_the_object_was)2133 on_data_channel_destroyed (gpointer data, GObject * where_the_object_was)
2134 {
2135 struct test_webrtc *t = data;
2136 struct test_data_channel *tdc = t->data_channel_data;
2137
2138 if (where_the_object_was == tdc->dc1) {
2139 tdc->dc1 = NULL;
2140 } else if (where_the_object_was == tdc->dc2) {
2141 tdc->dc2 = NULL;
2142 }
2143
2144 if (g_atomic_int_add (&tdc->n_destroyed, 1) == 1) {
2145 test_webrtc_signal_state (t, STATE_CUSTOM);
2146 }
2147 }
2148
GST_START_TEST(test_data_channel_close)2149 GST_START_TEST (test_data_channel_close)
2150 {
2151 #define NUM_CHANNELS 3
2152 struct test_webrtc *t = test_webrtc_new ();
2153 struct test_data_channel tdc = { NULL, NULL, 0, 0, 0 };
2154 guint channel_id[NUM_CHANNELS] = { 0, 1, 2 };
2155 gulong sigid = 0;
2156 int i;
2157 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2158 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2159
2160 t->on_negotiation_needed = NULL;
2161 t->on_ice_candidate = NULL;
2162 t->on_data_channel = have_data_channel_mark_open;
2163 t->data_channel_data = &tdc;
2164
2165 fail_if (gst_element_set_state (t->webrtc1,
2166 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2167 fail_if (gst_element_set_state (t->webrtc2,
2168 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2169
2170 /* open and close NUM_CHANNELS data channels to verify that we can reuse the
2171 * stream id of a previously closed data channel and that we have the same
2172 * behaviour no matter if we create the channel in READY or PLAYING state */
2173 for (i = 0; i < NUM_CHANNELS; i++) {
2174 tdc.n_open = 0;
2175 tdc.n_closed = 0;
2176 tdc.n_destroyed = 0;
2177
2178 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2179 &tdc.dc1);
2180 g_assert_nonnull (tdc.dc1);
2181 g_object_unref (tdc.dc1); /* webrtcbin should still hold a ref */
2182 g_object_weak_ref (tdc.dc1, on_data_channel_destroyed, t);
2183 g_signal_connect (tdc.dc1, "on-error",
2184 G_CALLBACK (on_channel_error_not_reached), NULL);
2185 sigid = g_signal_connect (tdc.dc1, "notify::ready-state",
2186 G_CALLBACK (on_data_channel_open), t);
2187
2188 if (i == 0) {
2189 fail_if (gst_element_set_state (t->webrtc1,
2190 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2191 fail_if (gst_element_set_state (t->webrtc2,
2192 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2193
2194 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2195 } else {
2196 /* FIXME: Creating a data channel may result in "on-open" being sent
2197 * before we even had a chance to register the signal. For this test we
2198 * want to make sure that the channel is actually open before we try to
2199 * close it. So if we didn't receive the signal we fall back to a 1s
2200 * timeout where we explicitly check if both channels are open. */
2201 gint64 timeout = g_get_monotonic_time () + 1 * G_TIME_SPAN_SECOND;
2202 g_mutex_lock (&t->lock);
2203 while (((1 << t->state) & STATE_CUSTOM) == 0) {
2204 if (!g_cond_wait_until (&t->cond, &t->lock, timeout)) {
2205 g_assert (is_data_channel_open (tdc.dc1)
2206 && is_data_channel_open (tdc.dc2));
2207 break;
2208 }
2209 }
2210 g_mutex_unlock (&t->lock);
2211 }
2212
2213 g_object_get (tdc.dc1, "id", &channel_id[i], NULL);
2214
2215 g_signal_handler_disconnect (tdc.dc1, sigid);
2216 g_object_weak_ref (tdc.dc2, on_data_channel_destroyed, t);
2217 g_signal_connect (tdc.dc1, "notify::ready-state",
2218 G_CALLBACK (on_data_channel_close), t);
2219 g_signal_connect (tdc.dc2, "notify::ready-state",
2220 G_CALLBACK (on_data_channel_close), t);
2221 test_webrtc_signal_state (t, STATE_NEW);
2222
2223 /* currently we assume there is no renegotiation if the last data channel is
2224 * removed but if it changes this test could be extended to verify both
2225 * the behaviour of removing the last channel as well as the behaviour when
2226 * there are still data channels remaining */
2227 t->on_negotiation_needed = _negotiation_not_reached;
2228 g_signal_emit_by_name (tdc.dc1, "close");
2229
2230 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2231
2232 assert_equals_int (g_atomic_int_get (&tdc.n_closed), 2);
2233 assert_equals_pointer (tdc.dc1, NULL);
2234 assert_equals_pointer (tdc.dc2, NULL);
2235
2236 test_webrtc_signal_state (t, STATE_NEW);
2237 }
2238
2239 /* verify the same stream id has been reused for each data channel */
2240 assert_equals_int (channel_id[0], channel_id[1]);
2241 assert_equals_int (channel_id[0], channel_id[2]);
2242
2243 test_webrtc_free (t);
2244 #undef NUM_CHANNELS
2245 }
2246
2247 GST_END_TEST;
2248
2249 static void
on_buffered_amount_low_emitted(GObject * channel,struct test_webrtc * t)2250 on_buffered_amount_low_emitted (GObject * channel, struct test_webrtc *t)
2251 {
2252 test_webrtc_signal_state (t, STATE_CUSTOM);
2253 }
2254
2255 static void
have_data_channel_check_low_threshold_emitted(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)2256 have_data_channel_check_low_threshold_emitted (struct test_webrtc *t,
2257 GstElement * element, GObject * our, gpointer user_data)
2258 {
2259 g_signal_connect (our, "on-buffered-amount-low",
2260 G_CALLBACK (on_buffered_amount_low_emitted), t);
2261 g_object_set (our, "buffered-amount-low-threshold", 1, NULL);
2262
2263 g_signal_connect (our, "on-error", G_CALLBACK (on_channel_error_not_reached),
2264 NULL);
2265 g_signal_emit_by_name (our, "send-string", "A");
2266 }
2267
GST_START_TEST(test_data_channel_low_threshold)2268 GST_START_TEST (test_data_channel_low_threshold)
2269 {
2270 struct test_webrtc *t = test_webrtc_new ();
2271 GObject *channel = NULL;
2272 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2273 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2274
2275 t->on_negotiation_needed = NULL;
2276 t->on_ice_candidate = NULL;
2277 t->on_data_channel = have_data_channel_check_low_threshold_emitted;
2278
2279 fail_if (gst_element_set_state (t->webrtc1,
2280 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2281 fail_if (gst_element_set_state (t->webrtc2,
2282 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2283
2284 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2285 &channel);
2286 g_assert_nonnull (channel);
2287 t->data_channel_data = channel;
2288 g_signal_connect (channel, "on-error",
2289 G_CALLBACK (on_channel_error_not_reached), NULL);
2290
2291 fail_if (gst_element_set_state (t->webrtc1,
2292 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2293 fail_if (gst_element_set_state (t->webrtc2,
2294 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2295
2296 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2297
2298 g_object_unref (channel);
2299 test_webrtc_free (t);
2300 }
2301
2302 GST_END_TEST;
2303
2304 static void
on_channel_error(GObject * channel,GError * error,struct test_webrtc * t)2305 on_channel_error (GObject * channel, GError * error, struct test_webrtc *t)
2306 {
2307 g_assert_nonnull (error);
2308
2309 test_webrtc_signal_state (t, STATE_CUSTOM);
2310 }
2311
2312 static void
have_data_channel_transfer_large_data(struct test_webrtc * t,GstElement * element,GObject * our,gpointer user_data)2313 have_data_channel_transfer_large_data (struct test_webrtc *t,
2314 GstElement * element, GObject * our, gpointer user_data)
2315 {
2316 GObject *other = user_data;
2317 const gsize size = 1024 * 1024;
2318 guint8 *random_data = g_new (guint8, size);
2319 GBytes *data;
2320 gsize i;
2321
2322 for (i = 0; i < size; i++)
2323 random_data[i] = (guint8) (i & 0xff);
2324
2325 data = g_bytes_new_with_free_func (random_data, size,
2326 (GDestroyNotify) g_free, random_data);
2327
2328 g_object_set_data_full (our, "expected", g_bytes_ref (data),
2329 (GDestroyNotify) g_bytes_unref);
2330 g_signal_connect (our, "on-message-data", G_CALLBACK (on_message_data), t);
2331
2332 g_signal_connect (other, "on-error", G_CALLBACK (on_channel_error), t);
2333 g_signal_emit_by_name (other, "send-data", data);
2334 g_bytes_unref (data);
2335 }
2336
GST_START_TEST(test_data_channel_max_message_size)2337 GST_START_TEST (test_data_channel_max_message_size)
2338 {
2339 struct test_webrtc *t = test_webrtc_new ();
2340 GObject *channel = NULL;
2341 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2342 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2343
2344 t->on_negotiation_needed = NULL;
2345 t->on_ice_candidate = NULL;
2346 t->on_data_channel = have_data_channel_transfer_large_data;
2347
2348 fail_if (gst_element_set_state (t->webrtc1,
2349 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2350 fail_if (gst_element_set_state (t->webrtc2,
2351 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2352
2353 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2354 &channel);
2355 g_assert_nonnull (channel);
2356 t->data_channel_data = channel;
2357
2358 fail_if (gst_element_set_state (t->webrtc1,
2359 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2360 fail_if (gst_element_set_state (t->webrtc2,
2361 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2362
2363 test_validate_sdp_full (t, &offer, &offer, 1 << STATE_CUSTOM, FALSE);
2364
2365 g_object_unref (channel);
2366 test_webrtc_free (t);
2367 }
2368
2369 GST_END_TEST;
2370
2371 static void
_on_ready_state_notify(GObject * channel,GParamSpec * pspec,struct test_webrtc * t)2372 _on_ready_state_notify (GObject * channel, GParamSpec * pspec,
2373 struct test_webrtc *t)
2374 {
2375 gint *n_ready = t->data_channel_data;
2376 GstWebRTCDataChannelState ready_state;
2377
2378 g_object_get (channel, "ready-state", &ready_state, NULL);
2379
2380 if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
2381 if (g_atomic_int_add (n_ready, 1) >= 1) {
2382 test_webrtc_signal_state (t, STATE_CUSTOM);
2383 }
2384 }
2385 }
2386
GST_START_TEST(test_data_channel_pre_negotiated)2387 GST_START_TEST (test_data_channel_pre_negotiated)
2388 {
2389 struct test_webrtc *t = test_webrtc_new ();
2390 GObject *channel1 = NULL, *channel2 = NULL;
2391 VAL_SDP_INIT (media_count, _count_num_sdp_media, GUINT_TO_POINTER (1), NULL);
2392 VAL_SDP_INIT (offer, on_sdp_has_datachannel, NULL, &media_count);
2393 GstStructure *s;
2394 gint n_ready = 0;
2395
2396 t->on_negotiation_needed = NULL;
2397 t->on_ice_candidate = NULL;
2398
2399 fail_if (gst_element_set_state (t->webrtc1,
2400 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2401 fail_if (gst_element_set_state (t->webrtc2,
2402 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2403
2404 s = gst_structure_new ("application/data-channel", "negotiated",
2405 G_TYPE_BOOLEAN, TRUE, "id", G_TYPE_INT, 1, NULL);
2406
2407 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", s,
2408 &channel1);
2409 g_assert_nonnull (channel1);
2410 g_signal_emit_by_name (t->webrtc2, "create-data-channel", "label", s,
2411 &channel2);
2412 g_assert_nonnull (channel2);
2413
2414 fail_if (gst_element_set_state (t->webrtc1,
2415 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2416 fail_if (gst_element_set_state (t->webrtc2,
2417 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
2418
2419 test_validate_sdp_full (t, &offer, &offer, 0, FALSE);
2420
2421 t->data_channel_data = &n_ready;
2422
2423 g_signal_connect (channel1, "notify::ready-state",
2424 G_CALLBACK (_on_ready_state_notify), t);
2425 g_signal_connect (channel2, "notify::ready-state",
2426 G_CALLBACK (_on_ready_state_notify), t);
2427
2428 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2429 test_webrtc_signal_state (t, STATE_NEW);
2430
2431 have_data_channel_transfer_string (t, t->webrtc1, channel1, channel2);
2432
2433 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
2434
2435 g_object_unref (channel1);
2436 g_object_unref (channel2);
2437 gst_structure_free (s);
2438 test_webrtc_free (t);
2439 }
2440
2441 GST_END_TEST;
2442
2443 static void
_count_non_rejected_media(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * sd,gpointer user_data)2444 _count_non_rejected_media (struct test_webrtc *t, GstElement * element,
2445 GstWebRTCSessionDescription * sd, gpointer user_data)
2446 {
2447 guint expected = GPOINTER_TO_UINT (user_data);
2448 guint non_rejected_media;
2449 guint i;
2450
2451 non_rejected_media = 0;
2452
2453 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2454 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2455
2456 if (gst_sdp_media_get_port (media) != 0)
2457 non_rejected_media += 1;
2458 }
2459
2460 fail_unless_equals_int (non_rejected_media, expected);
2461 }
2462
2463 static void
_check_bundle_tag(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * sd,gpointer user_data)2464 _check_bundle_tag (struct test_webrtc *t, GstElement * element,
2465 GstWebRTCSessionDescription * sd, gpointer user_data)
2466 {
2467 gchar **bundled = NULL;
2468 GStrv expected = user_data;
2469 guint i;
2470
2471 fail_unless (_parse_bundle (sd->sdp, &bundled, NULL));
2472
2473 if (!bundled) {
2474 fail_unless_equals_int (g_strv_length (expected), 0);
2475 } else {
2476 fail_unless_equals_int (g_strv_length (bundled), g_strv_length (expected));
2477 }
2478
2479 for (i = 0; i < g_strv_length (expected); i++) {
2480 fail_unless (g_strv_contains ((const gchar **) bundled, expected[i]));
2481 }
2482
2483 g_strfreev (bundled);
2484 }
2485
2486 static void
_check_bundle_only_media(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * sd,gpointer user_data)2487 _check_bundle_only_media (struct test_webrtc *t, GstElement * element,
2488 GstWebRTCSessionDescription * sd, gpointer user_data)
2489 {
2490 gchar **expected_bundle_only = user_data;
2491 guint i;
2492
2493 for (i = 0; i < gst_sdp_message_medias_len (sd->sdp); i++) {
2494 const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp, i);
2495 const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2496
2497 if (g_strv_contains ((const gchar **) expected_bundle_only, mid))
2498 fail_unless (_media_has_attribute_key (media, "bundle-only"));
2499 }
2500 }
2501
GST_START_TEST(test_bundle_audio_video_max_bundle_max_bundle)2502 GST_START_TEST (test_bundle_audio_video_max_bundle_max_bundle)
2503 {
2504 struct test_webrtc *t = create_audio_video_test ();
2505 const gchar *bundle[] = { "audio0", "video1", NULL };
2506 const gchar *offer_bundle_only[] = { "video1", NULL };
2507 const gchar *answer_bundle_only[] = { NULL };
2508
2509 guint media_format_count[] = { 1, 1, };
2510 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2511 media_format_count, NULL);
2512 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2513 &media_formats);
2514 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2515 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &payloads);
2516 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2517 GUINT_TO_POINTER (1), &bundle_tag);
2518 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2519 GUINT_TO_POINTER (2), &bundle_tag);
2520 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2521 &offer_non_reject);
2522 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2523 &answer_non_reject);
2524 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2525 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2526 &offer_bundle);
2527 const gchar *expected_answer_setup[] = { "active", "active" };
2528 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2529 &answer_bundle);
2530 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2531 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2532 &offer_setup);
2533 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2534 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2535 &answer_setup);
2536
2537 /* We set a max-bundle policy on the offering webrtcbin,
2538 * this means that all the offered medias should be part
2539 * of the group:BUNDLE attribute, and they should be marked
2540 * as bundle-only
2541 */
2542 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2543 "max-bundle");
2544 /* We also set a max-bundle policy on the answering webrtcbin,
2545 * this means that all the offered medias should be part
2546 * of the group:BUNDLE attribute, but need not be marked
2547 * as bundle-only.
2548 */
2549 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2550 "max-bundle");
2551
2552 test_validate_sdp (t, &offer, &answer);
2553
2554 test_webrtc_free (t);
2555 }
2556
2557 GST_END_TEST;
2558
GST_START_TEST(test_bundle_audio_video_max_compat_max_bundle)2559 GST_START_TEST (test_bundle_audio_video_max_compat_max_bundle)
2560 {
2561 struct test_webrtc *t = create_audio_video_test ();
2562 const gchar *bundle[] = { "audio0", "video1", NULL };
2563 const gchar *bundle_only[] = { NULL };
2564
2565 guint media_format_count[] = { 1, 1, };
2566 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2567 media_format_count, NULL);
2568 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2569 &media_formats);
2570 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &count);
2571 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2572 GUINT_TO_POINTER (2), &bundle_tag);
2573 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
2574 &count_non_reject);
2575 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2576 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2577 &bundle_sdp);
2578 const gchar *expected_answer_setup[] = { "active", "active" };
2579 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2580 &bundle_sdp);
2581 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2582 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2583 &offer_setup);
2584 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2585 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2586 &answer_setup);
2587
2588 /* We set a max-compat policy on the offering webrtcbin,
2589 * this means that all the offered medias should be part
2590 * of the group:BUNDLE attribute, and they should *not* be marked
2591 * as bundle-only
2592 */
2593 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2594 "max-compat");
2595 /* We set a max-bundle policy on the answering webrtcbin,
2596 * this means that all the offered medias should be part
2597 * of the group:BUNDLE attribute, but need not be marked
2598 * as bundle-only.
2599 */
2600 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2601 "max-bundle");
2602
2603 test_validate_sdp (t, &offer, &answer);
2604
2605 test_webrtc_free (t);
2606 }
2607
2608 GST_END_TEST;
2609
GST_START_TEST(test_bundle_audio_video_max_bundle_none)2610 GST_START_TEST (test_bundle_audio_video_max_bundle_none)
2611 {
2612 struct test_webrtc *t = create_audio_video_test ();
2613 const gchar *offer_mid[] = { "audio0", "video1", NULL };
2614 const gchar *offer_bundle_only[] = { "video1", NULL };
2615 const gchar *answer_mid[] = { NULL };
2616 const gchar *answer_bundle_only[] = { NULL };
2617
2618 guint media_format_count[] = { 1, 1, };
2619 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2620 media_format_count, NULL);
2621 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2622 &media_formats);
2623 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2624 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
2625 GUINT_TO_POINTER (1), &payloads);
2626 VAL_SDP_INIT (offer_bundle_tag, _check_bundle_tag, offer_mid,
2627 &count_non_reject);
2628 VAL_SDP_INIT (answer_bundle_tag, _check_bundle_tag, answer_mid,
2629 &count_non_reject);
2630 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2631 &offer_bundle_tag);
2632 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2633 &answer_bundle_tag);
2634 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2635 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2636 &offer_bundle);
2637 const gchar *expected_answer_setup[] = { "active", "active" };
2638 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2639 &answer_bundle);
2640 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2641 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2642 &offer_setup);
2643 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
2644 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2645 &answer_setup);
2646
2647 /* We set a max-bundle policy on the offering webrtcbin,
2648 * this means that all the offered medias should be part
2649 * of the group:BUNDLE attribute, and they should be marked
2650 * as bundle-only
2651 */
2652 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2653 "max-bundle");
2654 /* We set a none policy on the answering webrtcbin,
2655 * this means that the answer should contain no bundled
2656 * medias, and as the bundle-policy of the offering webrtcbin
2657 * is set to max-bundle, only one media should be active.
2658 */
2659 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy", "none");
2660
2661 test_validate_sdp (t, &offer, &answer);
2662
2663 test_webrtc_free (t);
2664 }
2665
2666 GST_END_TEST;
2667
GST_START_TEST(test_bundle_audio_video_data)2668 GST_START_TEST (test_bundle_audio_video_data)
2669 {
2670 struct test_webrtc *t = create_audio_video_test ();
2671 const gchar *mids[] = { "audio0", "video1", "application2", NULL };
2672 const gchar *offer_bundle_only[] = { "video1", "application2", NULL };
2673 const gchar *answer_bundle_only[] = { NULL };
2674 GObject *channel = NULL;
2675
2676 guint media_format_count[] = { 1, 1, 1 };
2677 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2678 media_format_count, NULL);
2679 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (3),
2680 &media_formats);
2681 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2682 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, mids, &payloads);
2683 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
2684 GUINT_TO_POINTER (1), &bundle_tag);
2685 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
2686 GUINT_TO_POINTER (3), &bundle_tag);
2687 VAL_SDP_INIT (offer_bundle, _check_bundle_only_media, &offer_bundle_only,
2688 &offer_non_reject);
2689 VAL_SDP_INIT (answer_bundle, _check_bundle_only_media, &answer_bundle_only,
2690 &answer_non_reject);
2691 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2692 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2693 &offer_bundle);
2694 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2695 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2696 &answer_bundle);
2697 const gchar *expected_offer_direction[] =
2698 { "sendrecv", "sendrecv", "sendrecv" };
2699 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2700 &offer_setup);
2701 const gchar *expected_answer_direction[] =
2702 { "recvonly", "recvonly", "recvonly" };
2703 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2704 &answer_setup);
2705
2706 /* We set a max-bundle policy on the offering webrtcbin,
2707 * this means that all the offered medias should be part
2708 * of the group:BUNDLE attribute, and they should be marked
2709 * as bundle-only
2710 */
2711 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
2712 "max-bundle");
2713 /* We also set a max-bundle policy on the answering webrtcbin,
2714 * this means that all the offered medias should be part
2715 * of the group:BUNDLE attribute, but need not be marked
2716 * as bundle-only.
2717 */
2718 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
2719 "max-bundle");
2720
2721 fail_if (gst_element_set_state (t->webrtc1,
2722 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2723 fail_if (gst_element_set_state (t->webrtc2,
2724 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
2725
2726 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
2727 &channel);
2728
2729 test_validate_sdp (t, &offer, &answer);
2730
2731 g_object_unref (channel);
2732 test_webrtc_free (t);
2733 }
2734
2735 GST_END_TEST;
2736
GST_START_TEST(test_duplicate_nego)2737 GST_START_TEST (test_duplicate_nego)
2738 {
2739 struct test_webrtc *t = create_audio_video_test ();
2740 guint media_format_count[] = { 1, 1, };
2741 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2742 media_format_count, NULL);
2743 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2744 &media_formats);
2745 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2746 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2747 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2748 &payloads);
2749 const gchar *expected_answer_setup[] = { "active", "active" };
2750 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2751 &payloads);
2752 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2753 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2754 &offer_setup);
2755 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2756 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2757 &answer_setup);
2758 GstHarness *h;
2759 guint negotiation_flag = 0;
2760
2761 /* check that negotiating twice succeeds */
2762
2763 t->on_negotiation_needed = on_negotiation_needed_hit;
2764 t->negotiation_data = &negotiation_flag;
2765
2766 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2767 add_fake_audio_src_harness (h, 96);
2768 t->harnesses = g_list_prepend (t->harnesses, h);
2769
2770 test_validate_sdp (t, &offer, &answer);
2771 fail_unless (negotiation_flag & (1 << 2));
2772
2773 test_webrtc_reset_negotiation (t);
2774 test_validate_sdp (t, &offer, &answer);
2775
2776 test_webrtc_free (t);
2777 }
2778
2779 GST_END_TEST;
2780
GST_START_TEST(test_dual_audio)2781 GST_START_TEST (test_dual_audio)
2782 {
2783 struct test_webrtc *t = create_audio_test ();
2784 guint media_format_count[] = { 1, 1, };
2785 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2786 media_format_count, NULL);
2787 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2788 &media_formats);
2789 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2790 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
2791 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2792 &payloads);
2793 const gchar *expected_answer_setup[] = { "active", "active" };
2794 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2795 &payloads);
2796 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
2797 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2798 &offer_setup);
2799 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly" };
2800 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2801 &answer_setup);
2802 GstHarness *h;
2803 GstWebRTCRTPTransceiver *trans;
2804 GArray *transceivers;
2805 guint mline;
2806
2807 /* test that each mline gets a unique transceiver even with the same caps */
2808
2809 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
2810 add_fake_audio_src_harness (h, 96);
2811 t->harnesses = g_list_prepend (t->harnesses, h);
2812
2813 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2814 add_fake_audio_src_harness (h, 96);
2815 t->harnesses = g_list_prepend (t->harnesses, h);
2816
2817 t->on_negotiation_needed = NULL;
2818 test_validate_sdp (t, &offer, &answer);
2819
2820 g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
2821 fail_unless (transceivers != NULL);
2822 fail_unless_equals_int (2, transceivers->len);
2823
2824 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0);
2825 fail_unless (trans != NULL);
2826 g_object_get (trans, "mlineindex", &mline, NULL);
2827 fail_unless_equals_int (mline, 0);
2828
2829 trans = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 1);
2830 fail_unless (trans != NULL);
2831 g_object_get (trans, "mlineindex", &mline, NULL);
2832 fail_unless_equals_int (mline, 1);
2833
2834 g_array_unref (transceivers);
2835 test_webrtc_free (t);
2836 }
2837
2838 GST_END_TEST;
2839
2840 static void
sdp_increasing_session_version(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)2841 sdp_increasing_session_version (struct test_webrtc *t, GstElement * element,
2842 GstWebRTCSessionDescription * desc, gpointer user_data)
2843 {
2844 GstWebRTCSessionDescription *previous;
2845 const GstSDPOrigin *our_origin, *previous_origin;
2846 const gchar *prop;
2847 guint64 our_v, previous_v;
2848
2849 prop =
2850 TEST_SDP_IS_LOCAL (t, element,
2851 desc) ? "current-local-description" : "current-remote-description";
2852 g_object_get (element, prop, &previous, NULL);
2853
2854 our_origin = gst_sdp_message_get_origin (desc->sdp);
2855 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2856
2857 our_v = g_ascii_strtoull (our_origin->sess_version, NULL, 10);
2858 previous_v = g_ascii_strtoull (previous_origin->sess_version, NULL, 10);
2859
2860 ck_assert_int_lt (previous_v, our_v);
2861
2862 gst_webrtc_session_description_free (previous);
2863 }
2864
2865 static void
sdp_equal_session_id(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)2866 sdp_equal_session_id (struct test_webrtc *t, GstElement * element,
2867 GstWebRTCSessionDescription * desc, gpointer user_data)
2868 {
2869 GstWebRTCSessionDescription *previous;
2870 const GstSDPOrigin *our_origin, *previous_origin;
2871 const gchar *prop;
2872
2873 prop =
2874 TEST_SDP_IS_LOCAL (t, element,
2875 desc) ? "current-local-description" : "current-remote-description";
2876 g_object_get (element, prop, &previous, NULL);
2877
2878 our_origin = gst_sdp_message_get_origin (desc->sdp);
2879 previous_origin = gst_sdp_message_get_origin (previous->sdp);
2880
2881 fail_unless_equals_string (previous_origin->sess_id, our_origin->sess_id);
2882 gst_webrtc_session_description_free (previous);
2883 }
2884
2885 static void
sdp_media_equal_attribute(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,GstWebRTCSessionDescription * previous,const gchar * attr)2886 sdp_media_equal_attribute (struct test_webrtc *t, GstElement * element,
2887 GstWebRTCSessionDescription * desc, GstWebRTCSessionDescription * previous,
2888 const gchar * attr)
2889 {
2890 guint i, n;
2891
2892 n = MIN (gst_sdp_message_medias_len (previous->sdp),
2893 gst_sdp_message_medias_len (desc->sdp));
2894
2895 for (i = 0; i < n; i++) {
2896 const GstSDPMedia *our_media, *other_media;
2897 const gchar *our_mid, *other_mid;
2898
2899 our_media = gst_sdp_message_get_media (desc->sdp, i);
2900 other_media = gst_sdp_message_get_media (previous->sdp, i);
2901
2902 our_mid = gst_sdp_media_get_attribute_val (our_media, attr);
2903 other_mid = gst_sdp_media_get_attribute_val (other_media, attr);
2904
2905 fail_unless_equals_string (our_mid, other_mid);
2906 }
2907 }
2908
2909 static void
sdp_media_equal_mid(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)2910 sdp_media_equal_mid (struct test_webrtc *t, GstElement * element,
2911 GstWebRTCSessionDescription * desc, gpointer user_data)
2912 {
2913 GstWebRTCSessionDescription *previous;
2914 const gchar *prop;
2915
2916 prop =
2917 TEST_SDP_IS_LOCAL (t, element,
2918 desc) ? "current-local-description" : "current-remote-description";
2919 g_object_get (element, prop, &previous, NULL);
2920
2921 sdp_media_equal_attribute (t, element, desc, previous, "mid");
2922
2923 gst_webrtc_session_description_free (previous);
2924 }
2925
2926 static void
sdp_media_equal_ice_params(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)2927 sdp_media_equal_ice_params (struct test_webrtc *t, GstElement * element,
2928 GstWebRTCSessionDescription * desc, gpointer user_data)
2929 {
2930 GstWebRTCSessionDescription *previous;
2931 const gchar *prop;
2932
2933 prop =
2934 TEST_SDP_IS_LOCAL (t, element,
2935 desc) ? "current-local-description" : "current-remote-description";
2936 g_object_get (element, prop, &previous, NULL);
2937
2938 sdp_media_equal_attribute (t, element, desc, previous, "ice-ufrag");
2939 sdp_media_equal_attribute (t, element, desc, previous, "ice-pwd");
2940
2941 gst_webrtc_session_description_free (previous);
2942 }
2943
2944 static void
sdp_media_equal_fingerprint(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)2945 sdp_media_equal_fingerprint (struct test_webrtc *t, GstElement * element,
2946 GstWebRTCSessionDescription * desc, gpointer user_data)
2947 {
2948 GstWebRTCSessionDescription *previous;
2949 const gchar *prop;
2950
2951 prop =
2952 TEST_SDP_IS_LOCAL (t, element,
2953 desc) ? "current-local-description" : "current-remote-description";
2954 g_object_get (element, prop, &previous, NULL);
2955
2956 sdp_media_equal_attribute (t, element, desc, previous, "fingerprint");
2957
2958 gst_webrtc_session_description_free (previous);
2959 }
2960
GST_START_TEST(test_renego_add_stream)2961 GST_START_TEST (test_renego_add_stream)
2962 {
2963 struct test_webrtc *t = create_audio_video_test ();
2964 guint media_format_count[] = { 1, 1, 1 };
2965 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
2966 media_format_count, NULL);
2967 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
2968 &media_formats);
2969 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
2970 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
2971 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
2972 &payloads);
2973 const gchar *expected_answer_setup[] = { "active", "active", "active" };
2974 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
2975 &payloads);
2976 const gchar *expected_offer_direction[] =
2977 { "sendrecv", "sendrecv", "sendrecv" };
2978 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
2979 &offer_setup);
2980 const gchar *expected_answer_direction[] =
2981 { "sendrecv", "recvonly", "recvonly" };
2982 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
2983 &answer_setup);
2984 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
2985 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
2986 &renego_mid);
2987 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
2988 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
2989 &renego_sess_id);
2990 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
2991 &renego_sess_ver);
2992 GstHarness *h;
2993
2994 /* negotiate an AV stream and then renegotiate an extra stream */
2995 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
2996 add_fake_audio_src_harness (h, 96);
2997 t->harnesses = g_list_prepend (t->harnesses, h);
2998
2999 test_validate_sdp (t, &offer, &answer);
3000
3001 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3002 add_fake_audio_src_harness (h, 98);
3003 t->harnesses = g_list_prepend (t->harnesses, h);
3004
3005 media_formats.next = &renego_fingerprint;
3006 count.user_data = GUINT_TO_POINTER (3);
3007
3008 /* renegotiate! */
3009 test_webrtc_reset_negotiation (t);
3010 test_validate_sdp (t, &offer, &answer);
3011
3012 test_webrtc_free (t);
3013 }
3014
3015 GST_END_TEST;
3016
GST_START_TEST(test_renego_stream_add_data_channel)3017 GST_START_TEST (test_renego_stream_add_data_channel)
3018 {
3019 struct test_webrtc *t = create_audio_video_test ();
3020
3021 guint media_format_count[] = { 1, 1, 1 };
3022 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3023 media_format_count, NULL);
3024 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3025 &media_formats);
3026 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3027 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3028 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3029 &payloads);
3030 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3031 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3032 &payloads);
3033 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv", NULL };
3034 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3035 &offer_setup);
3036 const gchar *expected_answer_direction[] = { "sendrecv", "recvonly", NULL };
3037 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3038 &answer_setup);
3039 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3040 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3041 &renego_mid);
3042 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3043 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3044 &renego_sess_id);
3045 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3046 &renego_sess_ver);
3047 GObject *channel;
3048 GstHarness *h;
3049
3050 /* negotiate an AV stream and then renegotiate a data channel */
3051 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3052 add_fake_audio_src_harness (h, 96);
3053 t->harnesses = g_list_prepend (t->harnesses, h);
3054
3055 test_validate_sdp (t, &offer, &answer);
3056
3057 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3058 &channel);
3059
3060 media_formats.next = &renego_fingerprint;
3061 count.user_data = GUINT_TO_POINTER (3);
3062
3063 /* renegotiate! */
3064 test_webrtc_reset_negotiation (t);
3065 test_validate_sdp (t, &offer, &answer);
3066
3067 g_object_unref (channel);
3068 test_webrtc_free (t);
3069 }
3070
3071 GST_END_TEST;
3072
GST_START_TEST(test_renego_data_channel_add_stream)3073 GST_START_TEST (test_renego_data_channel_add_stream)
3074 {
3075 struct test_webrtc *t = test_webrtc_new ();
3076 guint media_format_count[] = { 1, 1, 1 };
3077 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3078 media_format_count, NULL);
3079 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3080 &media_formats);
3081 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3082 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3083 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3084 &payloads);
3085 const gchar *expected_answer_setup[] = { "active", "active" };
3086 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3087 &payloads);
3088 const gchar *expected_offer_direction[] = { NULL, "sendrecv" };
3089 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3090 &offer_setup);
3091 const gchar *expected_answer_direction[] = { NULL, "recvonly" };
3092 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3093 &answer_setup);
3094 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3095 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3096 &renego_mid);
3097 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3098 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3099 &renego_sess_id);
3100 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3101 &renego_sess_ver);
3102 GObject *channel;
3103 GstHarness *h;
3104
3105 /* negotiate an data channel and then renegotiate to add a av stream */
3106 t->on_negotiation_needed = NULL;
3107 t->on_ice_candidate = NULL;
3108 t->on_data_channel = NULL;
3109 t->on_pad_added = _pad_added_fakesink;
3110
3111 fail_if (gst_element_set_state (t->webrtc1,
3112 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3113 fail_if (gst_element_set_state (t->webrtc2,
3114 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3115
3116 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3117 &channel);
3118
3119 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3120
3121 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3122 add_fake_audio_src_harness (h, 97);
3123 t->harnesses = g_list_prepend (t->harnesses, h);
3124
3125 media_formats.next = &renego_fingerprint;
3126 count.user_data = GUINT_TO_POINTER (2);
3127
3128 /* renegotiate! */
3129 test_webrtc_reset_negotiation (t);
3130 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3131
3132 g_object_unref (channel);
3133 test_webrtc_free (t);
3134 }
3135
3136 GST_END_TEST;
3137
3138
GST_START_TEST(test_renego_stream_data_channel_add_stream)3139 GST_START_TEST (test_renego_stream_data_channel_add_stream)
3140 {
3141 struct test_webrtc *t = test_webrtc_new ();
3142 guint media_format_count[] = { 1, 1, 1 };
3143 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3144 media_format_count, NULL);
3145 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3146 &media_formats);
3147 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3148 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3149 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3150 &payloads);
3151 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3152 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3153 &payloads);
3154 const gchar *expected_offer_direction[] = { "sendrecv", NULL, "sendrecv" };
3155 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3156 &offer_setup);
3157 const gchar *expected_answer_direction[] = { "recvonly", NULL, "recvonly" };
3158 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3159 &answer_setup);
3160 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3161 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3162 &renego_mid);
3163 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3164 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3165 &renego_sess_id);
3166 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3167 &renego_sess_ver);
3168 GObject *channel;
3169 GstHarness *h;
3170
3171 /* Negotiate a stream and a data channel, then renogotiate with a new stream */
3172 t->on_negotiation_needed = NULL;
3173 t->on_ice_candidate = NULL;
3174 t->on_data_channel = NULL;
3175 t->on_pad_added = _pad_added_fakesink;
3176
3177 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3178 add_fake_audio_src_harness (h, 97);
3179 t->harnesses = g_list_prepend (t->harnesses, h);
3180
3181 fail_if (gst_element_set_state (t->webrtc1,
3182 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3183 fail_if (gst_element_set_state (t->webrtc2,
3184 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
3185
3186 g_signal_emit_by_name (t->webrtc1, "create-data-channel", "label", NULL,
3187 &channel);
3188
3189 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3190
3191 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3192 add_fake_audio_src_harness (h, 97);
3193 t->harnesses = g_list_prepend (t->harnesses, h);
3194
3195 media_formats.next = &renego_fingerprint;
3196 count.user_data = GUINT_TO_POINTER (3);
3197
3198 /* renegotiate! */
3199 test_webrtc_reset_negotiation (t);
3200 test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
3201
3202 g_object_unref (channel);
3203 test_webrtc_free (t);
3204 }
3205
3206 GST_END_TEST;
3207
GST_START_TEST(test_bundle_renego_add_stream)3208 GST_START_TEST (test_bundle_renego_add_stream)
3209 {
3210 struct test_webrtc *t = create_audio_video_test ();
3211 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3212 const gchar *offer_bundle_only[] = { "video1", "audio2", NULL };
3213 const gchar *answer_bundle_only[] = { NULL };
3214 guint media_format_count[] = { 1, 1, 1 };
3215 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3216 media_format_count, NULL);
3217 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3218 &media_formats);
3219 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3220 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3221 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3222 &payloads);
3223 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3224 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3225 &payloads);
3226 const gchar *expected_offer_direction[] =
3227 { "sendrecv", "sendrecv", "sendrecv" };
3228 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3229 &offer_setup);
3230 const gchar *expected_answer_direction[] =
3231 { "sendrecv", "recvonly", "recvonly" };
3232 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3233 &answer_setup);
3234
3235 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, &payloads);
3236 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3237 &renego_mid);
3238 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3239 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3240 &renego_sess_id);
3241 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3242 &renego_sess_ver);
3243 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3244 VAL_SDP_INIT (offer_non_reject, _count_non_rejected_media,
3245 GUINT_TO_POINTER (1), &bundle_tag);
3246 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
3247 GUINT_TO_POINTER (3), &bundle_tag);
3248 VAL_SDP_INIT (offer_bundle_only_sdp, _check_bundle_only_media,
3249 &offer_bundle_only, &offer_non_reject);
3250 VAL_SDP_INIT (answer_bundle_only_sdp, _check_bundle_only_media,
3251 &answer_bundle_only, &answer_non_reject);
3252 GstHarness *h;
3253
3254 /* We set a max-bundle policy on the offering webrtcbin,
3255 * this means that all the offered medias should be part
3256 * of the group:BUNDLE attribute, and they should be marked
3257 * as bundle-only
3258 */
3259 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3260 "max-bundle");
3261 /* We also set a max-bundle policy on the answering webrtcbin,
3262 * this means that all the offered medias should be part
3263 * of the group:BUNDLE attribute, but need not be marked
3264 * as bundle-only.
3265 */
3266 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3267 "max-bundle");
3268
3269 /* negotiate an AV stream and then renegotiate an extra stream */
3270 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3271 add_fake_audio_src_harness (h, 96);
3272 t->harnesses = g_list_prepend (t->harnesses, h);
3273
3274 test_validate_sdp (t, &offer, &answer);
3275
3276 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3277 add_fake_audio_src_harness (h, 98);
3278 t->harnesses = g_list_prepend (t->harnesses, h);
3279
3280 offer_setup.next = &offer_bundle_only_sdp;
3281 answer_setup.next = &answer_bundle_only_sdp;
3282 count.user_data = GUINT_TO_POINTER (3);
3283
3284 /* renegotiate! */
3285 test_webrtc_reset_negotiation (t);
3286 test_validate_sdp (t, &offer, &answer);
3287
3288 test_webrtc_free (t);
3289 }
3290
3291 GST_END_TEST;
3292
GST_START_TEST(test_bundle_max_compat_max_bundle_renego_add_stream)3293 GST_START_TEST (test_bundle_max_compat_max_bundle_renego_add_stream)
3294 {
3295 struct test_webrtc *t = create_audio_video_test ();
3296 const gchar *bundle[] = { "audio0", "video1", "audio2", NULL };
3297 const gchar *bundle_only[] = { NULL };
3298 guint media_format_count[] = { 1, 1, 1 };
3299 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3300 media_format_count, NULL);
3301 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3302 &media_formats);
3303 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3304 const gchar *expected_offer_setup[] = { "actpass", "actpass", "actpass" };
3305 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3306 &payloads);
3307 const gchar *expected_answer_setup[] = { "active", "active", "active" };
3308 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3309 &payloads);
3310 const gchar *expected_offer_direction[] =
3311 { "sendrecv", "sendrecv", "sendrecv" };
3312 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3313 &offer_setup);
3314 const gchar *expected_answer_direction[] =
3315 { "sendrecv", "recvonly", "recvonly" };
3316 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3317 &answer_setup);
3318
3319 VAL_SDP_INIT (renego_mid, sdp_media_equal_mid, NULL, NULL);
3320 VAL_SDP_INIT (renego_ice_params, sdp_media_equal_ice_params, NULL,
3321 &renego_mid);
3322 VAL_SDP_INIT (renego_sess_id, sdp_equal_session_id, NULL, &renego_ice_params);
3323 VAL_SDP_INIT (renego_sess_ver, sdp_increasing_session_version, NULL,
3324 &renego_sess_id);
3325 VAL_SDP_INIT (renego_fingerprint, sdp_media_equal_fingerprint, NULL,
3326 &renego_sess_ver);
3327 VAL_SDP_INIT (bundle_tag, _check_bundle_tag, bundle, &renego_fingerprint);
3328 VAL_SDP_INIT (count_non_reject, _count_non_rejected_media,
3329 GUINT_TO_POINTER (3), &bundle_tag);
3330 VAL_SDP_INIT (bundle_sdp, _check_bundle_only_media, &bundle_only,
3331 &count_non_reject);
3332 GstHarness *h;
3333
3334 /* We set a max-compat policy on the offering webrtcbin,
3335 * this means that all the offered medias should be part
3336 * of the group:BUNDLE attribute, and they should *not* be marked
3337 * as bundle-only
3338 */
3339 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3340 "max-compat");
3341 /* We set a max-bundle policy on the answering webrtcbin,
3342 * this means that all the offered medias should be part
3343 * of the group:BUNDLE attribute, but need not be marked
3344 * as bundle-only.
3345 */
3346 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3347 "max-bundle");
3348
3349 /* negotiate an AV stream and then renegotiate an extra stream */
3350 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3351 add_fake_audio_src_harness (h, 96);
3352 t->harnesses = g_list_prepend (t->harnesses, h);
3353
3354 test_validate_sdp (t, &offer, &answer);
3355
3356 h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
3357 add_fake_audio_src_harness (h, 98);
3358 t->harnesses = g_list_prepend (t->harnesses, h);
3359
3360 media_formats.next = &bundle_sdp;
3361 count.user_data = GUINT_TO_POINTER (3);
3362
3363 /* renegotiate! */
3364 test_webrtc_reset_negotiation (t);
3365 test_validate_sdp (t, &offer, &answer);
3366
3367 test_webrtc_free (t);
3368 }
3369
3370 GST_END_TEST;
3371
GST_START_TEST(test_renego_transceiver_set_direction)3372 GST_START_TEST (test_renego_transceiver_set_direction)
3373 {
3374 struct test_webrtc *t = create_audio_test ();
3375 guint media_format_count[] = { 1, };
3376 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3377 media_format_count, NULL);
3378 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3379 &media_formats);
3380 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3381 const gchar *expected_offer_setup[] = { "actpass", };
3382 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3383 &payloads);
3384 const gchar *expected_answer_setup[] = { "active", };
3385 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3386 &payloads);
3387 const gchar *expected_offer_direction[] = { "sendrecv", };
3388 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3389 &offer_setup);
3390 const gchar *expected_answer_direction[] = { "sendrecv", };
3391 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3392 &answer_setup);
3393 GstWebRTCRTPTransceiver *transceiver;
3394 GstHarness *h;
3395 GstPad *pad;
3396
3397 /* negotiate an AV stream and then change the transceiver direction */
3398 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3399 add_fake_audio_src_harness (h, 96);
3400 t->harnesses = g_list_prepend (t->harnesses, h);
3401
3402 test_validate_sdp (t, &offer, &answer);
3403
3404 /* renegotiate an inactive transceiver! */
3405 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
3406 g_object_get (pad, "transceiver", &transceiver, NULL);
3407 fail_unless (transceiver != NULL);
3408 g_object_set (transceiver, "direction",
3409 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE, NULL);
3410 expected_offer_direction[0] = "inactive";
3411 expected_answer_direction[0] = "inactive";
3412
3413 /* TODO: also validate EOS events from the inactive change */
3414
3415 test_webrtc_reset_negotiation (t);
3416 test_validate_sdp (t, &offer, &answer);
3417
3418 gst_object_unref (pad);
3419 gst_object_unref (transceiver);
3420 test_webrtc_free (t);
3421 }
3422
3423 GST_END_TEST;
3424
3425 static void
offer_remove_last_media(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)3426 offer_remove_last_media (struct test_webrtc *t, GstElement * element,
3427 GstPromise * promise, gpointer user_data)
3428 {
3429 guint i, n;
3430 GstSDPMessage *new, *old;
3431 const GstSDPOrigin *origin;
3432 const GstSDPConnection *conn;
3433
3434 old = t->offer_desc->sdp;
3435 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_new (&new));
3436
3437 origin = gst_sdp_message_get_origin (old);
3438 conn = gst_sdp_message_get_connection (old);
3439 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_version (new,
3440 gst_sdp_message_get_version (old)));
3441 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_origin (new,
3442 origin->username, origin->sess_id, origin->sess_version,
3443 origin->nettype, origin->addrtype, origin->addr));
3444 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_session_name (new,
3445 gst_sdp_message_get_session_name (old)));
3446 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_information (new,
3447 gst_sdp_message_get_information (old)));
3448 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_uri (new,
3449 gst_sdp_message_get_uri (old)));
3450 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_connection (new,
3451 conn->nettype, conn->addrtype, conn->address, conn->ttl,
3452 conn->addr_number));
3453
3454 n = gst_sdp_message_attributes_len (old);
3455 for (i = 0; i < n; i++) {
3456 const GstSDPAttribute *a = gst_sdp_message_get_attribute (old, i);
3457 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_attribute (new,
3458 a->key, a->value));
3459 }
3460
3461 n = gst_sdp_message_medias_len (old);
3462 fail_unless (n > 0);
3463 for (i = 0; i < n - 1; i++) {
3464 const GstSDPMedia *m = gst_sdp_message_get_media (old, i);
3465 GstSDPMedia *new_m;
3466
3467 fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_copy (m, &new_m));
3468 fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_media (new, new_m));
3469 gst_sdp_media_init (new_m);
3470 gst_sdp_media_free (new_m);
3471 }
3472
3473 gst_webrtc_session_description_free (t->offer_desc);
3474 t->offer_desc = gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_OFFER,
3475 new);
3476 }
3477
3478 static void
offer_set_produced_error(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)3479 offer_set_produced_error (struct test_webrtc *t, GstElement * element,
3480 GstPromise * promise, gpointer user_data)
3481 {
3482 const GstStructure *reply;
3483 GError *error = NULL;
3484
3485 reply = gst_promise_get_reply (promise);
3486 fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
3487 GST_INFO ("error produced: %s", error->message);
3488 g_clear_error (&error);
3489
3490 test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
3491 }
3492
3493 static void
offer_created_produced_error(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)3494 offer_created_produced_error (struct test_webrtc *t, GstElement * element,
3495 GstPromise * promise, gpointer user_data)
3496 {
3497 const GstStructure *reply;
3498 GError *error = NULL;
3499
3500 reply = gst_promise_get_reply (promise);
3501 fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
3502 GST_INFO ("error produced: %s", error->message);
3503 g_clear_error (&error);
3504 }
3505
GST_START_TEST(test_renego_lose_media_fails)3506 GST_START_TEST (test_renego_lose_media_fails)
3507 {
3508 struct test_webrtc *t = create_audio_video_test ();
3509 VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3510 VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
3511
3512 /* check that removing an m=line will produce an error */
3513
3514 test_validate_sdp (t, &offer, &answer);
3515
3516 test_webrtc_reset_negotiation (t);
3517
3518 t->on_offer_created = offer_remove_last_media;
3519 t->on_offer_set = offer_set_produced_error;
3520 t->on_answer_created = NULL;
3521
3522 test_webrtc_create_offer (t);
3523 test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
3524
3525 test_webrtc_free (t);
3526 }
3527
3528 GST_END_TEST;
3529
GST_START_TEST(test_bundle_codec_preferences_rtx_no_duplicate_payloads)3530 GST_START_TEST (test_bundle_codec_preferences_rtx_no_duplicate_payloads)
3531 {
3532 struct test_webrtc *t = test_webrtc_new ();
3533 GstWebRTCRTPTransceiverDirection direction;
3534 GstWebRTCRTPTransceiver *trans;
3535 guint offer_media_format_count[] = { 2, };
3536 guint answer_media_format_count[] = { 1, };
3537 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3538 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3539 offer_media_format_count, &payloads);
3540 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3541 answer_media_format_count, &payloads);
3542 const gchar *expected_offer_setup[] = { "actpass", };
3543 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3544 &offer_media_formats);
3545 const gchar *expected_answer_setup[] = { "active", };
3546 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3547 &answer_media_formats);
3548 const gchar *expected_offer_direction[] = { "recvonly", };
3549 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3550 &offer_setup);
3551 const gchar *expected_answer_direction[] = { "sendonly", };
3552 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3553 &answer_setup);
3554 GstCaps *caps;
3555 GstHarness *h;
3556
3557 /* add a transceiver that will only receive an opus stream and check that
3558 * the created offer is marked as recvonly */
3559 t->on_negotiation_needed = NULL;
3560 t->on_ice_candidate = NULL;
3561 t->on_pad_added = _pad_added_fakesink;
3562
3563 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3564 "max-bundle");
3565 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3566 "max-bundle");
3567
3568 /* setup recvonly transceiver */
3569 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3570 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3571 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3572 &trans);
3573 g_object_set (GST_OBJECT (trans), "do-nack", TRUE, NULL);
3574 gst_caps_unref (caps);
3575 fail_unless (trans != NULL);
3576 gst_object_unref (trans);
3577
3578 /* setup sendonly peer */
3579 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3580 add_fake_video_src_harness (h, 96);
3581 t->harnesses = g_list_prepend (t->harnesses, h);
3582 test_validate_sdp (t, &offer, &answer);
3583
3584 test_webrtc_free (t);
3585 }
3586
3587 GST_END_TEST;
3588
3589 static void
on_sdp_media_no_duplicate_extmaps(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)3590 on_sdp_media_no_duplicate_extmaps (struct test_webrtc *t, GstElement * element,
3591 GstWebRTCSessionDescription * desc, gpointer user_data)
3592 {
3593 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, 0);
3594
3595 fail_unless (media != NULL);
3596
3597 fail_unless_equals_string (gst_sdp_media_get_attribute_val_n (media, "extmap",
3598 0), "1 foobar");
3599
3600 fail_unless (gst_sdp_media_get_attribute_val_n (media, "extmap", 1) == NULL);
3601 }
3602
3603 /* In this test, we validate that identical extmaps for multiple formats
3604 * in the caps of a single transceiver are deduplicated. This is necessary
3605 * because Firefox will complain about duplicate extmap ids and fail negotiation
3606 * otherwise. */
GST_START_TEST(test_codec_preferences_no_duplicate_extmaps)3607 GST_START_TEST (test_codec_preferences_no_duplicate_extmaps)
3608 {
3609 struct test_webrtc *t = test_webrtc_new ();
3610 GstWebRTCRTPTransceiver *trans;
3611 GstWebRTCRTPTransceiverDirection direction;
3612 VAL_SDP_INIT (extmaps, on_sdp_media_no_duplicate_extmaps, NULL, NULL);
3613 GstCaps *caps;
3614 GstStructure *s;
3615
3616 caps = gst_caps_new_empty ();
3617
3618 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3619 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3620 gst_caps_append_structure (caps, s);
3621 s = gst_structure_from_string (H264_RTP_CAPS (97), NULL);
3622 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3623 gst_caps_append_structure (caps, s);
3624
3625 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3626 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3627 &trans);
3628 gst_caps_unref (caps);
3629 fail_unless (trans != NULL);
3630
3631 t->on_negotiation_needed = NULL;
3632 t->on_pad_added = NULL;
3633 t->on_ice_candidate = NULL;
3634
3635 test_validate_sdp (t, &extmaps, NULL);
3636
3637 test_webrtc_free (t);
3638 }
3639
3640 GST_END_TEST;
3641
3642 /* In this test, we validate that trying to use different values
3643 * for the same extmap id in multiple formats in the caps of a
3644 * single transceiver errors out when creating the offer. */
GST_START_TEST(test_codec_preferences_incompatible_extmaps)3645 GST_START_TEST (test_codec_preferences_incompatible_extmaps)
3646 {
3647 struct test_webrtc *t = test_webrtc_new ();
3648 GstWebRTCRTPTransceiver *trans;
3649 GstWebRTCRTPTransceiverDirection direction;
3650 GstCaps *caps;
3651 GstStructure *s;
3652
3653 caps = gst_caps_new_empty ();
3654
3655 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3656 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobar", NULL);
3657 gst_caps_append_structure (caps, s);
3658 s = gst_structure_from_string (H264_RTP_CAPS (97), NULL);
3659 gst_structure_set (s, "extmap-1", G_TYPE_STRING, "foobaz", NULL);
3660 gst_caps_append_structure (caps, s);
3661
3662 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3663 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3664 &trans);
3665 gst_caps_unref (caps);
3666 fail_unless (trans != NULL);
3667
3668 t->on_negotiation_needed = NULL;
3669 t->on_pad_added = NULL;
3670 t->on_ice_candidate = NULL;
3671 t->on_offer_created = offer_created_produced_error;
3672
3673 test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
3674
3675 test_webrtc_free (t);
3676 }
3677
3678 GST_END_TEST;
3679
3680 /* In this test, we validate that extmap values must be of the correct type */
GST_START_TEST(test_codec_preferences_invalid_extmap)3681 GST_START_TEST (test_codec_preferences_invalid_extmap)
3682 {
3683 struct test_webrtc *t = test_webrtc_new ();
3684 GstWebRTCRTPTransceiver *trans;
3685 GstWebRTCRTPTransceiverDirection direction;
3686 GstCaps *caps;
3687 GstStructure *s;
3688
3689 caps = gst_caps_new_empty ();
3690
3691 s = gst_structure_from_string (VP8_RTP_CAPS (96), NULL);
3692 gst_structure_set (s, "extmap-1", G_TYPE_INT, 42, NULL);
3693 gst_caps_append_structure (caps, s);
3694
3695 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
3696 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3697 &trans);
3698 gst_caps_unref (caps);
3699 fail_unless (trans != NULL);
3700
3701 t->on_negotiation_needed = NULL;
3702 t->on_pad_added = NULL;
3703 t->on_ice_candidate = NULL;
3704 t->on_offer_created = offer_created_produced_error;
3705
3706 test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
3707
3708 test_webrtc_free (t);
3709 }
3710
3711 GST_END_TEST;
3712
GST_START_TEST(test_reject_request_pad)3713 GST_START_TEST (test_reject_request_pad)
3714 {
3715 struct test_webrtc *t = test_webrtc_new ();
3716 GstWebRTCRTPTransceiverDirection direction;
3717 GstWebRTCRTPTransceiver *trans, *trans2;
3718 guint offer_media_format_count[] = { 1, };
3719 guint answer_media_format_count[] = { 1, };
3720 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, NULL);
3721 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
3722 offer_media_format_count, &payloads);
3723 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
3724 answer_media_format_count, &payloads);
3725 const gchar *expected_offer_setup[] = { "actpass", };
3726 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3727 &offer_media_formats);
3728 const gchar *expected_answer_setup[] = { "active", };
3729 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3730 &answer_media_formats);
3731 const gchar *expected_offer_direction[] = { "recvonly", };
3732 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3733 &offer_setup);
3734 const gchar *expected_answer_direction[] = { "sendonly", };
3735 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3736 &answer_setup);
3737 GstCaps *caps;
3738 GstHarness *h;
3739 GstPad *pad;
3740 GstPadTemplate *templ;
3741
3742 t->on_negotiation_needed = NULL;
3743 t->on_ice_candidate = NULL;
3744 t->on_pad_added = _pad_added_fakesink;
3745
3746 gst_util_set_object_arg (G_OBJECT (t->webrtc1), "bundle-policy",
3747 "max-bundle");
3748 gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
3749 "max-bundle");
3750
3751 /* setup recvonly transceiver */
3752 caps = gst_caps_from_string (VP8_RTP_CAPS (96));
3753 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3754 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
3755 &trans);
3756 gst_caps_unref (caps);
3757 fail_unless (trans != NULL);
3758
3759 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
3760 add_fake_video_src_harness (h, 96);
3761 t->harnesses = g_list_prepend (t->harnesses, h);
3762
3763 test_validate_sdp (t, &offer, &answer);
3764
3765 /* This should fail because the direction is wrong */
3766 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3767 fail_unless (pad == NULL);
3768
3769 g_object_set (trans, "direction",
3770 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV, NULL);
3771
3772 templ = gst_element_get_pad_template (t->webrtc1, "sink_%u");
3773 fail_unless (templ != NULL);
3774
3775 /* This should fail because the caps are wrong */
3776 caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
3777 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3778 fail_unless (pad == NULL);
3779
3780 g_object_set (trans, "codec-preferences", NULL, NULL);
3781
3782 /* This should fail because the kind doesn't match */
3783 pad = gst_element_request_pad (t->webrtc1, templ, "sink_0", caps);
3784 fail_unless (pad == NULL);
3785 gst_caps_unref (caps);
3786
3787 /* This should succeed and give us sink_0 */
3788 pad = gst_element_request_pad_simple (t->webrtc1, "sink_0");
3789 fail_unless (pad != NULL);
3790
3791 g_object_get (pad, "transceiver", &trans2, NULL);
3792
3793 fail_unless (trans == trans2);
3794
3795 gst_object_unref (pad);
3796 gst_object_unref (trans);
3797 gst_object_unref (trans2);
3798
3799 test_webrtc_free (t);
3800 }
3801
3802 GST_END_TEST;
3803
3804 static void
_verify_media_types(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)3805 _verify_media_types (struct test_webrtc *t, GstElement * element,
3806 GstWebRTCSessionDescription * desc, gpointer user_data)
3807 {
3808 gchar **media_types = user_data;
3809 int i;
3810
3811 for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
3812 const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
3813
3814 fail_unless_equals_string (gst_sdp_media_get_media (media), media_types[i]);
3815 }
3816 }
3817
GST_START_TEST(test_reject_create_offer)3818 GST_START_TEST (test_reject_create_offer)
3819 {
3820 struct test_webrtc *t = test_webrtc_new ();
3821 GstHarness *h;
3822 GstPromise *promise;
3823 GstPromiseResult res;
3824 const GstStructure *s;
3825 GError *error = NULL;
3826
3827 const gchar *media_types[] = { "video", "audio" };
3828 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3829 guint media_format_count[] = { 1, 1 };
3830 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3831 media_format_count, &media_type);
3832 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3833 &media_formats);
3834 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
3835 const gchar *expected_offer_setup[] = { "actpass", "actpass" };
3836 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3837 &payloads);
3838 const gchar *expected_answer_setup[] = { "active", "active" };
3839 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3840 &payloads);
3841 const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv" };
3842 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
3843 &offer_setup);
3844 const gchar *expected_answer_direction[] = { "recvonly", "recvonly" };
3845 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
3846 &answer_setup);
3847
3848 t->on_negotiation_needed = NULL;
3849 t->on_ice_candidate = NULL;
3850 t->on_pad_added = _pad_added_fakesink;
3851
3852 /* setup sendonly peer */
3853 h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
3854 add_fake_audio_src_harness (h, 96);
3855 t->harnesses = g_list_prepend (t->harnesses, h);
3856
3857 /* Check that if there is no 0, we can't create an offer with a hole */
3858 promise = gst_promise_new ();
3859 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3860 res = gst_promise_wait (promise);
3861 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3862 s = gst_promise_get_reply (promise);
3863 fail_unless (s != NULL);
3864 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3865 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
3866 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
3867 fail_unless (g_str_match_string
3868 ("has locked mline 1 but the whole offer only has 0 sections",
3869 error->message, FALSE));
3870 g_clear_error (&error);
3871 gst_promise_unref (promise);
3872
3873 h = gst_harness_new_with_element (t->webrtc1, "sink_%u", NULL);
3874 add_fake_video_src_harness (h, 97);
3875 t->harnesses = g_list_prepend (t->harnesses, h);
3876
3877 /* Adding a second sink, which will fill m-line 0, should fix it */
3878 test_validate_sdp (t, &offer, &answer);
3879
3880 test_webrtc_free (t);
3881 }
3882
3883 GST_END_TEST;
3884
GST_START_TEST(test_reject_set_description)3885 GST_START_TEST (test_reject_set_description)
3886 {
3887 struct test_webrtc *t = test_webrtc_new ();
3888 GstHarness *h;
3889 GstPromise *promise;
3890 GstPromiseResult res;
3891 const GstStructure *s;
3892 GError *error = NULL;
3893 GstWebRTCSessionDescription *desc = NULL;
3894 GstPadTemplate *templ;
3895 GstCaps *caps;
3896 GstPad *pad;
3897
3898 t->on_negotiation_needed = NULL;
3899 t->on_ice_candidate = NULL;
3900 t->on_pad_added = _pad_added_fakesink;
3901
3902 /* setup peer 1 */
3903 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
3904 add_fake_audio_src_harness (h, 96);
3905 t->harnesses = g_list_prepend (t->harnesses, h);
3906
3907 /* Create a second side with specific video caps */
3908 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
3909 fail_unless (templ != NULL);
3910 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
3911 pad = gst_element_request_pad (t->webrtc2, templ, "sink_0", caps);
3912 fail_unless (pad != NULL);
3913 gst_caps_unref (caps);
3914 gst_object_unref (pad);
3915
3916 /* Create an offer */
3917 promise = gst_promise_new ();
3918 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
3919 res = gst_promise_wait (promise);
3920 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3921 s = gst_promise_get_reply (promise);
3922 fail_unless (s != NULL);
3923 gst_structure_get (s, "offer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &desc,
3924 NULL);
3925 fail_unless (desc != NULL);
3926 gst_promise_unref (promise);
3927
3928 fail_if (gst_element_set_state (t->webrtc2,
3929 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
3930
3931 /* Verify that setting an offer where there is a forced m-line with
3932 a different kind fails. */
3933 promise = gst_promise_new ();
3934 g_signal_emit_by_name (t->webrtc2, "set-remote-description", desc, promise);
3935 res = gst_promise_wait (promise);
3936 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
3937 s = gst_promise_get_reply (promise);
3938 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
3939 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
3940 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
3941 fail_unless (g_str_match_string
3942 ("m-line 0 was locked to audio, but SDP has audio media", error->message,
3943 FALSE));
3944
3945 g_clear_error (&error);
3946 fail_unless (s != NULL);
3947 gst_promise_unref (promise);
3948 gst_webrtc_session_description_free (desc);
3949
3950 test_webrtc_free (t);
3951 }
3952
3953 GST_END_TEST;
3954
GST_START_TEST(test_force_second_media)3955 GST_START_TEST (test_force_second_media)
3956 {
3957 struct test_webrtc *t = test_webrtc_new ();
3958 const gchar *media_types[] = { "audio" };
3959 VAL_SDP_INIT (media_type, _verify_media_types, &media_types, NULL);
3960 guint media_format_count[] = { 1, };
3961 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
3962 media_format_count, &media_type);
3963 const gchar *expected_offer_setup[] = { "actpass", };
3964 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
3965 &media_formats);
3966 const gchar *expected_answer_setup[] = { "active", };
3967 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
3968 &media_formats);
3969 const gchar *expected_offer_direction[] = { "sendrecv", };
3970 VAL_SDP_INIT (offer_direction, on_sdp_media_direction,
3971 expected_offer_direction, &offer_setup);
3972 const gchar *expected_answer_direction[] = { "recvonly", };
3973 VAL_SDP_INIT (answer_direction, on_sdp_media_direction,
3974 expected_answer_direction, &answer_setup);
3975 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3976 &answer_direction);
3977 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
3978 &offer_direction);
3979
3980 const gchar *second_media_types[] = { "audio", "video" };
3981 VAL_SDP_INIT (second_media_type, _verify_media_types, &second_media_types,
3982 NULL);
3983 guint second_media_format_count[] = { 1, 1 };
3984 VAL_SDP_INIT (second_media_formats, on_sdp_media_count_formats,
3985 second_media_format_count, &second_media_type);
3986 const gchar *second_expected_offer_setup[] = { "active", "actpass" };
3987 VAL_SDP_INIT (second_offer_setup, on_sdp_media_setup,
3988 second_expected_offer_setup, &second_media_formats);
3989 const gchar *second_expected_answer_setup[] = { "passive", "active" };
3990 VAL_SDP_INIT (second_answer_setup, on_sdp_media_setup,
3991 second_expected_answer_setup, &second_media_formats);
3992 const gchar *second_expected_answer_direction[] = { "sendonly", "recvonly" };
3993 VAL_SDP_INIT (second_answer_direction, on_sdp_media_direction,
3994 second_expected_answer_direction, &second_answer_setup);
3995 const gchar *second_expected_offer_direction[] = { "recvonly", "sendrecv" };
3996 VAL_SDP_INIT (second_offer_direction, on_sdp_media_direction,
3997 second_expected_offer_direction, &second_offer_setup);
3998 VAL_SDP_INIT (second_answer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
3999 &second_answer_direction);
4000 VAL_SDP_INIT (second_offer_count, _count_num_sdp_media, GUINT_TO_POINTER (2),
4001 &second_offer_direction);
4002
4003 GstHarness *h;
4004 guint negotiation_flag = 0;
4005 GstPadTemplate *templ;
4006 GstCaps *caps;
4007 GstPad *pad;
4008
4009 /* add a transceiver that will only receive an opus stream and check that
4010 * the created offer is marked as recvonly */
4011 t->on_negotiation_needed = on_negotiation_needed_hit;
4012 t->negotiation_data = &negotiation_flag;
4013 t->on_ice_candidate = NULL;
4014 t->on_pad_added = _pad_added_fakesink;
4015
4016 /* setup peer */
4017 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4018 add_fake_audio_src_harness (h, 96);
4019 t->harnesses = g_list_prepend (t->harnesses, h);
4020
4021 /* Create a second side with specific video caps */
4022 templ = gst_element_get_pad_template (t->webrtc2, "sink_%u");
4023 fail_unless (templ != NULL);
4024 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
4025 pad = gst_element_request_pad (t->webrtc2, templ, NULL, caps);
4026 gst_caps_unref (caps);
4027 fail_unless (pad != NULL);
4028 h = gst_harness_new_with_element (t->webrtc2, GST_PAD_NAME (pad), NULL);
4029 gst_object_unref (pad);
4030 add_fake_video_src_harness (h, 97);
4031 t->harnesses = g_list_prepend (t->harnesses, h);
4032
4033 test_validate_sdp (t, &offer_count, &answer_count);
4034 fail_unless (negotiation_flag & 1 << 2);
4035
4036 test_webrtc_reset_negotiation (t);
4037
4038 t->offerror = 2;
4039 test_validate_sdp (t, &second_offer_count, &second_answer_count);
4040
4041 test_webrtc_free (t);
4042 }
4043
4044 GST_END_TEST;
4045
GST_START_TEST(test_codec_preferences_caps)4046 GST_START_TEST (test_codec_preferences_caps)
4047 {
4048 GstHarness *h;
4049 GstPad *pad;
4050 GstWebRTCRTPTransceiver *trans;
4051 GstCaps *caps, *caps2;
4052
4053 h = gst_harness_new_with_padnames ("webrtcbin", "sink_0", NULL);
4054 pad = gst_element_get_static_pad (h->element, "sink_0");
4055
4056 g_object_get (pad, "transceiver", &trans, NULL);
4057
4058 caps = gst_caps_from_string ("application/x-rtp, media=video,"
4059 "encoding-name=VP8, payload=115; application/x-rtp, media=video,"
4060 " encoding-name=H264, payload=104");
4061 g_object_set (trans, "codec-preferences", caps, NULL);
4062
4063 caps2 = gst_pad_query_caps (pad, NULL);
4064 fail_unless (gst_caps_is_equal (caps, caps2));
4065 gst_caps_unref (caps2);
4066 gst_caps_unref (caps);
4067
4068 caps = gst_caps_from_string (VP8_RTP_CAPS (115));
4069 fail_unless (gst_pad_query_accept_caps (pad, caps));
4070 gst_harness_set_src_caps (h, g_steal_pointer (&caps));
4071
4072 caps = gst_caps_from_string (VP8_RTP_CAPS (99));
4073 fail_unless (!gst_pad_query_accept_caps (pad, caps));
4074 gst_caps_unref (caps);
4075
4076 gst_object_unref (pad);
4077 gst_object_unref (trans);
4078 gst_harness_teardown (h);
4079 }
4080
4081 GST_END_TEST;
4082
GST_START_TEST(test_codec_preferences_negotiation_sinkpad)4083 GST_START_TEST (test_codec_preferences_negotiation_sinkpad)
4084 {
4085 struct test_webrtc *t = test_webrtc_new ();
4086 guint media_format_count[] = { 1, };
4087 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4088 media_format_count, NULL);
4089 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4090 &media_formats);
4091 VAL_SDP_INIT (payloads2, on_sdp_media_payload_types, GUINT_TO_POINTER (0),
4092 &count);
4093 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &payloads2);
4094 const gchar *expected_offer_setup[] = { "actpass", };
4095 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4096 &payloads);
4097 const gchar *expected_answer_setup[] = { "active", };
4098 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4099 &payloads);
4100 const gchar *expected_offer_direction[] = { "sendrecv", };
4101 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4102 &offer_setup);
4103 const gchar *expected_answer_direction[] = { "recvonly", };
4104 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4105 &answer_setup);
4106
4107 GstPad *pad;
4108 GstWebRTCRTPTransceiver *transceiver;
4109 GstHarness *h;
4110 GstCaps *caps;
4111 GstPromise *promise;
4112 GstPromiseResult res;
4113 const GstStructure *s;
4114 GError *error = NULL;
4115
4116 t->on_negotiation_needed = NULL;
4117 t->on_ice_candidate = NULL;
4118 t->on_pad_added = _pad_added_fakesink;
4119
4120 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4121 pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
4122 g_object_get (pad, "transceiver", &transceiver, NULL);
4123 caps = gst_caps_from_string (VP8_RTP_CAPS (115) ";" VP8_RTP_CAPS (97));
4124 g_object_set (transceiver, "codec-preferences", caps, NULL);
4125 gst_caps_unref (caps);
4126 gst_object_unref (transceiver);
4127 gst_object_unref (pad);
4128
4129 add_fake_video_src_harness (h, 96);
4130 t->harnesses = g_list_prepend (t->harnesses, h);
4131
4132 promise = gst_promise_new ();
4133 g_signal_emit_by_name (t->webrtc1, "create-offer", NULL, promise);
4134 res = gst_promise_wait (promise);
4135 fail_unless_equals_int (res, GST_PROMISE_RESULT_REPLIED);
4136 s = gst_promise_get_reply (promise);
4137 fail_unless (s != NULL);
4138 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
4139 fail_unless (g_error_matches (error, GST_WEBRTC_ERROR,
4140 GST_WEBRTC_ERROR_INTERNAL_FAILURE));
4141 fail_unless (g_str_match_string
4142 ("Caps negotiation on pad sink_0 failed against codec preferences",
4143 error->message, FALSE));
4144 g_clear_error (&error);
4145 gst_promise_unref (promise);
4146
4147 caps = gst_caps_from_string (VP8_RTP_CAPS (97));
4148 gst_harness_set_src_caps (h, caps);
4149
4150 test_validate_sdp (t, &offer, &answer);
4151
4152 test_webrtc_free (t);
4153 }
4154
4155 GST_END_TEST;
4156
4157
4158 static void
add_audio_test_src_harness(GstHarness * h)4159 add_audio_test_src_harness (GstHarness * h)
4160 {
4161 #define L16_CAPS "application/x-rtp, payload=11, media=audio," \
4162 " encoding-name=L16, clock-rate=44100, ssrc=(uint)3484078952"
4163 GstCaps *caps = gst_caps_from_string (L16_CAPS);
4164 gst_harness_set_src_caps (h, caps);
4165 gst_harness_add_src_parse (h, "audiotestsrc is-live=true ! rtpL16pay ! "
4166 L16_CAPS " ! identity", TRUE);
4167 }
4168
4169 static void
_pad_added_harness(struct test_webrtc * t,GstElement * element,GstPad * pad,gpointer user_data)4170 _pad_added_harness (struct test_webrtc *t, GstElement * element,
4171 GstPad * pad, gpointer user_data)
4172 {
4173 GstHarness *h;
4174 GstHarness **sink_harness = user_data;
4175
4176 if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
4177 return;
4178
4179 h = gst_harness_new_with_element (element, NULL, GST_OBJECT_NAME (pad));
4180 t->harnesses = g_list_prepend (t->harnesses, h);
4181
4182 if (sink_harness) {
4183 *sink_harness = h;
4184 g_cond_broadcast (&t->cond);
4185 }
4186 }
4187
4188 static void
new_jitterbuffer_set_fast_start(GstElement * rtpbin,GstElement * rtpjitterbuffer,guint session_id,guint ssrc,gpointer user_data)4189 new_jitterbuffer_set_fast_start (GstElement * rtpbin,
4190 GstElement * rtpjitterbuffer, guint session_id, guint ssrc,
4191 gpointer user_data)
4192 {
4193 g_object_set (rtpjitterbuffer, "faststart-min-packets", 1, NULL);
4194 }
4195
GST_START_TEST(test_codec_preferences_negotiation_srcpad)4196 GST_START_TEST (test_codec_preferences_negotiation_srcpad)
4197 {
4198 struct test_webrtc *t = test_webrtc_new ();
4199 guint media_format_count[] = { 1, };
4200 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4201 media_format_count, NULL);
4202 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4203 &media_formats);
4204 VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL, &count);
4205 const gchar *expected_offer_setup[] = { "actpass", };
4206 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4207 &payloads);
4208 const gchar *expected_answer_setup[] = { "active", };
4209 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4210 &payloads);
4211 const gchar *expected_offer_direction[] = { "sendrecv", };
4212 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4213 &offer_setup);
4214 const gchar *expected_answer_direction[] = { "recvonly", };
4215 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4216 &answer_setup);
4217 VAL_SDP_INIT (answer_non_reject, _count_non_rejected_media,
4218 GUINT_TO_POINTER (0), &count);
4219 GstHarness *h;
4220 GstHarness *sink_harness = NULL;
4221 guint i;
4222 GstElement *rtpbin2;
4223 GstBuffer *buf;
4224
4225 t->on_negotiation_needed = NULL;
4226 t->on_ice_candidate = NULL;
4227 t->on_pad_added = _pad_added_harness;
4228 t->pad_added_data = &sink_harness;
4229
4230 rtpbin2 = gst_bin_get_by_name (GST_BIN (t->webrtc2), "rtpbin");
4231 fail_unless (rtpbin2 != NULL);
4232 g_signal_connect (rtpbin2, "new-jitterbuffer",
4233 G_CALLBACK (new_jitterbuffer_set_fast_start), NULL);
4234 g_object_unref (rtpbin2);
4235
4236 h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
4237 add_audio_test_src_harness (h);
4238 t->harnesses = g_list_prepend (t->harnesses, h);
4239
4240 test_validate_sdp (t, &offer, &answer);
4241
4242 fail_if (gst_element_set_state (t->webrtc1,
4243 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4244 fail_if (gst_element_set_state (t->webrtc2,
4245 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
4246
4247 for (i = 0; i < 10; i++)
4248 gst_harness_push_from_src (h);
4249
4250 g_mutex_lock (&t->lock);
4251 while (sink_harness == NULL) {
4252 gst_harness_push_from_src (h);
4253 g_cond_wait_until (&t->cond, &t->lock, g_get_monotonic_time () + 5000);
4254 }
4255 g_mutex_unlock (&t->lock);
4256 fail_unless (sink_harness->element == t->webrtc2);
4257
4258 /* Get one buffer out, this makes sure the capsfilter is primed and
4259 * avoids races.
4260 */
4261 buf = gst_harness_pull (sink_harness);
4262 fail_unless (buf != NULL);
4263 gst_buffer_unref (buf);
4264
4265 gst_harness_set_sink_caps_str (sink_harness, OPUS_RTP_CAPS (100));
4266
4267 test_webrtc_reset_negotiation (t);
4268 test_validate_sdp_full (t, &offer, &answer_non_reject, 0, FALSE);
4269
4270 test_webrtc_free (t);
4271 }
4272
4273 GST_END_TEST;
4274
4275 static void
_on_new_transceiver_codec_preferences_h264(GstElement * webrtcbin,GstWebRTCRTPTransceiver * trans,gpointer * user_data)4276 _on_new_transceiver_codec_preferences_h264 (GstElement * webrtcbin,
4277 GstWebRTCRTPTransceiver * trans, gpointer * user_data)
4278 {
4279 GstCaps *caps;
4280
4281 caps = gst_caps_from_string ("application/x-rtp,encoding-name=(string)H264");
4282 g_object_set (trans, "codec-preferences", caps, NULL);
4283 gst_caps_unref (caps);
4284 }
4285
4286 static void
on_sdp_media_payload_types_only_h264(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)4287 on_sdp_media_payload_types_only_h264 (struct test_webrtc *t,
4288 GstElement * element, GstWebRTCSessionDescription * desc,
4289 gpointer user_data)
4290 {
4291 const GstSDPMedia *vmedia;
4292 guint video_mline = GPOINTER_TO_UINT (user_data);
4293 guint j;
4294
4295 vmedia = gst_sdp_message_get_media (desc->sdp, video_mline);
4296
4297 for (j = 0; j < gst_sdp_media_attributes_len (vmedia); j++) {
4298 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (vmedia, j);
4299
4300 if (!g_strcmp0 (attr->key, "rtpmap")) {
4301 fail_unless_equals_string (attr->value, "101 H264/90000");
4302 }
4303 }
4304 }
4305
4306
GST_START_TEST(test_codec_preferences_in_on_new_transceiver)4307 GST_START_TEST (test_codec_preferences_in_on_new_transceiver)
4308 {
4309 struct test_webrtc *t = test_webrtc_new ();
4310 GstWebRTCRTPTransceiverDirection direction;
4311 GstWebRTCRTPTransceiver *trans;
4312 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4313 NULL, NULL);
4314 guint offer_media_format_count[] = { 2 };
4315 guint answer_media_format_count[] = { 1 };
4316 VAL_SDP_INIT (offer_media_formats, on_sdp_media_count_formats,
4317 offer_media_format_count, &no_duplicate_payloads);
4318 VAL_SDP_INIT (answer_media_formats, on_sdp_media_count_formats,
4319 answer_media_format_count, &no_duplicate_payloads);
4320 VAL_SDP_INIT (offer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4321 &offer_media_formats);
4322 VAL_SDP_INIT (answer_count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4323 &answer_media_formats);
4324 VAL_SDP_INIT (offer_payloads, on_sdp_media_payload_types,
4325 GUINT_TO_POINTER (0), &offer_count);
4326 VAL_SDP_INIT (answer_payloads, on_sdp_media_payload_types_only_h264,
4327 GUINT_TO_POINTER (0), &answer_count);
4328 const gchar *expected_offer_setup[] = { "actpass", };
4329 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
4330 &offer_payloads);
4331 const gchar *expected_answer_setup[] = { "active", };
4332 VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
4333 &answer_payloads);
4334 const gchar *expected_offer_direction[] = { "sendonly", };
4335 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4336 &offer_setup);
4337 const gchar *expected_answer_direction[] = { "recvonly", };
4338 VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
4339 &answer_setup);
4340 GstCaps *caps;
4341 GstHarness *h;
4342
4343 t->on_negotiation_needed = NULL;
4344 t->on_ice_candidate = NULL;
4345 t->on_pad_added = _pad_added_fakesink;
4346
4347 /* setup sendonly transceiver with VP8 and H264 */
4348 caps = gst_caps_from_string (VP8_RTP_CAPS (97) ";" H264_RTP_CAPS (101));
4349 direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
4350 g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
4351 &trans);
4352 gst_caps_unref (caps);
4353 fail_unless (trans != NULL);
4354 gst_object_unref (trans);
4355
4356 /* setup recvonly peer */
4357 h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
4358 add_fake_video_src_harness (h, 101);
4359 t->harnesses = g_list_prepend (t->harnesses, h);
4360
4361 /* connect to "on-new-transceiver" to set codec-preferences to H264 */
4362 g_signal_connect (t->webrtc2, "on-new-transceiver",
4363 G_CALLBACK (_on_new_transceiver_codec_preferences_h264), NULL);
4364
4365 /* Answer SDP should now have H264 only. Without the codec-preferences it
4366 * would only have VP8 because that comes first in the SDP */
4367
4368 test_validate_sdp (t, &offer, &answer);
4369 test_webrtc_free (t);
4370 }
4371
4372 GST_END_TEST;
4373
4374 static void
add_media_line(struct test_webrtc * t,GstElement * element,GstWebRTCSessionDescription * desc,gpointer user_data)4375 add_media_line (struct test_webrtc *t, GstElement * element,
4376 GstWebRTCSessionDescription * desc, gpointer user_data)
4377 {
4378 GstSDPMedia *media = NULL;
4379 const GstSDPMedia *existing_media;
4380 GstSDPResult res;
4381
4382 existing_media = gst_sdp_message_get_media (desc->sdp, 0);
4383
4384 res = gst_sdp_media_copy (existing_media, &media);
4385 fail_unless (res == GST_SDP_OK);
4386 res = gst_sdp_message_add_media (desc->sdp, media);
4387 fail_unless (res == GST_SDP_OK);
4388 gst_sdp_media_free (media);
4389 }
4390
4391 static void
on_answer_set_rejected(struct test_webrtc * t,GstElement * element,GstPromise * promise,gpointer user_data)4392 on_answer_set_rejected (struct test_webrtc *t, GstElement * element,
4393 GstPromise * promise, gpointer user_data)
4394 {
4395 const GstStructure *s;
4396 GError *error = NULL;
4397 GError *compare_error = user_data;
4398
4399 s = gst_promise_get_reply (promise);
4400 fail_unless (s != NULL);
4401 gst_structure_get (s, "error", G_TYPE_ERROR, &error, NULL);
4402 fail_unless (g_error_matches (error, compare_error->domain,
4403 compare_error->code));
4404 fail_unless_equals_string (compare_error->message, error->message);
4405 g_clear_error (&error);
4406 }
4407
GST_START_TEST(test_invalid_add_media_in_answer)4408 GST_START_TEST (test_invalid_add_media_in_answer)
4409 {
4410 struct test_webrtc *t = create_audio_test ();
4411 VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
4412 NULL, NULL);
4413 guint media_format_count[] = { 1 };
4414 VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
4415 media_format_count, &no_duplicate_payloads);
4416 VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
4417 &media_formats);
4418 const gchar *expected_offer_setup[] = { "actpass", };
4419 VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
4420 const gchar *expected_offer_direction[] = { "sendrecv", };
4421 VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
4422 &offer_setup);
4423 VAL_SDP_INIT (answer, add_media_line, NULL, NULL);
4424 GError answer_set_error = { GST_WEBRTC_ERROR,
4425 GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR,
4426 (gchar *) "Answer doesn't have the same number of m-lines as the offer."
4427 };
4428
4429 /* Ensure that if the answer has more m-lines than the offer, it gets
4430 * rejected.
4431 */
4432
4433 t->on_answer_set = on_answer_set_rejected;
4434 t->answer_set_data = &answer_set_error;
4435
4436 test_validate_sdp (t, &offer, &answer);
4437 test_webrtc_free (t);
4438 }
4439
4440 GST_END_TEST;
4441
4442 static Suite *
webrtcbin_suite(void)4443 webrtcbin_suite (void)
4444 {
4445 Suite *s = suite_create ("webrtcbin");
4446 TCase *tc = tcase_create ("general");
4447 GstPluginFeature *nicesrc, *nicesink, *dtlssrtpdec, *dtlssrtpenc;
4448 GstPluginFeature *sctpenc, *sctpdec;
4449 GstRegistry *registry;
4450
4451 registry = gst_registry_get ();
4452 nicesrc = gst_registry_lookup_feature (registry, "nicesrc");
4453 nicesink = gst_registry_lookup_feature (registry, "nicesink");
4454 dtlssrtpenc = gst_registry_lookup_feature (registry, "dtlssrtpenc");
4455 dtlssrtpdec = gst_registry_lookup_feature (registry, "dtlssrtpdec");
4456 sctpenc = gst_registry_lookup_feature (registry, "sctpenc");
4457 sctpdec = gst_registry_lookup_feature (registry, "sctpdec");
4458
4459 tcase_add_test (tc, test_no_nice_elements_request_pad);
4460 tcase_add_test (tc, test_no_nice_elements_state_change);
4461 if (nicesrc && nicesink && dtlssrtpenc && dtlssrtpdec) {
4462 tcase_add_test (tc, test_sdp_no_media);
4463 tcase_add_test (tc, test_session_stats);
4464 tcase_add_test (tc, test_audio);
4465 tcase_add_test (tc, test_ice_port_restriction);
4466 tcase_add_test (tc, test_audio_video);
4467 tcase_add_test (tc, test_media_direction);
4468 tcase_add_test (tc, test_add_transceiver);
4469 tcase_add_test (tc, test_get_transceivers);
4470 tcase_add_test (tc, test_add_recvonly_transceiver);
4471 tcase_add_test (tc, test_recvonly_sendonly);
4472 tcase_add_test (tc, test_payload_types);
4473 tcase_add_test (tc, test_bundle_audio_video_max_bundle_max_bundle);
4474 tcase_add_test (tc, test_bundle_audio_video_max_bundle_none);
4475 tcase_add_test (tc, test_bundle_audio_video_max_compat_max_bundle);
4476 tcase_add_test (tc, test_dual_audio);
4477 tcase_add_test (tc, test_duplicate_nego);
4478 tcase_add_test (tc, test_renego_add_stream);
4479 tcase_add_test (tc, test_bundle_renego_add_stream);
4480 tcase_add_test (tc, test_bundle_max_compat_max_bundle_renego_add_stream);
4481 tcase_add_test (tc, test_renego_transceiver_set_direction);
4482 tcase_add_test (tc, test_renego_lose_media_fails);
4483 tcase_add_test (tc,
4484 test_bundle_codec_preferences_rtx_no_duplicate_payloads);
4485 tcase_add_test (tc, test_reject_request_pad);
4486 tcase_add_test (tc, test_reject_create_offer);
4487 tcase_add_test (tc, test_reject_set_description);
4488 tcase_add_test (tc, test_force_second_media);
4489 tcase_add_test (tc, test_codec_preferences_caps);
4490 tcase_add_test (tc, test_codec_preferences_negotiation_sinkpad);
4491 tcase_add_test (tc, test_codec_preferences_negotiation_srcpad);
4492 tcase_add_test (tc, test_codec_preferences_in_on_new_transceiver);
4493 tcase_add_test (tc, test_codec_preferences_no_duplicate_extmaps);
4494 tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
4495 tcase_add_test (tc, test_codec_preferences_invalid_extmap);
4496 tcase_add_test (tc, test_invalid_add_media_in_answer);
4497 if (sctpenc && sctpdec) {
4498 tcase_add_test (tc, test_data_channel_create);
4499 tcase_add_test (tc, test_data_channel_remote_notify);
4500 tcase_add_test (tc, test_data_channel_transfer_string);
4501 tcase_add_test (tc, test_data_channel_transfer_data);
4502 tcase_add_test (tc, test_data_channel_create_after_negotiate);
4503 tcase_add_test (tc, test_data_channel_close);
4504 tcase_add_test (tc, test_data_channel_low_threshold);
4505 tcase_add_test (tc, test_data_channel_max_message_size);
4506 tcase_add_test (tc, test_data_channel_pre_negotiated);
4507 tcase_add_test (tc, test_bundle_audio_video_data);
4508 tcase_add_test (tc, test_renego_stream_add_data_channel);
4509 tcase_add_test (tc, test_renego_data_channel_add_stream);
4510 tcase_add_test (tc, test_renego_stream_data_channel_add_stream);
4511 } else {
4512 GST_WARNING ("Some required elements were not found. "
4513 "All datachannel tests are disabled. sctpenc %p, sctpdec %p", sctpenc,
4514 sctpdec);
4515 }
4516 } else {
4517 GST_WARNING ("Some required elements were not found. "
4518 "All media tests are disabled. nicesrc %p, nicesink %p, "
4519 "dtlssrtpenc %p, dtlssrtpdec %p", nicesrc, nicesink, dtlssrtpenc,
4520 dtlssrtpdec);
4521 }
4522
4523 if (nicesrc)
4524 gst_object_unref (nicesrc);
4525 if (nicesink)
4526 gst_object_unref (nicesink);
4527 if (dtlssrtpdec)
4528 gst_object_unref (dtlssrtpdec);
4529 if (dtlssrtpenc)
4530 gst_object_unref (dtlssrtpenc);
4531 if (sctpenc)
4532 gst_object_unref (sctpenc);
4533 if (sctpdec)
4534 gst_object_unref (sctpdec);
4535
4536 suite_add_tcase (s, tc);
4537
4538 return s;
4539 }
4540
4541 GST_CHECK_MAIN (webrtcbin);
4542