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