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