summaryrefslogtreecommitdiffstats
path: root/gst/rtpmanager
diff options
context:
space:
mode:
Diffstat (limited to 'gst/rtpmanager')
-rw-r--r--gst/rtpmanager/gstrtpbin-marshal.list1
-rw-r--r--gst/rtpmanager/gstrtpbin.c361
-rw-r--r--gst/rtpmanager/gstrtpsession.c60
-rw-r--r--gst/rtpmanager/gstrtpssrcdemux.c82
-rw-r--r--gst/rtpmanager/gstrtpssrcdemux.h6
-rw-r--r--gst/rtpmanager/rtpsource.c48
6 files changed, 369 insertions, 189 deletions
diff --git a/gst/rtpmanager/gstrtpbin-marshal.list b/gst/rtpmanager/gstrtpbin-marshal.list
index c4bc0bb2..ed73e43b 100644
--- a/gst/rtpmanager/gstrtpbin-marshal.list
+++ b/gst/rtpmanager/gstrtpbin-marshal.list
@@ -3,5 +3,6 @@ BOXED:UINT
BOXED:UINT,UINT
OBJECT:UINT
VOID:UINT,OBJECT
+VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT
diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
index 7d3b9823..19de4f1b 100644
--- a/gst/rtpmanager/gstrtpbin.c
+++ b/gst/rtpmanager/gstrtpbin.c
@@ -297,12 +297,17 @@ struct _GstRtpBinStream
/* the jitterbuffer of the SSRC */
GstElement *buffer;
+ gulong buffer_handlesync_sig;
+ gulong buffer_ptreq_sig;
+ gulong buffer_ntpstop_sig;
/* the PT demuxer of the SSRC */
GstElement *demux;
gulong demux_newpad_sig;
gulong demux_ptreq_sig;
gulong demux_pt_change_sig;
+ /* ghostpads from the ptdemuxer */
+ GSList *pads;
/* if we have calculated a valid unix_delta for this stream */
gboolean have_sync;
@@ -332,6 +337,7 @@ struct _GstRtpBinSession
/* the SSRC demuxer */
GstElement *demux;
gulong demux_newpad_sig;
+ gulong demux_padremoved_sig;
GMutex *lock;
@@ -343,12 +349,17 @@ struct _GstRtpBinSession
/* the pads of the session */
GstPad *recv_rtp_sink;
+ GstPad *recv_rtp_sink_ghost;
GstPad *recv_rtp_src;
GstPad *recv_rtcp_sink;
+ GstPad *recv_rtcp_sink_ghost;
GstPad *sync_src;
GstPad *send_rtp_sink;
+ GstPad *send_rtp_sink_ghost;
GstPad *send_rtp_src;
+ GstPad *send_rtp_src_ghost;
GstPad *send_rtcp_src;
+ GstPad *send_rtcp_src_ghost;
};
/* Manages the RTP streams that come from one client and should therefore be
@@ -389,9 +400,10 @@ find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad)
for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
- if ((sess->recv_rtp_sink == pad) ||
- (sess->recv_rtcp_sink == pad) ||
- (sess->send_rtp_sink == pad) || (sess->send_rtcp_src == pad))
+ if ((sess->recv_rtp_sink_ghost == pad) ||
+ (sess->recv_rtcp_sink_ghost == pad) ||
+ (sess->send_rtp_sink_ghost == pad)
+ || (sess->send_rtcp_src_ghost == pad))
return sess;
}
return NULL;
@@ -467,6 +479,36 @@ on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream)
stream->session->id, stream->ssrc);
}
+/* must be called with the SESSION lock */
+static GstRtpBinStream *
+find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
+{
+ GSList *walk;
+
+ for (walk = session->streams; walk; walk = g_slist_next (walk)) {
+ GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
+
+ if (stream->ssrc == ssrc)
+ return stream;
+ }
+ return NULL;
+}
+
+static void
+ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+ GstRtpBinSession * session)
+{
+ GstRtpBinStream *stream = NULL;
+
+ GST_RTP_SESSION_LOCK (session);
+ if ((stream = find_stream_by_ssrc (session, ssrc)))
+ session->streams = g_slist_remove (session->streams, stream);
+ GST_RTP_SESSION_UNLOCK (session);
+
+ if (stream)
+ free_stream (stream);
+}
+
/* create a session with the given id. Must be called with RTP_BIN_LOCK */
static GstRtpBinSession *
create_session (GstRtpBin * rtpbin, gint id)
@@ -474,6 +516,7 @@ create_session (GstRtpBin * rtpbin, gint id)
GstRtpBinSession *sess;
GstElement *session, *demux;
gint i;
+ GstState target;
if (!(session = gst_element_factory_make ("gstrtpsession", NULL)))
goto no_session;
@@ -522,11 +565,16 @@ create_session (GstRtpBin * rtpbin, gint id)
g_signal_connect (sess->session, "on-sender-timeout",
(GCallback) on_sender_timeout, sess);
- /* FIXME, change state only to what's needed */
gst_bin_add (GST_BIN_CAST (rtpbin), session);
- gst_element_set_state (session, GST_STATE_PLAYING);
gst_bin_add (GST_BIN_CAST (rtpbin), demux);
- gst_element_set_state (demux, GST_STATE_PLAYING);
+
+ GST_OBJECT_LOCK (rtpbin);
+ target = GST_STATE_TARGET (rtpbin);
+ GST_OBJECT_UNLOCK (rtpbin);
+
+ /* change state only to what's needed */
+ gst_element_set_state (demux, target);
+ gst_element_set_state (session, target);
return sess;
@@ -545,16 +593,12 @@ no_demux:
}
static void
-free_session (GstRtpBinSession * sess)
+free_session (GstRtpBinSession * sess, GstRtpBin * bin)
{
- GstRtpBin *bin;
-
- bin = sess->bin;
-
GST_DEBUG_OBJECT (bin, "freeing session %p", sess);
- gst_element_set_state (sess->session, GST_STATE_NULL);
gst_element_set_state (sess->demux, GST_STATE_NULL);
+ gst_element_set_state (sess->session, GST_STATE_NULL);
if (sess->recv_rtp_sink != NULL) {
gst_element_release_request_pad (sess->session, sess->recv_rtp_sink);
@@ -588,27 +632,9 @@ free_session (GstRtpBinSession * sess)
g_mutex_free (sess->lock);
g_hash_table_destroy (sess->ptmap);
- bin->sessions = g_slist_remove (bin->sessions, sess);
-
g_free (sess);
}
-#if 0
-static GstRtpBinStream *
-find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
-{
- GSList *walk;
-
- for (walk = session->streams; walk; walk = g_slist_next (walk)) {
- GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
-
- if (stream->ssrc == ssrc)
- return stream;
- }
- return NULL;
-}
-#endif
-
/* get the payload type caps for the specific payload @pt in @session */
static GstCaps *
get_pt_map (GstRtpBinSession * session, guint pt)
@@ -822,8 +848,9 @@ get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created)
}
static void
-free_client (GstRtpBinClient * client)
+free_client (GstRtpBinClient * client, GstRtpBin * bin)
{
+ GST_DEBUG_OBJECT (bin, "freeing client %p", client);
g_slist_free (client->streams);
g_free (client->cname);
g_free (client);
@@ -1079,6 +1106,8 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
{
GstElement *buffer, *demux;
GstRtpBinStream *stream;
+ GstRtpBin *rtpbin;
+ GstState target;
if (!(buffer = gst_element_factory_make ("gstrtpjitterbuffer", NULL)))
goto no_jitterbuffer;
@@ -1086,9 +1115,11 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
if (!(demux = gst_element_factory_make ("gstrtpptdemux", NULL)))
goto no_demux;
+ rtpbin = session->bin;
+
stream = g_new0 (GstRtpBinStream, 1);
stream->ssrc = ssrc;
- stream->bin = session->bin;
+ stream->bin = rtpbin;
stream->session = session;
stream->buffer = buffer;
stream->demux = demux;
@@ -1097,22 +1128,29 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
session->streams = g_slist_prepend (session->streams, stream);
/* provide clock_rate to the jitterbuffer when needed */
- g_signal_connect (buffer, "request-pt-map",
+ stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map",
(GCallback) pt_map_requested, session);
- g_signal_connect (buffer, "on-npt-stop", (GCallback) on_npt_stop, stream);
+ stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop",
+ (GCallback) on_npt_stop, stream);
/* configure latency and packet lost */
- g_object_set (buffer, "latency", session->bin->latency, NULL);
- g_object_set (buffer, "do-lost", session->bin->do_lost, NULL);
+ g_object_set (buffer, "latency", rtpbin->latency, NULL);
+ g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
- gst_bin_add (GST_BIN_CAST (session->bin), buffer);
- gst_element_set_state (buffer, GST_STATE_PLAYING);
- gst_bin_add (GST_BIN_CAST (session->bin), demux);
- gst_element_set_state (demux, GST_STATE_PLAYING);
+ gst_bin_add (GST_BIN_CAST (rtpbin), demux);
+ gst_bin_add (GST_BIN_CAST (rtpbin), buffer);
/* link stuff */
gst_element_link (buffer, demux);
+ GST_OBJECT_LOCK (rtpbin);
+ target = GST_STATE_TARGET (rtpbin);
+ GST_OBJECT_UNLOCK (rtpbin);
+
+ /* from sink to source */
+ gst_element_set_state (demux, target);
+ gst_element_set_state (buffer, target);
+
return stream;
/* ERRORS */
@@ -1133,16 +1171,29 @@ static void
free_stream (GstRtpBinStream * stream)
{
GstRtpBinSession *session;
+ GSList *walk;
session = stream->session;
- gst_element_set_state (stream->buffer, GST_STATE_NULL);
+ g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig);
+ g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig);
+
gst_element_set_state (stream->demux, GST_STATE_NULL);
+ gst_element_set_state (stream->buffer, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer);
gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux);
- session->streams = g_slist_remove (session->streams, stream);
+ for (walk = stream->pads; walk; walk = g_slist_next (walk)) {
+ GstPad *gpad = GST_PAD_CAST (walk->data);
+
+ gst_pad_set_active (gpad, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (session->bin), gpad);
+ }
+ g_slist_free (stream->pads);
g_free (stream);
}
@@ -1481,11 +1532,11 @@ gst_rtp_bin_dispose (GObject * object)
rtpbin = GST_RTP_BIN (object);
GST_DEBUG_OBJECT (object, "freeing sessions");
- g_slist_foreach (rtpbin->sessions, (GFunc) free_session, NULL);
+ g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin);
g_slist_free (rtpbin->sessions);
rtpbin->sessions = NULL;
GST_DEBUG_OBJECT (object, "freeing clients");
- g_slist_foreach (rtpbin->clients, (GFunc) free_client, NULL);
+ g_slist_foreach (rtpbin->clients, (GFunc) free_client, rtpbin);
g_slist_free (rtpbin->clients);
rtpbin->clients = NULL;
@@ -1556,6 +1607,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type,
if (type < 0 || type > 8)
return;
+ GST_RTP_BIN_LOCK (bin);
+
GST_OBJECT_LOCK (bin);
g_free (bin->sdes[type]);
bin->sdes[type] = g_strdup (data);
@@ -1564,6 +1617,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type,
for (item = bin->sessions; item; item = g_slist_next (item))
g_object_set (item->data, name, bin->sdes[type], NULL);
GST_OBJECT_UNLOCK (bin);
+
+ GST_RTP_BIN_UNLOCK (bin);
}
static gchar *
@@ -1836,6 +1891,8 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,
gst_pad_set_active (gpad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
+ stream->pads = g_slist_prepend (stream->pads, gpad);
+
GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
return;
@@ -1947,7 +2004,7 @@ new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
/* connect to the RTCP sync signal from the jitterbuffer */
GST_DEBUG_OBJECT (rtpbin, "connecting sync signal");
- g_signal_connect (stream->buffer,
+ stream->buffer_handlesync_sig = g_signal_connect (stream->buffer,
"handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream);
/* connect to the new-pad signal of the payload demuxer, this will expose the
@@ -1986,7 +2043,7 @@ no_stream:
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result, *sinkdpad;
+ GstPad *sinkdpad;
guint sessid;
GstRtpBinSession *session;
GstPadLinkReturn lres;
@@ -2008,8 +2065,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
}
/* check if pad was requested */
- if (session->recv_rtp_sink != NULL)
- goto existed;
+ if (session->recv_rtp_sink_ghost != NULL)
+ return session->recv_rtp_sink_ghost;
GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
/* get recv_rtp pad and store */
@@ -2039,14 +2096,16 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
/* 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, "ghosting session sink pad");
- result =
+ session->recv_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
- return result;
+ return session->recv_rtp_sink_ghost;
/* ERRORS */
no_name:
@@ -2059,12 +2118,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: recv_rtp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad");
@@ -2078,10 +2131,31 @@ link_failed:
}
static void
-remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->demux_newpad_sig) {
+ g_signal_handler_disconnect (session->demux, session->demux_newpad_sig);
+ session->demux_newpad_sig = 0;
+ }
+ if (session->demux_padremoved_sig) {
+ g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
+ session->demux_padremoved_sig = 0;
+ }
+ if (session->recv_rtp_src) {
+ gst_object_unref (session->recv_rtp_src);
+ session->recv_rtp_src = NULL;
+ }
+ if (session->recv_rtp_sink) {
+ gst_element_release_request_pad (session->session, session->recv_rtp_sink);
+ gst_object_unref (session->recv_rtp_sink);
+ session->recv_rtp_sink = NULL;
+ }
+ if (session->recv_rtp_sink_ghost) {
+ gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtp_sink_ghost);
+ session->recv_rtp_sink_ghost = NULL;
+ }
}
/* Create a pad for receiving RTCP for the session in @name. Must be called with
@@ -2091,7 +2165,6 @@ static GstPad *
create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
const gchar * name)
{
- GstPad *result;
guint sessid;
GstRtpBinSession *session;
GstPad *sinkdpad;
@@ -2114,8 +2187,8 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
}
/* check if pad was requested */
- if (session->recv_rtcp_sink != NULL)
- goto existed;
+ if (session->recv_rtcp_sink_ghost != NULL)
+ return session->recv_rtcp_sink_ghost;
/* get recv_rtp pad and store */
GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
@@ -2137,12 +2210,13 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
if (lres != GST_PAD_LINK_OK)
goto link_failed;
- result =
+ session->recv_rtcp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtcp_sink_ghost);
- return result;
+ return session->recv_rtcp_sink_ghost;
/* ERRORS */
no_name:
@@ -2155,12 +2229,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: recv_rtcp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad");
@@ -2174,10 +2242,24 @@ link_failed:
}
static void
-remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->recv_rtcp_sink_ghost) {
+ gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtcp_sink_ghost);
+ session->recv_rtcp_sink_ghost = NULL;
+ }
+ if (session->sync_src) {
+ /* releasing the request pad should also unref the sync pad */
+ gst_object_unref (session->sync_src);
+ session->sync_src = NULL;
+ }
+ if (session->recv_rtcp_sink) {
+ gst_element_release_request_pad (session->session, session->recv_rtcp_sink);
+ gst_object_unref (session->recv_rtcp_sink);
+ session->recv_rtcp_sink = NULL;
+ }
}
/* Create a pad for sending RTP for the session in @name. Must be called with
@@ -2186,7 +2268,6 @@ remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
static GstPad *
create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result, *srcghost;
gchar *gname;
guint sessid;
GstRtpBinSession *session;
@@ -2206,8 +2287,8 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
}
/* check if pad was requested */
- if (session->send_rtp_sink != NULL)
- goto existed;
+ if (session->send_rtp_sink_ghost != NULL)
+ return session->send_rtp_sink_ghost;
/* get send_rtp pad and store */
session->send_rtp_sink =
@@ -2215,10 +2296,10 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
if (session->send_rtp_sink == NULL)
goto pad_failed;
- result =
+ session->send_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
/* get srcpad */
session->send_rtp_src =
@@ -2230,13 +2311,13 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
klass = GST_ELEMENT_GET_CLASS (rtpbin);
gname = g_strdup_printf ("send_rtp_src_%d", sessid);
templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
- srcghost =
+ session->send_rtp_src_ghost =
gst_ghost_pad_new_from_template (gname, session->send_rtp_src, templ);
- gst_pad_set_active (srcghost, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
+ 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 result;
+ return session->send_rtp_sink_ghost;
/* ERRORS */
no_name:
@@ -2249,12 +2330,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: send_rtp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad for session %d", sessid);
@@ -2269,10 +2344,30 @@ no_srcpad:
}
static void
-remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->send_rtp_src_ghost) {
+ gst_pad_set_active (session->send_rtp_src_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtp_src_ghost);
+ session->send_rtp_src_ghost = NULL;
+ }
+ if (session->send_rtp_src) {
+ gst_object_unref (session->send_rtp_src);
+ session->send_rtp_src = NULL;
+ }
+ if (session->send_rtp_sink) {
+ gst_element_release_request_pad (GST_ELEMENT_CAST (session->session),
+ session->send_rtp_sink);
+ gst_object_unref (session->send_rtp_sink);
+ session->send_rtp_sink = NULL;
+ }
+ if (session->send_rtp_sink_ghost) {
+ gst_pad_set_active (session->send_rtp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtp_sink_ghost);
+ session->send_rtp_sink_ghost = NULL;
+ }
}
/* Create a pad for sending RTCP for the session in @name. Must be called with
@@ -2281,7 +2376,6 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
static GstPad *
create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result;
guint sessid;
GstRtpBinSession *session;
@@ -2295,8 +2389,8 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
goto no_session;
/* check if pad was requested */
- if (session->send_rtcp_src != NULL)
- goto existed;
+ if (session->send_rtcp_src_ghost != NULL)
+ return session->send_rtcp_src_ghost;
/* get rtcp_src pad and store */
session->send_rtcp_src =
@@ -2304,12 +2398,12 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
if (session->send_rtcp_src == NULL)
goto pad_failed;
- result =
+ session->send_rtcp_src_ghost =
gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
- return result;
+ return session->send_rtcp_src_ghost;
/* ERRORS */
no_name:
@@ -2322,12 +2416,6 @@ no_session:
g_warning ("gstrtpbin: session with id %d does not exist", sessid);
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: send_rtcp_src pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get rtcp pad for session %d", sessid);
@@ -2336,10 +2424,19 @@ pad_failed:
}
static void
-remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->send_rtcp_src_ghost) {
+ gst_pad_set_active (session->send_rtcp_src_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtcp_src_ghost);
+ session->send_rtcp_src_ghost = NULL;
+ }
+ if (session->send_rtcp_src) {
+ gst_element_release_request_pad (session->session, session->send_rtcp_src);
+ gst_object_unref (session->send_rtcp_src);
+ session->send_rtcp_src = NULL;
+ }
}
/* If the requested name is NULL we should create a name with
@@ -2403,7 +2500,7 @@ gst_rtp_bin_request_new_pad (GstElement * element,
pad_name = g_strdup (name);
}
- GST_DEBUG ("Trying to request a pad with name %s", pad_name);
+ GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name);
/* figure out the template */
if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
@@ -2440,32 +2537,39 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
{
GstRtpBinSession *session;
GstRtpBin *rtpbin;
- GstPad *target = NULL;
g_return_if_fail (GST_IS_GHOST_PAD (pad));
g_return_if_fail (GST_IS_RTP_BIN (element));
rtpbin = GST_RTP_BIN (element);
- target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
- g_return_if_fail (target);
-
GST_RTP_BIN_LOCK (rtpbin);
- if (!(session = find_session_by_pad (rtpbin, target)))
+ GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s",
+ GST_DEBUG_PAD_NAME (pad));
+
+ if (!(session = find_session_by_pad (rtpbin, pad)))
goto unknown_pad;
- if (session->recv_rtp_sink == target) {
- remove_recv_rtp (rtpbin, session, pad);
- } else if (session->recv_rtcp_sink == target) {
- remove_recv_rtcp (rtpbin, session, pad);
- } else if (session->send_rtp_sink == target) {
- remove_send_rtp (rtpbin, session, pad);
- } else if (session->send_rtcp_src == target) {
- remove_rtcp (rtpbin, session, pad);
+ if (session->recv_rtp_sink_ghost == pad) {
+ remove_recv_rtp (rtpbin, session);
+ } else if (session->recv_rtcp_sink_ghost == pad) {
+ remove_recv_rtcp (rtpbin, session);
+ } else if (session->send_rtp_sink_ghost == pad) {
+ remove_send_rtp (rtpbin, session);
+ } else if (session->send_rtcp_src_ghost == pad) {
+ remove_rtcp (rtpbin, session);
}
- GST_RTP_BIN_UNLOCK (rtpbin);
- gst_object_unref (target);
+ /* no more request pads, free the complete session */
+ if (session->recv_rtp_sink_ghost == NULL
+ && session->recv_rtcp_sink_ghost == NULL
+ && session->send_rtp_sink_ghost == NULL
+ && session->send_rtcp_src_ghost == NULL) {
+ GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session);
+ rtpbin->sessions = g_slist_remove (rtpbin->sessions, session);
+ free_session (session, rtpbin);
+ }
+ GST_RTP_BIN_UNLOCK (rtpbin);
return;
@@ -2473,7 +2577,6 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
unknown_pad:
{
GST_RTP_BIN_UNLOCK (rtpbin);
- gst_object_unref (target);
g_warning ("gstrtpbin: %s:%s is not one of our request pads",
GST_DEBUG_PAD_NAME (pad));
return;
diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
index 035d82a8..c33fdfc6 100644
--- a/gst/rtpmanager/gstrtpsession.c
+++ b/gst/rtpmanager/gstrtpsession.c
@@ -323,63 +323,6 @@ on_ssrc_active (RTPSession * session, RTPSource * src, GstRtpSession * sess)
src->ssrc);
}
-static GstStructure *
-source_get_sdes_structure (RTPSource * src)
-{
- GstStructure *result;
- GValue val = { 0 };
- gchar *str;
-
- result = gst_structure_empty_new ("GstRTPSessionSDES");
-
- gst_structure_set (result, "ssrc", G_TYPE_UINT, src->ssrc, NULL);
-
- g_value_init (&val, G_TYPE_STRING);
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "cname", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NAME);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "name", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_EMAIL);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "email", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PHONE);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "phone", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_LOC);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "location", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_TOOL);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "tool", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NOTE);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "note", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PRIV);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "priv", &val);
- }
- g_value_unset (&val);
-
- return result;
-}
-
static void
on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
@@ -388,8 +331,9 @@ on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
/* convert the new SDES info into a message */
RTP_SESSION_LOCK (session);
- s = source_get_sdes_structure (src);
+ g_object_get (src, "sdes", &s, NULL);
RTP_SESSION_UNLOCK (session);
+
m = gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (sess), s);
gst_element_post_message (GST_ELEMENT_CAST (sess), m);
diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c
index 64394c45..6a305d8e 100644
--- a/gst/rtpmanager/gstrtpssrcdemux.c
+++ b/gst/rtpmanager/gstrtpssrcdemux.c
@@ -97,6 +97,8 @@ static GstElementDetails gst_rtp_ssrc_demux_details = {
enum
{
SIGNAL_NEW_SSRC_PAD,
+ SIGNAL_REMOVED_SSRC_PAD,
+ SIGNAL_CLEAR_SSRC,
LAST_SIGNAL
};
@@ -112,6 +114,9 @@ static void gst_rtp_ssrc_demux_finalize (GObject * object);
static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
element, GstStateChange transition);
+static void gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux,
+ guint32 ssrc);
+
/* sinkpad stuff */
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event);
@@ -245,9 +250,11 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
+ GstRtpSsrcDemuxClass *gstrtpssrcdemux_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
+ gstrtpssrcdemux_klass = (GstRtpSsrcDemuxClass *) klass;
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_dispose);
gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_finalize);
@@ -267,8 +274,38 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
+ /**
+ * GstRtpSsrcDemux::removed-ssrc-pad:
+ * @demux: the object which received the signal
+ * @ssrc: the SSRC of the pad
+ * @pad: the removed pad.
+ *
+ * Emited when a SSRC pad has been removed.
+ */
+ gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD] =
+ g_signal_new ("removed-ssrc-pad",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, removed_ssrc_pad),
+ NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
+ G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
+
+ /**
+ * GstRtpSsrcDemux::clear-ssrc:
+ * @demux: the object which received the signal
+ * @ssrc: the SSRC of the pad
+ *
+ * Action signal to remove the pad for SSRC.
+ */
+ gst_rtp_ssrc_demux_signals[SIGNAL_CLEAR_SSRC] =
+ g_signal_new ("clear-ssrc",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, clear_ssrc),
+ NULL, NULL, gst_rtp_bin_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state);
+ gstrtpssrcdemux_klass->clear_ssrc =
+ GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_clear_ssrc);
GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug,
"rtpssrcdemux", 0, "RTP SSRC demuxer");
@@ -342,6 +379,43 @@ gst_rtp_ssrc_demux_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static void
+gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+{
+ GstRtpSsrcDemuxPad *dpad;
+
+ GST_PAD_LOCK (demux);
+ dpad = find_demux_pad_for_ssrc (demux, ssrc);
+ if (dpad != NULL)
+ goto unknown_pad;
+
+ GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc);
+
+ demux->srcpads = g_slist_remove (demux->srcpads, dpad);
+ GST_PAD_UNLOCK (demux);
+
+ gst_pad_set_active (dpad->rtp_pad, FALSE);
+ gst_pad_set_active (dpad->rtcp_pad, FALSE);
+
+ g_signal_emit (G_OBJECT (demux),
+ gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc,
+ dpad->rtp_pad);
+
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
+
+ g_free (dpad);
+
+ return;
+
+ /* ERRORS */
+unknown_pad:
+ {
+ g_warning ("unknown SSRC %08x", ssrc);
+ return;
+ }
+}
+
static gboolean
gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event)
{
@@ -483,7 +557,7 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf)
NULL);
break;
default:
- goto invalid_rtcp;
+ goto unexpected_rtcp;
}
GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);
@@ -511,6 +585,12 @@ invalid_rtcp:
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
+unexpected_rtcp:
+ {
+ GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ }
create_failed:
{
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
diff --git a/gst/rtpmanager/gstrtpssrcdemux.h b/gst/rtpmanager/gstrtpssrcdemux.h
index d89472af..d5a13caf 100644
--- a/gst/rtpmanager/gstrtpssrcdemux.h
+++ b/gst/rtpmanager/gstrtpssrcdemux.h
@@ -50,7 +50,11 @@ struct _GstRtpSsrcDemuxClass
GstElementClass parent_class;
/* signals */
- void (*new_ssrc_pad) (GstElement *element, guint32 ssrc, GstPad *pad);
+ void (*new_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+ void (*removed_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+
+ /* actions */
+ void (*clear_ssrc) (GstRtpSsrcDemux *demux, guint32 ssrc);
};
GType gst_rtp_ssrc_demux_get_type (void);
diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c
index a40d974f..6a3dc604 100644
--- a/gst/rtpmanager/rtpsource.c
+++ b/gst/rtpmanager/rtpsource.c
@@ -188,12 +188,50 @@ rtp_source_finalize (GObject * object)
G_OBJECT_CLASS (rtp_source_parent_class)->finalize (object);
}
+#define MAX_ADDRESS 64
+static void
+make_address_string (GstNetAddress * addr, gchar * dest, gulong n)
+{
+ switch (gst_netaddress_get_net_type (addr)) {
+ case GST_NET_TYPE_IP4:
+ {
+ guint32 address;
+ guint16 port;
+
+ gst_netaddress_get_ip4_address (addr, &address, &port);
+
+ g_snprintf (dest, n, "%d.%d.%d.%d:%d", (address >> 24) & 0xff,
+ (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff, port);
+ break;
+ }
+ case GST_NET_TYPE_IP6:
+ {
+ guint8 address[16];
+ guint16 port;
+
+ gst_netaddress_get_ip6_address (addr, address, &port);
+
+ g_snprintf (dest, n, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%d",
+ (address[0] << 8) | address[1], (address[2] << 8) | address[3],
+ (address[4] << 8) | address[5], (address[6] << 8) | address[7],
+ (address[8] << 8) | address[9], (address[10] << 8) | address[11],
+ (address[12] << 8) | address[13], (address[14] << 8) | address[15],
+ port);
+ break;
+ }
+ default:
+ dest[0] = 0;
+ break;
+ }
+}
+
static GstStructure *
rtp_source_create_stats (RTPSource * src)
{
GstStructure *s;
gboolean is_sender = src->is_sender;
gboolean internal = src->internal;
+ gchar address_str[MAX_ADDRESS];
/* common data for all types of sources */
s = gst_structure_new ("application/x-rtp-source-stats",
@@ -204,6 +242,16 @@ rtp_source_create_stats (RTPSource * src)
"is-csrc", G_TYPE_BOOLEAN, src->is_csrc,
"is-sender", G_TYPE_BOOLEAN, is_sender, NULL);
+ /* add address and port */
+ if (src->have_rtp_from) {
+ make_address_string (&src->rtp_from, address_str, sizeof (address_str));
+ gst_structure_set (s, "rtp-from", G_TYPE_STRING, address_str, NULL);
+ }
+ if (src->have_rtcp_from) {
+ make_address_string (&src->rtcp_from, address_str, sizeof (address_str));
+ gst_structure_set (s, "rtcp-from", G_TYPE_STRING, address_str, NULL);
+ }
+
if (internal) {
/* our internal source */
if (is_sender) {