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