gst/rtpmanager/async_jitter_queue.c: Fix the case where the buffer underruns and...
[platform/upstream/gst-plugins-good.git] / gst / rtpmanager / gstrtpsession.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-rtpsession
22  * @short_description: an RTP session manager
23  * @see_also: rtpjitterbuffer, rtpbin
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
43 #include "gstrtpbin-marshal.h"
44 #include "gstrtpsession.h"
45 #include "rtpsession.h"
46
47 GST_DEBUG_CATEGORY_STATIC (gst_rtp_session_debug);
48 #define GST_CAT_DEFAULT gst_rtp_session_debug
49
50 /* elementfactory information */
51 static const GstElementDetails rtpsession_details =
52 GST_ELEMENT_DETAILS ("RTP Session",
53     "Filter/Editor/Video",
54     "Implement an RTP session",
55     "Wim Taymans <wim@fluendo.com>");
56
57 /* sink pads */
58 static GstStaticPadTemplate rtpsession_recv_rtp_sink_template =
59 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink",
60     GST_PAD_SINK,
61     GST_PAD_REQUEST,
62     GST_STATIC_CAPS ("application/x-rtp")
63     );
64
65 static GstStaticPadTemplate rtpsession_recv_rtcp_sink_template =
66 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink",
67     GST_PAD_SINK,
68     GST_PAD_REQUEST,
69     GST_STATIC_CAPS ("application/x-rtcp")
70     );
71
72 static GstStaticPadTemplate rtpsession_send_rtp_sink_template =
73 GST_STATIC_PAD_TEMPLATE ("send_rtp_sink",
74     GST_PAD_SINK,
75     GST_PAD_REQUEST,
76     GST_STATIC_CAPS ("application/x-rtp")
77     );
78
79 /* src pads */
80 static GstStaticPadTemplate rtpsession_recv_rtp_src_template =
81 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src",
82     GST_PAD_SRC,
83     GST_PAD_SOMETIMES,
84     GST_STATIC_CAPS ("application/x-rtp")
85     );
86
87 static GstStaticPadTemplate rtpsession_sync_src_template =
88 GST_STATIC_PAD_TEMPLATE ("sync_src",
89     GST_PAD_SRC,
90     GST_PAD_SOMETIMES,
91     GST_STATIC_CAPS ("application/x-rtcp")
92     );
93
94 static GstStaticPadTemplate rtpsession_send_rtp_src_template =
95 GST_STATIC_PAD_TEMPLATE ("send_rtp_src",
96     GST_PAD_SRC,
97     GST_PAD_SOMETIMES,
98     GST_STATIC_CAPS ("application/x-rtp")
99     );
100
101 static GstStaticPadTemplate rtpsession_send_rtcp_src_template =
102 GST_STATIC_PAD_TEMPLATE ("send_rtcp_src",
103     GST_PAD_SRC,
104     GST_PAD_REQUEST,
105     GST_STATIC_CAPS ("application/x-rtcp")
106     );
107
108 /* signals and args */
109 enum
110 {
111   SIGNAL_REQUEST_PT_MAP,
112   LAST_SIGNAL
113 };
114
115 enum
116 {
117   PROP_0
118 };
119
120 #define GST_RTP_SESSION_GET_PRIVATE(obj)  \
121            (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_SESSION, GstRTPSessionPrivate))
122
123 #define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock ((sess)->priv->lock)
124 #define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock ((sess)->priv->lock)
125
126 struct _GstRTPSessionPrivate
127 {
128   GMutex *lock;
129   RTPSession *session;
130   /* thread for sending out RTCP */
131   GstClockID id;
132   gboolean stop_thread;
133   GThread *thread;
134 };
135
136 /* callbacks to handle actions from the session manager */
137 static GstFlowReturn gst_rtp_session_process_rtp (RTPSession * sess,
138     RTPSource * src, GstBuffer * buffer, gpointer user_data);
139 static GstFlowReturn gst_rtp_session_send_rtp (RTPSession * sess,
140     RTPSource * src, GstBuffer * buffer, gpointer user_data);
141 static GstFlowReturn gst_rtp_session_send_rtcp (RTPSession * sess,
142     RTPSource * src, GstBuffer * buffer, gpointer user_data);
143 static gint gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
144     gpointer user_data);
145 static GstClockTime gst_rtp_session_get_time (RTPSession * sess,
146     gpointer user_data);
147 static void gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data);
148
149 static RTPSessionCallbacks callbacks = {
150   gst_rtp_session_process_rtp,
151   gst_rtp_session_send_rtp,
152   gst_rtp_session_send_rtcp,
153   gst_rtp_session_clock_rate,
154   gst_rtp_session_get_time,
155   gst_rtp_session_reconsider
156 };
157
158 /* GObject vmethods */
159 static void gst_rtp_session_finalize (GObject * object);
160 static void gst_rtp_session_set_property (GObject * object, guint prop_id,
161     const GValue * value, GParamSpec * pspec);
162 static void gst_rtp_session_get_property (GObject * object, guint prop_id,
163     GValue * value, GParamSpec * pspec);
164
165 /* GstElement vmethods */
166 static GstStateChangeReturn gst_rtp_session_change_state (GstElement * element,
167     GstStateChange transition);
168 static GstPad *gst_rtp_session_request_new_pad (GstElement * element,
169     GstPadTemplate * templ, const gchar * name);
170 static void gst_rtp_session_release_pad (GstElement * element, GstPad * pad);
171
172 static guint gst_rtp_session_signals[LAST_SIGNAL] = { 0 };
173
174 GST_BOILERPLATE (GstRTPSession, gst_rtp_session, GstElement, GST_TYPE_ELEMENT);
175
176 static void
177 gst_rtp_session_base_init (gpointer klass)
178 {
179   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
180
181   /* sink pads */
182   gst_element_class_add_pad_template (element_class,
183       gst_static_pad_template_get (&rtpsession_recv_rtp_sink_template));
184   gst_element_class_add_pad_template (element_class,
185       gst_static_pad_template_get (&rtpsession_recv_rtcp_sink_template));
186   gst_element_class_add_pad_template (element_class,
187       gst_static_pad_template_get (&rtpsession_send_rtp_sink_template));
188
189   /* src pads */
190   gst_element_class_add_pad_template (element_class,
191       gst_static_pad_template_get (&rtpsession_recv_rtp_src_template));
192   gst_element_class_add_pad_template (element_class,
193       gst_static_pad_template_get (&rtpsession_sync_src_template));
194   gst_element_class_add_pad_template (element_class,
195       gst_static_pad_template_get (&rtpsession_send_rtp_src_template));
196   gst_element_class_add_pad_template (element_class,
197       gst_static_pad_template_get (&rtpsession_send_rtcp_src_template));
198
199   gst_element_class_set_details (element_class, &rtpsession_details);
200 }
201
202 static void
203 gst_rtp_session_class_init (GstRTPSessionClass * klass)
204 {
205   GObjectClass *gobject_class;
206   GstElementClass *gstelement_class;
207
208   gobject_class = (GObjectClass *) klass;
209   gstelement_class = (GstElementClass *) klass;
210
211   g_type_class_add_private (klass, sizeof (GstRTPSessionPrivate));
212
213   gobject_class->finalize = gst_rtp_session_finalize;
214   gobject_class->set_property = gst_rtp_session_set_property;
215   gobject_class->get_property = gst_rtp_session_get_property;
216
217   /**
218    * GstRTPSession::request-pt-map:
219    * @sess: the object which received the signal
220    * @pt: the pt
221    *
222    * Request the payload type as #GstCaps for @pt.
223    */
224   gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP] =
225       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
226       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPSessionClass, request_pt_map),
227       NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT, GST_TYPE_CAPS, 1,
228       G_TYPE_UINT);
229
230   gstelement_class->change_state =
231       GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
232   gstelement_class->request_new_pad =
233       GST_DEBUG_FUNCPTR (gst_rtp_session_request_new_pad);
234   gstelement_class->release_pad =
235       GST_DEBUG_FUNCPTR (gst_rtp_session_release_pad);
236
237   GST_DEBUG_CATEGORY_INIT (gst_rtp_session_debug,
238       "rtpsession", 0, "RTP Session");
239 }
240
241 static void
242 gst_rtp_session_init (GstRTPSession * rtpsession, GstRTPSessionClass * klass)
243 {
244   rtpsession->priv = GST_RTP_SESSION_GET_PRIVATE (rtpsession);
245   rtpsession->priv->lock = g_mutex_new ();
246   rtpsession->priv->session = rtp_session_new ();
247   /* configure callbacks */
248   rtp_session_set_callbacks (rtpsession->priv->session, &callbacks, rtpsession);
249 }
250
251 static void
252 gst_rtp_session_finalize (GObject * object)
253 {
254   GstRTPSession *rtpsession;
255
256   rtpsession = GST_RTP_SESSION (object);
257   g_mutex_free (rtpsession->priv->lock);
258   g_object_unref (rtpsession->priv->session);
259
260   G_OBJECT_CLASS (parent_class)->finalize (object);
261 }
262
263 static void
264 gst_rtp_session_set_property (GObject * object, guint prop_id,
265     const GValue * value, GParamSpec * pspec)
266 {
267   GstRTPSession *rtpsession;
268
269   rtpsession = GST_RTP_SESSION (object);
270
271   switch (prop_id) {
272     default:
273       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274       break;
275   }
276 }
277
278 static void
279 gst_rtp_session_get_property (GObject * object, guint prop_id,
280     GValue * value, GParamSpec * pspec)
281 {
282   GstRTPSession *rtpsession;
283
284   rtpsession = GST_RTP_SESSION (object);
285
286   switch (prop_id) {
287     default:
288       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
289       break;
290   }
291 }
292
293 static void
294 rtcp_thread (GstRTPSession * rtpsession)
295 {
296   GstClock *clock;
297   GstClockID id;
298   GstClockTime current_time;
299   GstClockTime next_timeout;
300
301   clock = gst_element_get_clock (GST_ELEMENT_CAST (rtpsession));
302   if (clock == NULL)
303     return;
304
305   current_time = gst_clock_get_time (clock);
306
307   GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");
308
309   GST_RTP_SESSION_LOCK (rtpsession);
310
311   while (!rtpsession->priv->stop_thread) {
312     GstClockReturn res;
313
314     /* get initial estimate */
315     next_timeout =
316         rtp_session_next_timeout (rtpsession->priv->session, current_time);
317
318
319     GST_DEBUG_OBJECT (rtpsession, "next check time %" GST_TIME_FORMAT,
320         GST_TIME_ARGS (next_timeout));
321
322     /* leave if no more timeouts, the session ended */
323     if (next_timeout == GST_CLOCK_TIME_NONE)
324       break;
325
326     id = rtpsession->priv->id =
327         gst_clock_new_single_shot_id (clock, next_timeout);
328     GST_RTP_SESSION_UNLOCK (rtpsession);
329
330     res = gst_clock_id_wait (id, NULL);
331
332     GST_RTP_SESSION_LOCK (rtpsession);
333     gst_clock_id_unref (id);
334     rtpsession->priv->id = NULL;
335
336     if (rtpsession->priv->stop_thread)
337       break;
338
339     /* update current time */
340     current_time = gst_clock_get_time (clock);
341
342     /* we get unlocked because we need to perform reconsideration, don't perform
343      * the timeout but get a new reporting estimate. */
344     GST_DEBUG_OBJECT (rtpsession, "unlocked %d, current %" GST_TIME_FORMAT,
345         res, GST_TIME_ARGS (current_time));
346
347     /* perform actions, we ignore result. */
348     rtp_session_on_timeout (rtpsession->priv->session, current_time);
349   }
350   GST_RTP_SESSION_UNLOCK (rtpsession);
351
352   gst_object_unref (clock);
353
354   GST_DEBUG_OBJECT (rtpsession, "leaving RTCP thread");
355 }
356
357 static gboolean
358 start_rtcp_thread (GstRTPSession * rtpsession)
359 {
360   GError *error = NULL;
361   gboolean res;
362
363   GST_DEBUG_OBJECT (rtpsession, "starting RTCP thread");
364
365   GST_RTP_SESSION_LOCK (rtpsession);
366   rtpsession->priv->stop_thread = FALSE;
367   rtpsession->priv->thread =
368       g_thread_create ((GThreadFunc) rtcp_thread, rtpsession, TRUE, &error);
369   GST_RTP_SESSION_UNLOCK (rtpsession);
370
371   if (error != NULL) {
372     res = FALSE;
373     GST_DEBUG_OBJECT (rtpsession, "failed to start thread, %s", error->message);
374     g_error_free (error);
375   } else {
376     res = TRUE;
377   }
378   return res;
379 }
380
381 static void
382 stop_rtcp_thread (GstRTPSession * rtpsession)
383 {
384   GST_DEBUG_OBJECT (rtpsession, "stopping RTCP thread");
385
386   GST_RTP_SESSION_LOCK (rtpsession);
387   rtpsession->priv->stop_thread = TRUE;
388   if (rtpsession->priv->id)
389     gst_clock_id_unschedule (rtpsession->priv->id);
390   GST_RTP_SESSION_UNLOCK (rtpsession);
391
392   g_thread_join (rtpsession->priv->thread);
393 }
394
395 static GstStateChangeReturn
396 gst_rtp_session_change_state (GstElement * element, GstStateChange transition)
397 {
398   GstStateChangeReturn res;
399   GstRTPSession *rtpsession;
400
401   rtpsession = GST_RTP_SESSION (element);
402
403   switch (transition) {
404     case GST_STATE_CHANGE_NULL_TO_READY:
405       break;
406     case GST_STATE_CHANGE_READY_TO_PAUSED:
407       break;
408     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
409       break;
410     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
411       stop_rtcp_thread (rtpsession);
412     default:
413       break;
414   }
415
416   res = parent_class->change_state (element, transition);
417
418   switch (transition) {
419     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
420       if (!start_rtcp_thread (rtpsession))
421         goto failed_thread;
422       break;
423     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
424       break;
425     case GST_STATE_CHANGE_PAUSED_TO_READY:
426       break;
427     case GST_STATE_CHANGE_READY_TO_NULL:
428       break;
429     default:
430       break;
431   }
432   return res;
433
434   /* ERRORS */
435 failed_thread:
436   {
437     return GST_STATE_CHANGE_FAILURE;
438   }
439 }
440
441 /* called when the session manager has an RTP packet ready for further
442  * processing */
443 static GstFlowReturn
444 gst_rtp_session_process_rtp (RTPSession * sess, RTPSource * src,
445     GstBuffer * buffer, gpointer user_data)
446 {
447   GstFlowReturn result;
448   GstRTPSession *rtpsession;
449   GstRTPSessionPrivate *priv;
450
451   rtpsession = GST_RTP_SESSION (user_data);
452   priv = rtpsession->priv;
453
454   GST_DEBUG_OBJECT (rtpsession, "reading receiving RTP packet");
455
456   if (rtpsession->recv_rtp_src) {
457     result = gst_pad_push (rtpsession->recv_rtp_src, buffer);
458   } else {
459     gst_buffer_unref (buffer);
460     result = GST_FLOW_OK;
461   }
462   return result;
463 }
464
465 /* called when the session manager has an RTP packet ready for further
466  * sending */
467 static GstFlowReturn
468 gst_rtp_session_send_rtp (RTPSession * sess, RTPSource * src,
469     GstBuffer * buffer, gpointer user_data)
470 {
471   GstFlowReturn result;
472   GstRTPSession *rtpsession;
473   GstRTPSessionPrivate *priv;
474
475   rtpsession = GST_RTP_SESSION (user_data);
476   priv = rtpsession->priv;
477
478   GST_DEBUG_OBJECT (rtpsession, "sending RTP packet");
479
480   if (rtpsession->send_rtp_src) {
481     result = gst_pad_push (rtpsession->send_rtp_src, buffer);
482   } else {
483     gst_buffer_unref (buffer);
484     result = GST_FLOW_OK;
485   }
486   return result;
487 }
488
489 /* called when the session manager has an RTCP packet ready for further
490  * sending */
491 static GstFlowReturn
492 gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
493     GstBuffer * buffer, gpointer user_data)
494 {
495   GstFlowReturn result;
496   GstRTPSession *rtpsession;
497   GstRTPSessionPrivate *priv;
498
499   rtpsession = GST_RTP_SESSION (user_data);
500   priv = rtpsession->priv;
501
502   GST_DEBUG_OBJECT (rtpsession, "sending RTCP");
503
504   if (rtpsession->send_rtcp_src) {
505     result = gst_pad_push (rtpsession->send_rtcp_src, buffer);
506   } else {
507     gst_buffer_unref (buffer);
508     result = GST_FLOW_OK;
509   }
510   return result;
511 }
512
513
514 /* called when the session manager needs the clock rate */
515 static gint
516 gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
517     gpointer user_data)
518 {
519   gint result = -1;
520   GstRTPSession *rtpsession;
521   GValue ret = { 0 };
522   GValue args[2] = { {0}, {0} };
523   GstCaps *caps;
524   const GstStructure *caps_struct;
525
526   rtpsession = GST_RTP_SESSION_CAST (user_data);
527
528   g_value_init (&args[0], GST_TYPE_ELEMENT);
529   g_value_set_object (&args[0], rtpsession);
530   g_value_init (&args[1], G_TYPE_UINT);
531   g_value_set_uint (&args[1], payload);
532
533   g_value_init (&ret, GST_TYPE_CAPS);
534   g_value_set_boxed (&ret, NULL);
535
536   g_signal_emitv (args, gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP], 0,
537       &ret);
538
539   caps = (GstCaps *) g_value_get_boxed (&ret);
540   if (!caps)
541     goto no_caps;
542
543   caps_struct = gst_caps_get_structure (caps, 0);
544   if (!gst_structure_get_int (caps_struct, "clock-rate", &result))
545     goto no_clock_rate;
546
547   GST_DEBUG_OBJECT (rtpsession, "parsed clock-rate %d", result);
548
549   return result;
550
551   /* ERRORS */
552 no_caps:
553   {
554     GST_DEBUG_OBJECT (rtpsession, "could not get caps");
555     return -1;
556   }
557 no_clock_rate:
558   {
559     GST_DEBUG_OBJECT (rtpsession, "could not clock-rate from caps");
560     return -1;
561   }
562 }
563
564 /* called when the session manager needs the time of clock */
565 static GstClockTime
566 gst_rtp_session_get_time (RTPSession * sess, gpointer user_data)
567 {
568   GstClockTime result;
569   GstRTPSession *rtpsession;
570   GstClock *clock;
571
572   rtpsession = GST_RTP_SESSION_CAST (user_data);
573
574   clock = gst_element_get_clock (GST_ELEMENT_CAST (rtpsession));
575   if (clock) {
576     result = gst_clock_get_time (clock);
577     gst_object_unref (clock);
578   } else
579     result = GST_CLOCK_TIME_NONE;
580
581   return result;
582 }
583
584 /* called when the session manager asks us to reconsider the timeout */
585 static void
586 gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data)
587 {
588   GstRTPSession *rtpsession;
589
590   rtpsession = GST_RTP_SESSION_CAST (user_data);
591
592   GST_RTP_SESSION_LOCK (rtpsession);
593   GST_DEBUG_OBJECT (rtpsession, "unlock timer for reconsideration");
594   if (rtpsession->priv->id)
595     gst_clock_id_unschedule (rtpsession->priv->id);
596   GST_RTP_SESSION_UNLOCK (rtpsession);
597 }
598
599 static GstFlowReturn
600 gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstEvent * event)
601 {
602   GstRTPSession *rtpsession;
603   GstRTPSessionPrivate *priv;
604   gboolean ret = FALSE;
605
606   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
607   priv = rtpsession->priv;
608
609   GST_DEBUG_OBJECT (rtpsession, "received event %s",
610       GST_EVENT_TYPE_NAME (event));
611
612   switch (GST_EVENT_TYPE (event)) {
613     default:
614       ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
615       break;
616   }
617   gst_object_unref (rtpsession);
618
619   return ret;
620 }
621
622 /* receive a packet from a sender, send it to the RTP session manager and
623  * forward the packet on the rtp_src pad
624  */
625 static GstFlowReturn
626 gst_rtp_session_chain_recv_rtp (GstPad * pad, GstBuffer * buffer)
627 {
628   GstRTPSession *rtpsession;
629   GstRTPSessionPrivate *priv;
630   GstFlowReturn ret;
631
632   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
633   priv = rtpsession->priv;
634
635   GST_DEBUG_OBJECT (rtpsession, "received RTP packet");
636
637   ret = rtp_session_process_rtp (priv->session, buffer);
638
639   gst_object_unref (rtpsession);
640
641   return ret;
642 }
643
644 static GstFlowReturn
645 gst_rtp_session_event_recv_rtcp_sink (GstPad * pad, GstEvent * event)
646 {
647   GstRTPSession *rtpsession;
648   GstRTPSessionPrivate *priv;
649   gboolean ret = FALSE;
650
651   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
652   priv = rtpsession->priv;
653
654   GST_DEBUG_OBJECT (rtpsession, "received event %s",
655       GST_EVENT_TYPE_NAME (event));
656
657   switch (GST_EVENT_TYPE (event)) {
658     default:
659       ret = gst_pad_push_event (rtpsession->sync_src, event);
660       break;
661   }
662   gst_object_unref (rtpsession);
663
664   return ret;
665 }
666
667 /* Receive an RTCP packet from a sender, send it to the RTP session manager and
668  * forward the SR packets to the sync_src pad.
669  */
670 static GstFlowReturn
671 gst_rtp_session_chain_recv_rtcp (GstPad * pad, GstBuffer * buffer)
672 {
673   GstRTPSession *rtpsession;
674   GstRTPSessionPrivate *priv;
675   GstFlowReturn ret;
676
677   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
678   priv = rtpsession->priv;
679
680   GST_DEBUG_OBJECT (rtpsession, "received RTCP packet");
681
682   ret = rtp_session_process_rtcp (priv->session, buffer);
683
684   gst_object_unref (rtpsession);
685
686   return GST_FLOW_OK;
687 }
688
689 static GstFlowReturn
690 gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstEvent * event)
691 {
692   GstRTPSession *rtpsession;
693   GstRTPSessionPrivate *priv;
694   gboolean ret = FALSE;
695
696   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
697   priv = rtpsession->priv;
698
699   GST_DEBUG_OBJECT (rtpsession, "received event");
700
701   switch (GST_EVENT_TYPE (event)) {
702     default:
703       ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
704       break;
705   }
706   gst_object_unref (rtpsession);
707
708   return ret;
709 }
710
711 /* Recieve an RTP packet to be send to the receivers, send to RTP session
712  * manager and forward to send_rtp_src.
713  */
714 static GstFlowReturn
715 gst_rtp_session_chain_send_rtp (GstPad * pad, GstBuffer * buffer)
716 {
717   GstRTPSession *rtpsession;
718   GstRTPSessionPrivate *priv;
719   GstFlowReturn ret;
720
721   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
722   priv = rtpsession->priv;
723
724   GST_DEBUG_OBJECT (rtpsession, "received RTP packet");
725
726   ret = rtp_session_send_rtp (priv->session, buffer);
727
728   gst_object_unref (rtpsession);
729
730   return ret;
731 }
732
733
734 /* Create sinkpad to receive RTP packets from senders. This will also create a
735  * srcpad for the RTP packets.
736  */
737 static GstPad *
738 create_recv_rtp_sink (GstRTPSession * rtpsession)
739 {
740   GST_DEBUG_OBJECT (rtpsession, "creating RTP sink pad");
741
742   rtpsession->recv_rtp_sink =
743       gst_pad_new_from_static_template (&rtpsession_recv_rtp_sink_template,
744       "recv_rtp_sink");
745   gst_pad_set_chain_function (rtpsession->recv_rtp_sink,
746       gst_rtp_session_chain_recv_rtp);
747   gst_pad_set_event_function (rtpsession->recv_rtp_sink,
748       gst_rtp_session_event_recv_rtp_sink);
749   gst_pad_set_active (rtpsession->recv_rtp_sink, TRUE);
750   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
751       rtpsession->recv_rtp_sink);
752
753   GST_DEBUG_OBJECT (rtpsession, "creating RTP src pad");
754   rtpsession->recv_rtp_src =
755       gst_pad_new_from_static_template (&rtpsession_recv_rtp_src_template,
756       "recv_rtp_src");
757   gst_pad_set_active (rtpsession->recv_rtp_src, TRUE);
758   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->recv_rtp_src);
759
760   return rtpsession->recv_rtp_sink;
761 }
762
763 /* Create a sinkpad to receive RTCP messages from senders, this will also create a
764  * sync_src pad for the SR packets.
765  */
766 static GstPad *
767 create_recv_rtcp_sink (GstRTPSession * rtpsession)
768 {
769   GST_DEBUG_OBJECT (rtpsession, "creating RTCP sink pad");
770
771   rtpsession->recv_rtcp_sink =
772       gst_pad_new_from_static_template (&rtpsession_recv_rtcp_sink_template,
773       "recv_rtcp_sink");
774   gst_pad_set_chain_function (rtpsession->recv_rtcp_sink,
775       gst_rtp_session_chain_recv_rtcp);
776   gst_pad_set_event_function (rtpsession->recv_rtcp_sink,
777       gst_rtp_session_event_recv_rtcp_sink);
778   gst_pad_set_active (rtpsession->recv_rtcp_sink, TRUE);
779   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
780       rtpsession->recv_rtcp_sink);
781
782   GST_DEBUG_OBJECT (rtpsession, "creating sync src pad");
783   rtpsession->sync_src =
784       gst_pad_new_from_static_template (&rtpsession_sync_src_template,
785       "sync_src");
786   gst_pad_set_active (rtpsession->sync_src, TRUE);
787   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->sync_src);
788
789   return rtpsession->recv_rtcp_sink;
790 }
791
792 /* Create a sinkpad to receive RTP packets for receivers. This will also create a
793  * send_rtp_src pad.
794  */
795 static GstPad *
796 create_send_rtp_sink (GstRTPSession * rtpsession)
797 {
798   GST_DEBUG_OBJECT (rtpsession, "creating pad");
799
800   rtpsession->send_rtp_sink =
801       gst_pad_new_from_static_template (&rtpsession_send_rtp_sink_template,
802       "send_rtp_sink");
803   gst_pad_set_chain_function (rtpsession->send_rtp_sink,
804       gst_rtp_session_chain_send_rtp);
805   gst_pad_set_event_function (rtpsession->send_rtp_sink,
806       gst_rtp_session_event_send_rtp_sink);
807   gst_pad_set_active (rtpsession->send_rtp_sink, TRUE);
808   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
809       rtpsession->send_rtp_sink);
810
811   rtpsession->send_rtp_src =
812       gst_pad_new_from_static_template (&rtpsession_send_rtp_src_template,
813       "send_rtp_src");
814   gst_pad_set_active (rtpsession->send_rtp_src, TRUE);
815   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->send_rtp_src);
816
817   return rtpsession->send_rtp_sink;
818 }
819
820 /* Create a srcpad with the RTCP packets to send out.
821  * This pad will be driven by the RTP session manager when it wants to send out
822  * RTCP packets.
823  */
824 static GstPad *
825 create_send_rtcp_src (GstRTPSession * rtpsession)
826 {
827   GST_DEBUG_OBJECT (rtpsession, "creating pad");
828
829   rtpsession->send_rtcp_src =
830       gst_pad_new_from_static_template (&rtpsession_send_rtcp_src_template,
831       "send_rtcp_src");
832   gst_pad_set_active (rtpsession->send_rtcp_src, TRUE);
833   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
834       rtpsession->send_rtcp_src);
835
836   return rtpsession->send_rtcp_src;
837 }
838
839 static GstPad *
840 gst_rtp_session_request_new_pad (GstElement * element,
841     GstPadTemplate * templ, const gchar * name)
842 {
843   GstRTPSession *rtpsession;
844   GstElementClass *klass;
845   GstPad *result;
846
847   g_return_val_if_fail (templ != NULL, NULL);
848   g_return_val_if_fail (GST_IS_RTP_SESSION (element), NULL);
849
850   rtpsession = GST_RTP_SESSION (element);
851   klass = GST_ELEMENT_GET_CLASS (element);
852
853   GST_DEBUG_OBJECT (element, "requesting pad %s", GST_STR_NULL (name));
854
855   GST_RTP_SESSION_LOCK (rtpsession);
856
857   /* figure out the template */
858   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink")) {
859     if (rtpsession->recv_rtp_sink != NULL)
860       goto exists;
861
862     result = create_recv_rtp_sink (rtpsession);
863   } else if (templ == gst_element_class_get_pad_template (klass,
864           "recv_rtcp_sink")) {
865     if (rtpsession->recv_rtcp_sink != NULL)
866       goto exists;
867
868     result = create_recv_rtcp_sink (rtpsession);
869   } else if (templ == gst_element_class_get_pad_template (klass,
870           "send_rtp_sink")) {
871     if (rtpsession->send_rtp_sink != NULL)
872       goto exists;
873
874     result = create_send_rtp_sink (rtpsession);
875   } else if (templ == gst_element_class_get_pad_template (klass,
876           "send_rtcp_src")) {
877     if (rtpsession->send_rtcp_src != NULL)
878       goto exists;
879
880     result = create_send_rtcp_src (rtpsession);
881   } else
882     goto wrong_template;
883
884   GST_RTP_SESSION_UNLOCK (rtpsession);
885
886   return result;
887
888   /* ERRORS */
889 wrong_template:
890   {
891     GST_RTP_SESSION_UNLOCK (rtpsession);
892     g_warning ("rtpsession: this is not our template");
893     return NULL;
894   }
895 exists:
896   {
897     GST_RTP_SESSION_UNLOCK (rtpsession);
898     g_warning ("rtpsession: pad already requested");
899     return NULL;
900   }
901 }
902
903 static void
904 gst_rtp_session_release_pad (GstElement * element, GstPad * pad)
905 {
906 }