* RTPSession object which further provides action signals to retrieve the
* internal source and other sources.
*
+ * #GstRtpBin also has action signals (#GstRtpBin::request-rtp-encoder,
+ * #GstRtpBin::request-rtp-decoder, #GstRtpBin::request-rtcp-encoder and
+ * #GstRtpBin::request-rtp-decoder) to dynamically request for RTP and RTCP encoders
+ * and decoders in order to support SRTP. The encoders must provide the pads
+ * rtp_sink_\%d and rtp_src_\%d for RTP and rtcp_sink_\%d and rtcp_src_\%d for
+ * RTCP. The session number will be used in the pad name. The decoders must provide
+ * rtp_sink and rtp_src for RTP and rtcp_sink and rtcp_src for RTCP. The decoders will
+ * be placed before the #GstRtpSession element, thus they must support SSRC demuxing
+ * internally.
+ *
* <refsect2>
* <title>Example pipelines</title>
* |[
/* sink pads */
static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
-GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
+ GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
- GST_STATIC_CAPS ("application/x-rtp")
+ GST_STATIC_CAPS ("application/x-rtp;application/x-srtp")
);
static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
-GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
+ GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
- GST_STATIC_CAPS ("application/x-rtcp")
+ GST_STATIC_CAPS ("application/x-rtcp;application/x-srtcp")
);
static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
);
static GstStaticPadTemplate rtpbin_send_rtcp_src_template =
-GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%u",
+ GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%u",
GST_PAD_SRC,
GST_PAD_REQUEST,
- GST_STATIC_CAPS ("application/x-rtcp")
+ GST_STATIC_CAPS ("application/x-rtcp;application/x-srtcp")
);
static GstStaticPadTemplate rtpbin_send_rtp_src_template =
-GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%u",
+ GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%u",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
- GST_STATIC_CAPS ("application/x-rtp")
+ GST_STATIC_CAPS ("application/x-rtp;application/x-srtp")
);
#define GST_RTP_BIN_GET_PRIVATE(obj) \
SIGNAL_ON_TIMEOUT,
SIGNAL_ON_SENDER_TIMEOUT,
SIGNAL_ON_NPT_STOP,
+
+ SIGNAL_REQUEST_RTP_ENCODER,
+ SIGNAL_REQUEST_RTP_DECODER,
+ SIGNAL_REQUEST_RTCP_ENCODER,
+ SIGNAL_REQUEST_RTCP_DECODER,
+
LAST_SIGNAL
};
/* list of GstRtpBinStream */
GSList *streams;
+ /* list of encoders */
+ GSList *encoders;
+
+ /* list of decoders */
+ GSList *decoders;
+
/* mapping of payload type to caps */
GHashTable *ptmap;
}
}
+static void
+remove_bin_element (GstElement * element, GstRtpBin * bin)
+{
+ gst_bin_remove (GST_BIN_CAST (bin), element);
+}
+
/* called with RTP_BIN_LOCK */
static void
free_session (GstRtpBinSession * sess, GstRtpBin * bin)
gst_bin_remove (GST_BIN_CAST (bin), sess->session);
gst_bin_remove (GST_BIN_CAST (bin), sess->demux);
+ g_slist_foreach (sess->encoders, (GFunc) remove_bin_element, bin);
+ g_slist_free (sess->encoders);
+
+ g_slist_foreach (sess->decoders, (GFunc) remove_bin_element, bin);
+ g_slist_free (sess->decoders);
+
g_slist_foreach (sess->streams, (GFunc) free_stream, bin);
g_slist_free (sess->streams);
return internal_session;
}
+static GstElement *
+gst_rtp_bin_request_encoder (GstRtpBin * bin, guint session_id)
+{
+ return NULL;
+}
+
+static GstElement *
+gst_rtp_bin_request_decoder (GstRtpBin * bin, guint session_id)
+{
+ return NULL;
+}
+
static void
gst_rtp_bin_propagate_property_to_jitterbuffer (GstRtpBin * bin,
const gchar * name, const GValue * value)
NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
G_TYPE_UINT);
+ /**
+ * GstRtpBin::request-rtp-encoder:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an RTP encoder element for the given @session. The encoder
+ * element will be added to the bin if not previously added.
+ *
+ * If no handler is connected, no encoder will be used.
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_RTP_ENCODER] =
+ g_signal_new ("request-rtp-encoder", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_rtp_encoder), NULL, NULL, g_cclosure_marshal_generic,
+ GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+ /**
+ * GstRtpBin::request-rtp-decoder:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an RTP decoder element for the given @session. The decoder
+ * element will be added to the bin if not previously added.
+ *
+ * If no handler is connected, no encoder will be used.
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_RTP_DECODER] =
+ g_signal_new ("request-rtp-decoder", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_rtp_decoder), NULL, NULL, g_cclosure_marshal_generic,
+ GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+ /**
+ * GstRtpBin::request-rtcp-encoder:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an RTCP encoder element for the given @session. The encoder
+ * element will be added to the bin if not previously added.
+ *
+ * If no handler is connected, no encoder will be used.
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_RTCP_ENCODER] =
+ g_signal_new ("request-rtcp-encoder", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_rtcp_encoder), NULL, NULL, g_cclosure_marshal_generic,
+ GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+ /**
+ * GstRtpBin::request-rtcp-decoder:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ *
+ * Request an RTCP decoder element for the given @session. The decoder
+ * element will be added to the bin if not previously added.
+ *
+ * If no handler is connected, no encoder will be used.
+ */
+ gst_rtp_bin_signals[SIGNAL_REQUEST_RTCP_DECODER] =
+ g_signal_new ("request-rtcp-decoder", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+ request_rtcp_decoder), NULL, 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",
klass->reset_sync = GST_DEBUG_FUNCPTR (gst_rtp_bin_reset_sync);
klass->get_internal_session =
GST_DEBUG_FUNCPTR (gst_rtp_bin_get_internal_session);
+ klass->request_rtp_encoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_encoder);
+ klass->request_rtp_decoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_decoder);
+ klass->request_rtcp_encoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_encoder);
+ klass->request_rtcp_decoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_decoder);
GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
}
return res;
}
+static GstElement *
+session_request_encoder (GstRtpBinSession * session, guint signal)
+{
+ GstElement *encoder = NULL;
+
+ g_signal_emit (session->bin, gst_rtp_bin_signals[signal], 0, session->id,
+ &encoder);
+
+ if (encoder) {
+ if (g_slist_find (session->encoders, encoder)) {
+ GST_DEBUG_OBJECT (session->bin, "requested encoder %p already in bin",
+ encoder);
+ } else {
+ GST_DEBUG_OBJECT (session->bin, "adding requested encoder %p", encoder);
+ if (!gst_bin_add (GST_BIN_CAST (session->bin), encoder))
+ goto add_failed;
+ if (!gst_element_sync_state_with_parent (encoder))
+ GST_WARNING_OBJECT (session->bin,
+ "unable to sync encoder state with rtpbin");
+ session->encoders = g_slist_append (session->encoders, encoder);
+ }
+ }
+
+ return encoder;
+
+ /* ERRORS */
+add_failed:
+ {
+ GST_WARNING_OBJECT (session->bin, "unable to add encoder");
+ gst_object_unref (encoder);
+ return NULL;
+ }
+}
+
+static GstElement *
+session_request_decoder (GstRtpBinSession * session, guint signal)
+{
+ GstElement *decoder = NULL;
+
+ g_signal_emit (session->bin, gst_rtp_bin_signals[signal], 0, session->id,
+ &decoder);
+
+ if (decoder) {
+ if (g_slist_find (session->decoders, decoder)) {
+ GST_DEBUG_OBJECT (session->bin, "requested decoder %p already in bin",
+ decoder);
+ } else {
+ GST_DEBUG_OBJECT (session->bin, "adding requested decoder %p", decoder);
+ if (!gst_bin_add (GST_BIN_CAST (session->bin), decoder))
+ goto add_failed;
+ if (!gst_element_sync_state_with_parent (decoder))
+ GST_WARNING_OBJECT (session->bin,
+ "unable to sync decoder state with rtpbin");
+ session->decoders = g_slist_append (session->decoders, decoder);
+ }
+ }
+
+ return decoder;
+
+ /* ERRORS */
+add_failed:
+ {
+ GST_WARNING_OBJECT (session->bin, "unable to add decoder");
+ gst_object_unref (decoder);
+ return NULL;
+ }
+}
+
/* a new pad (SSRC) was created in @session. This signal is emited from the
* payload demuxer. */
static void
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *sinkdpad;
guint sessid;
+ GstElement *decoder;
+ GstPad *sinkdpad, *decsink;
GstRtpBinSession *session;
/* first get the session number */
g_signal_connect (session->recv_rtp_sink, "notify::caps",
(GCallback) caps_changed, session);
+ GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
+ decoder = session_request_decoder (session, SIGNAL_REQUEST_RTP_DECODER);
+ if (decoder) {
+ GstPad *decsrc;
+ 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;
+
+ if (decsrc == NULL)
+ goto dec_src_failed;
+
+ ret = gst_pad_link (decsrc, session->recv_rtp_sink);
+ gst_object_unref (decsrc);
+
+ if (ret != GST_PAD_LINK_OK)
+ goto dec_link_failed;
+ } else {
+ GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
+ decsink = session->recv_rtp_sink;
+ }
+
GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
/* get srcpad, link to SSRCDemux */
session->recv_rtp_src =
GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
session->recv_rtp_sink_ghost =
- gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
+ gst_ghost_pad_new_from_template (name, decsink, templ);
gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
g_warning ("rtpbin: failed to get session pad");
return NULL;
}
+dec_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
+ return NULL;
+ }
+dec_src_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
+ return NULL;
+ }
+dec_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
+ return NULL;
+ }
}
static void
const gchar * name)
{
guint sessid;
+ GstElement *decoder;
GstRtpBinSession *session;
- GstPad *sinkdpad;
+ GstPad *sinkdpad, *decsink;
/* first get the session number */
if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
if (session->recv_rtcp_sink == NULL)
goto pad_failed;
+ GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
+ decoder = session_request_decoder (session, SIGNAL_REQUEST_RTCP_DECODER);
+ if (decoder) {
+ GstPad *decsrc;
+ GstPadLinkReturn ret;
+
+ GST_DEBUG_OBJECT (rtpbin, "linking RTCP decoder");
+ decsink = gst_element_get_static_pad (decoder, "rtcp_sink");
+ decsrc = gst_element_get_static_pad (decoder, "rtcp_src");
+
+ if (decsink == NULL)
+ goto dec_sink_failed;
+
+ if (decsrc == NULL)
+ goto dec_src_failed;
+
+ 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 = session->recv_rtcp_sink;
+ }
+
/* get srcpad, link to SSRCDemux */
GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
session->sync_src = gst_element_get_static_pad (session->session, "sync_src");
gst_object_unref (sinkdpad);
session->recv_rtcp_sink_ghost =
- gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
+ gst_ghost_pad_new_from_template (name, decsink, templ);
gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
session->recv_rtcp_sink_ghost);
g_warning ("rtpbin: failed to get session pad");
return NULL;
}
+dec_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
+ return NULL;
+ }
+dec_src_failed:
+ {
+ g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
+ return NULL;
+ }
+dec_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtcp decoder for session %d", sessid);
+ return NULL;
+ }
}
static void
{
gchar *gname;
guint sessid;
+ GstPad *encsrc;
+ GstElement *encoder;
GstRtpBinSession *session;
GstElementClass *klass;
if (session->send_rtp_src == NULL)
goto no_srcpad;
+ GST_DEBUG_OBJECT (rtpbin, "getting RTP encoder");
+ encoder = session_request_encoder (session, SIGNAL_REQUEST_RTP_ENCODER);
+ if (encoder) {
+ gchar *ename;
+ GstPad *encsink;
+ GstPadLinkReturn ret;
+
+ GST_DEBUG_OBJECT (rtpbin, "linking RTP encoder");
+ ename = g_strdup_printf ("rtp_sink_%d", sessid);
+ encsink = gst_element_get_request_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 (encsink == NULL)
+ goto enc_sink_failed;
+
+ if (encsrc == NULL)
+ goto enc_src_failed;
+
+ ret = gst_pad_link (session->send_rtp_src, encsink);
+ gst_object_unref (encsink);
+
+ if (ret != GST_PAD_LINK_OK)
+ goto enc_link_failed;
+ } else {
+ GST_DEBUG_OBJECT (rtpbin, "no RTP encoder given");
+ encsrc = session->send_rtp_src;
+ }
+
/* ghost the new source pad */
klass = GST_ELEMENT_GET_CLASS (rtpbin);
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, session->send_rtp_src, templ);
+ gst_ghost_pad_new_from_template (gname, encsrc, templ);
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);
g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
return NULL;
}
+enc_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
+ return NULL;
+ }
+enc_src_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
+ return NULL;
+ }
+enc_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtp encoder for session %d", sessid);
+ return NULL;
+ }
}
static void
create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
guint sessid;
+ GstPad *encsrc;
+ GstElement *encoder;
GstRtpBinSession *session;
/* first get the session number */
if (session->send_rtcp_src == NULL)
goto pad_failed;
+ GST_DEBUG_OBJECT (rtpbin, "getting RTCP encoder");
+ encoder = session_request_encoder (session, SIGNAL_REQUEST_RTCP_ENCODER);
+ if (encoder) {
+ gchar *ename;
+ GstPad *encsink;
+ GstPadLinkReturn ret;
+
+ GST_DEBUG_OBJECT (rtpbin, "linking RTCP encoder");
+ ename = g_strdup_printf ("rtcp_sink_%d", sessid);
+ encsink = gst_element_get_request_pad (encoder, ename);
+ g_free (ename);
+ ename = g_strdup_printf ("rtcp_src_%d", sessid);
+ encsrc = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
+
+ if (encsink == NULL)
+ goto enc_sink_failed;
+
+ if (encsrc == NULL)
+ goto enc_src_failed;
+
+ ret = gst_pad_link (session->send_rtcp_src, encsink);
+ gst_object_unref (encsink);
+
+ if (ret != GST_PAD_LINK_OK)
+ goto enc_link_failed;
+ } else {
+ GST_DEBUG_OBJECT (rtpbin, "no RTCP encoder given");
+ encsrc = session->send_rtcp_src;
+ }
+
session->send_rtcp_src_ghost =
- gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ);
+ gst_ghost_pad_new_from_template (name, encsrc, templ);
gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
return NULL;
}
+enc_sink_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
+ return NULL;
+ }
+enc_src_failed:
+ {
+ g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
+ return NULL;
+ }
+enc_link_failed:
+ {
+ g_warning ("rtpbin: failed to link rtcp encoder for session %d", sessid);
+ return NULL;
+ }
}
static void