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