return edata.extmap;
}
-struct has_hdrext
+struct hdrext_id
{
- const char *rtphdrext;
- gboolean result;
+ const char *rtphdrext_uri;
+ guint ext_id;
};
static gboolean
-structure_value_has_rtphdrext (GQuark field_id, const GValue * value,
+structure_value_get_rtphdrext_id (GQuark field_id, const GValue * value,
gpointer user_data)
{
- struct has_hdrext *rtphdrext = user_data;
+ struct hdrext_id *rtphdrext = user_data;
+ const char *field_name = g_quark_to_string (field_id);
- if (g_str_has_prefix (g_quark_to_string (field_id), "extmap-")) {
+ if (g_str_has_prefix (field_name, "extmap-")) {
const char *val = NULL;
if (GST_VALUE_HOLDS_ARRAY (value) && gst_value_array_get_size (value) >= 2) {
val = g_value_get_string (value);
}
- if (g_strcmp0 (val, rtphdrext->rtphdrext) == 0) {
- rtphdrext->result = TRUE;
+ if (g_strcmp0 (val, rtphdrext->rtphdrext_uri) == 0) {
+ gint64 id = g_ascii_strtoll (&field_name[strlen ("extmap-")], NULL, 10);
+
+ if (id > 0 && id < 256)
+ rtphdrext->ext_id = id;
+
return FALSE;
}
}
return TRUE;
}
-static gboolean
-caps_contain_rtp_header_extension (const GstCaps * caps,
- const char *rtphdrextname)
+// Returns -1 when not found
+static guint
+caps_get_rtp_header_extension_id (const GstCaps * caps,
+ const char *rtphdrext_uri)
{
- const GstStructure *s = gst_caps_get_structure (caps, 0);
- struct has_hdrext data = { rtphdrextname, FALSE };
+ guint i, n;
+
+ n = gst_caps_get_size (caps);
+ for (i = 0; i < n; i++) {
+ const GstStructure *s = gst_caps_get_structure (caps, i);
+ struct hdrext_id data = { rtphdrext_uri, -1 };
+
+ gst_structure_foreach (s, structure_value_get_rtphdrext_id, &data);
+
+ if (data.ext_id != -1)
+ return data.ext_id;
+ }
- gst_structure_foreach (s, structure_value_has_rtphdrext, &data);
+ return -1;
+}
- return data.result;
+static gboolean
+caps_contain_rtp_header_extension (const GstCaps * caps,
+ const char *rtphdrext_uri)
+{
+ return caps_get_rtp_header_extension_id (caps, rtphdrext_uri) != -1;
}
static gboolean
return TRUE;
}
+static guint
+transport_stream_ptmap_get_rtp_header_extension_id (TransportStream * stream,
+ const char *rtphdrext_uri)
+{
+ guint i;
+
+ for (i = 0; i < stream->ptmap->len; i++) {
+ PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
+ guint id;
+
+ id = caps_get_rtp_header_extension_id (item->caps, rtphdrext_uri);
+ if (id != -1)
+ return id;
+ }
+
+ return -1;
+}
+
+static void
+ensure_rtx_hdr_ext (TransportStream * stream)
+{
+ stream->rtphdrext_id_stream_id =
+ transport_stream_ptmap_get_rtp_header_extension_id (stream,
+ RTPHDREXT_STREAM_ID);
+ stream->rtphdrext_id_repaired_stream_id =
+ transport_stream_ptmap_get_rtp_header_extension_id (stream,
+ RTPHDREXT_REPAIRED_STREAM_ID);
+
+ /* TODO: removing header extensions usage from rtx on renegotiation */
+
+ if (stream->rtxsend) {
+ if (stream->rtphdrext_id_stream_id != -1 && !stream->rtxsend_stream_id) {
+ stream->rtxsend_stream_id =
+ gst_rtp_header_extension_create_from_uri (RTPHDREXT_STREAM_ID);
+ if (!stream->rtxsend_stream_id)
+ g_warn_if_reached ();
+ gst_rtp_header_extension_set_id (stream->rtxsend_stream_id,
+ stream->rtphdrext_id_stream_id);
+
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxsend_stream_id,
+ stream->rtphdrext_id_stream_id, stream->rtxsend);
+
+ g_signal_emit_by_name (stream->rtxsend, "add-extension",
+ stream->rtxsend_stream_id);
+ }
+
+ if (stream->rtphdrext_id_repaired_stream_id != -1
+ && !stream->rtxsend_repaired_stream_id) {
+ stream->rtxsend_repaired_stream_id =
+ gst_rtp_header_extension_create_from_uri
+ (RTPHDREXT_REPAIRED_STREAM_ID);
+ if (!stream->rtxsend_repaired_stream_id)
+ g_warn_if_reached ();
+ gst_rtp_header_extension_set_id (stream->rtxsend_repaired_stream_id,
+ stream->rtphdrext_id_repaired_stream_id);
+
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxsend_repaired_stream_id,
+ stream->rtphdrext_id_repaired_stream_id, stream->rtxsend);
+
+ g_signal_emit_by_name (stream->rtxsend, "add-extension",
+ stream->rtxsend_repaired_stream_id);
+ }
+ }
+
+ if (stream->rtxreceive) {
+ if (stream->rtphdrext_id_stream_id != -1 && !stream->rtxreceive_stream_id) {
+ stream->rtxreceive_stream_id =
+ gst_rtp_header_extension_create_from_uri (RTPHDREXT_STREAM_ID);
+ if (!stream->rtxreceive_stream_id)
+ g_warn_if_reached ();
+ gst_rtp_header_extension_set_id (stream->rtxreceive_stream_id,
+ stream->rtphdrext_id_stream_id);
+
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxsend_stream_id,
+ stream->rtphdrext_id_stream_id, stream->rtxreceive);
+
+ g_signal_emit_by_name (stream->rtxreceive, "add-extension",
+ stream->rtxreceive_stream_id);
+ }
+
+ if (stream->rtphdrext_id_repaired_stream_id != -1
+ && !stream->rtxreceive_repaired_stream_id) {
+ stream->rtxreceive_repaired_stream_id =
+ gst_rtp_header_extension_create_from_uri
+ (RTPHDREXT_REPAIRED_STREAM_ID);
+ if (!stream->rtxreceive_repaired_stream_id)
+ g_warn_if_reached ();
+ gst_rtp_header_extension_set_id (stream->rtxreceive_repaired_stream_id,
+ stream->rtphdrext_id_repaired_stream_id);
+
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxsend_repaired_stream_id,
+ stream->rtphdrext_id_repaired_stream_id, stream->rtxreceive);
+
+ g_signal_emit_by_name (stream->rtxreceive, "add-extension",
+ stream->rtxreceive_repaired_stream_id);
+ }
+ }
+}
+
static void
_update_transport_ptmap_from_media (GstWebRTCBin * webrtc,
TransportStream * stream, const GstSDPMessage * sdp, guint media_idx)
* parameters aren't set up properly for the bundled streams */
_update_transport_ptmap_from_media (webrtc, bundle_stream, sdp->sdp, i);
}
+ ensure_rtx_hdr_ext (bundle_stream);
_connect_rtpfunnel (webrtc, bundle_idx);
}
* bundling we need to do it now */
g_array_set_size (stream->ptmap, 0);
_update_transport_ptmap_from_media (webrtc, stream, sdp->sdp, i);
+ ensure_rtx_hdr_ext (stream);
}
if (trans)
if (!gst_bin_add (GST_BIN (ret), rtx))
g_warn_if_reached ();
+ ensure_rtx_hdr_ext (stream);
stream->rtxsend = gst_object_ref (rtx);
_set_internal_rtpbin_element_props_from_stream (webrtc, stream);
if (!gst_bin_add (GST_BIN (ret), stream->rtxreceive))
g_warn_if_reached ();
+ ensure_rtx_hdr_ext (stream);
+
stream->reddec = gst_element_factory_make ("rtpreddec", NULL);
gst_object_ref (stream->reddec);
if (!gst_bin_add (GST_BIN (ret), stream->reddec))
}
}
-GST_START_TEST (test_simulcast)
+static void
+do_test_simulcast (gboolean enable_fec_rtx)
{
struct test_webrtc *t = test_webrtc_new ();
- guint media_format_count[] = { 1, };
+ guint media_format_count[] = { enable_fec_rtx ? 5 : 1, };
VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
media_format_count, NULL);
VAL_SDP_INIT (payloads, on_sdp_media_no_duplicate_payloads, NULL,
gst_util_set_object_arg (G_OBJECT (t->webrtc2), "bundle-policy",
"max-bundle");
+ if (enable_fec_rtx) {
+ g_signal_connect (t->webrtc1, "on-new-transceiver",
+ G_CALLBACK (on_new_transceiver_set_rtx_fec), NULL);
+ g_signal_connect (t->webrtc2, "on-new-transceiver",
+ G_CALLBACK (on_new_transceiver_set_rtx_fec), NULL);
+ }
+
rtpbin2 = gst_bin_get_by_name (GST_BIN (t->webrtc2), "rtpbin");
fail_unless (rtpbin2 != NULL);
g_signal_connect (rtpbin2, "new-jitterbuffer",
g_array_unref (ssrcs_received);
}
+GST_START_TEST (test_simulcast)
+{
+ do_test_simulcast (FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_simulcast_fec_rtx)
+{
+ do_test_simulcast (TRUE);
+}
+
GST_END_TEST;
static Suite *
tcase_add_test (tc, test_bundle_mid_header_extension);
tcase_add_test (tc, test_max_bundle_fec);
tcase_add_test (tc, test_simulcast);
+ tcase_add_test (tc, test_simulcast_fec_rtx);
if (sctpenc && sctpdec) {
tcase_add_test (tc, test_data_channel_create);
tcase_add_test (tc, test_data_channel_remote_notify);