configure.ac: Disable rtpmanager for now because it depends on CVS -base.
[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-marshal.h"
45 #include "gstrtpbin.h"
46
47 GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
48 #define GST_CAT_DEFAULT gst_rtp_bin_debug
49
50
51 /* elementfactory information */
52 static const GstElementDetails rtpbin_details = GST_ELEMENT_DETAILS ("RTP Bin",
53     "Filter/Editor/Video",
54     "Implement an RTP bin",
55     "Wim Taymans <wim@fluendo.com>");
56
57 /* sink pads */
58 static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
59 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
60     GST_PAD_SINK,
61     GST_PAD_REQUEST,
62     GST_STATIC_CAPS ("application/x-rtp")
63     );
64
65 static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
66 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
67     GST_PAD_SINK,
68     GST_PAD_REQUEST,
69     GST_STATIC_CAPS ("application/x-rtcp")
70     );
71
72 static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
73 GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%d",
74     GST_PAD_SINK,
75     GST_PAD_REQUEST,
76     GST_STATIC_CAPS ("application/x-rtp")
77     );
78
79 /* src pads */
80 static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
81 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
82     GST_PAD_SRC,
83     GST_PAD_SOMETIMES,
84     GST_STATIC_CAPS ("application/x-rtp")
85     );
86
87 static GstStaticPadTemplate rtpbin_rtcp_src_template =
88 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
89     GST_PAD_SRC,
90     GST_PAD_REQUEST,
91     GST_STATIC_CAPS ("application/x-rtcp")
92     );
93
94 static GstStaticPadTemplate rtpbin_send_rtp_src_template =
95 GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%d",
96     GST_PAD_SRC,
97     GST_PAD_SOMETIMES,
98     GST_STATIC_CAPS ("application/x-rtp")
99     );
100
101 #define GST_RTP_BIN_GET_PRIVATE(obj)  \
102    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRTPBinPrivate))
103
104 #define GST_RTP_BIN_LOCK(bin)   g_mutex_lock ((bin)->priv->bin_lock)
105 #define GST_RTP_BIN_UNLOCK(bin) g_mutex_unlock ((bin)->priv->bin_lock)
106
107 struct _GstRTPBinPrivate
108 {
109   GMutex *bin_lock;
110 };
111
112 /* signals and args */
113 enum
114 {
115   SIGNAL_REQUEST_PT_MAP,
116   LAST_SIGNAL
117 };
118
119 enum
120 {
121   PROP_0
122 };
123
124 /* helper objects */
125 typedef struct _GstRTPBinSession GstRTPBinSession;
126 typedef struct _GstRTPBinStream GstRTPBinStream;
127 typedef struct _GstRTPBinClient GstRTPBinClient;
128
129 static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 };
130
131 static GstCaps *pt_map_requested (GstElement * element, guint pt,
132     GstRTPBinSession * session);
133
134 /* Manages the RTP stream for one SSRC.
135  *
136  * We pipe the stream (comming from the SSRC demuxer) into a jitterbuffer.
137  * If we see an SDES RTCP packet that links multiple SSRCs together based on a
138  * common CNAME, we create a GstRTPBinClient structure to group the SSRCs
139  * together (see below).
140  */
141 struct _GstRTPBinStream
142 {
143   /* the SSRC of this stream */
144   guint32 ssrc;
145   /* parent bin */
146   GstRTPBin *bin;
147   /* the session this SSRC belongs to */
148   GstRTPBinSession *session;
149   /* the jitterbuffer of the SSRC */
150   GstElement *buffer;
151   /* the PT demuxer of the SSRC */
152   GstElement *demux;
153   gulong demux_newpad_sig;
154   gulong demux_ptreq_sig;
155 };
156
157 #define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock ((sess)->lock)
158 #define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock ((sess)->lock)
159
160 /* Manages the receiving end of the packets.
161  *
162  * There is one such structure for each RTP session (audio/video/...).
163  * We get the RTP/RTCP packets and stuff them into the session manager. From
164  * there they are pushed into an SSRC demuxer that splits the stream based on
165  * SSRC. Each of the SSRC streams go into their own jitterbuffer (managed with
166  * the GstRTPBinStream above).
167  */
168 struct _GstRTPBinSession
169 {
170   /* session id */
171   gint id;
172   /* the parent bin */
173   GstRTPBin *bin;
174   /* the session element */
175   GstElement *session;
176   /* the SSRC demuxer */
177   GstElement *demux;
178   gulong demux_newpad_sig;
179
180   GMutex *lock;
181
182   /* list of GstRTPBinStream */
183   GSList *streams;
184
185   /* mapping of payload type to caps */
186   GHashTable *ptmap;
187
188   /* the pads of the session */
189   GstPad *recv_rtp_sink;
190   GstPad *recv_rtp_src;
191   GstPad *recv_rtcp_sink;
192   GstPad *recv_rtcp_src;
193   GstPad *send_rtp_sink;
194   GstPad *send_rtp_src;
195   GstPad *rtcp_src;
196 };
197
198 /* find a session with the given id. Must be called with RTP_BIN_LOCK */
199 static GstRTPBinSession *
200 find_session_by_id (GstRTPBin * rtpbin, gint id)
201 {
202   GSList *walk;
203
204   for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
205     GstRTPBinSession *sess = (GstRTPBinSession *) walk->data;
206
207     if (sess->id == id)
208       return sess;
209   }
210   return NULL;
211 }
212
213 /* create a session with the given id.  Must be called with RTP_BIN_LOCK */
214 static GstRTPBinSession *
215 create_session (GstRTPBin * rtpbin, gint id)
216 {
217   GstRTPBinSession *sess;
218   GstElement *session, *demux;
219
220   if (!(session = gst_element_factory_make ("rtpsession", NULL)))
221     goto no_session;
222
223   if (!(demux = gst_element_factory_make ("rtpssrcdemux", NULL)))
224     goto no_demux;
225
226   sess = g_new0 (GstRTPBinSession, 1);
227   sess->lock = g_mutex_new ();
228   sess->id = id;
229   sess->bin = rtpbin;
230   sess->session = session;
231   sess->demux = demux;
232   sess->ptmap = g_hash_table_new (NULL, NULL);
233   rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
234
235   /* provide clock_rate to the session manager when needed */
236   g_signal_connect (session, "request-pt-map",
237       (GCallback) pt_map_requested, sess);
238
239   gst_bin_add (GST_BIN_CAST (rtpbin), session);
240   gst_element_set_state (session, GST_STATE_PLAYING);
241   gst_bin_add (GST_BIN_CAST (rtpbin), demux);
242   gst_element_set_state (demux, GST_STATE_PLAYING);
243
244   return sess;
245
246   /* ERRORS */
247 no_session:
248   {
249     g_warning ("rtpbin: could not create rtpsession element");
250     return NULL;
251   }
252 no_demux:
253   {
254     gst_object_unref (session);
255     g_warning ("rtpbin: could not create rtpssrcdemux element");
256     return NULL;
257   }
258 }
259
260 #if 0
261 static GstRTPBinStream *
262 find_stream_by_ssrc (GstRTPBinSession * session, guint32 ssrc)
263 {
264   GSList *walk;
265
266   for (walk = session->streams; walk; walk = g_slist_next (walk)) {
267     GstRTPBinStream *stream = (GstRTPBinStream *) walk->data;
268
269     if (stream->ssrc == ssrc)
270       return stream;
271   }
272   return NULL;
273 }
274 #endif
275
276 /* get the payload type caps for the specific payload @pt in @session */
277 static GstCaps *
278 get_pt_map (GstRTPBinSession * session, guint pt)
279 {
280   GstCaps *caps = NULL;
281   GstRTPBin *bin;
282   GValue ret = { 0 };
283   GValue args[3] = { {0}, {0}, {0} };
284
285   GST_DEBUG ("searching pt %d in cache", pt);
286
287   GST_RTP_SESSION_LOCK (session);
288
289   /* first look in the cache */
290   caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
291   if (caps)
292     goto done;
293
294   bin = session->bin;
295
296   GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
297
298   /* not in cache, send signal to request caps */
299   g_value_init (&args[0], GST_TYPE_ELEMENT);
300   g_value_set_object (&args[0], bin);
301   g_value_init (&args[1], G_TYPE_UINT);
302   g_value_set_uint (&args[1], session->id);
303   g_value_init (&args[2], G_TYPE_UINT);
304   g_value_set_uint (&args[2], pt);
305
306   g_value_init (&ret, GST_TYPE_CAPS);
307   g_value_set_boxed (&ret, NULL);
308
309   g_signal_emitv (args, gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
310
311   caps = (GstCaps *) g_value_get_boxed (&ret);
312   if (!caps)
313     goto no_caps;
314
315   GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
316
317   /* store in cache */
318   g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt), caps);
319
320 done:
321   GST_RTP_SESSION_UNLOCK (session);
322
323   return caps;
324
325   /* ERRORS */
326 no_caps:
327   {
328     GST_RTP_SESSION_UNLOCK (session);
329     GST_DEBUG ("no pt map could be obtained");
330     return NULL;
331   }
332 }
333
334 /* create a new stream with @ssrc in @session. Must be called with
335  * RTP_SESSION_LOCK. */
336 static GstRTPBinStream *
337 create_stream (GstRTPBinSession * session, guint32 ssrc)
338 {
339   GstElement *buffer, *demux;
340   GstRTPBinStream *stream;
341
342   if (!(buffer = gst_element_factory_make ("rtpjitterbuffer", NULL)))
343     goto no_jitterbuffer;
344
345   if (!(demux = gst_element_factory_make ("rtpptdemux", NULL)))
346     goto no_demux;
347
348   stream = g_new0 (GstRTPBinStream, 1);
349   stream->ssrc = ssrc;
350   stream->bin = session->bin;
351   stream->session = session;
352   stream->buffer = buffer;
353   stream->demux = demux;
354   session->streams = g_slist_prepend (session->streams, stream);
355
356   /* provide clock_rate to the jitterbuffer when needed */
357   g_signal_connect (buffer, "request-pt-map",
358       (GCallback) pt_map_requested, session);
359
360   gst_bin_add (GST_BIN_CAST (session->bin), buffer);
361   gst_element_set_state (buffer, GST_STATE_PLAYING);
362   gst_bin_add (GST_BIN_CAST (session->bin), demux);
363   gst_element_set_state (demux, GST_STATE_PLAYING);
364
365   /* link stuff */
366   gst_element_link (buffer, demux);
367
368   return stream;
369
370   /* ERRORS */
371 no_jitterbuffer:
372   {
373     g_warning ("rtpbin: could not create rtpjitterbuffer element");
374     return NULL;
375   }
376 no_demux:
377   {
378     gst_object_unref (buffer);
379     g_warning ("rtpbin: could not create rtpptdemux element");
380     return NULL;
381   }
382 }
383
384 /* Manages the RTP streams that come from one client and should therefore be
385  * synchronized.
386  */
387 struct _GstRTPBinClient
388 {
389   /* the common CNAME for the streams */
390   gchar *cname;
391   /* the streams */
392   GSList *streams;
393 };
394
395 /* GObject vmethods */
396 static void gst_rtp_bin_finalize (GObject * object);
397 static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
398     const GValue * value, GParamSpec * pspec);
399 static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
400     GValue * value, GParamSpec * pspec);
401
402 /* GstElement vmethods */
403 static GstClock *gst_rtp_bin_provide_clock (GstElement * element);
404 static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
405     GstStateChange transition);
406 static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
407     GstPadTemplate * templ, const gchar * name);
408 static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
409
410 GST_BOILERPLATE (GstRTPBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
411
412 static void
413 gst_rtp_bin_base_init (gpointer klass)
414 {
415   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
416
417   /* sink pads */
418   gst_element_class_add_pad_template (element_class,
419       gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
420   gst_element_class_add_pad_template (element_class,
421       gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
422   gst_element_class_add_pad_template (element_class,
423       gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
424
425   /* src pads */
426   gst_element_class_add_pad_template (element_class,
427       gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
428   gst_element_class_add_pad_template (element_class,
429       gst_static_pad_template_get (&rtpbin_rtcp_src_template));
430   gst_element_class_add_pad_template (element_class,
431       gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
432
433   gst_element_class_set_details (element_class, &rtpbin_details);
434 }
435
436 static void
437 gst_rtp_bin_class_init (GstRTPBinClass * klass)
438 {
439   GObjectClass *gobject_class;
440   GstElementClass *gstelement_class;
441
442   gobject_class = (GObjectClass *) klass;
443   gstelement_class = (GstElementClass *) klass;
444
445   g_type_class_add_private (klass, sizeof (GstRTPBinPrivate));
446
447   gobject_class->finalize = gst_rtp_bin_finalize;
448   gobject_class->set_property = gst_rtp_bin_set_property;
449   gobject_class->get_property = gst_rtp_bin_get_property;
450
451   /**
452    * GstRTPBin::request-pt-map:
453    * @rtpbin: the object which received the signal
454    * @session: the session
455    * @pt: the pt
456    *
457    * Request the payload type as #GstCaps for @pt in @session.
458    */
459   gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP] =
460       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
461       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPBinClass, request_pt_map),
462       NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
463       G_TYPE_UINT, G_TYPE_UINT);
464
465   gstelement_class->provide_clock =
466       GST_DEBUG_FUNCPTR (gst_rtp_bin_provide_clock);
467   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
468   gstelement_class->request_new_pad =
469       GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
470   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
471
472   GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
473 }
474
475 static void
476 gst_rtp_bin_init (GstRTPBin * rtpbin, GstRTPBinClass * klass)
477 {
478   rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
479   rtpbin->priv->bin_lock = g_mutex_new ();
480   rtpbin->provided_clock = gst_system_clock_obtain ();
481 }
482
483 static void
484 gst_rtp_bin_finalize (GObject * object)
485 {
486   GstRTPBin *rtpbin;
487
488   rtpbin = GST_RTP_BIN (object);
489
490   g_mutex_free (rtpbin->priv->bin_lock);
491
492   G_OBJECT_CLASS (parent_class)->finalize (object);
493 }
494
495 static void
496 gst_rtp_bin_set_property (GObject * object, guint prop_id,
497     const GValue * value, GParamSpec * pspec)
498 {
499   GstRTPBin *rtpbin;
500
501   rtpbin = GST_RTP_BIN (object);
502
503   switch (prop_id) {
504     default:
505       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
506       break;
507   }
508 }
509
510 static void
511 gst_rtp_bin_get_property (GObject * object, guint prop_id,
512     GValue * value, GParamSpec * pspec)
513 {
514   GstRTPBin *rtpbin;
515
516   rtpbin = GST_RTP_BIN (object);
517
518   switch (prop_id) {
519     default:
520       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
521       break;
522   }
523 }
524
525 static GstClock *
526 gst_rtp_bin_provide_clock (GstElement * element)
527 {
528   GstRTPBin *rtpbin;
529
530   rtpbin = GST_RTP_BIN (element);
531
532   return GST_CLOCK_CAST (gst_object_ref (rtpbin->provided_clock));
533 }
534
535 static GstStateChangeReturn
536 gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
537 {
538   GstStateChangeReturn res;
539   GstRTPBin *rtpbin;
540
541   rtpbin = GST_RTP_BIN (element);
542
543   switch (transition) {
544     case GST_STATE_CHANGE_NULL_TO_READY:
545       break;
546     case GST_STATE_CHANGE_READY_TO_PAUSED:
547       break;
548     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
549       break;
550     default:
551       break;
552   }
553
554   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
555
556   switch (transition) {
557     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
558       break;
559     case GST_STATE_CHANGE_PAUSED_TO_READY:
560       break;
561     case GST_STATE_CHANGE_READY_TO_NULL:
562       break;
563     default:
564       break;
565   }
566   return res;
567 }
568
569 /* a new pad (SSRC) was created in @session */
570 static void
571 new_payload_found (GstElement * element, guint pt, GstPad * pad,
572     GstRTPBinStream * stream)
573 {
574   GstRTPBin *rtpbin;
575   GstElementClass *klass;
576   GstPadTemplate *templ;
577   gchar *padname;
578   GstPad *gpad;
579
580   rtpbin = stream->bin;
581
582   GST_DEBUG ("new payload pad %d", pt);
583
584   /* ghost the pad to the parent */
585   klass = GST_ELEMENT_GET_CLASS (rtpbin);
586   templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
587   padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
588       stream->session->id, stream->ssrc, pt);
589   gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
590   g_free (padname);
591
592   gst_pad_set_active (gpad, TRUE);
593   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
594 }
595
596 static GstCaps *
597 pt_map_requested (GstElement * element, guint pt, GstRTPBinSession * session)
598 {
599   GstRTPBin *rtpbin;
600   GstCaps *caps;
601
602   rtpbin = session->bin;
603
604   GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
605       session->id);
606
607   caps = get_pt_map (session, pt);
608   if (!caps)
609     goto no_caps;
610
611   return caps;
612
613   /* ERRORS */
614 no_caps:
615   {
616     GST_DEBUG_OBJECT (rtpbin, "could not get caps");
617     return NULL;
618   }
619 }
620
621 /* a new pad (SSRC) was created in @session */
622 static void
623 new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
624     GstRTPBinSession * session)
625 {
626   GstRTPBinStream *stream;
627   GstPad *sinkpad;
628
629   GST_DEBUG_OBJECT (session->bin, "new SSRC pad %08x", ssrc);
630
631   GST_RTP_SESSION_LOCK (session);
632
633   /* create new stream */
634   stream = create_stream (session, ssrc);
635   if (!stream)
636     goto no_stream;
637
638   /* get pad and link */
639   GST_DEBUG_OBJECT (session->bin, "linking jitterbuffer");
640   sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
641   gst_pad_link (pad, sinkpad);
642   gst_object_unref (sinkpad);
643
644   /* connect to the new-pad signal of the payload demuxer, this will expose the
645    * new pad by ghosting it. */
646   stream->demux_newpad_sig = g_signal_connect (stream->demux,
647       "new-payload-type", (GCallback) new_payload_found, stream);
648   /* connect to the request-pt-map signal. This signal will be emited by the
649    * demuxer so that it can apply a proper caps on the buffers for the
650    * depayloaders. */
651   stream->demux_ptreq_sig = g_signal_connect (stream->demux,
652       "request-pt-map", (GCallback) pt_map_requested, session);
653
654   GST_RTP_SESSION_UNLOCK (session);
655
656   return;
657
658   /* ERRORS */
659 no_stream:
660   {
661     GST_RTP_SESSION_UNLOCK (session);
662     GST_DEBUG ("could not create stream");
663     return;
664   }
665 }
666
667 /* Create a pad for receiving RTP for the session in @name. Must be called with
668  * RTP_BIN_LOCK.
669  */
670 static GstPad *
671 create_recv_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
672 {
673   GstPad *result, *sinkdpad;
674   guint sessid;
675   GstRTPBinSession *session;
676   GstPadLinkReturn lres;
677
678   /* first get the session number */
679   if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
680     goto no_name;
681
682   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
683
684   /* get or create session */
685   session = find_session_by_id (rtpbin, sessid);
686   if (!session) {
687     GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
688     /* create session now */
689     session = create_session (rtpbin, sessid);
690     if (session == NULL)
691       goto create_error;
692   }
693
694   /* check if pad was requested */
695   if (session->recv_rtp_sink != NULL)
696     goto existed;
697
698   GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
699   /* get recv_rtp pad and store */
700   session->recv_rtp_sink =
701       gst_element_get_request_pad (session->session, "recv_rtp_sink");
702   if (session->recv_rtp_sink == NULL)
703     goto pad_failed;
704
705   GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
706   /* get srcpad, link to SSRCDemux */
707   session->recv_rtp_src =
708       gst_element_get_static_pad (session->session, "recv_rtp_src");
709   if (session->recv_rtp_src == NULL)
710     goto pad_failed;
711
712   GST_DEBUG_OBJECT (rtpbin, "getting demuxer sink pad");
713   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
714   lres = gst_pad_link (session->recv_rtp_src, sinkdpad);
715   gst_object_unref (sinkdpad);
716   if (lres != GST_PAD_LINK_OK)
717     goto link_failed;
718
719   /* connect to the new-ssrc-pad signal of the SSRC demuxer */
720   session->demux_newpad_sig = g_signal_connect (session->demux,
721       "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
722
723   GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
724   result =
725       gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
726   gst_pad_set_active (result, TRUE);
727   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
728
729   return result;
730
731   /* ERRORS */
732 no_name:
733   {
734     g_warning ("rtpbin: invalid name given");
735     return NULL;
736   }
737 create_error:
738   {
739     /* create_session already warned */
740     return NULL;
741   }
742 existed:
743   {
744     g_warning ("rtpbin: recv_rtp pad already requested for session %d", sessid);
745     return NULL;
746   }
747 pad_failed:
748   {
749     g_warning ("rtpbin: failed to get session pad");
750     return NULL;
751   }
752 link_failed:
753   {
754     g_warning ("rtpbin: failed to link pads");
755     return NULL;
756   }
757 }
758
759 /* Create a pad for receiving RTCP for the session in @name. Must be called with
760  * RTP_BIN_LOCK.
761  */
762 static GstPad *
763 create_recv_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ,
764     const gchar * name)
765 {
766   GstPad *result;
767   guint sessid;
768   GstRTPBinSession *session;
769
770 #if 0
771   GstPad *sinkdpad;
772   GstPadLinkReturn lres;
773 #endif
774
775   /* first get the session number */
776   if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
777     goto no_name;
778
779   GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
780
781   /* get the session, it must exist or we error */
782   session = find_session_by_id (rtpbin, sessid);
783   if (!session)
784     goto no_session;
785
786   /* check if pad was requested */
787   if (session->recv_rtcp_sink != NULL)
788     goto existed;
789
790   GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
791
792   /* get recv_rtp pad and store */
793   session->recv_rtcp_sink =
794       gst_element_get_request_pad (session->session, "recv_rtcp_sink");
795   if (session->recv_rtcp_sink == NULL)
796     goto pad_failed;
797
798 #if 0
799   /* get srcpad, link to SSRCDemux */
800   GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
801   session->recv_rtcp_src =
802       gst_element_get_static_pad (session->session, "sync_src");
803   if (session->recv_rtcp_src == NULL)
804     goto pad_failed;
805
806   GST_DEBUG_OBJECT (rtpbin, "linking sync to demux");
807   sinkdpad = gst_element_get_static_pad (session->demux, "sink");
808   lres = gst_pad_link (session->recv_rtcp_src, sinkdpad);
809   gst_object_unref (sinkdpad);
810   if (lres != GST_PAD_LINK_OK)
811     goto link_failed;
812 #endif
813
814   result =
815       gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
816   gst_pad_set_active (result, TRUE);
817   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
818
819   return result;
820
821   /* ERRORS */
822 no_name:
823   {
824     g_warning ("rtpbin: invalid name given");
825     return NULL;
826   }
827 no_session:
828   {
829     g_warning ("rtpbin: no session with id %d", sessid);
830     return NULL;
831   }
832 existed:
833   {
834     g_warning ("rtpbin: recv_rtcp pad already requested for session %d",
835         sessid);
836     return NULL;
837   }
838 pad_failed:
839   {
840     g_warning ("rtpbin: failed to get session pad");
841     return NULL;
842   }
843 #if 0
844 link_failed:
845   {
846     g_warning ("rtpbin: failed to link pads");
847     return NULL;
848   }
849 #endif
850 }
851
852 /* Create a pad for sending RTP for the session in @name. Must be called with
853  * RTP_BIN_LOCK.
854  */
855 static GstPad *
856 create_send_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
857 {
858   GstPad *result, *srcpad, *srcghost;
859   gchar *gname;
860   guint sessid;
861   GstRTPBinSession *session;
862   GstElementClass *klass;
863
864   /* first get the session number */
865   if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
866     goto no_name;
867
868   /* get or create session */
869   session = find_session_by_id (rtpbin, sessid);
870   if (!session) {
871     /* create session now */
872     session = create_session (rtpbin, sessid);
873     if (session == NULL)
874       goto create_error;
875   }
876
877   /* check if pad was requested */
878   if (session->send_rtp_sink != NULL)
879     goto existed;
880
881   /* get recv_rtp pad and store */
882   session->send_rtp_sink =
883       gst_element_get_request_pad (session->session, "send_rtp_sink");
884   if (session->send_rtp_sink == NULL)
885     goto pad_failed;
886
887   result =
888       gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
889   gst_pad_set_active (result, TRUE);
890   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
891
892   /* get srcpad */
893   srcpad = gst_element_get_pad (session->session, "send_rtp_src");
894   if (srcpad == NULL)
895     goto no_srcpad;
896
897   /* ghost the new source pad */
898   klass = GST_ELEMENT_GET_CLASS (rtpbin);
899   gname = g_strdup_printf ("send_rtp_src_%d", sessid);
900   templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
901   srcghost =
902       gst_ghost_pad_new_from_template (gname, session->send_rtp_sink, templ);
903   gst_pad_set_active (srcghost, TRUE);
904   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
905   g_free (gname);
906
907   return result;
908
909   /* ERRORS */
910 no_name:
911   {
912     g_warning ("rtpbin: invalid name given");
913     return NULL;
914   }
915 create_error:
916   {
917     /* create_session already warned */
918     return NULL;
919   }
920 existed:
921   {
922     g_warning ("rtpbin: send_rtp pad already requested for session %d", sessid);
923     return NULL;
924   }
925 pad_failed:
926   {
927     g_warning ("rtpbin: failed to get session pad for session %d", sessid);
928     return NULL;
929   }
930 no_srcpad:
931   {
932     g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
933     return NULL;
934   }
935 }
936
937 /* Create a pad for sending RTCP for the session in @name. Must be called with
938  * RTP_BIN_LOCK.
939  */
940 static GstPad *
941 create_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
942 {
943   GstPad *result;
944   guint sessid;
945   GstRTPBinSession *session;
946
947   /* first get the session number */
948   if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
949     goto no_name;
950
951   /* get or create session */
952   session = find_session_by_id (rtpbin, sessid);
953   if (!session)
954     goto no_session;
955
956   /* check if pad was requested */
957   if (session->rtcp_src != NULL)
958     goto existed;
959
960   /* get rtcp_src pad and store */
961   session->rtcp_src =
962       gst_element_get_request_pad (session->session, "rtcp_src");
963   if (session->rtcp_src == NULL)
964     goto pad_failed;
965
966   result = gst_ghost_pad_new_from_template (name, session->rtcp_src, templ);
967   gst_pad_set_active (result, TRUE);
968   gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
969
970   return result;
971
972   /* ERRORS */
973 no_name:
974   {
975     g_warning ("rtpbin: invalid name given");
976     return NULL;
977   }
978 no_session:
979   {
980     g_warning ("rtpbin: session with id %d does not exist", sessid);
981     return NULL;
982   }
983 existed:
984   {
985     g_warning ("rtpbin: rtcp_src pad already requested for session %d", sessid);
986     return NULL;
987   }
988 pad_failed:
989   {
990     g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
991     return NULL;
992   }
993 }
994
995 /* 
996  */
997 static GstPad *
998 gst_rtp_bin_request_new_pad (GstElement * element,
999     GstPadTemplate * templ, const gchar * name)
1000 {
1001   GstRTPBin *rtpbin;
1002   GstElementClass *klass;
1003   GstPad *result;
1004
1005   g_return_val_if_fail (templ != NULL, NULL);
1006   g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
1007
1008   rtpbin = GST_RTP_BIN (element);
1009   klass = GST_ELEMENT_GET_CLASS (element);
1010
1011   GST_RTP_BIN_LOCK (rtpbin);
1012
1013   /* figure out the template */
1014   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
1015     result = create_recv_rtp (rtpbin, templ, name);
1016   } else if (templ == gst_element_class_get_pad_template (klass,
1017           "recv_rtcp_sink_%d")) {
1018     result = create_recv_rtcp (rtpbin, templ, name);
1019   } else if (templ == gst_element_class_get_pad_template (klass,
1020           "send_rtp_sink_%d")) {
1021     result = create_send_rtp (rtpbin, templ, name);
1022   } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
1023     result = create_rtcp (rtpbin, templ, name);
1024   } else
1025     goto wrong_template;
1026
1027   GST_RTP_BIN_UNLOCK (rtpbin);
1028
1029   return result;
1030
1031   /* ERRORS */
1032 wrong_template:
1033   {
1034     GST_RTP_BIN_UNLOCK (rtpbin);
1035     g_warning ("rtpbin: this is not our template");
1036     return NULL;
1037   }
1038 }
1039
1040 static void
1041 gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
1042 {
1043 }