g_param_spec_uint ("ssrc", "SSRC",
"The SSRC of the packets (-1 == random)",
0, G_MAXUINT, DEFAULT_SSRC,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_mux_request_new_pad);
gboolean result = FALSE;
gboolean done = FALSE;
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CUSTOM_UPSTREAM:
+ {
+ const GstStructure *s = gst_event_get_structure (event);
+
+ if (gst_structure_has_name (s, "GstRTPCollision")) {
+ guint ssrc = 0;
+
+ if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+ ssrc = -1;
+
+ GST_DEBUG_OBJECT (rtp_mux, "collided ssrc: %" G_GUINT32_FORMAT, ssrc);
+
+ /* choose another ssrc for our stream */
+ GST_OBJECT_LOCK (rtp_mux);
+ if (ssrc == rtp_mux->current_ssrc) {
+ GstCaps *caps;
+ guint suggested_ssrc = 0;
+ guint32 new_ssrc;
+
+ if (gst_structure_get_uint (s, "suggested-ssrc", &suggested_ssrc))
+ rtp_mux->current_ssrc = suggested_ssrc;
+
+ while (ssrc == rtp_mux->current_ssrc)
+ rtp_mux->current_ssrc = g_random_int ();
+
+ new_ssrc = rtp_mux->current_ssrc;
+ GST_OBJECT_UNLOCK (rtp_mux);
+
+ caps = gst_pad_get_current_caps (rtp_mux->srcpad);
+ caps = gst_caps_make_writable (caps);
+ gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, new_ssrc, NULL);
+ gst_pad_set_caps (rtp_mux->srcpad, caps);
+ gst_caps_unref (caps);
+ } else {
+ GST_OBJECT_UNLOCK (rtp_mux);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+
iter = gst_element_iterate_sink_pads (GST_ELEMENT (rtp_mux));
while (!done) {
gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
rtp_mux->ssrc = DEFAULT_SSRC;
+ rtp_mux->current_ssrc = DEFAULT_SSRC;
rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
rtp_mux = GST_RTP_MUX (parent);
+ if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
+ GstCaps *current_caps = gst_pad_get_current_caps (pad);
+
+ if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ gst_buffer_list_unref (bufferlist);
+ goto out;
+ }
+ gst_caps_unref (current_caps);
+ }
+
GST_OBJECT_LOCK (rtp_mux);
padpriv = gst_pad_get_element_private (pad);
gboolean changed = FALSE;
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
- rtp_mux = GST_RTP_MUX (GST_OBJECT_PARENT (pad));
+ rtp_mux = GST_RTP_MUX (parent);
+
+ if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
+ GstCaps *current_caps = gst_pad_get_current_caps (pad);
+
+ if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ gst_buffer_unref (buffer);
+ goto out;
+ }
+ gst_caps_unref (current_caps);
+ }
GST_OBJECT_LOCK (rtp_mux);
padpriv = gst_pad_get_element_private (pad);
ret = gst_pad_push (rtp_mux->srcpad, buffer);
}
+out:
return ret;
}
GstStructure *structure;
gboolean ret = FALSE;
GstRTPMuxPadPrivate *padpriv;
+ GstCaps *peercaps;
+
+ if (!gst_caps_is_fixed (caps))
+ return FALSE;
+
+ peercaps = gst_pad_peer_query_caps (rtp_mux->srcpad, NULL);
+ if (peercaps) {
+ GstCaps *tcaps, *othercaps;;
+ tcaps = gst_pad_get_pad_template_caps (pad);
+ othercaps = gst_caps_intersect_full (peercaps, tcaps,
+ GST_CAPS_INTERSECT_FIRST);
+
+ if (gst_caps_get_size (othercaps) > 0) {
+ structure = gst_caps_get_structure (othercaps, 0);
+ GST_OBJECT_LOCK (rtp_mux);
+ if (gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc)) {
+ GST_DEBUG_OBJECT (pad, "Use downstream ssrc: %x",
+ rtp_mux->current_ssrc);
+ rtp_mux->have_ssrc = TRUE;
+ }
+ GST_OBJECT_UNLOCK (rtp_mux);
+ }
+
+ gst_caps_unref (othercaps);
+
+ gst_caps_unref (peercaps);
+ gst_caps_unref (tcaps);
+ }
structure = gst_caps_get_structure (caps, 0);
&padpriv->timestamp_offset)) {
padpriv->have_timestamp_offset = TRUE;
}
- GST_OBJECT_UNLOCK (rtp_mux);
caps = gst_caps_copy (caps);
+ /* if we don't have a specified ssrc, first try to take one from the caps,
+ and if that fails, generate one */
+ if (!rtp_mux->have_ssrc) {
+ if (rtp_mux->ssrc == DEFAULT_SSRC) {
+ if (!gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc))
+ rtp_mux->current_ssrc = g_random_int ();
+ rtp_mux->have_ssrc = TRUE;
+ }
+ }
+
gst_caps_set_simple (caps,
"timestamp-offset", G_TYPE_UINT, rtp_mux->ts_base,
- "seqnum-offset", G_TYPE_UINT, rtp_mux->seqnum_base, NULL);
+ "seqnum-offset", G_TYPE_UINT, rtp_mux->seqnum_base,
+ "ssrc", G_TYPE_UINT, rtp_mux->current_ssrc, NULL);
+
+ GST_OBJECT_UNLOCK (rtp_mux);
if (rtp_mux->send_stream_start) {
gchar s_id[32];
"setting caps %" GST_PTR_FORMAT " on src pad..", caps);
ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
- gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc);
gst_caps_unref (caps);
GstCaps *peercaps;
GstCaps *othercaps;
GstCaps *tcaps;
- GstCaps *other_filtered;
- peercaps = gst_pad_peer_query_caps (mux->srcpad, filter);
+ peercaps = gst_pad_peer_query_caps (mux->srcpad, NULL);
if (peercaps) {
tcaps = gst_pad_get_pad_template_caps (pad);
}
gst_caps_unref (tcaps);
- clear_caps (othercaps, FALSE);
+ GST_LOG_OBJECT (pad, "Intersected srcpad-peercaps and template caps: %"
+ GST_PTR_FORMAT, othercaps);
- other_filtered = gst_caps_copy (othercaps);
- clear_caps (other_filtered, TRUE);
+ clear_caps (othercaps, TRUE);
g_value_init (&v, GST_TYPE_CAPS);
iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
do {
- gst_value_set_caps (&v, other_filtered);
+ gst_value_set_caps (&v, othercaps);
res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
gst_iterator_resync (iter);
} while (res == GST_ITERATOR_RESYNC);
gst_iterator_free (iter);
- gst_caps_unref (other_filtered);
caps = gst_caps_intersect ((GstCaps *) gst_value_get_caps (&v), othercaps);
GstCaps *filter, *caps;
gst_query_parse_caps (query, &filter);
+ GST_LOG_OBJECT (pad, "Received caps-query with filter-caps: %"
+ GST_PTR_FORMAT, filter);
caps = gst_rtp_mux_getcaps (pad, mux, filter);
gst_query_set_caps_result (query, caps);
+ GST_LOG_OBJECT (mux, "Answering caps-query with caps: %"
+ GST_PTR_FORMAT, caps);
gst_caps_unref (caps);
res = TRUE;
break;
}
return res;
-
-
}
-
static void
gst_rtp_mux_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
rtp_mux = GST_RTP_MUX (object);
+ GST_OBJECT_LOCK (rtp_mux);
switch (prop_id) {
case PROP_TIMESTAMP_OFFSET:
g_value_set_int (value, rtp_mux->ts_offset);
g_value_set_int (value, rtp_mux->seqnum_offset);
break;
case PROP_SEQNUM:
- GST_OBJECT_LOCK (rtp_mux);
g_value_set_uint (value, rtp_mux->seqnum);
- GST_OBJECT_UNLOCK (rtp_mux);
break;
case PROP_SSRC:
g_value_set_uint (value, rtp_mux->ssrc);
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
+ GST_OBJECT_UNLOCK (rtp_mux);
}
static void
rtp_mux->seqnum_offset = g_value_get_int (value);
break;
case PROP_SSRC:
+ GST_OBJECT_LOCK (rtp_mux);
rtp_mux->ssrc = g_value_get_uint (value);
+ rtp_mux->current_ssrc = rtp_mux->ssrc;
+ rtp_mux->have_ssrc = TRUE;
+ GST_OBJECT_UNLOCK (rtp_mux);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GstCaps *caps;
gst_event_parse_caps (event, &caps);
+ GST_LOG_OBJECT (pad, "Received caps-event with caps: %"
+ GST_PTR_FORMAT, caps);
ret = gst_rtp_mux_setcaps (pad, mux, caps);
gst_event_unref (event);
return ret;
g_clear_object (&rtp_mux->last_pad);
rtp_mux->send_stream_start = TRUE;
- if (rtp_mux->ssrc == -1)
- rtp_mux->current_ssrc = g_random_int ();
- else
- rtp_mux->current_ssrc = rtp_mux->ssrc;
-
if (rtp_mux->seqnum_offset == -1)
rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
else
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+ if (rtp_mux->ssrc == DEFAULT_SSRC) {
+ rtp_mux->have_ssrc = FALSE;
+ } else {
+ rtp_mux->current_ssrc = rtp_mux->ssrc;
+ rtp_mux->have_ssrc = TRUE;
+ }
+
GST_DEBUG_OBJECT (rtp_mux, "set timestamp-offset to %u", rtp_mux->ts_base);
GST_OBJECT_UNLOCK (rtp_mux);
return TRUE;
}
+static GstCaps *
+remove_ssrc_from_caps (GstCaps * caps)
+{
+ GstCaps *copy = gst_caps_copy (caps);
+ GstStructure *s = gst_caps_get_structure (copy, 0);
+ gst_structure_remove_field (s, "ssrc");
+ return copy;
+}
+
static gboolean
event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
{
{
GstCaps *caps;
GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
+ GstCaps *caps_no_ssrc;
+ GstCaps *caps2_no_ssrc;
gst_event_parse_caps (event, &caps);
+ caps_no_ssrc = remove_ssrc_from_caps (caps);
+ caps2_no_ssrc = remove_ssrc_from_caps (*caps2);
+
fail_unless (caps2 != NULL && *caps2 != NULL);
fail_unless (gst_caps_is_fixed (caps));
fail_unless (gst_caps_is_fixed (*caps2));
- fail_unless (gst_caps_is_equal_fixed (caps, *caps2));
+
+ fail_unless (gst_caps_is_equal_fixed (caps_no_ssrc, caps2_no_ssrc));
+ gst_caps_unref (caps_no_ssrc);
+ gst_caps_unref (caps2_no_ssrc);
break;
}
default:
gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
caps = gst_pad_peer_query_caps (src1, NULL);
- fail_unless (gst_caps_is_equal (caps, sinkcaps));
gst_caps_unref (caps);
g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
fail_unless (buffers && g_list_length (buffers) == 1);
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
- fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 66);
- fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
- 200 - 57 + 1000 + i);
- fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
+ fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
+ fail_unless_equals_int64 (200 - 57 + 1000 + i,
+ gst_rtp_buffer_get_timestamp (&rtpbuffer));
+ fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
gst_rtp_buffer_unmap (&rtpbuffer);
}
fail_unless (buffers && g_list_length (buffers) == 1);
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
- fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 66);
- fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
- 200 - 57 + 1000 + i);
- fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
+ fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
+ fail_unless_equals_int64 (200 - 57 + 1000 + i,
+ gst_rtp_buffer_get_timestamp (&rtpbuffer));
+ fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
gst_rtp_buffer_unmap (&rtpbuffer);
inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
return buf;
}
-GST_START_TEST (test_rtpmux_ssrc)
+static guint32
+_rtp_buffer_get_ssrc (GstBuffer * buf)
+{
+ GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+ guint32 ret;
+ g_assert (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
+ ret = gst_rtp_buffer_get_ssrc (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+ return ret;
+}
+
+GST_START_TEST (test_rtpmux_ssrc_property)
+{
+ GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+ GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+ GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+ GstBuffer *buf0;
+ GstBuffer *buf1;
+
+ /* set ssrc to 111111 */
+ g_object_set (h->element, "ssrc", 111111, NULL);
+
+ /* both sinkpads have their own idea of what the ssrc should be */
+ gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+ gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+ /* push on both sinkpads with different ssrc */
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h0, generate_test_buffer (0, 222222)));
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+ buf0 = gst_harness_pull (h);
+ buf1 = gst_harness_pull (h);
+
+ /* we expect the ssrc to be what we specified in the property */
+ fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
+ fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));
+
+ gst_buffer_unref (buf0);
+ gst_buffer_unref (buf1);
+
+ gst_harness_teardown (h0);
+ gst_harness_teardown (h1);
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_property_not_set)
+{
+ GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+ GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+ GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+ GstBuffer *buf0;
+ GstBuffer *buf1;
+
+ gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+ gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h0, generate_test_buffer (0, 222222)));
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+ buf0 = gst_harness_pull (h);
+ buf1 = gst_harness_pull (h);
+
+ /* we expect the ssrc to be the first ssrc that came in */
+ fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf0));
+ fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf1));
+
+ gst_buffer_unref (buf0);
+ gst_buffer_unref (buf1);
+
+ gst_harness_teardown (h0);
+ gst_harness_teardown (h1);
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_downstream_can_overrule)
{
- GstHarness * h = gst_harness_new_with_padnames ("rtpdtmfmux", NULL, "src");
- GstHarness * h0 = gst_harness_new_with_element (
- h->element, "sink_0", NULL);
- GstHarness * h1 = gst_harness_new_with_element (
- h->element, "sink_1", NULL);
+ GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+ GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+ GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+ GstBuffer *buf0;
+ GstBuffer *buf1;
+
+ /* downstream is specifying 444444 as ssrc */
+ gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");
+ /* rtpmux ssrc is set to 111111 */
g_object_set (h->element, "ssrc", 111111, NULL);
+ /* while upstream ssrc is 222222 and 333333 */
+ gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+ gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h0, generate_test_buffer (0, 222222)));
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+ buf0 = gst_harness_pull (h);
+ buf1 = gst_harness_pull (h);
+
+ /* we expect the ssrc to be downstream ssrc */
+ fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
+ fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
+
+ gst_buffer_unref (buf0);
+ gst_buffer_unref (buf1);
+
+ gst_harness_teardown (h0);
+ gst_harness_teardown (h1);
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_downstream_dynamic)
+{
+ GstHarness *h = gst_harness_new_parse ("rtpmux ! capsfilter");
+ GstElement *rtpmux = gst_harness_find_element (h, "rtpmux");
+ GstElement *capsfilter = gst_harness_find_element (h, "capsfilter");
+
+ GstHarness *h0 = gst_harness_new_with_element (rtpmux, "sink_0", NULL);
+ GstHarness *h1 = gst_harness_new_with_element (rtpmux, "sink_1", NULL);
+ GstCaps *caps;
+ GstBuffer *buf0;
+ GstBuffer *buf1;
+
+ gst_harness_play (h);
+
+ caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)444444");
+ g_object_set (capsfilter, "caps", caps, NULL);
+ gst_caps_unref (caps);
+
+ /* while upstream ssrc is 222222 and 333333 */
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
fail_unless_equals_int (GST_FLOW_OK,
gst_harness_push (h1, generate_test_buffer (0, 333333)));
+ /* we expect the ssrc to be downstream ssrc (444444) */
+ buf0 = gst_harness_pull (h);
+ buf1 = gst_harness_pull (h);
+ fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
+ fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
+ gst_buffer_unref (buf0);
+ gst_buffer_unref (buf1);
+
+ caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)555555");
+ g_object_set (capsfilter, "caps", caps, NULL);
+ gst_caps_unref (caps);
+
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h0, generate_test_buffer (0, 222222)));
+ fail_unless_equals_int (GST_FLOW_OK,
+ gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+ /* we expect the ssrc to be the new downstream ssrc (555555) */
+ buf0 = gst_harness_pull (h);
+ buf1 = gst_harness_pull (h);
+ fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf0));
+ fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf1));
+ gst_buffer_unref (buf0);
+ gst_buffer_unref (buf1);
+
+ gst_object_unref (rtpmux);
gst_harness_teardown (h0);
gst_harness_teardown (h1);
gst_harness_teardown (h);
}
+
GST_END_TEST;
static Suite *
tc_chain = tcase_create ("rtpmux_basic");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_rtpmux_basic);
- tcase_add_test (tc_chain, test_rtpmux_ssrc);
+ tcase_add_test (tc_chain, test_rtpmux_ssrc_property);
+ tcase_add_test (tc_chain, test_rtpmux_ssrc_property_not_set);
+ tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_can_overrule);
+ tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_dynamic);
tc_chain = tcase_create ("rtpdtmfmux_basic");
tcase_add_test (tc_chain, test_rtpdtmfmux_basic);