gst/rtpmanager/gstrtpsession.c: Remove debug.
[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   if (rtpsession->recv_rtp_src) {
455     result = gst_pad_push (rtpsession->recv_rtp_src, buffer);
456   } else {
457     gst_buffer_unref (buffer);
458     result = GST_FLOW_OK;
459   }
460   return result;
461 }
462
463 /* called when the session manager has an RTP packet ready for further
464  * sending */
465 static GstFlowReturn
466 gst_rtp_session_send_rtp (RTPSession * sess, RTPSource * src,
467     GstBuffer * buffer, gpointer user_data)
468 {
469   GstFlowReturn result;
470   GstRTPSession *rtpsession;
471   GstRTPSessionPrivate *priv;
472
473   rtpsession = GST_RTP_SESSION (user_data);
474   priv = rtpsession->priv;
475
476   if (rtpsession->send_rtp_src) {
477     result = gst_pad_push (rtpsession->send_rtp_src, buffer);
478   } else {
479     gst_buffer_unref (buffer);
480     result = GST_FLOW_OK;
481   }
482   return result;
483 }
484
485 /* called when the session manager has an RTCP packet ready for further
486  * sending */
487 static GstFlowReturn
488 gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
489     GstBuffer * buffer, gpointer user_data)
490 {
491   GstFlowReturn result;
492   GstRTPSession *rtpsession;
493   GstRTPSessionPrivate *priv;
494
495   rtpsession = GST_RTP_SESSION (user_data);
496   priv = rtpsession->priv;
497
498   GST_DEBUG_OBJECT (rtpsession, "sending RTCP");
499
500   if (rtpsession->send_rtcp_src) {
501     result = gst_pad_push (rtpsession->send_rtcp_src, buffer);
502   } else {
503     gst_buffer_unref (buffer);
504     result = GST_FLOW_OK;
505   }
506   return result;
507 }
508
509
510 /* called when the session manager needs the clock rate */
511 static gint
512 gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
513     gpointer user_data)
514 {
515   gint result = -1;
516   GstRTPSession *rtpsession;
517   GValue ret = { 0 };
518   GValue args[2] = { {0}, {0} };
519   GstCaps *caps;
520   const GstStructure *caps_struct;
521
522   rtpsession = GST_RTP_SESSION_CAST (user_data);
523
524   g_value_init (&args[0], GST_TYPE_ELEMENT);
525   g_value_set_object (&args[0], rtpsession);
526   g_value_init (&args[1], G_TYPE_UINT);
527   g_value_set_uint (&args[1], payload);
528
529   g_value_init (&ret, GST_TYPE_CAPS);
530   g_value_set_boxed (&ret, NULL);
531
532   g_signal_emitv (args, gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP], 0,
533       &ret);
534
535   caps = (GstCaps *) g_value_get_boxed (&ret);
536   if (!caps)
537     goto no_caps;
538
539   caps_struct = gst_caps_get_structure (caps, 0);
540   if (!gst_structure_get_int (caps_struct, "clock-rate", &result))
541     goto no_clock_rate;
542
543   GST_DEBUG_OBJECT (rtpsession, "parsed clock-rate %d", result);
544
545   return result;
546
547   /* ERRORS */
548 no_caps:
549   {
550     GST_DEBUG_OBJECT (rtpsession, "could not get caps");
551     return -1;
552   }
553 no_clock_rate:
554   {
555     GST_DEBUG_OBJECT (rtpsession, "could not clock-rate from caps");
556     return -1;
557   }
558 }
559
560 /* called when the session manager needs the time of clock */
561 static GstClockTime
562 gst_rtp_session_get_time (RTPSession * sess, gpointer user_data)
563 {
564   GstClockTime result;
565   GstRTPSession *rtpsession;
566   GstClock *clock;
567
568   rtpsession = GST_RTP_SESSION_CAST (user_data);
569
570   clock = gst_element_get_clock (GST_ELEMENT_CAST (rtpsession));
571   if (clock) {
572     result = gst_clock_get_time (clock);
573     gst_object_unref (clock);
574   } else
575     result = GST_CLOCK_TIME_NONE;
576
577   return result;
578 }
579
580 /* called when the session manager asks us to reconsider the timeout */
581 static void
582 gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data)
583 {
584   GstRTPSession *rtpsession;
585
586   rtpsession = GST_RTP_SESSION_CAST (user_data);
587
588   GST_RTP_SESSION_LOCK (rtpsession);
589   GST_DEBUG_OBJECT (rtpsession, "unlock timer for reconsideration");
590   if (rtpsession->priv->id)
591     gst_clock_id_unschedule (rtpsession->priv->id);
592   GST_RTP_SESSION_UNLOCK (rtpsession);
593 }
594
595 static GstFlowReturn
596 gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstEvent * event)
597 {
598   GstRTPSession *rtpsession;
599   GstRTPSessionPrivate *priv;
600   gboolean ret = FALSE;
601
602   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
603   priv = rtpsession->priv;
604
605   GST_DEBUG_OBJECT (rtpsession, "received event %s",
606       GST_EVENT_TYPE_NAME (event));
607
608   switch (GST_EVENT_TYPE (event)) {
609     default:
610       ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
611       break;
612   }
613   gst_object_unref (rtpsession);
614
615   return ret;
616 }
617
618 /* receive a packet from a sender, send it to the RTP session manager and
619  * forward the packet on the rtp_src pad
620  */
621 static GstFlowReturn
622 gst_rtp_session_chain_recv_rtp (GstPad * pad, GstBuffer * buffer)
623 {
624   GstRTPSession *rtpsession;
625   GstRTPSessionPrivate *priv;
626   GstFlowReturn ret;
627
628   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
629   priv = rtpsession->priv;
630
631   GST_DEBUG_OBJECT (rtpsession, "received RTP packet");
632
633   ret = rtp_session_process_rtp (priv->session, buffer);
634
635   gst_object_unref (rtpsession);
636
637   return ret;
638 }
639
640 static GstFlowReturn
641 gst_rtp_session_event_recv_rtcp_sink (GstPad * pad, GstEvent * event)
642 {
643   GstRTPSession *rtpsession;
644   GstRTPSessionPrivate *priv;
645   gboolean ret = FALSE;
646
647   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
648   priv = rtpsession->priv;
649
650   GST_DEBUG_OBJECT (rtpsession, "received event %s",
651       GST_EVENT_TYPE_NAME (event));
652
653   switch (GST_EVENT_TYPE (event)) {
654     default:
655       ret = gst_pad_push_event (rtpsession->sync_src, event);
656       break;
657   }
658   gst_object_unref (rtpsession);
659
660   return ret;
661 }
662
663 /* Receive an RTCP packet from a sender, send it to the RTP session manager and
664  * forward the SR packets to the sync_src pad.
665  */
666 static GstFlowReturn
667 gst_rtp_session_chain_recv_rtcp (GstPad * pad, GstBuffer * buffer)
668 {
669   GstRTPSession *rtpsession;
670   GstRTPSessionPrivate *priv;
671   GstFlowReturn ret;
672
673   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
674   priv = rtpsession->priv;
675
676   GST_DEBUG_OBJECT (rtpsession, "received RTCP packet");
677
678   ret = rtp_session_process_rtcp (priv->session, buffer);
679
680   gst_object_unref (rtpsession);
681
682   return GST_FLOW_OK;
683 }
684
685 static GstFlowReturn
686 gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstEvent * event)
687 {
688   GstRTPSession *rtpsession;
689   GstRTPSessionPrivate *priv;
690   gboolean ret = FALSE;
691
692   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
693   priv = rtpsession->priv;
694
695   GST_DEBUG_OBJECT (rtpsession, "received event");
696
697   switch (GST_EVENT_TYPE (event)) {
698     default:
699       ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
700       break;
701   }
702   gst_object_unref (rtpsession);
703
704   return ret;
705 }
706
707 /* Recieve an RTP packet to be send to the receivers, send to RTP session
708  * manager and forward to send_rtp_src.
709  */
710 static GstFlowReturn
711 gst_rtp_session_chain_send_rtp (GstPad * pad, GstBuffer * buffer)
712 {
713   GstRTPSession *rtpsession;
714   GstRTPSessionPrivate *priv;
715   GstFlowReturn ret;
716
717   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
718   priv = rtpsession->priv;
719
720   GST_DEBUG_OBJECT (rtpsession, "received RTP packet");
721
722   ret = rtp_session_send_rtp (priv->session, buffer);
723
724   gst_object_unref (rtpsession);
725
726   return ret;
727 }
728
729
730 /* Create sinkpad to receive RTP packets from senders. This will also create a
731  * srcpad for the RTP packets.
732  */
733 static GstPad *
734 create_recv_rtp_sink (GstRTPSession * rtpsession)
735 {
736   GST_DEBUG_OBJECT (rtpsession, "creating RTP sink pad");
737
738   rtpsession->recv_rtp_sink =
739       gst_pad_new_from_static_template (&rtpsession_recv_rtp_sink_template,
740       NULL);
741   gst_pad_set_chain_function (rtpsession->recv_rtp_sink,
742       gst_rtp_session_chain_recv_rtp);
743   gst_pad_set_event_function (rtpsession->recv_rtp_sink,
744       gst_rtp_session_event_recv_rtp_sink);
745   gst_pad_set_active (rtpsession->recv_rtp_sink, TRUE);
746   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
747       rtpsession->recv_rtp_sink);
748
749   GST_DEBUG_OBJECT (rtpsession, "creating RTP src pad");
750   rtpsession->recv_rtp_src =
751       gst_pad_new_from_static_template (&rtpsession_recv_rtp_src_template,
752       "recv_rtp_src");
753   gst_pad_set_active (rtpsession->recv_rtp_src, TRUE);
754   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->recv_rtp_src);
755
756   return rtpsession->recv_rtp_sink;
757 }
758
759 /* Create a sinkpad to receive RTCP messages from senders, this will also create a
760  * sync_src pad for the SR packets.
761  */
762 static GstPad *
763 create_recv_rtcp_sink (GstRTPSession * rtpsession)
764 {
765   GST_DEBUG_OBJECT (rtpsession, "creating RTCP sink pad");
766
767   rtpsession->recv_rtcp_sink =
768       gst_pad_new_from_static_template (&rtpsession_recv_rtcp_sink_template,
769       NULL);
770   gst_pad_set_chain_function (rtpsession->recv_rtcp_sink,
771       gst_rtp_session_chain_recv_rtcp);
772   gst_pad_set_event_function (rtpsession->recv_rtcp_sink,
773       gst_rtp_session_event_recv_rtcp_sink);
774   gst_pad_set_active (rtpsession->recv_rtcp_sink, TRUE);
775   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
776       rtpsession->recv_rtcp_sink);
777
778   GST_DEBUG_OBJECT (rtpsession, "creating sync src pad");
779   rtpsession->sync_src =
780       gst_pad_new_from_static_template (&rtpsession_sync_src_template,
781       "sync_src");
782   gst_pad_set_active (rtpsession->sync_src, TRUE);
783   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->sync_src);
784
785   return rtpsession->recv_rtcp_sink;
786 }
787
788 /* Create a sinkpad to receive RTP packets for receivers. This will also create a
789  * send_rtp_src pad.
790  */
791 static GstPad *
792 create_send_rtp_sink (GstRTPSession * rtpsession)
793 {
794   GST_DEBUG_OBJECT (rtpsession, "creating pad");
795
796   rtpsession->send_rtp_sink =
797       gst_pad_new_from_static_template (&rtpsession_send_rtp_sink_template,
798       NULL);
799   gst_pad_set_chain_function (rtpsession->send_rtp_sink,
800       gst_rtp_session_chain_send_rtp);
801   gst_pad_set_event_function (rtpsession->send_rtp_sink,
802       gst_rtp_session_event_send_rtp_sink);
803   gst_pad_set_active (rtpsession->send_rtp_sink, TRUE);
804   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
805       rtpsession->recv_rtcp_sink);
806
807   rtpsession->send_rtp_src =
808       gst_pad_new_from_static_template (&rtpsession_send_rtp_src_template,
809       NULL);
810   gst_pad_set_active (rtpsession->send_rtp_src, TRUE);
811   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->send_rtp_src);
812
813   return rtpsession->send_rtp_sink;
814 }
815
816 /* Create a srcpad with the RTCP packets to send out.
817  * This pad will be driven by the RTP session manager when it wants to send out
818  * RTCP packets.
819  */
820 static GstPad *
821 create_send_rtcp_src (GstRTPSession * rtpsession)
822 {
823   GST_DEBUG_OBJECT (rtpsession, "creating pad");
824
825   rtpsession->send_rtcp_src =
826       gst_pad_new_from_static_template (&rtpsession_send_rtcp_src_template,
827       NULL);
828   gst_pad_set_active (rtpsession->send_rtcp_src, TRUE);
829   gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
830       rtpsession->send_rtcp_src);
831
832   return rtpsession->send_rtcp_src;
833 }
834
835 static GstPad *
836 gst_rtp_session_request_new_pad (GstElement * element,
837     GstPadTemplate * templ, const gchar * name)
838 {
839   GstRTPSession *rtpsession;
840   GstElementClass *klass;
841   GstPad *result;
842
843   g_return_val_if_fail (templ != NULL, NULL);
844   g_return_val_if_fail (GST_IS_RTP_SESSION (element), NULL);
845
846   rtpsession = GST_RTP_SESSION (element);
847   klass = GST_ELEMENT_GET_CLASS (element);
848
849   GST_DEBUG_OBJECT (element, "requesting pad %s", GST_STR_NULL (name));
850
851   GST_RTP_SESSION_LOCK (rtpsession);
852
853   /* figure out the template */
854   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink")) {
855     if (rtpsession->recv_rtp_sink != NULL)
856       goto exists;
857
858     result = create_recv_rtp_sink (rtpsession);
859   } else if (templ == gst_element_class_get_pad_template (klass,
860           "recv_rtcp_sink")) {
861     if (rtpsession->recv_rtcp_sink != NULL)
862       goto exists;
863
864     result = create_recv_rtcp_sink (rtpsession);
865   } else if (templ == gst_element_class_get_pad_template (klass,
866           "send_rtp_sink")) {
867     if (rtpsession->send_rtp_sink != NULL)
868       goto exists;
869
870     result = create_send_rtp_sink (rtpsession);
871   } else if (templ == gst_element_class_get_pad_template (klass,
872           "send_rtcp_src")) {
873     if (rtpsession->send_rtcp_src != NULL)
874       goto exists;
875
876     result = create_send_rtcp_src (rtpsession);
877   } else
878     goto wrong_template;
879
880   GST_RTP_SESSION_UNLOCK (rtpsession);
881
882   return result;
883
884   /* ERRORS */
885 wrong_template:
886   {
887     GST_RTP_SESSION_UNLOCK (rtpsession);
888     g_warning ("rtpsession: this is not our template");
889     return NULL;
890   }
891 exists:
892   {
893     GST_RTP_SESSION_UNLOCK (rtpsession);
894     g_warning ("rtpsession: pad already requested");
895     return NULL;
896   }
897 }
898
899 static void
900 gst_rtp_session_release_pad (GstElement * element, GstPad * pad)
901 {
902 }