#include "../../../ext/webrtc/utils.c"
#define OPUS_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=OPUS,media=audio,clock-rate=48000,ssrc=(uint)3384078950"
-#define VP8_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=VP8,media=video,clock-rate=90000,ssrc=(uint)3484078950"
-#define H264_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=H264,media=video,clock-rate=90000,ssrc=(uint)3484078951"
+#define VP8_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=VP8,media=video,clock-rate=90000,ssrc=(uint)3484078951"
+#define H264_RTP_CAPS(pt) "application/x-rtp,payload=" G_STRINGIFY(pt) ",encoding-name=H264,media=video,clock-rate=90000,ssrc=(uint)3484078952"
#define TEST_IS_OFFER_ELEMENT(t, e) ((((t)->offerror == 1 && (e) == (t)->webrtc1) || ((t)->offerror == 2 && (e) == (t)->webrtc2)) ? TRUE : FALSE)
#define TEST_GET_OFFEROR(t) (TEST_IS_OFFER_ELEMENT(t, t->webrtc1) ? (t)->webrtc1 : t->webrtc2)
}
static void
-add_fake_audio_src_harness (GstHarness * h, gint pt)
+add_fake_audio_src_harness (GstHarness * h, gint pt, guint ssrc)
{
GstCaps *caps = gst_caps_from_string (OPUS_RTP_CAPS (pt));
GstStructure *s = gst_caps_get_structure (caps, 0);
+ if (ssrc != 0)
+ gst_structure_set (s, "ssrc", G_TYPE_UINT, ssrc, NULL);
gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
gst_harness_set_src_caps (h, caps);
gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
}
static void
-add_fake_video_src_harness (GstHarness * h, gint pt)
+add_fake_video_src_harness (GstHarness * h, gint pt, guint ssrc)
{
GstCaps *caps = gst_caps_from_string (VP8_RTP_CAPS (pt));
GstStructure *s = gst_caps_get_structure (caps, 0);
+ if (ssrc != 0)
+ gst_structure_set (s, "ssrc", G_TYPE_UINT, ssrc, NULL);
gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
gst_harness_set_src_caps (h, caps);
gst_harness_add_src_parse (h, "fakesrc is-live=true", TRUE);
t->on_pad_added = _pad_added_fakesink;
h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
return t;
GstHarness *h;
h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
- add_fake_video_src_harness (h, 97);
+ add_fake_video_src_harness (h, 97, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
return t;
/* check the default media directions for transceivers */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
GST_END_TEST;
+static void
+on_sdp_media_check_mid (struct test_webrtc *t, GstElement * element,
+ GstWebRTCSessionDescription * desc, gpointer user_data)
+{
+ const char **mid = user_data;
+ guint i;
+
+ for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
+ const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
+ gboolean seen_mid = FALSE;
+ guint j;
+
+ for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
+ const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
+
+ if (g_strcmp0 (attr->key, "mid") == 0) {
+ fail_unless (!seen_mid);
+ seen_mid = TRUE;
+ fail_unless_equals_string (attr->value, mid[i]);
+ }
+ }
+ }
+}
+
GST_START_TEST (test_add_recvonly_transceiver)
{
struct test_webrtc *t = test_webrtc_new ();
media_format_count, &no_duplicate_payloads);
VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
&media_formats);
+ const char *expected_mid[] = { "gst", };
+ VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
const gchar *expected_offer_setup[] = { "actpass", };
- VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count);
+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
const gchar *expected_answer_setup[] = { "active", };
- VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
- &count);
+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
const gchar *expected_offer_direction[] = { "recvonly", };
VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
&offer_setup);
t->on_pad_added = _pad_added_fakesink;
/* setup recvonly transceiver */
- caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
+ caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
&trans);
/* setup sendonly peer */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
/* setup recvonly transceiver */
caps = gst_caps_from_string (OPUS_RTP_CAPS (96));
+ gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, 0xDEADBEEF, NULL);
direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
&trans);
/* setup sendonly stream */
h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers);
fail_unless (transceivers != NULL);
/* setup sendonly peer */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
t->negotiation_data = &negotiation_flag;
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
/* test that each mline gets a unique transceiver even with the same caps */
h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
t->on_negotiation_needed = NULL;
/* negotiate an AV stream and then renegotiate an extra stream */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
- add_fake_audio_src_harness (h, 98);
+ add_fake_audio_src_harness (h, 98, 0xBEEFFFFF);
t->harnesses = g_list_prepend (t->harnesses, h);
media_formats.next = &renego_fingerprint;
/* negotiate an AV stream and then renegotiate a data channel */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
- add_fake_audio_src_harness (h, 97);
+ add_fake_audio_src_harness (h, 97, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
media_formats.next = &renego_fingerprint;
t->on_pad_added = _pad_added_fakesink;
h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
- add_fake_audio_src_harness (h, 97);
+ add_fake_audio_src_harness (h, 97, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
fail_if (gst_element_set_state (t->webrtc1,
test_validate_sdp_full (t, &offer, &answer, 0, FALSE);
h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
- add_fake_audio_src_harness (h, 97);
+ add_fake_audio_src_harness (h, 97, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
media_formats.next = &renego_fingerprint;
/* negotiate an AV stream and then renegotiate an extra stream */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
- add_fake_audio_src_harness (h, 98);
+ add_fake_audio_src_harness (h, 98, 0xBEEFFFFF);
t->harnesses = g_list_prepend (t->harnesses, h);
offer_setup.next = &offer_bundle_only_sdp;
/* negotiate an AV stream and then renegotiate an extra stream */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
h = gst_harness_new_with_element (t->webrtc1, "sink_2", NULL);
- add_fake_audio_src_harness (h, 98);
+ add_fake_audio_src_harness (h, 98, 0xBEEFFFFF);
t->harnesses = g_list_prepend (t->harnesses, h);
media_formats.next = &bundle_sdp;
/* negotiate an AV stream and then change the transceiver direction */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
/* setup sendonly peer */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_video_src_harness (h, 96);
+ add_fake_video_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
fail_unless (trans != NULL);
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_video_src_harness (h, 96);
+ add_fake_video_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
/* setup sendonly peer */
h = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
/* Check that if there is no 0, we can't create an offer with a hole */
gst_promise_unref (promise);
h = gst_harness_new_with_element (t->webrtc1, "sink_%u", NULL);
- add_fake_video_src_harness (h, 97);
+ add_fake_video_src_harness (h, 97, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
/* Adding a second sink, which will fill m-line 0, should fix it */
/* setup peer 1 */
h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
/* Create a second side with specific video caps */
/* setup peer */
h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
- add_fake_audio_src_harness (h, 96);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
/* Create a second side with specific video caps */
fail_unless (pad != NULL);
h = gst_harness_new_with_element (t->webrtc2, GST_PAD_NAME (pad), NULL);
gst_object_unref (pad);
- add_fake_video_src_harness (h, 97);
+ add_fake_video_src_harness (h, 97, 0xBEEFDEAD);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer_count, &answer_count);
gst_object_unref (transceiver);
gst_object_unref (pad);
- add_fake_video_src_harness (h, 96);
+ add_fake_video_src_harness (h, 96, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
promise = gst_promise_new ();
static void
-add_audio_test_src_harness (GstHarness * h)
+add_audio_test_src_harness (GstHarness * h, guint ssrc)
{
#define L16_CAPS "application/x-rtp, payload=11, media=audio," \
" encoding-name=L16, clock-rate=44100, ssrc=(uint)3484078952"
GstCaps *caps = gst_caps_from_string (L16_CAPS);
- gst_harness_set_src_caps (h, caps);
+ GstElement *capsfilter;
+ if (ssrc != 0) {
+ gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, ssrc, NULL);
+ }
gst_harness_add_src_parse (h, "audiotestsrc is-live=true ! rtpL16pay ! "
- L16_CAPS " ! identity", TRUE);
+ "capsfilter name=capsfilter ! identity", TRUE);
+ capsfilter =
+ gst_bin_get_by_name (GST_BIN (h->src_harness->element), "capsfilter");
+ g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
+ gst_harness_set_src_caps (h, caps);
+ caps = NULL;
+ gst_clear_object (&capsfilter);
+#undef L16_CAPS
}
static void
g_object_unref (rtpbin2);
h = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL);
- add_audio_test_src_harness (h);
+ add_audio_test_src_harness (h, 0xDEADBEEF);
t->harnesses = g_list_prepend (t->harnesses, h);
test_validate_sdp (t, &offer, &answer);
/* setup recvonly peer */
h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
- add_fake_video_src_harness (h, 101);
+ add_fake_video_src_harness (h, 101, 0);
t->harnesses = g_list_prepend (t->harnesses, h);
/* connect to "on-new-transceiver" to set codec-preferences to H264 */
GST_END_TEST;
+GST_START_TEST (test_bundle_mid_header_extension)
+{
+ struct test_webrtc *t = test_webrtc_new ();
+ GstWebRTCRTPTransceiverDirection direction;
+ GstWebRTCRTPTransceiver *trans;
+ VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
+ NULL, NULL);
+ guint media_format_count[] = { 1, 1, };
+ VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
+ media_format_count, &no_duplicate_payloads);
+ VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1),
+ &media_formats);
+ const char *expected_mid[] = { "gst", };
+ VAL_SDP_INIT (mid, on_sdp_media_check_mid, expected_mid, &count);
+ const gchar *expected_offer_setup[] = { "actpass", };
+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &mid);
+ const gchar *expected_answer_setup[] = { "active", };
+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, &mid);
+ const gchar *expected_offer_direction[] = { "recvonly", };
+ VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
+ &offer_setup);
+ const gchar *expected_answer_direction[] = { "sendonly", };
+ VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
+ &answer_setup);
+ GstCaps *caps;
+ GstHarness *h;
+ guint mline;
+ char *trans_mid;
+
+ /* add a transceiver that will only receive an opus stream and check that
+ * the created offer is marked as recvonly */
+ t->on_negotiation_needed = NULL;
+ t->on_ice_candidate = NULL;
+ t->on_pad_added = _pad_added_fakesink;
+
+ /* setup recvonly transceiver */
+ caps = gst_caps_from_string (OPUS_RTP_CAPS (96) ", a-mid=(string)gst");
+ direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
+ g_signal_emit_by_name (t->webrtc1, "add-transceiver", direction, caps,
+ &trans);
+ gst_caps_unref (caps);
+ fail_unless (trans != NULL);
+ g_object_get (trans, "mlineindex", &mline, NULL);
+ fail_unless_equals_int (mline, -1);
+
+ /* setup sendonly peer */
+ h = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL);
+ add_fake_audio_src_harness (h, 96, 0xDEADBEEF);
+ t->harnesses = g_list_prepend (t->harnesses, h);
+
+ test_validate_sdp (t, &offer, &answer);
+
+ g_object_get (trans, "mlineindex", &mline, "mid", &trans_mid, NULL);
+ fail_unless_equals_int (mline, 0);
+ fail_unless_equals_string (trans_mid, "gst");
+ g_clear_pointer (&trans_mid, g_free);
+ gst_object_unref (trans);
+
+ test_webrtc_free (t);
+}
+
+GST_END_TEST;
+
static Suite *
webrtcbin_suite (void)
{
tcase_add_test (tc, test_codec_preferences_incompatible_extmaps);
tcase_add_test (tc, test_codec_preferences_invalid_extmap);
tcase_add_test (tc, test_renego_rtx);
+ tcase_add_test (tc, test_bundle_mid_header_extension);
if (sctpenc && sctpdec) {
tcase_add_test (tc, test_data_channel_create);
tcase_add_test (tc, test_data_channel_remote_notify);