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