gst/rtpmanager/gstrtpbin.*: Provide a clock.
[platform/upstream/gst-plugins-good.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 GstClock *gst_rtp_bin_provide_clock (GstElement * element);
316 static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
317     GstStateChange transition);
318 static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
319     GstPadTemplate * templ, const gchar * name);
320 static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
321
322 /*static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 }; */
323
324 GST_BOILERPLATE (GstRTPBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
325
326 static void
327 gst_rtp_bin_base_init (gpointer klass)
328 {
329   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
330
331   /* sink pads */
332   gst_element_class_add_pad_template (element_class,
333       gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
334   gst_element_class_add_pad_template (element_class,
335       gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
336   gst_element_class_add_pad_template (element_class,
337       gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
338
339   /* src pads */
340   gst_element_class_add_pad_template (element_class,
341       gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
342   gst_element_class_add_pad_template (element_class,
343       gst_static_pad_template_get (&rtpbin_rtcp_src_template));
344   gst_element_class_add_pad_template (element_class,
345       gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
346
347   gst_element_class_set_details (element_class, &rtpbin_details);
348 }
349
350 static void
351 gst_rtp_bin_class_init (GstRTPBinClass * klass)
352 {
353   GObjectClass *gobject_class;
354   GstElementClass *gstelement_class;
355
356   gobject_class = (GObjectClass *) klass;
357   gstelement_class = (GstElementClass *) klass;
358
359   g_type_class_add_private (klass, sizeof (GstRTPBinPrivate));
360
361   gobject_class->finalize = gst_rtp_bin_finalize;
362   gobject_class->set_property = gst_rtp_bin_set_property;
363   gobject_class->get_property = gst_rtp_bin_get_property;
364
365   gstelement_class->provide_clock =
366       GST_DEBUG_FUNCPTR (gst_rtp_bin_provide_clock);
367   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
368   gstelement_class->request_new_pad =
369       GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
370   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
371
372   GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
373 }
374
375 static void
376 gst_rtp_bin_init (GstRTPBin * rtpbin, GstRTPBinClass * klass)
377 {
378   rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
379   rtpbin->provided_clock = gst_system_clock_obtain ();
380 }
381
382 static void
383 gst_rtp_bin_finalize (GObject * object)
384 {
385   GstRTPBin *rtpbin;
386
387   rtpbin = GST_RTP_BIN (object);
388
389   G_OBJECT_CLASS (parent_class)->finalize (object);
390 }
391
392 static void
393 gst_rtp_bin_set_property (GObject * object, guint prop_id,
394     const GValue * value, GParamSpec * pspec)
395 {
396   GstRTPBin *rtpbin;
397
398   rtpbin = GST_RTP_BIN (object);
399
400   switch (prop_id) {
401     default:
402       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
403       break;
404   }
405 }
406
407 static void
408 gst_rtp_bin_get_property (GObject * object, guint prop_id,
409     GValue * value, GParamSpec * pspec)
410 {
411   GstRTPBin *rtpbin;
412
413   rtpbin = GST_RTP_BIN (object);
414
415   switch (prop_id) {
416     default:
417       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
418       break;
419   }
420 }
421
422 static GstClock *
423 gst_rtp_bin_provide_clock (GstElement * element)
424 {
425   GstRTPBin *rtpbin;
426
427   rtpbin = GST_RTP_BIN (element);
428
429   return GST_CLOCK_CAST (gst_object_ref (rtpbin->provided_clock));
430 }
431
432 static GstStateChangeReturn
433 gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
434 {
435   GstStateChangeReturn res;
436   GstRTPBin *rtpbin;
437
438   rtpbin = GST_RTP_BIN (element);
439
440   switch (transition) {
441     case GST_STATE_CHANGE_NULL_TO_READY:
442       break;
443     case GST_STATE_CHANGE_READY_TO_PAUSED:
444       break;
445     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
446       break;
447     default:
448       break;
449   }
450
451   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
452
453   switch (transition) {
454     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
455       break;
456     case GST_STATE_CHANGE_PAUSED_TO_READY:
457       break;
458     case GST_STATE_CHANGE_READY_TO_NULL:
459       break;
460     default:
461       break;
462   }
463   return res;
464 }
465
466 /* a new pad (SSRC) was created in @session */
467 static void
468 new_payload_found (GstElement * element, guint pt, GstPad * pad,
469     GstRTPBinStream * stream)
470 {
471   GstRTPBin *rtpbin;
472   GstElementClass *klass;
473   GstPadTemplate *templ;
474   gchar *padname;
475   GstPad *gpad;
476
477   rtpbin = stream->bin;
478
479   GST_DEBUG ("new payload pad %d", pt);
480
481   /* ghost the pad to the parent */
482   klass = GST_ELEMENT_GET_CLASS (rtpbin);
483   templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
484   padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
485       stream->session->id, stream->ssrc, pt);
486   gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
487   g_free (padname);
488
489   gst_pad_set_active (gpad, TRUE);
490   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
491 }
492
493 /* a new pad (SSRC) was created in @session */
494 static void
495 new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
496     GstRTPBinSession * session)
497 {
498   GstRTPBinStream *stream;
499   GstPad *sinkpad;
500
501   GST_DEBUG_OBJECT (session->bin, "new SSRC pad %08x", ssrc);
502
503   /* create new stream */
504   stream = create_stream (session, ssrc);
505   if (!stream)
506     goto no_stream;
507
508   /* get pad and link */
509   GST_DEBUG_OBJECT (session->bin, "linking jitterbuffer");
510   sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
511   gst_pad_link (pad, sinkpad);
512   gst_object_unref (sinkpad);
513
514   /* connect to the new-pad signal of the payload demuxer */
515   stream->demux_newpad_sig = g_signal_connect (stream->demux,
516       "new-payload-type", (GCallback) new_payload_found, stream);
517
518   return;
519
520   /* ERRORS */
521 no_stream:
522   {
523     GST_DEBUG ("could not create stream");
524     return;
525   }
526 }
527
528 /* Create a pad for receiving RTP for the session in @name
529  */
530 static GstPad *
531 create_recv_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
532 {
533   GstPad *result, *sinkdpad;
534   guint sessid;
535   GstRTPBinSession *session;
536   GstPadLinkReturn lres;
537
538   /* first get the session number */
539   if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
540     goto no_name;
541
542   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
543
544   /* get or create session */
545   session = find_session_by_id (rtpbin, sessid);
546   if (!session) {
547     GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
548     /* create session now */
549     session = create_session (rtpbin, sessid);
550     if (session == NULL)
551       goto create_error;
552   }
553   /* check if pad was requested */
554   if (session->recv_rtp_sink != NULL)
555     goto existed;
556
557   GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
558   /* get recv_rtp pad and store */
559   session->recv_rtp_sink =
560       gst_element_get_request_pad (session->session, "recv_rtp_sink");
561   if (session->recv_rtp_sink == NULL)
562     goto pad_failed;
563
564   GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
565   /* get srcpad, link to SSRCDemux */
566   session->recv_rtp_src =
567       gst_element_get_static_pad (session->session, "recv_rtp_src");
568   if (session->recv_rtp_src == NULL)
569     goto pad_failed;
570
571   GST_DEBUG_OBJECT (rtpbin, "getting demuxer sink pad");
572   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
573   lres = gst_pad_link (session->recv_rtp_src, sinkdpad);
574   gst_object_unref (sinkdpad);
575   if (lres != GST_PAD_LINK_OK)
576     goto link_failed;
577
578   /* connect to the new-ssrc-pad signal of the demuxer */
579   session->demux_newpad_sig = g_signal_connect (session->demux,
580       "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
581
582   GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
583   result =
584       gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
585   gst_pad_set_active (result, TRUE);
586   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
587
588   return result;
589
590   /* ERRORS */
591 no_name:
592   {
593     g_warning ("rtpbin: invalid name given");
594     return NULL;
595   }
596 create_error:
597   {
598     /* create_session already warned */
599     return NULL;
600   }
601 existed:
602   {
603     g_warning ("rtpbin: recv_rtp pad already requested for session %d", sessid);
604     return NULL;
605   }
606 pad_failed:
607   {
608     g_warning ("rtpbin: failed to get session pad");
609     return NULL;
610   }
611 link_failed:
612   {
613     g_warning ("rtpbin: failed to link pads");
614     return NULL;
615   }
616 }
617
618 /* Create a pad for receiving RTCP for the session in @name
619  */
620 static GstPad *
621 create_recv_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ,
622     const gchar * name)
623 {
624   GstPad *result;
625   guint sessid;
626   GstRTPBinSession *session;
627
628 #if 0
629   GstPad *sinkdpad;
630   GstPadLinkReturn lres;
631 #endif
632
633   /* first get the session number */
634   if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
635     goto no_name;
636
637   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
638
639   /* get the session, it must exist or we error */
640   session = find_session_by_id (rtpbin, sessid);
641   if (!session)
642     goto no_session;
643
644   /* check if pad was requested */
645   if (session->recv_rtcp_sink != NULL)
646     goto existed;
647
648   GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
649
650   /* get recv_rtp pad and store */
651   session->recv_rtcp_sink =
652       gst_element_get_request_pad (session->session, "recv_rtcp_sink");
653   if (session->recv_rtcp_sink == NULL)
654     goto pad_failed;
655
656 #if 0
657   /* get srcpad, link to SSRCDemux */
658   GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
659   session->recv_rtcp_src =
660       gst_element_get_static_pad (session->session, "sync_src");
661   if (session->recv_rtcp_src == NULL)
662     goto pad_failed;
663
664   GST_DEBUG_OBJECT (rtpbin, "linking sync to demux");
665   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
666   lres = gst_pad_link (session->recv_rtcp_src, sinkdpad);
667   gst_object_unref (sinkdpad);
668   if (lres != GST_PAD_LINK_OK)
669     goto link_failed;
670 #endif
671
672   result =
673       gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
674   gst_pad_set_active (result, TRUE);
675   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
676
677   return result;
678
679   /* ERRORS */
680 no_name:
681   {
682     g_warning ("rtpbin: invalid name given");
683     return NULL;
684   }
685 no_session:
686   {
687     g_warning ("rtpbin: no session with id %d", sessid);
688     return NULL;
689   }
690 existed:
691   {
692     g_warning ("rtpbin: recv_rtcp pad already requested for session %d",
693         sessid);
694     return NULL;
695   }
696 pad_failed:
697   {
698     g_warning ("rtpbin: failed to get session pad");
699     return NULL;
700   }
701 #if 0
702 link_failed:
703   {
704     g_warning ("rtpbin: failed to link pads");
705     return NULL;
706   }
707 #endif
708 }
709
710 /* Create a pad for sending RTP for the session in @name
711  */
712 static GstPad *
713 create_send_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
714 {
715   GstPad *result, *srcpad, *srcghost;
716   gchar *gname;
717   guint sessid;
718   GstRTPBinSession *session;
719   GstElementClass *klass;
720
721   /* first get the session number */
722   if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
723     goto no_name;
724
725   /* get or create session */
726   session = find_session_by_id (rtpbin, sessid);
727   if (!session) {
728     /* create session now */
729     session = create_session (rtpbin, sessid);
730     if (session == NULL)
731       goto create_error;
732   }
733
734   /* check if pad was requested */
735   if (session->send_rtp_sink != NULL)
736     goto existed;
737
738   /* get recv_rtp pad and store */
739   session->send_rtp_sink =
740       gst_element_get_request_pad (session->session, "send_rtp_sink");
741   if (session->send_rtp_sink == NULL)
742     goto pad_failed;
743
744   result =
745       gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
746   gst_pad_set_active (result, TRUE);
747   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
748
749   /* get srcpad */
750   srcpad = gst_element_get_pad (session->session, "send_rtp_src");
751   if (srcpad == NULL)
752     goto no_srcpad;
753
754   /* ghost the new source pad */
755   klass = GST_ELEMENT_GET_CLASS (rtpbin);
756   gname = g_strdup_printf ("send_rtp_src_%d", sessid);
757   templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
758   srcghost =
759       gst_ghost_pad_new_from_template (gname, session->send_rtp_sink, templ);
760   gst_pad_set_active (srcghost, TRUE);
761   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
762   g_free (gname);
763
764   return result;
765
766   /* ERRORS */
767 no_name:
768   {
769     g_warning ("rtpbin: invalid name given");
770     return NULL;
771   }
772 create_error:
773   {
774     /* create_session already warned */
775     return NULL;
776   }
777 existed:
778   {
779     g_warning ("rtpbin: send_rtp pad already requested for session %d", sessid);
780     return NULL;
781   }
782 pad_failed:
783   {
784     g_warning ("rtpbin: failed to get session pad for session %d", sessid);
785     return NULL;
786   }
787 no_srcpad:
788   {
789     g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
790     return NULL;
791   }
792 }
793
794 /* Create a pad for sending RTCP for the session in @name
795  */
796 static GstPad *
797 create_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
798 {
799   GstPad *result;
800   guint sessid;
801   GstRTPBinSession *session;
802
803   /* first get the session number */
804   if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
805     goto no_name;
806
807   /* get or create session */
808   session = find_session_by_id (rtpbin, sessid);
809   if (!session)
810     goto no_session;
811
812   /* check if pad was requested */
813   if (session->rtcp_src != NULL)
814     goto existed;
815
816   /* get rtcp_src pad and store */
817   session->rtcp_src =
818       gst_element_get_request_pad (session->session, "rtcp_src");
819   if (session->rtcp_src == NULL)
820     goto pad_failed;
821
822   result = gst_ghost_pad_new_from_template (name, session->rtcp_src, templ);
823   gst_pad_set_active (result, TRUE);
824   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
825
826   return result;
827
828   /* ERRORS */
829 no_name:
830   {
831     g_warning ("rtpbin: invalid name given");
832     return NULL;
833   }
834 no_session:
835   {
836     g_warning ("rtpbin: session with id %d does not exist", sessid);
837     return NULL;
838   }
839 existed:
840   {
841     g_warning ("rtpbin: rtcp_src pad already requested for session %d", sessid);
842     return NULL;
843   }
844 pad_failed:
845   {
846     g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
847     return NULL;
848   }
849 }
850
851 /* 
852  */
853 static GstPad *
854 gst_rtp_bin_request_new_pad (GstElement * element,
855     GstPadTemplate * templ, const gchar * name)
856 {
857   GstRTPBin *rtpbin;
858   GstElementClass *klass;
859   GstPad *result;
860
861   g_return_val_if_fail (templ != NULL, NULL);
862   g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
863
864   rtpbin = GST_RTP_BIN (element);
865   klass = GST_ELEMENT_GET_CLASS (element);
866
867   /* figure out the template */
868   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
869     result = create_recv_rtp (rtpbin, templ, name);
870   } else if (templ == gst_element_class_get_pad_template (klass,
871           "recv_rtcp_sink_%d")) {
872     result = create_recv_rtcp (rtpbin, templ, name);
873   } else if (templ == gst_element_class_get_pad_template (klass,
874           "send_rtp_sink_%d")) {
875     result = create_send_rtp (rtpbin, templ, name);
876   } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
877     result = create_rtcp (rtpbin, templ, name);
878   } else
879     goto wrong_template;
880
881   return result;
882
883   /* ERRORS */
884 wrong_template:
885   {
886     g_warning ("rtpbin: this is not our template");
887     return NULL;
888   }
889 }
890
891 static void
892 gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
893 {
894 }