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