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