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