2 * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.com>
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.
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.
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.
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
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:
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
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
42 /* Element-Checklist-Version: 5 */
45 * SECTION:element-rtpdec
47 * A simple RTP session manager used internally by rtspsrc.
49 * Last reviewed on 2006-06-20 (0.10.4)
52 /* #define HAVE_RTCP */
54 #include <gst/rtp/gstrtpbuffer.h>
57 #include <gst/rtp/gstrtcpbuffer.h>
60 #include "gstrtpdec.h"
63 GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
64 #define GST_CAT_DEFAULT (rtpdec_debug)
66 /* GstRTPDec signals and args */
69 SIGNAL_REQUEST_PT_MAP,
73 SIGNAL_ON_SSRC_COLLISION,
74 SIGNAL_ON_SSRC_VALIDATED,
76 SIGNAL_ON_BYE_TIMEOUT,
81 #define DEFAULT_LATENCY_MS 200
89 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
93 GST_STATIC_CAPS ("application/x-rtp")
96 static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
97 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
100 GST_STATIC_CAPS ("application/x-rtcp")
103 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
104 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
107 GST_STATIC_CAPS ("application/x-rtp")
110 static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
111 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
114 GST_STATIC_CAPS ("application/x-rtcp")
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);
123 static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
124 static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
125 GstStateChange transition);
126 static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
127 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
128 static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
130 static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer);
131 static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
134 /* Manages the receiving end of the packets.
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.
139 struct _GstRTPDecSession
147 /* we only support one ssrc and one pt */
152 /* the pads of the session */
153 GstPad *recv_rtp_sink;
154 GstPad *recv_rtp_src;
155 GstPad *recv_rtcp_sink;
159 /* find a session with the given id */
160 static GstRTPDecSession *
161 find_session_by_id (GstRTPDec * rtpdec, gint id)
165 for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
166 GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
174 /* create a session with the given id */
175 static GstRTPDecSession *
176 create_session (GstRTPDec * rtpdec, gint id)
178 GstRTPDecSession *sess;
180 sess = g_new0 (GstRTPDecSession, 1);
183 rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
189 free_session (GstRTPDecSession * session)
194 static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
196 #define gst_rtp_dec_parent_class parent_class
197 G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
200 /* BOXED:UINT,UINT */
201 #define g_marshal_value_peek_uint(v) g_value_get_uint (v)
204 gst_rtp_dec_marshal_BOXED__UINT_UINT (GClosure * closure,
205 GValue * return_value,
206 guint n_param_values,
207 const GValue * param_values,
208 gpointer invocation_hint, gpointer marshal_data)
210 typedef gpointer (*GMarshalFunc_BOXED__UINT_UINT) (gpointer data1,
211 guint arg_1, guint arg_2, gpointer data2);
212 register GMarshalFunc_BOXED__UINT_UINT callback;
213 register GCClosure *cc = (GCClosure *) closure;
214 register gpointer data1, data2;
217 g_return_if_fail (return_value != NULL);
218 g_return_if_fail (n_param_values == 3);
220 if (G_CCLOSURE_SWAP_DATA (closure)) {
221 data1 = closure->data;
222 data2 = g_value_peek_pointer (param_values + 0);
224 data1 = g_value_peek_pointer (param_values + 0);
225 data2 = closure->data;
228 (GMarshalFunc_BOXED__UINT_UINT) (marshal_data ? marshal_data :
231 v_return = callback (data1,
232 g_marshal_value_peek_uint (param_values + 1),
233 g_marshal_value_peek_uint (param_values + 2), data2);
235 g_value_take_boxed (return_value, v_return);
239 gst_rtp_dec_marshal_VOID__UINT_UINT (GClosure * closure,
240 GValue * return_value,
241 guint n_param_values,
242 const GValue * param_values,
243 gpointer invocation_hint, gpointer marshal_data)
245 typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
246 guint arg_1, guint arg_2, gpointer data2);
247 register GMarshalFunc_VOID__UINT_UINT callback;
248 register GCClosure *cc = (GCClosure *) closure;
249 register gpointer data1, data2;
251 g_return_if_fail (n_param_values == 3);
253 if (G_CCLOSURE_SWAP_DATA (closure)) {
254 data1 = closure->data;
255 data2 = g_value_peek_pointer (param_values + 0);
257 data1 = g_value_peek_pointer (param_values + 0);
258 data2 = closure->data;
261 (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data :
265 g_marshal_value_peek_uint (param_values + 1),
266 g_marshal_value_peek_uint (param_values + 2), data2);
270 gst_rtp_dec_class_init (GstRTPDecClass * g_class)
272 GObjectClass *gobject_class;
273 GstElementClass *gstelement_class;
274 GstRTPDecClass *klass;
276 klass = (GstRTPDecClass *) g_class;
277 gobject_class = (GObjectClass *) klass;
278 gstelement_class = (GstElementClass *) klass;
280 GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
282 gobject_class->finalize = gst_rtp_dec_finalize;
283 gobject_class->set_property = gst_rtp_dec_set_property;
284 gobject_class->get_property = gst_rtp_dec_get_property;
286 g_object_class_install_property (gobject_class, PROP_LATENCY,
287 g_param_spec_uint ("latency", "Buffer latency in ms",
288 "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
289 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
292 * GstRTPDec::request-pt-map:
293 * @rtpdec: the object which received the signal
294 * @session: the session
297 * Request the payload type as #GstCaps for @pt in @session.
299 gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
300 g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
301 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map),
302 NULL, NULL, gst_rtp_dec_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
303 G_TYPE_UINT, G_TYPE_UINT);
305 gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
306 g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
307 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map),
308 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
311 * GstRTPDec::on-new-ssrc:
312 * @rtpbin: the object which received the signal
313 * @session: the session
316 * Notify of a new SSRC that entered @session.
318 gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
319 g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
320 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc),
321 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
322 G_TYPE_UINT, G_TYPE_UINT);
324 * GstRTPDec::on-ssrc_collision:
325 * @rtpbin: the object which received the signal
326 * @session: the session
329 * Notify when we have an SSRC collision
331 gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
332 g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
333 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
334 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
335 G_TYPE_UINT, G_TYPE_UINT);
337 * GstRTPDec::on-ssrc_validated:
338 * @rtpbin: the object which received the signal
339 * @session: the session
342 * Notify of a new SSRC that became validated.
344 gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
345 g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
346 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
347 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
348 G_TYPE_UINT, G_TYPE_UINT);
351 * GstRTPDec::on-bye-ssrc:
352 * @rtpbin: the object which received the signal
353 * @session: the session
356 * Notify of an SSRC that became inactive because of a BYE packet.
358 gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
359 g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
360 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc),
361 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
362 G_TYPE_UINT, G_TYPE_UINT);
364 * GstRTPDec::on-bye-timeout:
365 * @rtpbin: the object which received the signal
366 * @session: the session
369 * Notify of an SSRC that has timed out because of BYE
371 gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
372 g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
373 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
374 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
375 G_TYPE_UINT, G_TYPE_UINT);
377 * GstRTPDec::on-timeout:
378 * @rtpbin: the object which received the signal
379 * @session: the session
382 * Notify of an SSRC that has timed out
384 gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
385 g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
386 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout),
387 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
388 G_TYPE_UINT, G_TYPE_UINT);
391 gstelement_class->provide_clock =
392 GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
393 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
394 gstelement_class->request_new_pad =
395 GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
396 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
399 gst_element_class_add_pad_template (gstelement_class,
400 gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_sink_template));
401 gst_element_class_add_pad_template (gstelement_class,
402 gst_static_pad_template_get (&gst_rtp_dec_recv_rtcp_sink_template));
404 gst_element_class_add_pad_template (gstelement_class,
405 gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_src_template));
406 gst_element_class_add_pad_template (gstelement_class,
407 gst_static_pad_template_get (&gst_rtp_dec_rtcp_src_template));
409 gst_element_class_set_details_simple (gstelement_class, "RTP Decoder",
410 "Codec/Parser/Network",
411 "Accepts raw RTP and RTCP packets and sends them forward",
412 "Wim Taymans <wim.taymans@gmail.com>");
416 gst_rtp_dec_init (GstRTPDec * rtpdec)
418 rtpdec->provided_clock = gst_system_clock_obtain ();
419 rtpdec->latency = DEFAULT_LATENCY_MS;
423 gst_rtp_dec_finalize (GObject * object)
427 rtpdec = GST_RTP_DEC (object);
429 g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
430 g_slist_free (rtpdec->sessions);
432 G_OBJECT_CLASS (parent_class)->finalize (object);
436 gst_rtp_dec_query_src (GstPad * pad, GstQuery * query)
440 switch (GST_QUERY_TYPE (query)) {
441 case GST_QUERY_LATENCY:
443 /* we pretend to be live with a 3 second latency */
444 gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
449 res = gst_pad_query_default (pad, query);
456 gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer)
460 GstRTPDecSession *session;
463 GstRTPBuffer rtp = { NULL, };
465 rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
467 GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
469 if (!gst_rtp_buffer_validate (buffer))
473 gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
474 ssrc = gst_rtp_buffer_get_ssrc (&rtp);
475 pt = gst_rtp_buffer_get_payload_type (&rtp);
476 gst_rtp_buffer_unmap (&rtp);
478 GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
481 session = gst_pad_get_element_private (pad);
483 /* see if we have the pad */
484 if (!session->active) {
485 GstPadTemplate *templ;
486 GstElementClass *klass;
490 GValue args[3] = { {0}
495 GST_DEBUG_OBJECT (rtpdec, "creating stream");
497 session->ssrc = ssrc;
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);
508 g_value_init (&ret, GST_TYPE_CAPS);
509 g_value_set_boxed (&ret, NULL);
511 g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
513 caps = (GstCaps *) g_value_get_boxed (&ret);
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);
521 gst_pad_push_event (session->recv_rtp_src, gst_event_new_caps (caps));
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);
528 session->active = TRUE;
531 res = gst_pad_push (session->recv_rtp_src, buffer);
537 GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
538 ("RTP packet did not validate, dropping"));
539 gst_buffer_unref (buffer);
545 gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
551 GstRTCPPacket packet;
555 src = GST_RTP_DEC (GST_PAD_PARENT (pad));
557 GST_DEBUG_OBJECT (src, "got rtcp packet");
560 valid = gst_rtcp_buffer_validate (buffer);
564 /* position on first packet */
565 more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
567 switch (gst_rtcp_packet_get_type (&packet)) {
568 case GST_RTCP_TYPE_SR:
570 guint32 ssrc, rtptime, packet_count, octet_count;
574 gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
575 &packet_count, &octet_count);
577 GST_DEBUG_OBJECT (src,
578 "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
579 ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
582 count = gst_rtcp_packet_get_rb_count (&packet);
583 for (i = 0; i < count; i++) {
584 guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
588 gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
589 &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
591 GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
592 ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
593 packetslost, exthighestseq, jitter, lsr, dlsr);
597 case GST_RTCP_TYPE_RR:
602 ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
604 GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
606 count = gst_rtcp_packet_get_rb_count (&packet);
607 for (i = 0; i < count; i++) {
608 guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
612 gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
613 &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
615 GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
616 ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
617 packetslost, exthighestseq, jitter, lsr, dlsr);
621 case GST_RTCP_TYPE_SDES:
624 gboolean more_chunks, more_items;
626 chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
627 GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
629 more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
631 while (more_chunks) {
634 ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
636 GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
638 more_items = gst_rtcp_packet_sdes_first_item (&packet);
641 GstRTCPSDESType type;
645 gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
647 GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
650 more_items = gst_rtcp_packet_sdes_next_item (&packet);
653 more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
658 case GST_RTCP_TYPE_BYE:
663 reason = gst_rtcp_packet_bye_get_reason (&packet);
664 GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
665 GST_STR_NULL (reason));
668 count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
669 for (i = 0; i < count; i++) {
673 ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
675 GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
679 case GST_RTCP_TYPE_APP:
680 GST_DEBUG_OBJECT (src, "got APP packet");
683 GST_WARNING_OBJECT (src, "got unknown RTCP packet");
686 more = gst_rtcp_packet_move_to_next (&packet);
688 gst_buffer_unref (buffer);
693 GST_WARNING_OBJECT (src, "got invalid RTCP packet");
694 gst_buffer_unref (buffer);
698 gst_buffer_unref (buffer);
704 gst_rtp_dec_set_property (GObject * object, guint prop_id,
705 const GValue * value, GParamSpec * pspec)
709 src = GST_RTP_DEC (object);
713 src->latency = g_value_get_uint (value);
716 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
722 gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
727 src = GST_RTP_DEC (object);
731 g_value_set_uint (value, src->latency);
734 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
740 gst_rtp_dec_provide_clock (GstElement * element)
744 rtpdec = GST_RTP_DEC (element);
746 return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
749 static GstStateChangeReturn
750 gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
752 GstStateChangeReturn ret;
754 switch (transition) {
759 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
761 switch (transition) {
762 case GST_STATE_CHANGE_READY_TO_PAUSED:
763 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
764 /* we're NO_PREROLL when going to PAUSED */
765 ret = GST_STATE_CHANGE_NO_PREROLL;
774 /* Create a pad for receiving RTP for the session in @name
777 create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
780 GstRTPDecSession *session;
782 /* first get the session number */
783 if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
786 GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
788 /* get or create session */
789 session = find_session_by_id (rtpdec, sessid);
791 GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
792 /* create session now */
793 session = create_session (rtpdec, sessid);
797 /* check if pad was requested */
798 if (session->recv_rtp_sink != NULL)
801 GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
803 session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
804 gst_pad_set_element_private (session->recv_rtp_sink, session);
805 gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
806 gst_pad_set_active (session->recv_rtp_sink, TRUE);
807 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
809 return session->recv_rtp_sink;
814 g_warning ("rtpdec: invalid name given");
819 /* create_session already warned */
824 g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
829 /* Create a pad for receiving RTCP for the session in @name
832 create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
836 GstRTPDecSession *session;
838 /* first get the session number */
839 if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
842 GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
844 /* get the session, it must exist or we error */
845 session = find_session_by_id (rtpdec, sessid);
849 /* check if pad was requested */
850 if (session->recv_rtcp_sink != NULL)
853 GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
855 session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
856 gst_pad_set_element_private (session->recv_rtp_sink, session);
857 gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
858 gst_pad_set_active (session->recv_rtcp_sink, TRUE);
859 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
861 return session->recv_rtcp_sink;
866 g_warning ("rtpdec: invalid name given");
871 g_warning ("rtpdec: no session with id %d", sessid);
876 g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
882 /* Create a pad for sending RTCP for the session in @name
885 create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
888 GstRTPDecSession *session;
890 /* first get the session number */
891 if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
894 /* get or create session */
895 session = find_session_by_id (rtpdec, sessid);
899 /* check if pad was requested */
900 if (session->rtcp_src != NULL)
903 session->rtcp_src = gst_pad_new_from_template (templ, name);
904 gst_pad_set_active (session->rtcp_src, TRUE);
905 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
907 return session->rtcp_src;
912 g_warning ("rtpdec: invalid name given");
917 g_warning ("rtpdec: session with id %d does not exist", sessid);
922 g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
930 gst_rtp_dec_request_new_pad (GstElement * element,
931 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
934 GstElementClass *klass;
937 g_return_val_if_fail (templ != NULL, NULL);
938 g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
940 rtpdec = GST_RTP_DEC (element);
941 klass = GST_ELEMENT_GET_CLASS (element);
943 /* figure out the template */
944 if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
945 result = create_recv_rtp (rtpdec, templ, name);
946 } else if (templ == gst_element_class_get_pad_template (klass,
947 "recv_rtcp_sink_%d")) {
948 result = create_recv_rtcp (rtpdec, templ, name);
949 } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
950 result = create_rtcp (rtpdec, templ, name);
959 g_warning ("rtpdec: this is not our template");
965 gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)