gst/rtpmanager/gstrtpbin.*: Add debugging category.
[platform/upstream/gstreamer.git] / gst / rtpmanager / gstrtpbin.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * SECTION:element-rtpbin
22  * @short_description: handle media from one RTP bin
23  * @see_also: rtpjitterbuffer, rtpclient, rtpsession
24  *
25  * <refsect2>
26  * <para>
27  * </para>
28  * <title>Example pipelines</title>
29  * <para>
30  * <programlisting>
31  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
32  * </programlisting>
33  * </para>
34  * </refsect2>
35  *
36  * Last reviewed on 2007-04-02 (0.10.6)
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 #include <string.h>
43
44 #include "gstrtpbin.h"
45
46 GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
47 #define GST_CAT_DEFAULT gst_rtp_bin_debug
48
49
50 /* elementfactory information */
51 static const GstElementDetails rtpbin_details = GST_ELEMENT_DETAILS ("RTP Bin",
52     "Filter/Editor/Video",
53     "Implement an RTP bin",
54     "Wim Taymans <wim@fluendo.com>");
55
56 /* sink pads */
57 static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
58 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
59     GST_PAD_SINK,
60     GST_PAD_REQUEST,
61     GST_STATIC_CAPS ("application/x-rtp")
62     );
63
64 static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
65 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
66     GST_PAD_SINK,
67     GST_PAD_REQUEST,
68     GST_STATIC_CAPS ("application/x-rtcp")
69     );
70
71 static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
72 GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%d",
73     GST_PAD_SINK,
74     GST_PAD_REQUEST,
75     GST_STATIC_CAPS ("application/x-rtp")
76     );
77
78 /* src pads */
79 static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
80 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
81     GST_PAD_SRC,
82     GST_PAD_SOMETIMES,
83     GST_STATIC_CAPS ("application/x-rtp")
84     );
85
86 static GstStaticPadTemplate rtpbin_rtcp_src_template =
87 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
88     GST_PAD_SRC,
89     GST_PAD_REQUEST,
90     GST_STATIC_CAPS ("application/x-rtcp")
91     );
92
93 static GstStaticPadTemplate rtpbin_send_rtp_src_template =
94 GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%d",
95     GST_PAD_SRC,
96     GST_PAD_SOMETIMES,
97     GST_STATIC_CAPS ("application/x-rtp")
98     );
99
100 #define GST_RTP_BIN_GET_PRIVATE(obj)  \
101    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRTPBinPrivate))
102
103 struct _GstRTPBinPrivate
104 {
105   guint foo;
106 };
107
108 /* signals and args */
109 enum
110 {
111   /* FILL ME */
112   LAST_SIGNAL
113 };
114
115 enum
116 {
117   PROP_0
118 };
119
120 /* helper objects */
121 typedef struct _GstRTPBinSession GstRTPBinSession;
122 typedef struct _GstRTPBinStream GstRTPBinStream;
123 typedef struct _GstRTPBinClient GstRTPBinClient;
124
125 /* Manages the RTP stream for one SSRC.
126  *
127  * We pipe the stream (comming from the SSRC demuxer) into a jitterbuffer.
128  * If we see an SDES RTCP packet that links multiple SSRCs together based on a
129  * common CNAME, we create a GstRTPBinClient structure to group the SSRCs
130  * together (see below).
131  */
132 struct _GstRTPBinStream
133 {
134   /* the SSRC of this stream */
135   guint32 ssrc;
136   /* parent bin */
137   GstRTPBin *bin;
138   /* the session this SSRC belongs to */
139   GstRTPBinSession *session;
140   /* the jitterbuffer of the SSRC */
141   GstElement *buffer;
142   /* the PT demuxer of the SSRC */
143   GstElement *demux;
144   gulong demux_newpad_sig;
145 };
146
147 /* Manages the receiving end of the packets.
148  *
149  * There is one such structure for each RTP session (audio/video/...).
150  * We get the RTP/RTCP packets and stuff them into the session manager. From
151  * there they are pushed into an SSRC demuxer that splits the stream based on
152  * SSRC. Each of the SSRC streams go into their own jitterbuffer (managed with
153  * the GstRTPBinStream above).
154  */
155 struct _GstRTPBinSession
156 {
157   /* session id */
158   gint id;
159   /* the parent bin */
160   GstRTPBin *bin;
161   /* the session element */
162   GstElement *session;
163   /* the SSRC demuxer */
164   GstElement *demux;
165   gulong demux_newpad_sig;
166
167   /* list of GstRTPBinStream */
168   GSList *streams;
169
170   /* the pads of the session */
171   GstPad *recv_rtp_sink;
172   GstPad *recv_rtp_src;
173   GstPad *recv_rtcp_sink;
174   GstPad *recv_rtcp_src;
175   GstPad *send_rtp_sink;
176   GstPad *send_rtp_src;
177   GstPad *rtcp_src;
178 };
179
180 /* find a session with the given id */
181 static GstRTPBinSession *
182 find_session_by_id (GstRTPBin * rtpbin, gint id)
183 {
184   GSList *walk;
185
186   for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
187     GstRTPBinSession *sess = (GstRTPBinSession *) walk->data;
188
189     if (sess->id == id)
190       return sess;
191   }
192   return NULL;
193 }
194
195 /* create a session with the given id */
196 static GstRTPBinSession *
197 create_session (GstRTPBin * rtpbin, gint id)
198 {
199   GstRTPBinSession *sess;
200   GstElement *elem, *demux;
201
202   if (!(elem = gst_element_factory_make ("rtpsession", NULL)))
203     goto no_session;
204
205   if (!(demux = gst_element_factory_make ("rtpssrcdemux", NULL)))
206     goto no_demux;
207
208   sess = g_new0 (GstRTPBinSession, 1);
209   sess->id = id;
210   sess->bin = rtpbin;
211   sess->session = elem;
212   sess->demux = demux;
213   rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
214
215   gst_bin_add (GST_BIN_CAST (rtpbin), elem);
216   gst_element_set_state (elem, GST_STATE_PLAYING);
217   gst_bin_add (GST_BIN_CAST (rtpbin), demux);
218   gst_element_set_state (demux, GST_STATE_PLAYING);
219
220   return sess;
221
222   /* ERRORS */
223 no_session:
224   {
225     g_warning ("rtpbin: could not create rtpsession element");
226     return NULL;
227   }
228 no_demux:
229   {
230     gst_object_unref (elem);
231     g_warning ("rtpbin: could not create rtpssrcdemux element");
232     return NULL;
233   }
234 }
235
236 #if 0
237 static GstRTPBinStream *
238 find_stream_by_ssrc (GstRTPBinSession * session, guint32 ssrc)
239 {
240   GSList *walk;
241
242   for (walk = session->streams; walk; walk = g_slist_next (walk)) {
243     GstRTPBinStream *stream = (GstRTPBinStream *) walk->data;
244
245     if (stream->ssrc == ssrc)
246       return stream;
247   }
248   return NULL;
249 }
250 #endif
251
252 static GstRTPBinStream *
253 create_stream (GstRTPBinSession * session, guint32 ssrc)
254 {
255   GstElement *buffer, *demux;
256   GstRTPBinStream *stream;
257
258   if (!(buffer = gst_element_factory_make ("rtpjitterbuffer", NULL)))
259     goto no_jitterbuffer;
260
261   if (!(demux = gst_element_factory_make ("rtpptdemux", NULL)))
262     goto no_demux;
263
264   stream = g_new0 (GstRTPBinStream, 1);
265   stream->ssrc = ssrc;
266   stream->bin = session->bin;
267   stream->session = session;
268   stream->buffer = buffer;
269   stream->demux = demux;
270   session->streams = g_slist_prepend (session->streams, stream);
271
272   gst_bin_add (GST_BIN_CAST (session->bin), buffer);
273   gst_element_set_state (buffer, GST_STATE_PLAYING);
274   gst_bin_add (GST_BIN_CAST (session->bin), demux);
275   gst_element_set_state (demux, GST_STATE_PLAYING);
276
277   /* link stuff */
278   gst_element_link (buffer, demux);
279
280   return stream;
281
282   /* ERRORS */
283 no_jitterbuffer:
284   {
285     g_warning ("rtpbin: could not create rtpjitterbuffer element");
286     return NULL;
287   }
288 no_demux:
289   {
290     gst_object_unref (buffer);
291     g_warning ("rtpbin: could not create rtpptdemux element");
292     return NULL;
293   }
294 }
295
296 /* Manages the RTP streams that come from one client and should therefore be
297  * synchronized.
298  */
299 struct _GstRTPBinClient
300 {
301   /* the common CNAME for the streams */
302   gchar *cname;
303   /* the streams */
304   GSList *streams;
305 };
306
307 /* GObject vmethods */
308 static void gst_rtp_bin_finalize (GObject * object);
309 static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
310     const GValue * value, GParamSpec * pspec);
311 static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
312     GValue * value, GParamSpec * pspec);
313
314 /* GstElement vmethods */
315 static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
316     GstStateChange transition);
317 static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
318     GstPadTemplate * templ, const gchar * name);
319 static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
320
321 /*static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 }; */
322
323 GST_BOILERPLATE (GstRTPBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
324
325 static void
326 gst_rtp_bin_base_init (gpointer klass)
327 {
328   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
329
330   /* sink pads */
331   gst_element_class_add_pad_template (element_class,
332       gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
333   gst_element_class_add_pad_template (element_class,
334       gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
335   gst_element_class_add_pad_template (element_class,
336       gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
337
338   /* src pads */
339   gst_element_class_add_pad_template (element_class,
340       gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
341   gst_element_class_add_pad_template (element_class,
342       gst_static_pad_template_get (&rtpbin_rtcp_src_template));
343   gst_element_class_add_pad_template (element_class,
344       gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
345
346   gst_element_class_set_details (element_class, &rtpbin_details);
347 }
348
349 static void
350 gst_rtp_bin_class_init (GstRTPBinClass * klass)
351 {
352   GObjectClass *gobject_class;
353   GstElementClass *gstelement_class;
354
355   gobject_class = (GObjectClass *) klass;
356   gstelement_class = (GstElementClass *) klass;
357
358   g_type_class_add_private (klass, sizeof (GstRTPBinPrivate));
359
360   gobject_class->finalize = gst_rtp_bin_finalize;
361   gobject_class->set_property = gst_rtp_bin_set_property;
362   gobject_class->get_property = gst_rtp_bin_get_property;
363
364   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
365   gstelement_class->request_new_pad =
366       GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
367   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
368
369   GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
370 }
371
372 static void
373 gst_rtp_bin_init (GstRTPBin * rtpbin, GstRTPBinClass * klass)
374 {
375   rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
376 }
377
378 static void
379 gst_rtp_bin_finalize (GObject * object)
380 {
381   GstRTPBin *rtpbin;
382
383   rtpbin = GST_RTP_BIN (object);
384
385   G_OBJECT_CLASS (parent_class)->finalize (object);
386 }
387
388 static void
389 gst_rtp_bin_set_property (GObject * object, guint prop_id,
390     const GValue * value, GParamSpec * pspec)
391 {
392   GstRTPBin *rtpbin;
393
394   rtpbin = GST_RTP_BIN (object);
395
396   switch (prop_id) {
397     default:
398       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399       break;
400   }
401 }
402
403 static void
404 gst_rtp_bin_get_property (GObject * object, guint prop_id,
405     GValue * value, GParamSpec * pspec)
406 {
407   GstRTPBin *rtpbin;
408
409   rtpbin = GST_RTP_BIN (object);
410
411   switch (prop_id) {
412     default:
413       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
414       break;
415   }
416 }
417
418 static GstStateChangeReturn
419 gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
420 {
421   GstStateChangeReturn res;
422   GstRTPBin *rtpbin;
423
424   rtpbin = GST_RTP_BIN (element);
425
426   switch (transition) {
427     case GST_STATE_CHANGE_NULL_TO_READY:
428       break;
429     case GST_STATE_CHANGE_READY_TO_PAUSED:
430       break;
431     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
432       break;
433     default:
434       break;
435   }
436
437   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
438
439   switch (transition) {
440     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
441       break;
442     case GST_STATE_CHANGE_PAUSED_TO_READY:
443       break;
444     case GST_STATE_CHANGE_READY_TO_NULL:
445       break;
446     default:
447       break;
448   }
449   return res;
450 }
451
452 /* a new pad (SSRC) was created in @session */
453 static void
454 new_payload_found (GstElement * element, guint pt, GstPad * pad,
455     GstRTPBinStream * stream)
456 {
457   GstRTPBin *rtpbin;
458   GstElementClass *klass;
459   GstPadTemplate *templ;
460   gchar *padname;
461   GstPad *gpad;
462
463   rtpbin = stream->bin;
464
465   GST_DEBUG ("new payload pad %d", pt);
466
467   /* ghost the pad to the parent */
468   klass = GST_ELEMENT_GET_CLASS (rtpbin);
469   templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
470   padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
471       stream->session->id, stream->ssrc, pt);
472   gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
473   g_free (padname);
474
475   gst_pad_set_active (gpad, TRUE);
476   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
477 }
478
479 /* a new pad (SSRC) was created in @session */
480 static void
481 new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
482     GstRTPBinSession * session)
483 {
484   GstRTPBinStream *stream;
485   GstPad *sinkpad;
486
487   GST_DEBUG_OBJECT (session->bin, "new SSRC pad %08x", ssrc);
488
489   /* create new stream */
490   stream = create_stream (session, ssrc);
491   if (!stream)
492     goto no_stream;
493
494   /* get pad and link */
495   GST_DEBUG_OBJECT (session->bin, "linking jitterbuffer");
496   sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
497   gst_pad_link (pad, sinkpad);
498   gst_object_unref (sinkpad);
499
500   /* connect to the new-pad signal of the payload demuxer */
501   stream->demux_newpad_sig = g_signal_connect (stream->demux,
502       "new-payload-type", (GCallback) new_payload_found, stream);
503
504   return;
505
506   /* ERRORS */
507 no_stream:
508   {
509     GST_DEBUG ("could not create stream");
510     return;
511   }
512 }
513
514 /* Create a pad for receiving RTP for the session in @name
515  */
516 static GstPad *
517 create_recv_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
518 {
519   GstPad *result, *sinkdpad;
520   guint sessid;
521   GstRTPBinSession *session;
522   GstPadLinkReturn lres;
523
524   /* first get the session number */
525   if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
526     goto no_name;
527
528   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
529
530   /* get or create session */
531   session = find_session_by_id (rtpbin, sessid);
532   if (!session) {
533     GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
534     /* create session now */
535     session = create_session (rtpbin, sessid);
536     if (session == NULL)
537       goto create_error;
538   }
539   /* check if pad was requested */
540   if (session->recv_rtp_sink != NULL)
541     goto existed;
542
543   GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
544   /* get recv_rtp pad and store */
545   session->recv_rtp_sink =
546       gst_element_get_request_pad (session->session, "recv_rtp_sink");
547   if (session->recv_rtp_sink == NULL)
548     goto pad_failed;
549
550   GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
551   /* get srcpad, link to SSRCDemux */
552   session->recv_rtp_src =
553       gst_element_get_static_pad (session->session, "recv_rtp_src");
554   if (session->recv_rtp_src == NULL)
555     goto pad_failed;
556
557   GST_DEBUG_OBJECT (rtpbin, "getting demuxer sink pad");
558   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
559   lres = gst_pad_link (session->recv_rtp_src, sinkdpad);
560   gst_object_unref (sinkdpad);
561   if (lres != GST_PAD_LINK_OK)
562     goto link_failed;
563
564   /* connect to the new-ssrc-pad signal of the demuxer */
565   session->demux_newpad_sig = g_signal_connect (session->demux,
566       "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
567
568   GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
569   result =
570       gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
571   gst_pad_set_active (result, TRUE);
572   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
573
574   return result;
575
576   /* ERRORS */
577 no_name:
578   {
579     g_warning ("rtpbin: invalid name given");
580     return NULL;
581   }
582 create_error:
583   {
584     /* create_session already warned */
585     return NULL;
586   }
587 existed:
588   {
589     g_warning ("rtpbin: recv_rtp pad already requested for session %d", sessid);
590     return NULL;
591   }
592 pad_failed:
593   {
594     g_warning ("rtpbin: failed to get session pad");
595     return NULL;
596   }
597 link_failed:
598   {
599     g_warning ("rtpbin: failed to link pads");
600     return NULL;
601   }
602 }
603
604 /* Create a pad for receiving RTCP for the session in @name
605  */
606 static GstPad *
607 create_recv_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ,
608     const gchar * name)
609 {
610   GstPad *result;
611   guint sessid;
612   GstRTPBinSession *session;
613
614 #if 0
615   GstPad *sinkdpad;
616   GstPadLinkReturn lres;
617 #endif
618
619   /* first get the session number */
620   if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
621     goto no_name;
622
623   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
624
625   /* get the session, it must exist or we error */
626   session = find_session_by_id (rtpbin, sessid);
627   if (!session)
628     goto no_session;
629
630   /* check if pad was requested */
631   if (session->recv_rtcp_sink != NULL)
632     goto existed;
633
634   GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
635
636   /* get recv_rtp pad and store */
637   session->recv_rtcp_sink =
638       gst_element_get_request_pad (session->session, "recv_rtcp_sink");
639   if (session->recv_rtcp_sink == NULL)
640     goto pad_failed;
641
642 #if 0
643   /* get srcpad, link to SSRCDemux */
644   GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
645   session->recv_rtcp_src =
646       gst_element_get_static_pad (session->session, "sync_src");
647   if (session->recv_rtcp_src == NULL)
648     goto pad_failed;
649
650   GST_DEBUG_OBJECT (rtpbin, "linking sync to demux");
651   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
652   lres = gst_pad_link (session->recv_rtcp_src, sinkdpad);
653   gst_object_unref (sinkdpad);
654   if (lres != GST_PAD_LINK_OK)
655     goto link_failed;
656 #endif
657
658   result =
659       gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
660   gst_pad_set_active (result, TRUE);
661   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
662
663   return result;
664
665   /* ERRORS */
666 no_name:
667   {
668     g_warning ("rtpbin: invalid name given");
669     return NULL;
670   }
671 no_session:
672   {
673     g_warning ("rtpbin: no session with id %d", sessid);
674     return NULL;
675   }
676 existed:
677   {
678     g_warning ("rtpbin: recv_rtcp pad already requested for session %d",
679         sessid);
680     return NULL;
681   }
682 pad_failed:
683   {
684     g_warning ("rtpbin: failed to get session pad");
685     return NULL;
686   }
687 #if 0
688 link_failed:
689   {
690     g_warning ("rtpbin: failed to link pads");
691     return NULL;
692   }
693 #endif
694 }
695
696 /* Create a pad for sending RTP for the session in @name
697  */
698 static GstPad *
699 create_send_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
700 {
701   GstPad *result, *srcpad, *srcghost;
702   gchar *gname;
703   guint sessid;
704   GstRTPBinSession *session;
705   GstElementClass *klass;
706
707   /* first get the session number */
708   if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
709     goto no_name;
710
711   /* get or create session */
712   session = find_session_by_id (rtpbin, sessid);
713   if (!session) {
714     /* create session now */
715     session = create_session (rtpbin, sessid);
716     if (session == NULL)
717       goto create_error;
718   }
719
720   /* check if pad was requested */
721   if (session->send_rtp_sink != NULL)
722     goto existed;
723
724   /* get recv_rtp pad and store */
725   session->send_rtp_sink =
726       gst_element_get_request_pad (session->session, "send_rtp_sink");
727   if (session->send_rtp_sink == NULL)
728     goto pad_failed;
729
730   result =
731       gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
732   gst_pad_set_active (result, TRUE);
733   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
734
735   /* get srcpad */
736   srcpad = gst_element_get_pad (session->session, "send_rtp_src");
737   if (srcpad == NULL)
738     goto no_srcpad;
739
740   /* ghost the new source pad */
741   klass = GST_ELEMENT_GET_CLASS (rtpbin);
742   gname = g_strdup_printf ("send_rtp_src_%d", sessid);
743   templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
744   srcghost =
745       gst_ghost_pad_new_from_template (gname, session->send_rtp_sink, templ);
746   gst_pad_set_active (srcghost, TRUE);
747   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
748   g_free (gname);
749
750   return result;
751
752   /* ERRORS */
753 no_name:
754   {
755     g_warning ("rtpbin: invalid name given");
756     return NULL;
757   }
758 create_error:
759   {
760     /* create_session already warned */
761     return NULL;
762   }
763 existed:
764   {
765     g_warning ("rtpbin: send_rtp pad already requested for session %d", sessid);
766     return NULL;
767   }
768 pad_failed:
769   {
770     g_warning ("rtpbin: failed to get session pad for session %d", sessid);
771     return NULL;
772   }
773 no_srcpad:
774   {
775     g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
776     return NULL;
777   }
778 }
779
780 /* Create a pad for sending RTCP for the session in @name
781  */
782 static GstPad *
783 create_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
784 {
785   GstPad *result;
786   guint sessid;
787   GstRTPBinSession *session;
788
789   /* first get the session number */
790   if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
791     goto no_name;
792
793   /* get or create session */
794   session = find_session_by_id (rtpbin, sessid);
795   if (!session)
796     goto no_session;
797
798   /* check if pad was requested */
799   if (session->rtcp_src != NULL)
800     goto existed;
801
802   /* get rtcp_src pad and store */
803   session->rtcp_src =
804       gst_element_get_request_pad (session->session, "rtcp_src");
805   if (session->rtcp_src == NULL)
806     goto pad_failed;
807
808   result = gst_ghost_pad_new_from_template (name, session->rtcp_src, templ);
809   gst_pad_set_active (result, TRUE);
810   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
811
812   return result;
813
814   /* ERRORS */
815 no_name:
816   {
817     g_warning ("rtpbin: invalid name given");
818     return NULL;
819   }
820 no_session:
821   {
822     g_warning ("rtpbin: session with id %d does not exist", sessid);
823     return NULL;
824   }
825 existed:
826   {
827     g_warning ("rtpbin: rtcp_src pad already requested for session %d", sessid);
828     return NULL;
829   }
830 pad_failed:
831   {
832     g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
833     return NULL;
834   }
835 }
836
837 /* 
838  */
839 static GstPad *
840 gst_rtp_bin_request_new_pad (GstElement * element,
841     GstPadTemplate * templ, const gchar * name)
842 {
843   GstRTPBin *rtpbin;
844   GstElementClass *klass;
845   GstPad *result;
846
847   g_return_val_if_fail (templ != NULL, NULL);
848   g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
849
850   rtpbin = GST_RTP_BIN (element);
851   klass = GST_ELEMENT_GET_CLASS (element);
852
853   /* figure out the template */
854   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
855     result = create_recv_rtp (rtpbin, templ, name);
856   } else if (templ == gst_element_class_get_pad_template (klass,
857           "recv_rtcp_sink_%d")) {
858     result = create_recv_rtcp (rtpbin, templ, name);
859   } else if (templ == gst_element_class_get_pad_template (klass,
860           "send_rtp_sink_%d")) {
861     result = create_send_rtp (rtpbin, templ, name);
862   } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
863     result = create_rtcp (rtpbin, templ, name);
864   } else
865     goto wrong_template;
866
867   return result;
868
869   /* ERRORS */
870 wrong_template:
871   {
872     g_warning ("rtpbin: this is not our template");
873     return NULL;
874   }
875 }
876
877 static void
878 gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
879 {
880 }