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