Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / rtsp / gstrtpdec.c
1 /* GStreamer
2  * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.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  * Unless otherwise indicated, Source Code is licensed under MIT license.
21  * See further explanation attached in License Statement (distributed in the file
22  * LICENSE).
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy of
25  * this software and associated documentation files (the "Software"), to deal in
26  * the Software without restriction, including without limitation the rights to
27  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28  * of the Software, and to permit persons to whom the Software is furnished to do
29  * so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in all
32  * copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40  * SOFTWARE.
41  */
42 /* Element-Checklist-Version: 5 */
43
44 /**
45  * SECTION:element-rtpdec
46  *
47  * A simple RTP session manager used internally by rtspsrc.
48  *
49  * Last reviewed on 2006-06-20 (0.10.4)
50  */
51
52 /* #define HAVE_RTCP */
53
54 #include <gst/rtp/gstrtpbuffer.h>
55
56 #ifdef HAVE_RTCP
57 #include <gst/rtp/gstrtcpbuffer.h>
58 #endif
59
60 #include "gstrtpdec.h"
61 #include <stdio.h>
62
63 GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
64 #define GST_CAT_DEFAULT (rtpdec_debug)
65
66 /* GstRTPDec signals and args */
67 enum
68 {
69   SIGNAL_REQUEST_PT_MAP,
70   SIGNAL_CLEAR_PT_MAP,
71
72   SIGNAL_ON_NEW_SSRC,
73   SIGNAL_ON_SSRC_COLLISION,
74   SIGNAL_ON_SSRC_VALIDATED,
75   SIGNAL_ON_BYE_SSRC,
76   SIGNAL_ON_BYE_TIMEOUT,
77   SIGNAL_ON_TIMEOUT,
78   LAST_SIGNAL
79 };
80
81 #define DEFAULT_LATENCY_MS      200
82
83 enum
84 {
85   PROP_0,
86   PROP_LATENCY
87 };
88
89 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
91     GST_PAD_SINK,
92     GST_PAD_REQUEST,
93     GST_STATIC_CAPS ("application/x-rtp")
94     );
95
96 static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
97 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
98     GST_PAD_SINK,
99     GST_PAD_REQUEST,
100     GST_STATIC_CAPS ("application/x-rtcp")
101     );
102
103 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
104 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
105     GST_PAD_SRC,
106     GST_PAD_SOMETIMES,
107     GST_STATIC_CAPS ("application/x-rtp")
108     );
109
110 static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
111 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
112     GST_PAD_SRC,
113     GST_PAD_REQUEST,
114     GST_STATIC_CAPS ("application/x-rtcp")
115     );
116
117 static void gst_rtp_dec_finalize (GObject * object);
118 static void gst_rtp_dec_set_property (GObject * object,
119     guint prop_id, const GValue * value, GParamSpec * pspec);
120 static void gst_rtp_dec_get_property (GObject * object,
121     guint prop_id, GValue * value, GParamSpec * pspec);
122
123 static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
124 static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
125     GstStateChange transition);
126 static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
127     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
128 static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
129
130 static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer);
131 static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
132
133
134 /* Manages the receiving end of the packets.
135  *
136  * There is one such structure for each RTP session (audio/video/...).
137  * We get the RTP/RTCP packets and stuff them into the session manager. 
138  */
139 struct _GstRTPDecSession
140 {
141   /* session id */
142   gint id;
143   /* the parent bin */
144   GstRTPDec *dec;
145
146   gboolean active;
147   /* we only support one ssrc and one pt */
148   guint32 ssrc;
149   guint8 pt;
150   GstCaps *caps;
151
152   /* the pads of the session */
153   GstPad *recv_rtp_sink;
154   GstPad *recv_rtp_src;
155   GstPad *recv_rtcp_sink;
156   GstPad *rtcp_src;
157 };
158
159 /* find a session with the given id */
160 static GstRTPDecSession *
161 find_session_by_id (GstRTPDec * rtpdec, gint id)
162 {
163   GSList *walk;
164
165   for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
166     GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
167
168     if (sess->id == id)
169       return sess;
170   }
171   return NULL;
172 }
173
174 /* create a session with the given id */
175 static GstRTPDecSession *
176 create_session (GstRTPDec * rtpdec, gint id)
177 {
178   GstRTPDecSession *sess;
179
180   sess = g_new0 (GstRTPDecSession, 1);
181   sess->id = id;
182   sess->dec = rtpdec;
183   rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
184
185   return sess;
186 }
187
188 static void
189 free_session (GstRTPDecSession * session)
190 {
191   g_free (session);
192 }
193
194 static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
195
196 #define gst_rtp_dec_parent_class parent_class
197 G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
198
199
200 /* BOXED:UINT,UINT */
201 #define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
202
203 static void
204 gst_rtp_dec_marshal_BOXED__UINT_UINT (GClosure * closure,
205     GValue * return_value,
206     guint n_param_values,
207     const GValue * param_values,
208     gpointer invocation_hint, gpointer marshal_data)
209 {
210   typedef gpointer (*GMarshalFunc_BOXED__UINT_UINT) (gpointer data1,
211       guint arg_1, guint arg_2, gpointer data2);
212   register GMarshalFunc_BOXED__UINT_UINT callback;
213   register GCClosure *cc = (GCClosure *) closure;
214   register gpointer data1, data2;
215   gpointer v_return;
216
217   g_return_if_fail (return_value != NULL);
218   g_return_if_fail (n_param_values == 3);
219
220   if (G_CCLOSURE_SWAP_DATA (closure)) {
221     data1 = closure->data;
222     data2 = g_value_peek_pointer (param_values + 0);
223   } else {
224     data1 = g_value_peek_pointer (param_values + 0);
225     data2 = closure->data;
226   }
227   callback =
228       (GMarshalFunc_BOXED__UINT_UINT) (marshal_data ? marshal_data :
229       cc->callback);
230
231   v_return = callback (data1,
232       g_marshal_value_peek_uint (param_values + 1),
233       g_marshal_value_peek_uint (param_values + 2), data2);
234
235   g_value_take_boxed (return_value, v_return);
236 }
237
238 static void
239 gst_rtp_dec_marshal_VOID__UINT_UINT (GClosure * closure,
240     GValue * return_value,
241     guint n_param_values,
242     const GValue * param_values,
243     gpointer invocation_hint, gpointer marshal_data)
244 {
245   typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
246       guint arg_1, guint arg_2, gpointer data2);
247   register GMarshalFunc_VOID__UINT_UINT callback;
248   register GCClosure *cc = (GCClosure *) closure;
249   register gpointer data1, data2;
250
251   g_return_if_fail (n_param_values == 3);
252
253   if (G_CCLOSURE_SWAP_DATA (closure)) {
254     data1 = closure->data;
255     data2 = g_value_peek_pointer (param_values + 0);
256   } else {
257     data1 = g_value_peek_pointer (param_values + 0);
258     data2 = closure->data;
259   }
260   callback =
261       (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data :
262       cc->callback);
263
264   callback (data1,
265       g_marshal_value_peek_uint (param_values + 1),
266       g_marshal_value_peek_uint (param_values + 2), data2);
267 }
268
269 static void
270 gst_rtp_dec_class_init (GstRTPDecClass * g_class)
271 {
272   GObjectClass *gobject_class;
273   GstElementClass *gstelement_class;
274   GstRTPDecClass *klass;
275
276   klass = (GstRTPDecClass *) g_class;
277   gobject_class = (GObjectClass *) klass;
278   gstelement_class = (GstElementClass *) klass;
279
280   GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
281
282   gobject_class->finalize = gst_rtp_dec_finalize;
283   gobject_class->set_property = gst_rtp_dec_set_property;
284   gobject_class->get_property = gst_rtp_dec_get_property;
285
286   g_object_class_install_property (gobject_class, PROP_LATENCY,
287       g_param_spec_uint ("latency", "Buffer latency in ms",
288           "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
289           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
290
291   /**
292    * GstRTPDec::request-pt-map:
293    * @rtpdec: the object which received the signal
294    * @session: the session
295    * @pt: the pt
296    *
297    * Request the payload type as #GstCaps for @pt in @session.
298    */
299   gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
300       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
301       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map),
302       NULL, NULL, gst_rtp_dec_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
303       G_TYPE_UINT, G_TYPE_UINT);
304
305   gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
306       g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
307       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map),
308       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
309
310   /**
311    * GstRTPDec::on-new-ssrc:
312    * @rtpbin: the object which received the signal
313    * @session: the session
314    * @ssrc: the SSRC 
315    *
316    * Notify of a new SSRC that entered @session.
317    */
318   gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
319       g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
320       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc),
321       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
322       G_TYPE_UINT, G_TYPE_UINT);
323   /**
324    * GstRTPDec::on-ssrc_collision:
325    * @rtpbin: the object which received the signal
326    * @session: the session
327    * @ssrc: the SSRC 
328    *
329    * Notify when we have an SSRC collision
330    */
331   gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
332       g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
333       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
334       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
335       G_TYPE_UINT, G_TYPE_UINT);
336   /**
337    * GstRTPDec::on-ssrc_validated:
338    * @rtpbin: the object which received the signal
339    * @session: the session
340    * @ssrc: the SSRC 
341    *
342    * Notify of a new SSRC that became validated.
343    */
344   gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
345       g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
346       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
347       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
348       G_TYPE_UINT, G_TYPE_UINT);
349
350   /**
351    * GstRTPDec::on-bye-ssrc:
352    * @rtpbin: the object which received the signal
353    * @session: the session
354    * @ssrc: the SSRC 
355    *
356    * Notify of an SSRC that became inactive because of a BYE packet.
357    */
358   gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
359       g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
360       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc),
361       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
362       G_TYPE_UINT, G_TYPE_UINT);
363   /**
364    * GstRTPDec::on-bye-timeout:
365    * @rtpbin: the object which received the signal
366    * @session: the session
367    * @ssrc: the SSRC 
368    *
369    * Notify of an SSRC that has timed out because of BYE
370    */
371   gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
372       g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
373       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
374       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
375       G_TYPE_UINT, G_TYPE_UINT);
376   /**
377    * GstRTPDec::on-timeout:
378    * @rtpbin: the object which received the signal
379    * @session: the session
380    * @ssrc: the SSRC 
381    *
382    * Notify of an SSRC that has timed out
383    */
384   gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
385       g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
386       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout),
387       NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
388       G_TYPE_UINT, G_TYPE_UINT);
389
390
391   gstelement_class->provide_clock =
392       GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
393   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
394   gstelement_class->request_new_pad =
395       GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
396   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
397
398   /* sink pads */
399   gst_element_class_add_pad_template (gstelement_class,
400       gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_sink_template));
401   gst_element_class_add_pad_template (gstelement_class,
402       gst_static_pad_template_get (&gst_rtp_dec_recv_rtcp_sink_template));
403   /* src pads */
404   gst_element_class_add_pad_template (gstelement_class,
405       gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_src_template));
406   gst_element_class_add_pad_template (gstelement_class,
407       gst_static_pad_template_get (&gst_rtp_dec_rtcp_src_template));
408
409   gst_element_class_set_details_simple (gstelement_class, "RTP Decoder",
410       "Codec/Parser/Network",
411       "Accepts raw RTP and RTCP packets and sends them forward",
412       "Wim Taymans <wim.taymans@gmail.com>");
413 }
414
415 static void
416 gst_rtp_dec_init (GstRTPDec * rtpdec)
417 {
418   rtpdec->provided_clock = gst_system_clock_obtain ();
419   rtpdec->latency = DEFAULT_LATENCY_MS;
420 }
421
422 static void
423 gst_rtp_dec_finalize (GObject * object)
424 {
425   GstRTPDec *rtpdec;
426
427   rtpdec = GST_RTP_DEC (object);
428
429   g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
430   g_slist_free (rtpdec->sessions);
431
432   G_OBJECT_CLASS (parent_class)->finalize (object);
433 }
434
435 static gboolean
436 gst_rtp_dec_query_src (GstPad * pad, GstQuery * query)
437 {
438   gboolean res;
439
440   switch (GST_QUERY_TYPE (query)) {
441     case GST_QUERY_LATENCY:
442     {
443       /* we pretend to be live with a 3 second latency */
444       gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
445       res = TRUE;
446       break;
447     }
448     default:
449       res = gst_pad_query_default (pad, query);
450       break;
451   }
452   return res;
453 }
454
455 static GstFlowReturn
456 gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer)
457 {
458   GstFlowReturn res;
459   GstRTPDec *rtpdec;
460   GstRTPDecSession *session;
461   guint32 ssrc;
462   guint8 pt;
463   GstRTPBuffer rtp = { NULL, };
464
465   rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
466
467   GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
468
469   if (!gst_rtp_buffer_validate (buffer))
470     goto bad_packet;
471
472
473   gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
474   ssrc = gst_rtp_buffer_get_ssrc (&rtp);
475   pt = gst_rtp_buffer_get_payload_type (&rtp);
476   gst_rtp_buffer_unmap (&rtp);
477
478   GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
479
480   /* find session */
481   session = gst_pad_get_element_private (pad);
482
483   /* see if we have the pad */
484   if (!session->active) {
485     GstPadTemplate *templ;
486     GstElementClass *klass;
487     gchar *name;
488     GstCaps *caps;
489     GValue ret = { 0 };
490     GValue args[3] = { {0}
491     , {0}
492     , {0}
493     };
494
495     GST_DEBUG_OBJECT (rtpdec, "creating stream");
496
497     session->ssrc = ssrc;
498     session->pt = pt;
499
500     /* get pt map */
501     g_value_init (&args[0], GST_TYPE_ELEMENT);
502     g_value_set_object (&args[0], rtpdec);
503     g_value_init (&args[1], G_TYPE_UINT);
504     g_value_set_uint (&args[1], session->id);
505     g_value_init (&args[2], G_TYPE_UINT);
506     g_value_set_uint (&args[2], pt);
507
508     g_value_init (&ret, GST_TYPE_CAPS);
509     g_value_set_boxed (&ret, NULL);
510
511     g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
512
513     caps = (GstCaps *) g_value_get_boxed (&ret);
514
515     name = g_strdup_printf ("recv_rtp_src_%d_%u_%d", session->id, ssrc, pt);
516     klass = GST_ELEMENT_GET_CLASS (rtpdec);
517     templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
518     session->recv_rtp_src = gst_pad_new_from_template (templ, name);
519     g_free (name);
520
521     gst_pad_push_event (session->recv_rtp_src, gst_event_new_caps (caps));
522
523     gst_pad_set_element_private (session->recv_rtp_src, session);
524     gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
525     gst_pad_set_active (session->recv_rtp_src, TRUE);
526     gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
527
528     session->active = TRUE;
529   }
530
531   res = gst_pad_push (session->recv_rtp_src, buffer);
532
533   return res;
534
535 bad_packet:
536   {
537     GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
538         ("RTP packet did not validate, dropping"));
539     gst_buffer_unref (buffer);
540     return GST_FLOW_OK;
541   }
542 }
543
544 static GstFlowReturn
545 gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
546 {
547   GstRTPDec *src;
548
549 #ifdef HAVE_RTCP
550   gboolean valid;
551   GstRTCPPacket packet;
552   gboolean more;
553 #endif
554
555   src = GST_RTP_DEC (GST_PAD_PARENT (pad));
556
557   GST_DEBUG_OBJECT (src, "got rtcp packet");
558
559 #ifdef HAVE_RTCP
560   valid = gst_rtcp_buffer_validate (buffer);
561   if (!valid)
562     goto bad_packet;
563
564   /* position on first packet */
565   more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
566   while (more) {
567     switch (gst_rtcp_packet_get_type (&packet)) {
568       case GST_RTCP_TYPE_SR:
569       {
570         guint32 ssrc, rtptime, packet_count, octet_count;
571         guint64 ntptime;
572         guint count, i;
573
574         gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
575             &packet_count, &octet_count);
576
577         GST_DEBUG_OBJECT (src,
578             "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
579             ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
580             octet_count);
581
582         count = gst_rtcp_packet_get_rb_count (&packet);
583         for (i = 0; i < count; i++) {
584           guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
585           guint8 fractionlost;
586           gint32 packetslost;
587
588           gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
589               &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
590
591           GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
592               ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
593               packetslost, exthighestseq, jitter, lsr, dlsr);
594         }
595         break;
596       }
597       case GST_RTCP_TYPE_RR:
598       {
599         guint32 ssrc;
600         guint count, i;
601
602         ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
603
604         GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
605
606         count = gst_rtcp_packet_get_rb_count (&packet);
607         for (i = 0; i < count; i++) {
608           guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
609           guint8 fractionlost;
610           gint32 packetslost;
611
612           gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
613               &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
614
615           GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
616               ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
617               packetslost, exthighestseq, jitter, lsr, dlsr);
618         }
619         break;
620       }
621       case GST_RTCP_TYPE_SDES:
622       {
623         guint chunks, i, j;
624         gboolean more_chunks, more_items;
625
626         chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
627         GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
628
629         more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
630         i = 0;
631         while (more_chunks) {
632           guint32 ssrc;
633
634           ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
635
636           GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
637
638           more_items = gst_rtcp_packet_sdes_first_item (&packet);
639           j = 0;
640           while (more_items) {
641             GstRTCPSDESType type;
642             guint8 len;
643             gchar *data;
644
645             gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
646
647             GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
648                 type, len, data);
649
650             more_items = gst_rtcp_packet_sdes_next_item (&packet);
651             j++;
652           }
653           more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
654           i++;
655         }
656         break;
657       }
658       case GST_RTCP_TYPE_BYE:
659       {
660         guint count, i;
661         gchar *reason;
662
663         reason = gst_rtcp_packet_bye_get_reason (&packet);
664         GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
665             GST_STR_NULL (reason));
666         g_free (reason);
667
668         count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
669         for (i = 0; i < count; i++) {
670           guint32 ssrc;
671
672
673           ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
674
675           GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
676         }
677         break;
678       }
679       case GST_RTCP_TYPE_APP:
680         GST_DEBUG_OBJECT (src, "got APP packet");
681         break;
682       default:
683         GST_WARNING_OBJECT (src, "got unknown RTCP packet");
684         break;
685     }
686     more = gst_rtcp_packet_move_to_next (&packet);
687   }
688   gst_buffer_unref (buffer);
689   return GST_FLOW_OK;
690
691 bad_packet:
692   {
693     GST_WARNING_OBJECT (src, "got invalid RTCP packet");
694     gst_buffer_unref (buffer);
695     return GST_FLOW_OK;
696   }
697 #else
698   gst_buffer_unref (buffer);
699   return GST_FLOW_OK;
700 #endif
701 }
702
703 static void
704 gst_rtp_dec_set_property (GObject * object, guint prop_id,
705     const GValue * value, GParamSpec * pspec)
706 {
707   GstRTPDec *src;
708
709   src = GST_RTP_DEC (object);
710
711   switch (prop_id) {
712     case PROP_LATENCY:
713       src->latency = g_value_get_uint (value);
714       break;
715     default:
716       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
717       break;
718   }
719 }
720
721 static void
722 gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
723     GParamSpec * pspec)
724 {
725   GstRTPDec *src;
726
727   src = GST_RTP_DEC (object);
728
729   switch (prop_id) {
730     case PROP_LATENCY:
731       g_value_set_uint (value, src->latency);
732       break;
733     default:
734       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
735       break;
736   }
737 }
738
739 static GstClock *
740 gst_rtp_dec_provide_clock (GstElement * element)
741 {
742   GstRTPDec *rtpdec;
743
744   rtpdec = GST_RTP_DEC (element);
745
746   return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
747 }
748
749 static GstStateChangeReturn
750 gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
751 {
752   GstStateChangeReturn ret;
753
754   switch (transition) {
755     default:
756       break;
757   }
758
759   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
760
761   switch (transition) {
762     case GST_STATE_CHANGE_READY_TO_PAUSED:
763     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
764       /* we're NO_PREROLL when going to PAUSED */
765       ret = GST_STATE_CHANGE_NO_PREROLL;
766       break;
767     default:
768       break;
769   }
770
771   return ret;
772 }
773
774 /* Create a pad for receiving RTP for the session in @name
775  */
776 static GstPad *
777 create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
778 {
779   guint sessid;
780   GstRTPDecSession *session;
781
782   /* first get the session number */
783   if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
784     goto no_name;
785
786   GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
787
788   /* get or create session */
789   session = find_session_by_id (rtpdec, sessid);
790   if (!session) {
791     GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
792     /* create session now */
793     session = create_session (rtpdec, sessid);
794     if (session == NULL)
795       goto create_error;
796   }
797   /* check if pad was requested */
798   if (session->recv_rtp_sink != NULL)
799     goto existed;
800
801   GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
802
803   session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
804   gst_pad_set_element_private (session->recv_rtp_sink, session);
805   gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
806   gst_pad_set_active (session->recv_rtp_sink, TRUE);
807   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
808
809   return session->recv_rtp_sink;
810
811   /* ERRORS */
812 no_name:
813   {
814     g_warning ("rtpdec: invalid name given");
815     return NULL;
816   }
817 create_error:
818   {
819     /* create_session already warned */
820     return NULL;
821   }
822 existed:
823   {
824     g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
825     return NULL;
826   }
827 }
828
829 /* Create a pad for receiving RTCP for the session in @name
830  */
831 static GstPad *
832 create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
833     const gchar * name)
834 {
835   guint sessid;
836   GstRTPDecSession *session;
837
838   /* first get the session number */
839   if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
840     goto no_name;
841
842   GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
843
844   /* get the session, it must exist or we error */
845   session = find_session_by_id (rtpdec, sessid);
846   if (!session)
847     goto no_session;
848
849   /* check if pad was requested */
850   if (session->recv_rtcp_sink != NULL)
851     goto existed;
852
853   GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
854
855   session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
856   gst_pad_set_element_private (session->recv_rtp_sink, session);
857   gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
858   gst_pad_set_active (session->recv_rtcp_sink, TRUE);
859   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
860
861   return session->recv_rtcp_sink;
862
863   /* ERRORS */
864 no_name:
865   {
866     g_warning ("rtpdec: invalid name given");
867     return NULL;
868   }
869 no_session:
870   {
871     g_warning ("rtpdec: no session with id %d", sessid);
872     return NULL;
873   }
874 existed:
875   {
876     g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
877         sessid);
878     return NULL;
879   }
880 }
881
882 /* Create a pad for sending RTCP for the session in @name
883  */
884 static GstPad *
885 create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
886 {
887   guint sessid;
888   GstRTPDecSession *session;
889
890   /* first get the session number */
891   if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
892     goto no_name;
893
894   /* get or create session */
895   session = find_session_by_id (rtpdec, sessid);
896   if (!session)
897     goto no_session;
898
899   /* check if pad was requested */
900   if (session->rtcp_src != NULL)
901     goto existed;
902
903   session->rtcp_src = gst_pad_new_from_template (templ, name);
904   gst_pad_set_active (session->rtcp_src, TRUE);
905   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
906
907   return session->rtcp_src;
908
909   /* ERRORS */
910 no_name:
911   {
912     g_warning ("rtpdec: invalid name given");
913     return NULL;
914   }
915 no_session:
916   {
917     g_warning ("rtpdec: session with id %d does not exist", sessid);
918     return NULL;
919   }
920 existed:
921   {
922     g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
923     return NULL;
924   }
925 }
926
927 /* 
928  */
929 static GstPad *
930 gst_rtp_dec_request_new_pad (GstElement * element,
931     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
932 {
933   GstRTPDec *rtpdec;
934   GstElementClass *klass;
935   GstPad *result;
936
937   g_return_val_if_fail (templ != NULL, NULL);
938   g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
939
940   rtpdec = GST_RTP_DEC (element);
941   klass = GST_ELEMENT_GET_CLASS (element);
942
943   /* figure out the template */
944   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
945     result = create_recv_rtp (rtpdec, templ, name);
946   } else if (templ == gst_element_class_get_pad_template (klass,
947           "recv_rtcp_sink_%d")) {
948     result = create_recv_rtcp (rtpdec, templ, name);
949   } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
950     result = create_rtcp (rtpdec, templ, name);
951   } else
952     goto wrong_template;
953
954   return result;
955
956   /* ERRORS */
957 wrong_template:
958   {
959     g_warning ("rtpdec: this is not our template");
960     return NULL;
961   }
962 }
963
964 static void
965 gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
966 {
967 }