Commit dcd3ce97 authored by Philippe Normand's avatar Philippe Normand 🦀

rtpbin: receive bundle support

A new signal named on-bundled-ssrc is provided and can be
used by the application to redirect a stream to a different
GstRtpSession or to keep the RTX stream grouped within the
GstRtpSession of the same media type.

https://bugzilla.gnome.org/show_bug.cgi?id=772740
parent f1726c70
......@@ -374,6 +374,14 @@ GstRtpBin *gstrtpbin
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-bundled-ssrc</NAME>
<RETURNS>guint</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpJitterBuffer::clear-pt-map</NAME>
<RETURNS>void</RETURNS>
......
......@@ -53,6 +53,13 @@
* SSRC in the RTP packets to its own SSRC and wil forward the packets on the
* send_rtp_src_\%u pad after updating its internal state.
*
* #GstRtpBin can also demultiplex incoming bundled streams. The first
* #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
* based on their SSRC and potentially dispatched to a different #GstRtpSession.
* Because retransmission SSRCs need to be merged with the corresponding media
* stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
* application can find out to which session the SSRC belongs.
*
* The session manager needs the clock-rate of the payload types it is handling
* and will signal the #GstRtpSession::request-pt-map signal when it needs such a
* mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
......@@ -276,6 +283,8 @@ enum
SIGNAL_ON_NEW_SENDER_SSRC,
SIGNAL_ON_SENDER_SSRC_ACTIVE,
SIGNAL_ON_BUNDLED_SSRC,
LAST_SIGNAL
};
......@@ -362,6 +371,14 @@ static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
static GstPad *complete_session_sink (GstRtpBin * rtpbin,
GstRtpBinSession * session, gboolean bundle_demuxer_needed);
static void
complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
guint sessid);
static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);
/* Manages the RTP stream for one SSRC.
*
......@@ -428,6 +445,12 @@ struct _GstRtpBinSession
gulong demux_newpad_sig;
gulong demux_padremoved_sig;
/* Bundling support */
GstElement *rtp_funnel;
GstElement *rtcp_funnel;
GstElement *bundle_demux;
gulong bundle_demux_newpad_sig;
GMutex lock;
/* list of GstRtpBinStream */
......@@ -629,6 +652,96 @@ ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
GST_RTP_BIN_UNLOCK (rtpbin);
}
static void
new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
GstRtpBinSession * session)
{
GValue result = G_VALUE_INIT;
GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
guint session_id = 0;
GstRtpBinSession *target_session = NULL;
GstRtpBin *rtpbin = session->bin;
gchar *name;
GstPad *src_pad;
GstPad *recv_rtp_sink = NULL;
GstPad *recv_rtcp_sink = NULL;
GstPadLinkReturn ret;
GST_RTP_BIN_DYN_LOCK (rtpbin);
GST_DEBUG_OBJECT (rtpbin, "new bundled SSRC pad %08x, %s:%s", ssrc,
GST_DEBUG_PAD_NAME (pad));
g_value_init (&result, G_TYPE_UINT);
g_value_init (&params[0], GST_TYPE_ELEMENT);
g_value_set_object (&params[0], rtpbin);
g_value_init (&params[1], G_TYPE_UINT);
g_value_set_uint (&params[1], ssrc);
g_signal_emitv (params,
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &result);
g_value_unset (&params[0]);
session_id = g_value_get_uint (&result);
if (session_id == 0) {
target_session = session;
} else {
target_session = find_session_by_id (rtpbin, (gint) session_id);
if (!target_session) {
target_session = create_session (rtpbin, session_id);
}
if (!target_session->recv_rtp_sink) {
recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
}
if (!target_session->recv_rtp_src)
complete_session_receiver (rtpbin, target_session, session_id);
if (!target_session->recv_rtcp_sink) {
recv_rtcp_sink =
complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
}
}
GST_DEBUG_OBJECT (rtpbin, "Assigning bundled ssrc %u to session %u", ssrc,
session_id);
if (!recv_rtp_sink) {
recv_rtp_sink =
gst_element_get_request_pad (target_session->rtp_funnel, "sink_%u");
}
if (!recv_rtcp_sink) {
recv_rtcp_sink =
gst_element_get_request_pad (target_session->rtcp_funnel, "sink_%u");
}
name = g_strdup_printf ("src_%u", ssrc);
src_pad = gst_element_get_static_pad (element, name);
ret = gst_pad_link (src_pad, recv_rtp_sink);
g_free (name);
gst_object_unref (src_pad);
gst_object_unref (recv_rtp_sink);
if (ret != GST_PAD_LINK_OK) {
g_warning
("rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u",
session_id);
}
name = g_strdup_printf ("rtcp_src_%u", ssrc);
src_pad = gst_element_get_static_pad (element, name);
gst_pad_link (src_pad, recv_rtcp_sink);
g_free (name);
gst_object_unref (src_pad);
gst_object_unref (recv_rtcp_sink);
if (ret != GST_PAD_LINK_OK) {
g_warning
("rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u",
session_id);
}
GST_RTP_BIN_DYN_UNLOCK (rtpbin);
}
/* create a session with the given id. Must be called with RTP_BIN_LOCK */
static GstRtpBinSession *
create_session (GstRtpBin * rtpbin, gint id)
......@@ -649,6 +762,10 @@ create_session (GstRtpBin * rtpbin, gint id)
sess->bin = rtpbin;
sess->session = session;
sess->demux = demux;
sess->rtp_funnel = gst_element_factory_make ("funnel", NULL);
sess->rtcp_funnel = gst_element_factory_make ("funnel", NULL);
sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) gst_caps_unref);
rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
......@@ -696,6 +813,8 @@ create_session (GstRtpBin * rtpbin, gint id)
gst_bin_add (GST_BIN_CAST (rtpbin), session);
gst_bin_add (GST_BIN_CAST (rtpbin), demux);
gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtp_funnel);
gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtcp_funnel);
GST_OBJECT_LOCK (rtpbin);
target = GST_STATE_TARGET (rtpbin);
......@@ -704,6 +823,8 @@ create_session (GstRtpBin * rtpbin, gint id)
/* change state only to what's needed */
gst_element_set_state (demux, target);
gst_element_set_state (session, target);
gst_element_set_state (sess->rtp_funnel, target);
gst_element_set_state (sess->rtcp_funnel, target);
return sess;
......@@ -807,7 +928,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
GValue ret = { 0 };
GValue args[3] = { {0}, {0}, {0} };
GST_DEBUG ("searching pt %d in cache", pt);
GST_DEBUG ("searching pt %u in cache", pt);
GST_RTP_SESSION_LOCK (session);
......@@ -820,7 +941,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
bin = session->bin;
GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
GST_DEBUG ("emiting signal for pt %u in session %u", pt, session->id);
/* not in cache, send signal to request caps */
g_value_init (&args[0], GST_TYPE_ELEMENT);
......@@ -856,7 +977,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
if (!caps)
goto no_caps;
GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
GST_DEBUG ("caching pt %u as %" GST_PTR_FORMAT, pt, caps);
/* store in cache, take additional ref */
g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
......@@ -947,7 +1068,7 @@ gst_rtp_bin_get_session (GstRtpBin * bin, guint session_id)
GstElement *ret = NULL;
GST_RTP_BIN_LOCK (bin);
GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %d", session_id);
GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %u", session_id);
session = find_session_by_id (bin, (gint) session_id);
if (session) {
ret = gst_object_ref (session->session);
......@@ -964,7 +1085,7 @@ gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
GstRtpBinSession *session;
GST_RTP_BIN_LOCK (bin);
GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %d",
GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %u",
session_id);
session = find_session_by_id (bin, (gint) session_id);
if (session) {
......@@ -2194,6 +2315,29 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
/**
* GstRtpBin::on-bundled-ssrc:
* @rtpbin: the object which received the signal
* @ssrc: the bundled SSRC
*
* Notify of a new incoming bundled SSRC. If no handler is connected to the
* signal then the #GstRtpSession created for the recv_rtp_sink_\%u
* request pad will be managing this new SSRC. However if there is a handler
* connected then the application can decided to dispatch this new stream to
* another session by providing its ID as return value of the handler. This
* can be particularly useful to keep retransmission SSRCs grouped with the
* session for which they handle retransmission.
*
* Since: 1.12
*/
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
g_signal_new ("on-bundled-ssrc", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
on_bundled_ssrc), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
g_object_class_install_property (gobject_class, PROP_SDES,
g_param_spec_boxed ("sdes", "SDES",
"The SDES items of this session",
......@@ -3021,7 +3165,7 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,
rtpbin = stream->bin;
GST_DEBUG ("new payload pad %d", pt);
GST_DEBUG_OBJECT (rtpbin, "new payload pad %u", pt);
GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
......@@ -3078,7 +3222,7 @@ pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
rtpbin = session->bin;
GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %u in session %u", pt,
session->id);
caps = get_pt_map (session, pt);
......@@ -3099,7 +3243,7 @@ static void
payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
{
GST_DEBUG_OBJECT (session->bin,
"emiting signal for pt type changed to %d in session %d", pt,
"emiting signal for pt type changed to %u in session %u", pt,
session->id);
g_signal_emit (session->bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
......@@ -3246,15 +3390,42 @@ no_stream:
}
}
static gboolean
complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
static void
session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
{
GstRtpBin *rtpbin;
if (session->bundle_demux)
return;
rtpbin = session->bin;
if (g_signal_has_handler_pending (rtpbin,
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
GST_DEBUG_OBJECT (rtpbin, "Adding a bundle SSRC demuxer to session %u",
session->id);
session->bundle_demux = gst_element_factory_make ("rtpssrcdemux", NULL);
session->bundle_demux_newpad_sig = g_signal_connect (session->bundle_demux,
"new-ssrc-pad", (GCallback) new_bundled_ssrc_pad_found, session);
gst_bin_add (GST_BIN_CAST (rtpbin), session->bundle_demux);
gst_element_sync_state_with_parent (session->bundle_demux);
} else {
GST_DEBUG_OBJECT (rtpbin,
"No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u",
session->id);
}
}
static GstPad *
complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
gboolean bundle_demuxer_needed)
{
gchar *gname;
guint sessid = session->id;
GstPad *recv_rtp_sink;
GstPad *funnel_src;
GstElement *decoder;
GstElementClass *klass;
GstPadTemplate *templ;
g_assert (!session->recv_rtp_sink);
/* get recv_rtp pad and store */
session->recv_rtp_sink =
......@@ -3265,6 +3436,9 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
g_signal_connect (session->recv_rtp_sink, "notify::caps",
(GCallback) caps_changed, session);
if (bundle_demuxer_needed)
session_maybe_create_bundle_demuxer (session);
GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
if (decoder) {
......@@ -3282,7 +3456,14 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
if (decsrc == NULL)
goto dec_src_failed;
ret = gst_pad_link (decsrc, session->recv_rtp_sink);
if (session->bundle_demux) {
GstPad *demux_sink;
demux_sink = gst_element_get_static_pad (session->bundle_demux, "sink");
ret = gst_pad_link (decsrc, demux_sink);
gst_object_unref (demux_sink);
} else {
ret = gst_pad_link (decsrc, session->recv_rtp_sink);
}
gst_object_unref (decsrc);
if (ret != GST_PAD_LINK_OK)
......@@ -3290,81 +3471,54 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
recv_rtp_sink = gst_object_ref (session->recv_rtp_sink);
if (session->bundle_demux) {
recv_rtp_sink =
gst_element_get_static_pad (session->bundle_demux, "sink");
} else {
recv_rtp_sink =
gst_element_get_request_pad (session->rtp_funnel, "sink_%u");
}
}
GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
klass = GST_ELEMENT_GET_CLASS (rtpbin);
gname = g_strdup_printf ("recv_rtp_sink_%u", sessid);
templ = gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u");
session->recv_rtp_sink_ghost =
gst_ghost_pad_new_from_template (gname, recv_rtp_sink, templ);
gst_object_unref (recv_rtp_sink);
gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
g_free (gname);
funnel_src = gst_element_get_static_pad (session->rtp_funnel, "src");
gst_pad_link (funnel_src, session->recv_rtp_sink);
gst_object_unref (funnel_src);
return TRUE;
return recv_rtp_sink;
/* ERRORS */
pad_failed:
{
g_warning ("rtpbin: failed to get session recv_rtp_sink pad");
return FALSE;
return NULL;
}
dec_sink_failed:
{
g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
return FALSE;
g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
return NULL;
}
dec_src_failed:
{
g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
gst_object_unref (recv_rtp_sink);
return FALSE;
return NULL;
}
dec_link_failed:
{
g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
g_warning ("rtpbin: failed to link rtp decoder for session %u", sessid);
gst_object_unref (recv_rtp_sink);
return FALSE;
return NULL;
}
}
/* Create a pad for receiving RTP for the session in @name. Must be called with
* RTP_BIN_LOCK.
*/
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
static void
complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
guint sessid)
{
guint sessid;
GstElement *aux;
GstPad *recv_rtp_src;
GstRtpBinSession *session;
/* first get the session number */
if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
goto no_name;
GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
/* get or create session */
session = find_session_by_id (rtpbin, sessid);
if (!session) {
GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
/* create session now */
session = create_session (rtpbin, sessid);
if (session == NULL)
goto create_error;
}
/* check if pad was requested */
if (session->recv_rtp_sink_ghost != NULL)
return session->recv_rtp_sink_ghost;
/* setup the session sink pad */
if (!complete_session_sink (rtpbin, session))
goto session_sink_failed;
g_assert (!session->recv_rtp_src);
session->recv_rtp_src =
gst_element_get_static_pad (session->session, "recv_rtp_src");
......@@ -3381,7 +3535,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
GST_DEBUG_OBJECT (rtpbin, "linking AUX receiver");
pname = g_strdup_printf ("sink_%d", sessid);
pname = g_strdup_printf ("sink_%u", sessid);
auxsink = gst_element_get_static_pad (aux, pname);
g_free (pname);
if (auxsink == NULL)
......@@ -3394,7 +3548,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
/* this can be NULL when this AUX element is not to be linked to
* an SSRC demuxer */
pname = g_strdup_printf ("src_%d", sessid);
pname = g_strdup_printf ("src_%u", sessid);
recv_rtp_src = gst_element_get_static_pad (aux, pname);
g_free (pname);
} else {
......@@ -3408,8 +3562,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
sinkdpad = gst_element_get_static_pad (session->demux, "sink");
GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
gst_pad_link_full (recv_rtp_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
gst_object_unref (recv_rtp_src);
gst_object_unref (sinkdpad);
gst_object_unref (recv_rtp_src);
/* connect to the new-ssrc-pad signal of the SSRC demuxer */
session->demux_newpad_sig = g_signal_connect (session->demux,
......@@ -3417,6 +3571,71 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
session->demux_padremoved_sig = g_signal_connect (session->demux,
"removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
}
return;
pad_failed:
{
g_warning ("rtpbin: failed to get session recv_rtp_src pad");
return;
}
aux_sink_failed:
{
g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
return;
}
aux_link_failed:
{
g_warning ("rtpbin: failed to link AUX pad to session %u", sessid);
return;
}
}
/* Create a pad for receiving RTP for the session in @name. Must be called with
* RTP_BIN_LOCK.
*/
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
guint sessid;
GstRtpBinSession *session;
GstPad *recv_rtp_sink;
/* first get the session number */
if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
goto no_name;
GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
/* get or create session */
session = find_session_by_id (rtpbin, sessid);
if (!session) {
GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
/* create session now */
session = create_session (rtpbin, sessid);
if (session == NULL)
goto create_error;
}
/* check if pad was requested */
if (session->recv_rtp_sink_ghost != NULL)
return session->recv_rtp_sink_ghost;
/* setup the session sink pad */
recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
if (!recv_rtp_sink)
goto session_sink_failed;
GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
session->recv_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
gst_object_unref (recv_rtp_sink);
gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
complete_session_receiver (rtpbin, session, sessid);
return session->recv_rtp_sink_ghost;
/* ERRORS */
......@@ -3435,21 +3654,6 @@ session_sink_failed:
/* warning already done */
return NULL;
}
pad_failed:
{
g_warning ("rtpbin: failed to get session recv_rtp_src pad");
return NULL;
}
aux_sink_failed:
{
g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
return NULL;
}
aux_link_failed:
{
g_warning ("rtpbin: failed to link AUX pad to session %d", sessid);
return NULL;
}
}
static void
......@@ -3463,6 +3667,11 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
session->demux_padremoved_sig = 0;
}
if (session->bundle_demux_newpad_sig) {
g_signal_handler_disconnect (session->bundle_demux,
session->bundle_demux_newpad_sig);
session->bundle_demux_newpad_sig = 0;
}
if (session->recv_rtp_src) {
gst_object_unref (session->recv_rtp_src);
session->recv_rtp_src = NULL;
......@@ -3480,37 +3689,14 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
}
}
/* Create a pad for receiving RTCP for the session in @name. Must be called with
* RTP_BIN_LOCK.
*/
static GstPad *
create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
const gchar * name)
complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
guint sessid, gboolean bundle_demuxer_needed)
{
guint sessid;
GstElement *decoder;
GstRtpBinSession *session;
GstPad *sinkdpad, *decsink;
/* first get the session number */
if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
goto no_name;
GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
/* get or create the session */
session = find_session_by_id (rtpbin, sessid);
if (!session) {
GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
/* create session now */
session = create_session (rtpbin, sessid);
if (session == NULL)
goto create_error;
}
/* check if pad was requested */
if (session->recv_rtcp_sink_ghost != NULL)
return session->recv_rtcp_sink_ghost;
GstPad *sinkdpad;
GstPad *decsink = NULL;
GstPad *funnel_src;
/* get recv_rtp pad and store */
GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
......@@ -3519,6 +3705,9 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
if (session->recv_rtcp_sink == NULL)
goto pad_failed;
if (bundle_demuxer_needed)
session_maybe_create_bundle_demuxer (session);
GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
if (decoder) {
......@@ -3535,14 +3724,26 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
if (decsrc == NULL)
goto dec_src_failed;
ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
if (session->bundle_demux) {
GstPad *demux_sink;
demux_sink =
gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
ret = gst_pad_link (decsrc, demux_sink);
gst_object_unref (demux_sink);
} else {
ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
}
gst_object_unref (decsrc);
if (ret != GST_PAD_LINK_OK)
goto dec_link_failed;
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTCP decoder given");
decsink = gst_object_ref (session->recv_rtcp_sink);
if (session->bundle_demux) {
decsink = gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
} else {
decsink = gst_element_get_request_pad (session->rtcp_funnel, "sink_%u");
}
}
/* get srcpad, link to SSRCDemux */
......@@ -3556,26 +3757,12 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
gst_pad_link_full (session->sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
gst_object_unref (sinkdpad);
session->recv_rtcp_sink_ghost =
gst_ghost_pad_new_from_template (name, decsink, templ);
gst_object_unref (decsink);
gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
session->recv_rtcp_sink_ghost);
funnel_src = gst_element_get_static_pad (session->rtcp_funnel, "src");
gst_pad_link (funnel_src, session->recv_rtcp_sink);
gst_object_unref (funnel_src);
return session->recv_rtcp_sink_ghost;
return decsink;
/* ERRORS */
no_name:
{
g_warning ("rtpbin: invalid name given");
return NULL;
}
create_error:
{
/* create_session already warned */
return NULL;
}
pad_failed:
{
g_warning ("rtpbin: failed to get session rtcp_sink pad");
......@@ -3583,25 +3770,82 @@ pad_failed:
}
dec_sink_failed:
{
g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
return NULL;
}
dec_src_failed:
{
g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
gst_object_unref (decsink);
return NULL;
g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
goto cleanup;
}
dec_link_failed:
{
g_warning ("rtpbin: failed to link rtcp decoder for session %d", sessid);
gst_object_unref (decsink);
return NULL;
g_warning ("rtpbin: failed to link rtcp decoder for session %u", sessid);
goto cleanup;
}
src_pad_failed:
{
g_warning ("rtpbin: failed to get session sync_src pad");
gst_object_unref (decsink);
}
cleanup: