2 * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-rtpbin
22 * @short_description: handle media from one RTP bin
23 * @see_also: rtpjitterbuffer, rtpclient, rtpsession
28 * <title>Example pipelines</title>
31 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
36 * Last reviewed on 2007-04-02 (0.10.6)
44 #include "gstrtpbin.h"
46 /* elementfactory information */
47 static const GstElementDetails rtpbin_details = GST_ELEMENT_DETAILS ("RTP Bin",
48 "Filter/Editor/Video",
49 "Implement an RTP bin",
50 "Wim Taymans <wim@fluendo.com>");
53 static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
54 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
57 GST_STATIC_CAPS ("application/x-rtp")
60 static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
61 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
64 GST_STATIC_CAPS ("application/x-rtcp")
67 static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
68 GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%d",
71 GST_STATIC_CAPS ("application/x-rtp")
75 static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
76 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
79 GST_STATIC_CAPS ("application/x-rtp")
82 static GstStaticPadTemplate rtpbin_rtcp_src_template =
83 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
86 GST_STATIC_CAPS ("application/x-rtcp")
89 static GstStaticPadTemplate rtpbin_send_rtp_src_template =
90 GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%d",
93 GST_STATIC_CAPS ("application/x-rtp")
96 #define GST_RTP_BIN_GET_PRIVATE(obj) \
97 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRTPBinPrivate))
99 struct _GstRTPBinPrivate
103 /* signals and args */
120 /* the session element */
122 /* the SSRC demuxer */
123 GstElement *ssrcdemux;
125 /* the pads of the session */
126 GstPad *recv_rtp_sink;
127 GstPad *recv_rtcp_sink;
128 GstPad *send_rtp_sink;
133 /* find a session with the given id */
134 static GstRTPBinSession *
135 find_session_by_id (GstRTPBin * rtpbin, gint id)
139 for (walk = rtpbin->sessions; walk; walk = g_list_next (walk)) {
140 GstRTPBinSession *sess = (GstRTPBinSession *) walk->data;
148 /* create a session with the given id */
149 static GstRTPBinSession *
150 create_session (GstRTPBin * rtpbin, gint id)
152 GstRTPBinSession *sess;
155 if (!(elem = gst_element_factory_make ("rtpsession", NULL)))
158 sess = g_new0 (GstRTPBinSession, 1);
160 sess->session = elem;
167 g_warning ("rtpbin: could not create rtpsession element");
172 /* GObject vmethods */
173 static void gst_rtp_bin_finalize (GObject * object);
174 static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
175 const GValue * value, GParamSpec * pspec);
176 static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
177 GValue * value, GParamSpec * pspec);
179 /* GstElement vmethods */
180 static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
181 GstStateChange transition);
182 static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
183 GstPadTemplate * templ, const gchar * name);
184 static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
186 /*static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 }; */
188 GST_BOILERPLATE (GstRTPBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
191 gst_rtp_bin_base_init (gpointer klass)
193 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
196 gst_element_class_add_pad_template (element_class,
197 gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
198 gst_element_class_add_pad_template (element_class,
199 gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
200 gst_element_class_add_pad_template (element_class,
201 gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
204 gst_element_class_add_pad_template (element_class,
205 gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
206 gst_element_class_add_pad_template (element_class,
207 gst_static_pad_template_get (&rtpbin_rtcp_src_template));
208 gst_element_class_add_pad_template (element_class,
209 gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
211 gst_element_class_set_details (element_class, &rtpbin_details);
215 gst_rtp_bin_class_init (GstRTPBinClass * klass)
217 GObjectClass *gobject_class;
218 GstElementClass *gstelement_class;
220 gobject_class = (GObjectClass *) klass;
221 gstelement_class = (GstElementClass *) klass;
223 g_type_class_add_private (klass, sizeof (GstRTPBinPrivate));
225 gobject_class->finalize = gst_rtp_bin_finalize;
226 gobject_class->set_property = gst_rtp_bin_set_property;
227 gobject_class->get_property = gst_rtp_bin_get_property;
229 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
230 gstelement_class->request_new_pad =
231 GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
232 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
236 gst_rtp_bin_init (GstRTPBin * rtpbin, GstRTPBinClass * klass)
238 rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
242 gst_rtp_bin_finalize (GObject * object)
246 rtpbin = GST_RTP_BIN (object);
248 G_OBJECT_CLASS (parent_class)->finalize (object);
252 gst_rtp_bin_set_property (GObject * object, guint prop_id,
253 const GValue * value, GParamSpec * pspec)
257 rtpbin = GST_RTP_BIN (object);
261 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 gst_rtp_bin_get_property (GObject * object, guint prop_id,
268 GValue * value, GParamSpec * pspec)
272 rtpbin = GST_RTP_BIN (object);
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281 static GstStateChangeReturn
282 gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
284 GstStateChangeReturn res;
287 rtpbin = GST_RTP_BIN (element);
289 switch (transition) {
290 case GST_STATE_CHANGE_NULL_TO_READY:
292 case GST_STATE_CHANGE_READY_TO_PAUSED:
294 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
300 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
302 switch (transition) {
303 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
305 case GST_STATE_CHANGE_PAUSED_TO_READY:
307 case GST_STATE_CHANGE_READY_TO_NULL:
315 /* Create a pad for receiving RTP for the session in @name
318 create_recv_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
322 GstRTPBinSession *session;
324 /* first get the session number */
325 if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
328 /* get or create session */
329 session = find_session_by_id (rtpbin, sessid);
331 /* create session now */
332 session = create_session (rtpbin, sessid);
336 /* check if pad was requested */
337 if (session->recv_rtp_sink != NULL)
340 /* get recv_rtp pad and store */
341 session->recv_rtp_sink =
342 gst_element_get_request_pad (session->session, "recv_rtp_sink");
343 if (session->recv_rtp_sink == NULL)
347 gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
348 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
350 /* FIXME, get srcpad, link to SSRCDemux */
357 g_warning ("rtpbin: invalid name given");
362 /* create_session already warned */
367 g_warning ("rtpbin: recv_rtp pad already requested for session %d", sessid);
372 g_warning ("rtpbin: failed to get session pad");
377 /* Create a pad for receiving RTCP for the session in @name
380 create_recv_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ,
385 GstRTPBinSession *session;
387 /* first get the session number */
388 if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
391 /* get the session, it must exist or we error */
392 session = find_session_by_id (rtpbin, sessid);
396 /* check if pad was requested */
397 if (session->recv_rtcp_sink != NULL)
400 /* get recv_rtp pad and store */
401 session->recv_rtcp_sink =
402 gst_element_get_request_pad (session->session, "recv_rtcp_sink");
403 if (session->recv_rtcp_sink == NULL)
407 gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
408 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
410 /* FIXME, get srcpad, link to SSRCDemux */
417 g_warning ("rtpbin: invalid name given");
422 g_warning ("rtpbin: no session with id %d", sessid);
427 g_warning ("rtpbin: recv_rtcp pad already requested for session %d",
433 g_warning ("rtpbin: failed to get session pad");
438 /* Create a pad for sending RTP for the session in @name
441 create_send_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
443 GstPad *result, *srcpad, *srcghost;
446 GstRTPBinSession *session;
447 GstElementClass *klass;
449 /* first get the session number */
450 if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
453 /* get or create session */
454 session = find_session_by_id (rtpbin, sessid);
456 /* create session now */
457 session = create_session (rtpbin, sessid);
462 /* check if pad was requested */
463 if (session->send_rtp_sink != NULL)
466 /* get recv_rtp pad and store */
467 session->send_rtp_sink =
468 gst_element_get_request_pad (session->session, "send_rtp_sink");
469 if (session->send_rtp_sink == NULL)
473 gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
474 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
477 srcpad = gst_element_get_pad (session->session, "send_rtp_src");
481 /* ghost the new source pad */
482 klass = GST_ELEMENT_GET_CLASS (rtpbin);
483 gname = g_strdup_printf ("send_rtp_src_%d", sessid);
484 templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
486 gst_ghost_pad_new_from_template (gname, session->send_rtp_sink, templ);
487 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
495 g_warning ("rtpbin: invalid name given");
500 /* create_session already warned */
505 g_warning ("rtpbin: send_rtp pad already requested for session %d", sessid);
510 g_warning ("rtpbin: failed to get session pad for session %d", sessid);
515 g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
520 /* Create a pad for sending RTCP for the session in @name
523 create_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
527 GstRTPBinSession *session;
529 /* first get the session number */
530 if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
533 /* get or create session */
534 session = find_session_by_id (rtpbin, sessid);
538 /* check if pad was requested */
539 if (session->rtcp_src != NULL)
542 /* get rtcp_src pad and store */
544 gst_element_get_request_pad (session->session, "rtcp_src");
545 if (session->rtcp_src == NULL)
548 result = gst_ghost_pad_new_from_template (name, session->rtcp_src, templ);
549 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
556 g_warning ("rtpbin: invalid name given");
561 g_warning ("rtpbin: session with id %d does not exist", sessid);
566 g_warning ("rtpbin: rtcp_src pad already requested for session %d", sessid);
571 g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
579 gst_rtp_bin_request_new_pad (GstElement * element,
580 GstPadTemplate * templ, const gchar * name)
583 GstElementClass *klass;
586 g_return_val_if_fail (templ != NULL, NULL);
587 g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
589 rtpbin = GST_RTP_BIN (element);
590 klass = GST_ELEMENT_GET_CLASS (element);
592 /* figure out the template */
593 if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
594 result = create_recv_rtp (rtpbin, templ, name);
595 } else if (templ == gst_element_class_get_pad_template (klass,
596 "recv_rtcp_sink_%d")) {
597 result = create_recv_rtcp (rtpbin, templ, name);
598 } else if (templ == gst_element_class_get_pad_template (klass,
599 "send_rtp_sink_%d")) {
600 result = create_send_rtp (rtpbin, templ, name);
601 } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
602 result = create_rtcp (rtpbin, templ, name);
611 g_warning ("rtpbin: this is not our template");
617 gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)