SIGNAL_NEW_JITTERBUFFER,
+ SIGNAL_REQUEST_AUX_SENDER,
+ SIGNAL_REQUEST_AUX_RECEIVER,
+
LAST_SIGNAL
};
new_jitterbuffer), NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 3, GST_TYPE_ELEMENT, G_TYPE_UINT, G_TYPE_UINT);
+ /**
+ * GstRtpBin::request-aux-sender:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an AUX sender element for the given @session. The AUX
+ * element will be added to the bin.
+ *
+ * If no handler is connected, no AUX element will be used.
+ *
+ * Since: 1.4
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_AUX_SENDER] =
+ g_signal_new ("request-aux-sender", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_aux_sender), _gst_element_accumulator, NULL,
+ g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+ /**
+ * GstRtpBin::request-aux-receiver:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an AUX receiver element for the given @session. The AUX
+ * element will be added to the bin.
+ *
+ * If no handler is connected, no AUX element will be used.
+ *
+ * Since: 1.4
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_AUX_RECEIVER] =
+ g_signal_new ("request-aux-receiver", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_aux_receiver), _gst_element_accumulator, NULL,
+ g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 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",
}
}
-/* 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 gboolean
+complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- guint sessid;
+ gchar *gname;
+ guint sessid = session->id;
+ GstPad *recv_rtp_sink;
GstElement *decoder;
- GstPad *sinkdpad, *decsink;
- 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;
+ GstElementClass *klass;
+ GstPadTemplate *templ;
- GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
/* get recv_rtp pad and store */
session->recv_rtp_sink =
gst_element_get_request_pad (session->session, "recv_rtp_sink");
GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
if (decoder) {
- GstPad *decsrc;
+ GstPad *decsrc, *decsink;
GstPadLinkReturn ret;
GST_DEBUG_OBJECT (rtpbin, "linking RTP decoder");
decsink = gst_element_get_static_pad (decoder, "rtp_sink");
- decsrc = gst_element_get_static_pad (decoder, "rtp_src");
-
if (decsink == NULL)
goto dec_sink_failed;
+ recv_rtp_sink = decsink;
+
+ decsrc = gst_element_get_static_pad (decoder, "rtp_src");
if (decsrc == NULL)
goto dec_src_failed;
if (ret != GST_PAD_LINK_OK)
goto dec_link_failed;
+
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
- decsink = gst_object_ref (session->recv_rtp_sink);
+ recv_rtp_sink = gst_object_ref (session->recv_rtp_sink);
}
- GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
- /* get srcpad, link to SSRCDemux */
+ 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);
+
+ return TRUE;
+
+ /* ERRORS */
+pad_failed:
+ {
+ g_warning ("rtpbin: failed to get session recv_rtp_sink pad");
+ return FALSE;
+ }
+dec_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
+ return FALSE;
+ }
+dec_src_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
+ gst_object_unref (recv_rtp_sink);
+ return FALSE;
+ }
+dec_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
+ gst_object_unref (recv_rtp_sink);
+ return FALSE;
+ }
+}
+
+/* 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;
+ 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;
+
session->recv_rtp_src =
gst_element_get_static_pad (session->session, "recv_rtp_src");
if (session->recv_rtp_src == NULL)
- goto src_pad_failed;
+ goto pad_failed;
- GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTP sink pad");
- sinkdpad = gst_element_get_static_pad (session->demux, "sink");
- GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
- gst_pad_link_full (session->recv_rtp_src, sinkdpad,
- GST_PAD_LINK_CHECK_NOTHING);
- gst_object_unref (sinkdpad);
+ /* find out if we need AUX elements or if we can go into the SSRC demuxer
+ * directly */
+ aux = session_request_element (session, SIGNAL_REQUEST_AUX_RECEIVER);
+ if (aux) {
+ gchar *pname;
+ GstPad *auxsink;
+ GstPadLinkReturn ret;
- /* connect to the new-ssrc-pad signal of the SSRC demuxer */
- session->demux_newpad_sig = g_signal_connect (session->demux,
- "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
- session->demux_padremoved_sig = g_signal_connect (session->demux,
- "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
+ GST_DEBUG_OBJECT (rtpbin, "linking AUX receiver");
- GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
- session->recv_rtp_sink_ghost =
- gst_ghost_pad_new_from_template (name, decsink, templ);
- gst_object_unref (decsink);
- gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
+ pname = g_strdup_printf ("sink_%d", sessid);
+ auxsink = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+ if (auxsink == NULL)
+ goto aux_sink_failed;
+ ret = gst_pad_link (session->recv_rtp_src, auxsink);
+ gst_object_unref (auxsink);
+ if (ret != GST_PAD_LINK_OK)
+ goto aux_link_failed;
+
+ /* this can be NULL when this AUX element is not to be linked to
+ * an SSRC demuxer */
+ pname = g_strdup_printf ("src_%d", sessid);
+ recv_rtp_src = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+ } else {
+ recv_rtp_src = gst_object_ref (session->recv_rtp_src);
+ }
+
+ if (recv_rtp_src) {
+ GstPad *sinkdpad;
+
+ GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTP sink pad");
+ 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);
+
+ /* connect to the new-ssrc-pad signal of the SSRC demuxer */
+ session->demux_newpad_sig = g_signal_connect (session->demux,
+ "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
+ session->demux_padremoved_sig = g_signal_connect (session->demux,
+ "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
+ }
return session->recv_rtp_sink_ghost;
/* ERRORS */
/* create_session already warned */
return NULL;
}
-pad_failed:
+session_sink_failed:
{
- g_warning ("rtpbin: failed to get session rtp_sink pad");
+ /* warning already done */
return NULL;
}
-dec_sink_failed:
- {
- g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
- return NULL;
- }
-dec_src_failed:
+pad_failed:
{
- g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
- gst_object_unref (decsink);
+ g_warning ("rtpbin: failed to get session recv_rtp_src pad");
return NULL;
}
-dec_link_failed:
+aux_sink_failed:
{
- g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
- gst_object_unref (decsink);
+ g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
return NULL;
}
-src_pad_failed:
+aux_link_failed:
{
- g_warning ("rtpbin: failed to get session rtp_src pad");
- gst_object_unref (decsink);
+ g_warning ("rtpbin: failed to link AUX pad to session %d", sessid);
return NULL;
}
}
}
}
-/* Create a pad for sending RTP for the session in @name. Must be called with
- * RTP_BIN_LOCK.
- */
-static GstPad *
-create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+static gboolean
+complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
gchar *gname;
- guint sessid;
- GstPad *encsrc;
+ guint sessid = session->id;
+ GstPad *send_rtp_src;
GstElement *encoder;
- GstRtpBinSession *session;
GstElementClass *klass;
-
- /* first get the session number */
- if (name == NULL || sscanf (name, "send_rtp_sink_%u", &sessid) != 1)
- goto no_name;
-
- /* get or create session */
- session = find_session_by_id (rtpbin, sessid);
- if (!session) {
- /* create session now */
- session = create_session (rtpbin, sessid);
- if (session == NULL)
- goto create_error;
- }
-
- /* check if pad was requested */
- if (session->send_rtp_sink_ghost != NULL)
- return session->send_rtp_sink_ghost;
-
- /* get send_rtp pad and store */
- session->send_rtp_sink =
- gst_element_get_request_pad (session->session, "send_rtp_sink");
- if (session->send_rtp_sink == NULL)
- goto pad_failed;
-
- session->send_rtp_sink_ghost =
- gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
- gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
+ GstPadTemplate *templ;
/* get srcpad */
session->send_rtp_src =
encoder = session_request_element (session, SIGNAL_REQUEST_RTP_ENCODER);
if (encoder) {
gchar *ename;
- GstPad *encsink;
+ GstPad *encsrc, *encsink;
GstPadLinkReturn ret;
GST_DEBUG_OBJECT (rtpbin, "linking RTP encoder");
- ename = g_strdup_printf ("rtp_sink_%d", sessid);
- encsink = gst_element_get_static_pad (encoder, ename);
- g_free (ename);
ename = g_strdup_printf ("rtp_src_%d", sessid);
encsrc = gst_element_get_static_pad (encoder, ename);
g_free (ename);
if (encsrc == NULL)
goto enc_src_failed;
+ send_rtp_src = encsrc;
+
+ ename = g_strdup_printf ("rtp_sink_%d", sessid);
+ encsink = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
if (encsink == NULL)
goto enc_sink_failed;
goto enc_link_failed;
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTP encoder given");
- encsrc = gst_object_ref (session->send_rtp_src);
+ send_rtp_src = gst_object_ref (session->send_rtp_src);
}
/* ghost the new source pad */
gname = g_strdup_printf ("send_rtp_src_%u", sessid);
templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%u");
session->send_rtp_src_ghost =
- gst_ghost_pad_new_from_template (gname, encsrc, templ);
- gst_object_unref (encsrc);
+ gst_ghost_pad_new_from_template (gname, send_rtp_src, templ);
+ gst_object_unref (send_rtp_src);
gst_pad_set_active (session->send_rtp_src_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost);
g_free (gname);
+ return TRUE;
+
+ /* ERRORS */
+no_srcpad:
+ {
+ g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
+ return FALSE;
+ }
+enc_src_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
+ return FALSE;
+ }
+enc_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
+ gst_object_unref (send_rtp_src);
+ return FALSE;
+ }
+enc_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtp encoder for session %d", sessid);
+ gst_object_unref (send_rtp_src);
+ return FALSE;
+ }
+}
+
+static gboolean
+setup_aux_sender_fold (const GValue * item, GValue * result, gpointer user_data)
+{
+ GstPad *pad;
+ gchar *name;
+ guint sessid;
+ GstRtpBinSession *session = user_data, *newsess;
+ GstRtpBin *rtpbin = session->bin;
+ GstPadLinkReturn ret;
+
+ pad = g_value_get_object (item);
+ name = gst_pad_get_name (pad);
+
+ if (name == NULL || sscanf (name, "src_%u", &sessid) != 1)
+ goto no_name;
+
+ g_free (name);
+
+ newsess = find_session_by_id (rtpbin, sessid);
+ if (newsess == NULL) {
+ /* create new session */
+ newsess = create_session (rtpbin, sessid);
+ if (newsess == NULL)
+ goto create_error;
+ } else if (newsess->send_rtp_sink != NULL)
+ goto existing_session;
+
+ /* get send_rtp pad and store */
+ newsess->send_rtp_sink =
+ gst_element_get_request_pad (newsess->session, "send_rtp_sink");
+ if (newsess->send_rtp_sink == NULL)
+ goto pad_failed;
+
+ ret = gst_pad_link (pad, newsess->send_rtp_sink);
+ if (ret != GST_PAD_LINK_OK)
+ goto aux_link_failed;
+
+ if (!complete_session_src (rtpbin, newsess))
+ goto session_src_failed;
+
+ return TRUE;
+
+ /* ERRORS */
+no_name:
+ {
+ GST_WARNING ("ignoring invalid pad name %s", GST_STR_NULL (name));
+ g_free (name);
+ return TRUE;
+ }
+create_error:
+ {
+ /* create_session already warned */
+ return FALSE;
+ }
+existing_session:
+ {
+ g_warning ("rtpbin: session %d is already a sender", sessid);
+ return FALSE;
+ }
+pad_failed:
+ {
+ g_warning ("rtpbin: failed to get session pad for session %d", sessid);
+ return FALSE;
+ }
+aux_link_failed:
+ {
+ g_warning ("rtpbin: failed to link AUX for session %d", sessid);
+ return FALSE;
+ }
+session_src_failed:
+ {
+ g_warning ("rtpbin: failed to complete AUX for session %d", sessid);
+ return FALSE;
+ }
+}
+
+static gboolean
+setup_aux_sender (GstRtpBin * rtpbin, GstRtpBinSession * session,
+ GstElement * aux)
+{
+ GstIterator *it;
+ GValue result = { 0, };
+ GstIteratorResult res;
+
+ it = gst_element_iterate_src_pads (aux);
+ res = gst_iterator_fold (it, setup_aux_sender_fold, &result, session);
+ gst_iterator_free (it);
+
+ return res == GST_ITERATOR_DONE;
+}
+
+/* Create a pad for sending RTP for the session in @name. Must be called with
+ * RTP_BIN_LOCK.
+ */
+static GstPad *
+create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+ gchar *pname;
+ guint sessid;
+ GstPad *send_rtp_sink;
+ GstElement *aux;
+ GstRtpBinSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "send_rtp_sink_%u", &sessid) != 1)
+ goto no_name;
+
+ /* get or create session */
+ session = find_session_by_id (rtpbin, sessid);
+ if (!session) {
+ /* create session now */
+ session = create_session (rtpbin, sessid);
+ if (session == NULL)
+ goto create_error;
+ }
+
+ /* check if pad was requested */
+ if (session->send_rtp_sink_ghost != NULL)
+ return session->send_rtp_sink_ghost;
+
+ /* check if we are already using this session as a sender */
+ if (session->send_rtp_sink != NULL)
+ goto existing_session;
+
+ GST_DEBUG_OBJECT (rtpbin, "getting RTP AUX sender");
+ aux = session_request_element (session, SIGNAL_REQUEST_AUX_SENDER);
+ if (aux) {
+ GST_DEBUG_OBJECT (rtpbin, "linking AUX sender");
+ if (!setup_aux_sender (rtpbin, session, aux))
+ goto aux_session_failed;
+
+ pname = g_strdup_printf ("sink_%d", sessid);
+ send_rtp_sink = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+
+ if (send_rtp_sink == NULL)
+ goto aux_sink_failed;
+ } else {
+ /* get send_rtp pad and store */
+ session->send_rtp_sink =
+ gst_element_get_request_pad (session->session, "send_rtp_sink");
+ if (session->send_rtp_sink == NULL)
+ goto pad_failed;
+
+ if (!complete_session_src (rtpbin, session))
+ goto session_src_failed;
+
+ send_rtp_sink = gst_object_ref (session->send_rtp_sink);
+ }
+
+ session->send_rtp_sink_ghost =
+ gst_ghost_pad_new_from_template (name, send_rtp_sink, templ);
+ gst_object_unref (send_rtp_sink);
+ gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
+
return session->send_rtp_sink_ghost;
/* ERRORS */
/* create_session already warned */
return NULL;
}
-pad_failed:
+existing_session:
{
- g_warning ("rtpbin: failed to get session pad for session %d", sessid);
+ g_warning ("rtpbin: session %d is already in use", sessid);
return NULL;
}
-no_srcpad:
+aux_session_failed:
{
- g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
+ g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
return NULL;
}
-enc_src_failed:
+aux_sink_failed:
{
- g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
+ g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
return NULL;
}
-enc_sink_failed:
+pad_failed:
{
- g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
- gst_object_unref (encsrc);
+ g_warning ("rtpbin: failed to get session pad for session %d", sessid);
return NULL;
}
-enc_link_failed:
+session_src_failed:
{
- g_warning ("rtpbin: failed to link rtp encoder for session %d", sessid);
- gst_object_unref (encsrc);
+ g_warning ("rtpbin: failed to setup source pads for session %d", sessid);
return NULL;
}
}