2 * Copyright (C) <2007> 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.
21 * SECTION:element-gstrtpbin
22 * @see_also: gstrtpjitterbuffer, gstrtpsession, gstrtpptdemux, gstrtpssrcdemux
24 * RTP bin combines the functions of #GstRtpSession, #GstRtpSsrcDemux,
25 * #GstRtpJitterBuffer and #GstRtpPtDemux in one element. It allows for multiple
26 * RTP sessions that will be synchronized together using RTCP SR packets.
28 * #GstRtpBin is configured with a number of request pads that define the
29 * functionality that is activated, similar to the #GstRtpSession element.
31 * To use #GstRtpBin as an RTP receiver, request a recv_rtp_sink_\%d pad. The session
32 * number must be specified in the pad name.
33 * Data received on the recv_rtp_sink_\%d pad will be processed in the #GstRtpSession
34 * manager and after being validated forwarded on #GstRtpSsrcDemux element. Each
35 * RTP stream is demuxed based on the SSRC and send to a #GstRtpJitterBuffer. After
36 * the packets are released from the jitterbuffer, they will be forwarded to a
37 * #GstRtpPtDemux element. The #GstRtpPtDemux element will demux the packets based
38 * on the payload type and will create a unique pad recv_rtp_src_\%d_\%d_\%d on
39 * gstrtpbin with the session number, SSRC and payload type respectively as the pad
42 * To also use #GstRtpBin as an RTCP receiver, request a recv_rtcp_sink_\%d pad. The
43 * session number must be specified in the pad name.
45 * If you want the session manager to generate and send RTCP packets, request
46 * the send_rtcp_src_\%d pad with the session number in the pad name. Packet pushed
47 * on this pad contain SR/RR RTCP reports that should be sent to all participants
50 * To use #GstRtpBin as a sender, request a send_rtp_sink_\%d pad, which will
51 * automatically create a send_rtp_src_\%d pad. If the session number is not provided,
52 * the pad from the lowest available session will be returned. The session manager will modify the
53 * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
54 * send_rtp_src_\%d pad after updating its internal state.
56 * The session manager needs the clock-rate of the payload types it is handling
57 * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
58 * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
61 * Access to the internal statistics of gstrtpbin is provided with the
62 * get-internal-session property. This action signal gives access to the
63 * RTPSession object which further provides action signals to retrieve the
64 * internal source and other sources.
67 * <title>Example pipelines</title>
69 * gst-launch udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink_0 \
70 * gstrtpbin ! rtptheoradepay ! theoradec ! xvimagesink
71 * ]| Receive RTP data from port 5000 and send to the session 0 in gstrtpbin.
73 * gst-launch gstrtpbin name=rtpbin \
74 * v4l2src ! ffmpegcolorspace ! ffenc_h263 ! rtph263ppay ! rtpbin.send_rtp_sink_0 \
75 * rtpbin.send_rtp_src_0 ! udpsink port=5000 \
76 * rtpbin.send_rtcp_src_0 ! udpsink port=5001 sync=false async=false \
77 * udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0 \
78 * audiotestsrc ! amrnbenc ! rtpamrpay ! rtpbin.send_rtp_sink_1 \
79 * rtpbin.send_rtp_src_1 ! udpsink port=5002 \
80 * rtpbin.send_rtcp_src_1 ! udpsink port=5003 sync=false async=false \
81 * udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
82 * ]| Encode and payload H263 video captured from a v4l2src. Encode and payload AMR
83 * audio generated from audiotestsrc. The video is sent to session 0 in rtpbin
84 * and the audio is sent to session 1. Video packets are sent on UDP port 5000
85 * and audio packets on port 5002. The video RTCP packets for session 0 are sent
86 * on port 5001 and the audio RTCP packets for session 0 are sent on port 5003.
87 * RTCP packets for session 0 are received on port 5005 and RTCP for session 1
88 * is received on port 5007. Since RTCP packets from the sender should be sent
89 * as soon as possible and do not participate in preroll, sync=false and
90 * async=false is configured on udpsink
92 * gst-launch -v gstrtpbin name=rtpbin \
93 * udpsrc caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998" \
94 * port=5000 ! rtpbin.recv_rtp_sink_0 \
95 * rtpbin. ! rtph263pdepay ! ffdec_h263 ! xvimagesink \
96 * udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0 \
97 * rtpbin.send_rtcp_src_0 ! udpsink port=5005 sync=false async=false \
98 * udpsrc caps="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)AMR,encoding-params=(string)1,octet-align=(string)1" \
99 * port=5002 ! rtpbin.recv_rtp_sink_1 \
100 * rtpbin. ! rtpamrdepay ! amrnbdec ! alsasink \
101 * udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1 \
102 * rtpbin.send_rtcp_src_1 ! udpsink port=5007 sync=false async=false
103 * ]| Receive H263 on port 5000, send it through rtpbin in session 0, depayload,
104 * decode and display the video.
105 * Receive AMR on port 5002, send it through rtpbin in session 1, depayload,
106 * decode and play the audio.
107 * Receive server RTCP packets for session 0 on port 5001 and RTCP packets for
108 * session 1 on port 5003. These packets will be used for session management and
110 * Send RTCP reports for session 0 on port 5005 and RTCP reports for session 1
114 * Last reviewed on 2007-08-30 (0.10.6)
123 #include <gst/rtp/gstrtpbuffer.h>
124 #include <gst/rtp/gstrtcpbuffer.h>
126 #include "gstrtpbin-marshal.h"
127 #include "gstrtpbin.h"
128 #include "rtpsession.h"
129 #include "gstrtpsession.h"
130 #include "gstrtpjitterbuffer.h"
132 GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
133 #define GST_CAT_DEFAULT gst_rtp_bin_debug
136 static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
137 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
140 GST_STATIC_CAPS ("application/x-rtp")
143 static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
144 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
147 GST_STATIC_CAPS ("application/x-rtcp")
150 static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
151 GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%d",
154 GST_STATIC_CAPS ("application/x-rtp")
158 static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
159 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
162 GST_STATIC_CAPS ("application/x-rtp")
165 static GstStaticPadTemplate rtpbin_send_rtcp_src_template =
166 GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%d",
169 GST_STATIC_CAPS ("application/x-rtcp")
172 static GstStaticPadTemplate rtpbin_send_rtp_src_template =
173 GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%d",
176 GST_STATIC_CAPS ("application/x-rtp")
179 #define GST_RTP_BIN_GET_PRIVATE(obj) \
180 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRtpBinPrivate))
182 #define GST_RTP_BIN_LOCK(bin) g_mutex_lock ((bin)->priv->bin_lock)
183 #define GST_RTP_BIN_UNLOCK(bin) g_mutex_unlock ((bin)->priv->bin_lock)
185 /* lock to protect dynamic callbacks, like pad-added and new ssrc. */
186 #define GST_RTP_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->priv->dyn_lock)
187 #define GST_RTP_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->priv->dyn_lock)
189 /* lock for shutdown */
190 #define GST_RTP_BIN_SHUTDOWN_LOCK(bin,label) \
192 if (g_atomic_int_get (&bin->priv->shutdown)) \
194 GST_RTP_BIN_DYN_LOCK (bin); \
195 if (g_atomic_int_get (&bin->priv->shutdown)) { \
196 GST_RTP_BIN_DYN_UNLOCK (bin); \
201 /* unlock for shutdown */
202 #define GST_RTP_BIN_SHUTDOWN_UNLOCK(bin) \
203 GST_RTP_BIN_DYN_UNLOCK (bin); \
205 struct _GstRtpBinPrivate
209 /* lock protecting dynamic adding/removing */
212 /* if we are shutting down or not */
217 /* UNIX (ntp) time of last SR sync used */
221 /* signals and args */
224 SIGNAL_REQUEST_PT_MAP,
225 SIGNAL_PAYLOAD_TYPE_CHANGE,
228 SIGNAL_GET_INTERNAL_SESSION,
231 SIGNAL_ON_SSRC_COLLISION,
232 SIGNAL_ON_SSRC_VALIDATED,
233 SIGNAL_ON_SSRC_ACTIVE,
236 SIGNAL_ON_BYE_TIMEOUT,
238 SIGNAL_ON_SENDER_TIMEOUT,
243 #define DEFAULT_LATENCY_MS 200
244 #define DEFAULT_SDES NULL
245 #define DEFAULT_DO_LOST FALSE
246 #define DEFAULT_IGNORE_PT FALSE
247 #define DEFAULT_NTP_SYNC FALSE
248 #define DEFAULT_AUTOREMOVE FALSE
249 #define DEFAULT_BUFFER_MODE RTP_JITTER_BUFFER_MODE_SLAVE
250 #define DEFAULT_USE_PIPELINE_CLOCK FALSE
251 #define DEFAULT_RTCP_SYNC_INTERVAL 0
261 PROP_RTCP_SYNC_INTERVAL,
264 PROP_USE_PIPELINE_CLOCK,
269 typedef struct _GstRtpBinSession GstRtpBinSession;
270 typedef struct _GstRtpBinStream GstRtpBinStream;
271 typedef struct _GstRtpBinClient GstRtpBinClient;
273 static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 };
275 static GstCaps *pt_map_requested (GstElement * element, guint pt,
276 GstRtpBinSession * session);
277 static void payload_type_change (GstElement * element, guint pt,
278 GstRtpBinSession * session);
279 static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
280 static void free_stream (GstRtpBinStream * stream);
282 /* Manages the RTP stream for one SSRC.
284 * We pipe the stream (comming from the SSRC demuxer) into a jitterbuffer.
285 * If we see an SDES RTCP packet that links multiple SSRCs together based on a
286 * common CNAME, we create a GstRtpBinClient structure to group the SSRCs
287 * together (see below).
289 struct _GstRtpBinStream
291 /* the SSRC of this stream */
297 /* the session this SSRC belongs to */
298 GstRtpBinSession *session;
300 /* the jitterbuffer of the SSRC */
302 gulong buffer_handlesync_sig;
303 gulong buffer_ptreq_sig;
304 gulong buffer_ntpstop_sig;
307 /* the PT demuxer of the SSRC */
309 gulong demux_newpad_sig;
310 gulong demux_padremoved_sig;
311 gulong demux_ptreq_sig;
312 gulong demux_ptchange_sig;
314 /* if we have calculated a valid rt_delta for this stream */
316 /* mapping to local RTP and NTP time */
320 #define GST_RTP_SESSION_LOCK(sess) g_mutex_lock ((sess)->lock)
321 #define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock ((sess)->lock)
323 /* Manages the receiving end of the packets.
325 * There is one such structure for each RTP session (audio/video/...).
326 * We get the RTP/RTCP packets and stuff them into the session manager. From
327 * there they are pushed into an SSRC demuxer that splits the stream based on
328 * SSRC. Each of the SSRC streams go into their own jitterbuffer (managed with
329 * the GstRtpBinStream above).
331 struct _GstRtpBinSession
337 /* the session element */
339 /* the SSRC demuxer */
341 gulong demux_newpad_sig;
342 gulong demux_padremoved_sig;
346 /* list of GstRtpBinStream */
349 /* mapping of payload type to caps */
352 /* the pads of the session */
353 GstPad *recv_rtp_sink;
354 GstPad *recv_rtp_sink_ghost;
355 GstPad *recv_rtp_src;
356 GstPad *recv_rtcp_sink;
357 GstPad *recv_rtcp_sink_ghost;
359 GstPad *send_rtp_sink;
360 GstPad *send_rtp_sink_ghost;
361 GstPad *send_rtp_src;
362 GstPad *send_rtp_src_ghost;
363 GstPad *send_rtcp_src;
364 GstPad *send_rtcp_src_ghost;
367 /* Manages the RTP streams that come from one client and should therefore be
370 struct _GstRtpBinClient
372 /* the common CNAME for the streams */
381 /* find a session with the given id. Must be called with RTP_BIN_LOCK */
382 static GstRtpBinSession *
383 find_session_by_id (GstRtpBin * rtpbin, gint id)
387 for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
388 GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
396 /* find a session with the given request pad. Must be called with RTP_BIN_LOCK */
397 static GstRtpBinSession *
398 find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad)
402 for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
403 GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
405 if ((sess->recv_rtp_sink_ghost == pad) ||
406 (sess->recv_rtcp_sink_ghost == pad) ||
407 (sess->send_rtp_sink_ghost == pad)
408 || (sess->send_rtcp_src_ghost == pad))
415 on_new_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
417 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC], 0,
422 on_ssrc_collision (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
424 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION], 0,
429 on_ssrc_validated (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
431 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
436 on_ssrc_active (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
438 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE], 0,
443 on_ssrc_sdes (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
445 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES], 0,
450 on_bye_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
452 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC], 0,
457 on_bye_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
459 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT], 0,
462 if (sess->bin->priv->autoremove)
463 g_signal_emit_by_name (sess->demux, "clear-ssrc", ssrc, NULL);
467 on_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
469 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT], 0,
472 if (sess->bin->priv->autoremove)
473 g_signal_emit_by_name (sess->demux, "clear-ssrc", ssrc, NULL);
477 on_sender_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
479 g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
484 on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream)
486 g_signal_emit (stream->bin, gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP], 0,
487 stream->session->id, stream->ssrc);
490 /* must be called with the SESSION lock */
491 static GstRtpBinStream *
492 find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
496 for (walk = session->streams; walk; walk = g_slist_next (walk)) {
497 GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
499 if (stream->ssrc == ssrc)
506 ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
507 GstRtpBinSession * session)
509 GstRtpBinStream *stream = NULL;
511 GST_RTP_SESSION_LOCK (session);
512 if ((stream = find_stream_by_ssrc (session, ssrc)))
513 session->streams = g_slist_remove (session->streams, stream);
514 GST_RTP_SESSION_UNLOCK (session);
517 free_stream (stream);
520 /* create a session with the given id. Must be called with RTP_BIN_LOCK */
521 static GstRtpBinSession *
522 create_session (GstRtpBin * rtpbin, gint id)
524 GstRtpBinSession *sess;
525 GstElement *session, *demux;
528 if (!(session = gst_element_factory_make ("gstrtpsession", NULL)))
531 if (!(demux = gst_element_factory_make ("gstrtpssrcdemux", NULL)))
534 sess = g_new0 (GstRtpBinSession, 1);
535 sess->lock = g_mutex_new ();
538 sess->session = session;
540 sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
541 (GDestroyNotify) gst_caps_unref);
542 rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
544 /* configure SDES items */
545 GST_OBJECT_LOCK (rtpbin);
546 g_object_set (session, "sdes", rtpbin->sdes, "use-pipeline-clock",
547 rtpbin->use_pipeline_clock, NULL);
548 GST_OBJECT_UNLOCK (rtpbin);
550 /* provide clock_rate to the session manager when needed */
551 g_signal_connect (session, "request-pt-map",
552 (GCallback) pt_map_requested, sess);
554 g_signal_connect (sess->session, "on-new-ssrc",
555 (GCallback) on_new_ssrc, sess);
556 g_signal_connect (sess->session, "on-ssrc-collision",
557 (GCallback) on_ssrc_collision, sess);
558 g_signal_connect (sess->session, "on-ssrc-validated",
559 (GCallback) on_ssrc_validated, sess);
560 g_signal_connect (sess->session, "on-ssrc-active",
561 (GCallback) on_ssrc_active, sess);
562 g_signal_connect (sess->session, "on-ssrc-sdes",
563 (GCallback) on_ssrc_sdes, sess);
564 g_signal_connect (sess->session, "on-bye-ssrc",
565 (GCallback) on_bye_ssrc, sess);
566 g_signal_connect (sess->session, "on-bye-timeout",
567 (GCallback) on_bye_timeout, sess);
568 g_signal_connect (sess->session, "on-timeout", (GCallback) on_timeout, sess);
569 g_signal_connect (sess->session, "on-sender-timeout",
570 (GCallback) on_sender_timeout, sess);
572 gst_bin_add (GST_BIN_CAST (rtpbin), session);
573 gst_bin_add (GST_BIN_CAST (rtpbin), demux);
575 GST_OBJECT_LOCK (rtpbin);
576 target = GST_STATE_TARGET (rtpbin);
577 GST_OBJECT_UNLOCK (rtpbin);
579 /* change state only to what's needed */
580 gst_element_set_state (demux, target);
581 gst_element_set_state (session, target);
588 g_warning ("gstrtpbin: could not create gstrtpsession element");
593 gst_object_unref (session);
594 g_warning ("gstrtpbin: could not create gstrtpssrcdemux element");
600 free_session (GstRtpBinSession * sess, GstRtpBin * bin)
604 GST_DEBUG_OBJECT (bin, "freeing session %p", sess);
606 gst_element_set_locked_state (sess->demux, TRUE);
607 gst_element_set_locked_state (sess->session, TRUE);
609 gst_element_set_state (sess->demux, GST_STATE_NULL);
610 gst_element_set_state (sess->session, GST_STATE_NULL);
612 if (sess->recv_rtp_sink != NULL) {
613 gst_element_release_request_pad (sess->session, sess->recv_rtp_sink);
614 gst_object_unref (sess->recv_rtp_sink);
616 if (sess->recv_rtp_src != NULL)
617 gst_object_unref (sess->recv_rtp_src);
618 if (sess->recv_rtcp_sink != NULL) {
619 gst_element_release_request_pad (sess->session, sess->recv_rtcp_sink);
620 gst_object_unref (sess->recv_rtcp_sink);
622 if (sess->sync_src != NULL)
623 gst_object_unref (sess->sync_src);
624 if (sess->send_rtp_sink != NULL) {
625 gst_element_release_request_pad (sess->session, sess->send_rtp_sink);
626 gst_object_unref (sess->send_rtp_sink);
628 if (sess->send_rtp_src != NULL)
629 gst_object_unref (sess->send_rtp_src);
630 if (sess->send_rtcp_src != NULL) {
631 gst_element_release_request_pad (sess->session, sess->send_rtcp_src);
632 gst_object_unref (sess->send_rtcp_src);
635 gst_bin_remove (GST_BIN_CAST (bin), sess->session);
636 gst_bin_remove (GST_BIN_CAST (bin), sess->demux);
638 /* remove any references in bin->clients to the streams in sess->streams */
639 client_walk = bin->clients;
640 while (client_walk) {
641 GSList *client_node = client_walk;
642 GstRtpBinClient *client = (GstRtpBinClient *) client_node->data;
643 GSList *stream_walk = client->streams;
645 while (stream_walk) {
646 GSList *stream_node = stream_walk;
647 GstRtpBinStream *stream = (GstRtpBinStream *) stream_node->data;
650 stream_walk = g_slist_next (stream_walk);
652 for (inner_walk = sess->streams; inner_walk;
653 inner_walk = g_slist_next (inner_walk)) {
654 if ((GstRtpBinStream *) inner_walk->data == stream) {
655 client->streams = g_slist_delete_link (client->streams, stream_node);
661 client_walk = g_slist_next (client_walk);
663 g_assert ((client->streams && client->nstreams > 0) || (!client->streams
664 && client->streams == 0));
665 if (client->nstreams == 0) {
666 free_client (client, bin);
667 bin->clients = g_slist_delete_link (bin->clients, client_node);
671 g_slist_foreach (sess->streams, (GFunc) free_stream, NULL);
672 g_slist_free (sess->streams);
674 g_mutex_free (sess->lock);
675 g_hash_table_destroy (sess->ptmap);
680 /* get the payload type caps for the specific payload @pt in @session */
682 get_pt_map (GstRtpBinSession * session, guint pt)
684 GstCaps *caps = NULL;
687 GValue args[3] = { {0}, {0}, {0} };
689 GST_DEBUG ("searching pt %d in cache", pt);
691 GST_RTP_SESSION_LOCK (session);
693 /* first look in the cache */
694 caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
702 GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
704 /* not in cache, send signal to request caps */
705 g_value_init (&args[0], GST_TYPE_ELEMENT);
706 g_value_set_object (&args[0], bin);
707 g_value_init (&args[1], G_TYPE_UINT);
708 g_value_set_uint (&args[1], session->id);
709 g_value_init (&args[2], G_TYPE_UINT);
710 g_value_set_uint (&args[2], pt);
712 g_value_init (&ret, GST_TYPE_CAPS);
713 g_value_set_boxed (&ret, NULL);
715 GST_RTP_SESSION_UNLOCK (session);
717 g_signal_emitv (args, gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
719 GST_RTP_SESSION_LOCK (session);
721 g_value_unset (&args[0]);
722 g_value_unset (&args[1]);
723 g_value_unset (&args[2]);
725 /* look in the cache again because we let the lock go */
726 caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
729 g_value_unset (&ret);
733 caps = (GstCaps *) g_value_dup_boxed (&ret);
734 g_value_unset (&ret);
738 GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
740 /* store in cache, take additional ref */
741 g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
742 gst_caps_ref (caps));
745 GST_RTP_SESSION_UNLOCK (session);
752 GST_RTP_SESSION_UNLOCK (session);
753 GST_DEBUG ("no pt map could be obtained");
759 return_true (gpointer key, gpointer value, gpointer user_data)
765 gst_rtp_bin_reset_sync (GstRtpBin * rtpbin)
767 GSList *clients, *streams;
769 GST_DEBUG_OBJECT (rtpbin, "Reset sync on all clients");
771 GST_RTP_BIN_LOCK (rtpbin);
772 for (clients = rtpbin->clients; clients; clients = g_slist_next (clients)) {
773 GstRtpBinClient *client = (GstRtpBinClient *) clients->data;
775 /* reset sync on all streams for this client */
776 for (streams = client->streams; streams; streams = g_slist_next (streams)) {
777 GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
779 /* make use require a new SR packet for this stream before we attempt new
781 stream->have_sync = FALSE;
782 stream->rt_delta = 0;
785 GST_RTP_BIN_UNLOCK (rtpbin);
789 gst_rtp_bin_clear_pt_map (GstRtpBin * bin)
791 GSList *sessions, *streams;
793 GST_RTP_BIN_LOCK (bin);
794 GST_DEBUG_OBJECT (bin, "clearing pt map");
795 for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
796 GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
798 GST_DEBUG_OBJECT (bin, "clearing session %p", session);
799 g_signal_emit_by_name (session->session, "clear-pt-map", NULL);
801 GST_RTP_SESSION_LOCK (session);
802 g_hash_table_foreach_remove (session->ptmap, return_true, NULL);
804 for (streams = session->streams; streams; streams = g_slist_next (streams)) {
805 GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
807 GST_DEBUG_OBJECT (bin, "clearing stream %p", stream);
808 g_signal_emit_by_name (stream->buffer, "clear-pt-map", NULL);
810 g_signal_emit_by_name (stream->demux, "clear-pt-map", NULL);
812 GST_RTP_SESSION_UNLOCK (session);
814 GST_RTP_BIN_UNLOCK (bin);
817 gst_rtp_bin_reset_sync (bin);
821 gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
823 RTPSession *internal_session = NULL;
824 GstRtpBinSession *session;
826 GST_RTP_BIN_LOCK (bin);
827 GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %d",
829 session = find_session_by_id (bin, (gint) session_id);
831 g_object_get (session->session, "internal-session", &internal_session,
834 GST_RTP_BIN_UNLOCK (bin);
836 return internal_session;
840 gst_rtp_bin_propagate_property_to_jitterbuffer (GstRtpBin * bin,
841 const gchar * name, const GValue * value)
843 GSList *sessions, *streams;
845 GST_RTP_BIN_LOCK (bin);
846 for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
847 GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
849 GST_RTP_SESSION_LOCK (session);
850 for (streams = session->streams; streams; streams = g_slist_next (streams)) {
851 GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
853 g_object_set_property (G_OBJECT (stream->buffer), name, value);
855 GST_RTP_SESSION_UNLOCK (session);
857 GST_RTP_BIN_UNLOCK (bin);
860 /* get a client with the given SDES name. Must be called with RTP_BIN_LOCK */
861 static GstRtpBinClient *
862 get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created)
864 GstRtpBinClient *result = NULL;
867 for (walk = bin->clients; walk; walk = g_slist_next (walk)) {
868 GstRtpBinClient *client = (GstRtpBinClient *) walk->data;
870 if (len != client->cname_len)
873 if (!strncmp ((gchar *) data, client->cname, client->cname_len)) {
874 GST_DEBUG_OBJECT (bin, "found existing client %p with CNAME %s", client,
881 /* nothing found, create one */
882 if (result == NULL) {
883 result = g_new0 (GstRtpBinClient, 1);
884 result->cname = g_strndup ((gchar *) data, len);
885 result->cname_len = len;
886 bin->clients = g_slist_prepend (bin->clients, result);
887 GST_DEBUG_OBJECT (bin, "created new client %p with CNAME %s", result,
894 free_client (GstRtpBinClient * client, GstRtpBin * bin)
896 GST_DEBUG_OBJECT (bin, "freeing client %p", client);
897 g_slist_free (client->streams);
898 g_free (client->cname);
903 get_current_times (GstRtpBin * bin, GstClockTime * running_time,
908 GstClockTime base_time, rt, clock_time;
910 GST_OBJECT_LOCK (bin);
911 if ((clock = GST_ELEMENT_CLOCK (bin))) {
912 base_time = GST_ELEMENT_CAST (bin)->base_time;
913 gst_object_ref (clock);
914 GST_OBJECT_UNLOCK (bin);
916 clock_time = gst_clock_get_time (clock);
918 if (bin->use_pipeline_clock) {
923 /* get current NTP time */
924 g_get_current_time (¤t);
925 ntpns = GST_TIMEVAL_TO_TIME (current);
928 /* add constant to convert from 1970 based time to 1900 based time */
929 ntpns += (2208988800LL * GST_SECOND);
931 /* get current clock time and convert to running time */
932 rt = clock_time - base_time;
934 gst_object_unref (clock);
936 GST_OBJECT_UNLOCK (bin);
947 stream_set_ts_offset (GstRtpBin * bin, GstRtpBinStream * stream,
950 gint64 prev_ts_offset;
952 g_object_get (stream->buffer, "ts-offset", &prev_ts_offset, NULL);
954 /* delta changed, see how much */
955 if (prev_ts_offset != ts_offset) {
958 diff = prev_ts_offset - ts_offset;
960 GST_DEBUG_OBJECT (bin,
961 "ts-offset %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT
962 ", diff: %" G_GINT64_FORMAT, ts_offset, prev_ts_offset, diff);
964 /* only change diff when it changed more than 4 milliseconds. This
965 * compensates for rounding errors in NTP to RTP timestamp
967 if (ABS (diff) > 4 * GST_MSECOND) {
968 if (ABS (diff) < (3 * GST_SECOND)) {
969 g_object_set (stream->buffer, "ts-offset", ts_offset, NULL);
971 GST_WARNING_OBJECT (bin, "offset unusually large, ignoring");
974 GST_DEBUG_OBJECT (bin, "offset too small, ignoring");
977 GST_DEBUG_OBJECT (bin, "stream SSRC %08x, delta %" G_GINT64_FORMAT,
978 stream->ssrc, ts_offset);
981 /* associate a stream to the given CNAME. This will make sure all streams for
982 * that CNAME are synchronized together.
983 * Must be called with GST_RTP_BIN_LOCK */
985 gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len,
986 guint8 * data, guint64 ntptime, guint64 last_extrtptime,
987 guint64 base_rtptime, guint64 base_time, guint clock_rate)
989 GstRtpBinClient *client;
994 GstClockTime running_time;
996 gint64 ntpdiff, rtdiff;
999 /* first find or create the CNAME */
1000 client = get_client (bin, len, data, &created);
1002 /* find stream in the client */
1003 for (walk = client->streams; walk; walk = g_slist_next (walk)) {
1004 GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
1006 if (ostream == stream)
1009 /* not found, add it to the list */
1011 GST_DEBUG_OBJECT (bin,
1012 "new association of SSRC %08x with client %p with CNAME %s",
1013 stream->ssrc, client, client->cname);
1014 client->streams = g_slist_prepend (client->streams, stream);
1017 GST_DEBUG_OBJECT (bin,
1018 "found association of SSRC %08x with client %p with CNAME %s",
1019 stream->ssrc, client, client->cname);
1022 /* Take the extended rtptime we found in the SR packet and map it to the
1023 * local rtptime. The local rtp time is used to construct timestamps on the
1024 * buffers so we will calculate what running_time corresponds to the RTP
1025 * timestamp in the SR packet. */
1026 local_rtp = last_extrtptime - base_rtptime;
1028 GST_DEBUG_OBJECT (bin,
1029 "base %" G_GUINT64_FORMAT ", extrtptime %" G_GUINT64_FORMAT
1030 ", local RTP %" G_GUINT64_FORMAT ", clock-rate %d", base_rtptime,
1031 last_extrtptime, local_rtp, clock_rate);
1033 /* calculate local RTP time in gstreamer timestamp, we essentially perform the
1034 * same conversion that a jitterbuffer would use to convert an rtp timestamp
1035 * into a corresponding gstreamer timestamp. Note that the base_time also
1036 * contains the drift between sender and receiver. */
1037 local_rt = gst_util_uint64_scale_int (local_rtp, GST_SECOND, clock_rate);
1038 local_rt += base_time;
1040 /* convert ntptime to unix time since 1900 */
1041 last_unix = gst_util_uint64_scale (ntptime, GST_SECOND,
1042 (G_GINT64_CONSTANT (1) << 32));
1044 stream->have_sync = TRUE;
1046 GST_DEBUG_OBJECT (bin,
1047 "local UNIX %" G_GUINT64_FORMAT ", remote UNIX %" G_GUINT64_FORMAT,
1048 local_rt, last_unix);
1050 /* recalc inter stream playout offset, but only if there is more than one
1051 * stream or we're doing NTP sync. */
1052 if (bin->ntp_sync) {
1053 /* For NTP sync we need to first get a snapshot of running_time and NTP
1054 * time. We know at what running_time we play a certain RTP time, we also
1055 * calculated when we would play the RTP time in the SR packet. Now we need
1056 * to know how the running_time and the NTP time relate to eachother. */
1057 get_current_times (bin, &running_time, &ntpnstime);
1059 /* see how far away the NTP time is. This is the difference between the
1060 * current NTP time and the NTP time in the last SR packet. */
1061 ntpdiff = ntpnstime - last_unix;
1062 /* see how far away the running_time is. This is the difference between the
1063 * current running_time and the running_time of the RTP timestamp in the
1064 * last SR packet. */
1065 rtdiff = running_time - local_rt;
1067 GST_DEBUG_OBJECT (bin,
1068 "NTP time %" G_GUINT64_FORMAT ", last unix %" G_GUINT64_FORMAT,
1069 ntpnstime, last_unix);
1070 GST_DEBUG_OBJECT (bin,
1071 "NTP diff %" G_GINT64_FORMAT ", RT diff %" G_GINT64_FORMAT, ntpdiff,
1074 /* combine to get the final diff to apply to the running_time */
1075 stream->rt_delta = rtdiff - ntpdiff;
1077 stream_set_ts_offset (bin, stream, stream->rt_delta);
1078 } else if (client->nstreams > 1) {
1081 /* calculate delta between server and receiver. last_unix is created by
1082 * converting the ntptime in the last SR packet to a gstreamer timestamp. This
1083 * delta expresses the difference to our timeline and the server timeline. The
1084 * difference in itself doesn't mean much but we can combine the delta of
1085 * multiple streams to create a stream specific offset. */
1086 stream->rt_delta = last_unix - local_rt;
1088 /* calculate the min of all deltas, ignoring streams that did not yet have a
1089 * valid rt_delta because we did not yet receive an SR packet for those
1091 * We calculate the mininum because we would like to only apply positive
1092 * offsets to streams, delaying their playback instead of trying to speed up
1093 * other streams (which might be imposible when we have to create negative
1095 * The stream that has the smallest diff is selected as the reference stream,
1096 * all other streams will have a positive offset to this difference. */
1098 for (walk = client->streams; walk; walk = g_slist_next (walk)) {
1099 GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
1101 if (!ostream->have_sync)
1104 if (ostream->rt_delta < min)
1105 min = ostream->rt_delta;
1108 GST_DEBUG_OBJECT (bin, "client %p min delta %" G_GINT64_FORMAT, client,
1111 /* bail out if we adjusted recently enough */
1112 if (all_sync && (last_unix - bin->priv->last_unix) <
1113 bin->rtcp_sync_interval * GST_MSECOND) {
1114 GST_DEBUG_OBJECT (bin, "discarding RTCP sender packet for sync; "
1115 "previous sender info too recent "
1116 "(previous UNIX %" G_GUINT64_FORMAT ")", bin->priv->last_unix);
1119 bin->priv->last_unix = last_unix;
1121 /* calculate offsets for each stream */
1122 for (walk = client->streams; walk; walk = g_slist_next (walk)) {
1123 GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
1126 /* ignore streams for which we didn't receive an SR packet yet, we
1127 * can't synchronize them yet. We can however sync other streams just
1129 if (!ostream->have_sync)
1132 /* calculate offset to our reference stream, this should always give a
1133 * positive number. */
1134 ts_offset = ostream->rt_delta - min;
1136 stream_set_ts_offset (bin, ostream, ts_offset);
1142 #define GST_RTCP_BUFFER_FOR_PACKETS(b,buffer,packet) \
1143 for ((b) = gst_rtcp_buffer_get_first_packet ((buffer), (packet)); (b); \
1144 (b) = gst_rtcp_packet_move_to_next ((packet)))
1146 #define GST_RTCP_SDES_FOR_ITEMS(b,packet) \
1147 for ((b) = gst_rtcp_packet_sdes_first_item ((packet)); (b); \
1148 (b) = gst_rtcp_packet_sdes_next_item ((packet)))
1150 #define GST_RTCP_SDES_FOR_ENTRIES(b,packet) \
1151 for ((b) = gst_rtcp_packet_sdes_first_entry ((packet)); (b); \
1152 (b) = gst_rtcp_packet_sdes_next_entry ((packet)))
1155 gst_rtp_bin_handle_sync (GstElement * jitterbuffer, GstStructure * s,
1156 GstRtpBinStream * stream)
1159 GstRTCPPacket packet;
1162 gboolean have_sr, have_sdes;
1164 guint64 base_rtptime;
1172 GST_DEBUG_OBJECT (bin, "sync handler called");
1174 /* get the last relation between the rtp timestamps and the gstreamer
1175 * timestamps. We get this info directly from the jitterbuffer which
1176 * constructs gstreamer timestamps from rtp timestamps and so it know exactly
1177 * what the current situation is. */
1179 g_value_get_uint64 (gst_structure_get_value (s, "base-rtptime"));
1180 base_time = g_value_get_uint64 (gst_structure_get_value (s, "base-time"));
1181 clock_rate = g_value_get_uint (gst_structure_get_value (s, "clock-rate"));
1183 g_value_get_uint64 (gst_structure_get_value (s, "sr-ext-rtptime"));
1184 buffer = gst_value_get_buffer (gst_structure_get_value (s, "sr-buffer"));
1188 GST_RTCP_BUFFER_FOR_PACKETS (more, buffer, &packet) {
1189 /* first packet must be SR or RR or else the validate would have failed */
1190 switch (gst_rtcp_packet_get_type (&packet)) {
1191 case GST_RTCP_TYPE_SR:
1192 /* only parse first. There is only supposed to be one SR in the packet
1193 * but we will deal with malformed packets gracefully */
1196 /* get NTP and RTP times */
1197 gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, NULL,
1200 GST_DEBUG_OBJECT (bin, "received sync packet from SSRC %08x", ssrc);
1201 /* ignore SR that is not ours */
1202 if (ssrc != stream->ssrc)
1207 case GST_RTCP_TYPE_SDES:
1209 gboolean more_items, more_entries;
1211 /* only deal with first SDES, there is only supposed to be one SDES in
1212 * the RTCP packet but we deal with bad packets gracefully. Also bail
1213 * out if we have not seen an SR item yet. */
1214 if (have_sdes || !have_sr)
1217 GST_RTCP_SDES_FOR_ITEMS (more_items, &packet) {
1218 /* skip items that are not about the SSRC of the sender */
1219 if (gst_rtcp_packet_sdes_get_ssrc (&packet) != ssrc)
1222 /* find the CNAME entry */
1223 GST_RTCP_SDES_FOR_ENTRIES (more_entries, &packet) {
1224 GstRTCPSDESType type;
1228 gst_rtcp_packet_sdes_get_entry (&packet, &type, &len, &data);
1230 if (type == GST_RTCP_SDES_CNAME) {
1231 GST_RTP_BIN_LOCK (bin);
1232 /* associate the stream to CNAME */
1233 gst_rtp_bin_associate (bin, stream, len, data,
1234 ntptime, extrtptime, base_rtptime, base_time, clock_rate);
1235 GST_RTP_BIN_UNLOCK (bin);
1243 /* we can ignore these packets */
1249 /* create a new stream with @ssrc in @session. Must be called with
1250 * RTP_SESSION_LOCK. */
1251 static GstRtpBinStream *
1252 create_stream (GstRtpBinSession * session, guint32 ssrc)
1254 GstElement *buffer, *demux = NULL;
1255 GstRtpBinStream *stream;
1259 rtpbin = session->bin;
1261 if (!(buffer = gst_element_factory_make ("gstrtpjitterbuffer", NULL)))
1262 goto no_jitterbuffer;
1264 if (!rtpbin->ignore_pt)
1265 if (!(demux = gst_element_factory_make ("gstrtpptdemux", NULL)))
1269 stream = g_new0 (GstRtpBinStream, 1);
1270 stream->ssrc = ssrc;
1271 stream->bin = rtpbin;
1272 stream->session = session;
1273 stream->buffer = buffer;
1274 stream->demux = demux;
1276 stream->have_sync = FALSE;
1277 stream->rt_delta = 0;
1278 stream->percent = 100;
1279 session->streams = g_slist_prepend (session->streams, stream);
1281 /* provide clock_rate to the jitterbuffer when needed */
1282 stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map",
1283 (GCallback) pt_map_requested, session);
1284 stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop",
1285 (GCallback) on_npt_stop, stream);
1287 g_object_set_data (G_OBJECT (buffer), "GstRTPBin.session", session);
1288 g_object_set_data (G_OBJECT (buffer), "GstRTPBin.stream", stream);
1290 /* configure latency and packet lost */
1291 g_object_set (buffer, "latency", rtpbin->latency_ms, NULL);
1292 g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
1293 g_object_set (buffer, "mode", rtpbin->buffer_mode, NULL);
1295 if (!rtpbin->ignore_pt)
1296 gst_bin_add (GST_BIN_CAST (rtpbin), demux);
1297 gst_bin_add (GST_BIN_CAST (rtpbin), buffer);
1301 gst_element_link (buffer, demux);
1303 if (rtpbin->buffering) {
1306 GST_INFO_OBJECT (rtpbin,
1307 "bin is buffering, set jitterbuffer as not active");
1308 g_signal_emit_by_name (buffer, "set-active", FALSE, (gint64) 0, &last_out);
1312 GST_OBJECT_LOCK (rtpbin);
1313 target = GST_STATE_TARGET (rtpbin);
1314 GST_OBJECT_UNLOCK (rtpbin);
1316 /* from sink to source */
1318 gst_element_set_state (demux, target);
1320 gst_element_set_state (buffer, target);
1327 g_warning ("gstrtpbin: could not create gstrtpjitterbuffer element");
1332 gst_object_unref (buffer);
1333 g_warning ("gstrtpbin: could not create gstrtpptdemux element");
1339 free_stream (GstRtpBinStream * stream)
1341 GstRtpBinSession *session;
1343 session = stream->session;
1345 if (stream->demux) {
1346 g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig);
1347 g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig);
1348 g_signal_handler_disconnect (stream->demux, stream->demux_ptchange_sig);
1350 g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig);
1351 g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig);
1352 g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig);
1355 gst_element_set_locked_state (stream->demux, TRUE);
1356 gst_element_set_locked_state (stream->buffer, TRUE);
1359 gst_element_set_state (stream->demux, GST_STATE_NULL);
1360 gst_element_set_state (stream->buffer, GST_STATE_NULL);
1362 /* now remove this signal, we need this while going to NULL because it to
1363 * do some cleanups */
1365 g_signal_handler_disconnect (stream->demux, stream->demux_padremoved_sig);
1367 gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer);
1369 gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux);
1374 /* GObject vmethods */
1375 static void gst_rtp_bin_dispose (GObject * object);
1376 static void gst_rtp_bin_finalize (GObject * object);
1377 static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
1378 const GValue * value, GParamSpec * pspec);
1379 static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
1380 GValue * value, GParamSpec * pspec);
1382 /* GstElement vmethods */
1383 static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
1384 GstStateChange transition);
1385 static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
1386 GstPadTemplate * templ, const gchar * name);
1387 static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
1388 static void gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message);
1390 GST_BOILERPLATE (GstRtpBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
1393 gst_rtp_bin_base_init (gpointer klass)
1395 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1398 gst_element_class_add_pad_template (element_class,
1399 gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
1400 gst_element_class_add_pad_template (element_class,
1401 gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
1402 gst_element_class_add_pad_template (element_class,
1403 gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
1406 gst_element_class_add_pad_template (element_class,
1407 gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
1408 gst_element_class_add_pad_template (element_class,
1409 gst_static_pad_template_get (&rtpbin_send_rtcp_src_template));
1410 gst_element_class_add_pad_template (element_class,
1411 gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
1413 gst_element_class_set_details_simple (element_class, "RTP Bin",
1414 "Filter/Network/RTP",
1415 "Real-Time Transport Protocol bin",
1416 "Wim Taymans <wim.taymans@gmail.com>");
1420 gst_rtp_bin_class_init (GstRtpBinClass * klass)
1422 GObjectClass *gobject_class;
1423 GstElementClass *gstelement_class;
1424 GstBinClass *gstbin_class;
1426 gobject_class = (GObjectClass *) klass;
1427 gstelement_class = (GstElementClass *) klass;
1428 gstbin_class = (GstBinClass *) klass;
1430 g_type_class_add_private (klass, sizeof (GstRtpBinPrivate));
1432 gobject_class->dispose = gst_rtp_bin_dispose;
1433 gobject_class->finalize = gst_rtp_bin_finalize;
1434 gobject_class->set_property = gst_rtp_bin_set_property;
1435 gobject_class->get_property = gst_rtp_bin_get_property;
1437 g_object_class_install_property (gobject_class, PROP_LATENCY,
1438 g_param_spec_uint ("latency", "Buffer latency in ms",
1439 "Default amount of ms to buffer in the jitterbuffers", 0,
1440 G_MAXUINT, DEFAULT_LATENCY_MS,
1441 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1444 * GstRtpBin::request-pt-map:
1445 * @rtpbin: the object which received the signal
1446 * @session: the session
1449 * Request the payload type as #GstCaps for @pt in @session.
1451 gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP] =
1452 g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
1453 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, request_pt_map),
1454 NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
1455 G_TYPE_UINT, G_TYPE_UINT);
1458 * GstRtpBin::payload-type-change:
1459 * @rtpbin: the object which received the signal
1460 * @session: the session
1463 * Signal that the current payload type changed to @pt in @session.
1467 gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
1468 g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
1469 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, payload_type_change),
1470 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1471 G_TYPE_UINT, G_TYPE_UINT);
1474 * GstRtpBin::clear-pt-map:
1475 * @rtpbin: the object which received the signal
1477 * Clear all previously cached pt-mapping obtained with
1478 * #GstRtpBin::request-pt-map.
1480 gst_rtp_bin_signals[SIGNAL_CLEAR_PT_MAP] =
1481 g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
1482 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1483 clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
1487 * GstRtpBin::reset-sync:
1488 * @rtpbin: the object which received the signal
1490 * Reset all currently configured lip-sync parameters and require new SR
1491 * packets for all streams before lip-sync is attempted again.
1493 gst_rtp_bin_signals[SIGNAL_RESET_SYNC] =
1494 g_signal_new ("reset-sync", G_TYPE_FROM_CLASS (klass),
1495 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1496 reset_sync), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
1500 * GstRtpBin::get-internal-session:
1501 * @rtpbin: the object which received the signal
1502 * @id: the session id
1504 * Request the internal RTPSession object as #GObject in session @id.
1506 gst_rtp_bin_signals[SIGNAL_GET_INTERNAL_SESSION] =
1507 g_signal_new ("get-internal-session", G_TYPE_FROM_CLASS (klass),
1508 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1509 get_internal_session), NULL, NULL, gst_rtp_bin_marshal_OBJECT__UINT,
1510 RTP_TYPE_SESSION, 1, G_TYPE_UINT);
1513 * GstRtpBin::on-new-ssrc:
1514 * @rtpbin: the object which received the signal
1515 * @session: the session
1518 * Notify of a new SSRC that entered @session.
1520 gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC] =
1521 g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
1522 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_new_ssrc),
1523 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1524 G_TYPE_UINT, G_TYPE_UINT);
1526 * GstRtpBin::on-ssrc-collision:
1527 * @rtpbin: the object which received the signal
1528 * @session: the session
1531 * Notify when we have an SSRC collision
1533 gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION] =
1534 g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
1535 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_collision),
1536 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1537 G_TYPE_UINT, G_TYPE_UINT);
1539 * GstRtpBin::on-ssrc-validated:
1540 * @rtpbin: the object which received the signal
1541 * @session: the session
1544 * Notify of a new SSRC that became validated.
1546 gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED] =
1547 g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
1548 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_validated),
1549 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1550 G_TYPE_UINT, G_TYPE_UINT);
1552 * GstRtpBin::on-ssrc-active:
1553 * @rtpbin: the object which received the signal
1554 * @session: the session
1557 * Notify of a SSRC that is active, i.e., sending RTCP.
1559 gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE] =
1560 g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
1561 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_active),
1562 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1563 G_TYPE_UINT, G_TYPE_UINT);
1565 * GstRtpBin::on-ssrc-sdes:
1566 * @rtpbin: the object which received the signal
1567 * @session: the session
1570 * Notify of a SSRC that is active, i.e., sending RTCP.
1572 gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES] =
1573 g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
1574 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_sdes),
1575 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1576 G_TYPE_UINT, G_TYPE_UINT);
1579 * GstRtpBin::on-bye-ssrc:
1580 * @rtpbin: the object which received the signal
1581 * @session: the session
1584 * Notify of an SSRC that became inactive because of a BYE packet.
1586 gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC] =
1587 g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
1588 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_ssrc),
1589 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1590 G_TYPE_UINT, G_TYPE_UINT);
1592 * GstRtpBin::on-bye-timeout:
1593 * @rtpbin: the object which received the signal
1594 * @session: the session
1597 * Notify of an SSRC that has timed out because of BYE
1599 gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT] =
1600 g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
1601 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_timeout),
1602 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1603 G_TYPE_UINT, G_TYPE_UINT);
1605 * GstRtpBin::on-timeout:
1606 * @rtpbin: the object which received the signal
1607 * @session: the session
1610 * Notify of an SSRC that has timed out
1612 gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT] =
1613 g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
1614 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_timeout),
1615 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1616 G_TYPE_UINT, G_TYPE_UINT);
1618 * GstRtpBin::on-sender-timeout:
1619 * @rtpbin: the object which received the signal
1620 * @session: the session
1623 * Notify of a sender SSRC that has timed out and became a receiver
1625 gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT] =
1626 g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
1627 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_sender_timeout),
1628 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1629 G_TYPE_UINT, G_TYPE_UINT);
1632 * GstRtpBin::on-npt-stop:
1633 * @rtpbin: the object which received the signal
1634 * @session: the session
1637 * Notify that SSRC sender has sent data up to the configured NPT stop time.
1639 gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP] =
1640 g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
1641 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_npt_stop),
1642 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1643 G_TYPE_UINT, G_TYPE_UINT);
1645 g_object_class_install_property (gobject_class, PROP_SDES,
1646 g_param_spec_boxed ("sdes", "SDES",
1647 "The SDES items of this session",
1648 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1650 g_object_class_install_property (gobject_class, PROP_DO_LOST,
1651 g_param_spec_boolean ("do-lost", "Do Lost",
1652 "Send an event downstream when a packet is lost", DEFAULT_DO_LOST,
1653 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1655 g_object_class_install_property (gobject_class, PROP_AUTOREMOVE,
1656 g_param_spec_boolean ("autoremove", "Auto Remove",
1657 "Automatically remove timed out sources", DEFAULT_AUTOREMOVE,
1658 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1660 g_object_class_install_property (gobject_class, PROP_IGNORE_PT,
1661 g_param_spec_boolean ("ignore-pt", "Ignore PT",
1662 "Do not demultiplex based on PT values", DEFAULT_IGNORE_PT,
1663 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1665 g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK,
1666 g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock",
1667 "Use the pipeline clock to set the NTP time in the RTCP SR messages",
1668 DEFAULT_USE_PIPELINE_CLOCK,
1669 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1671 * GstRtpBin::buffer-mode:
1673 * Control the buffering and timestamping mode used by the jitterbuffer.
1677 g_object_class_install_property (gobject_class, PROP_BUFFER_MODE,
1678 g_param_spec_enum ("buffer-mode", "Buffer Mode",
1679 "Control the buffering algorithm in use", RTP_TYPE_JITTER_BUFFER_MODE,
1680 DEFAULT_BUFFER_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1682 * GstRtpBin::ntp-sync:
1684 * Synchronize received streams to the NTP clock. When the NTP clock is shared
1685 * between the receivers and the senders (such as when using ntpd) this option
1686 * can be used to synchronize receivers on multiple machines.
1690 g_object_class_install_property (gobject_class, PROP_NTP_SYNC,
1691 g_param_spec_boolean ("ntp-sync", "Sync on NTP clock",
1692 "Synchronize received streams to the NTP clock", DEFAULT_NTP_SYNC,
1693 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1696 * GstRtpBin::rtcp-sync-interval:
1698 * Determines how often to sync streams using RTCP data.
1702 g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_INTERVAL,
1703 g_param_spec_uint ("rtcp-sync-interval", "RTCP Sync Interval",
1704 "RTCP SR interval synchronization (ms) (0 = always)",
1705 0, G_MAXUINT, DEFAULT_RTCP_SYNC_INTERVAL,
1706 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1708 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
1709 gstelement_class->request_new_pad =
1710 GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
1711 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
1713 gstbin_class->handle_message = GST_DEBUG_FUNCPTR (gst_rtp_bin_handle_message);
1715 klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_bin_clear_pt_map);
1716 klass->reset_sync = GST_DEBUG_FUNCPTR (gst_rtp_bin_reset_sync);
1717 klass->get_internal_session =
1718 GST_DEBUG_FUNCPTR (gst_rtp_bin_get_internal_session);
1720 GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
1724 gst_rtp_bin_init (GstRtpBin * rtpbin, GstRtpBinClass * klass)
1728 rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
1729 rtpbin->priv->bin_lock = g_mutex_new ();
1730 rtpbin->priv->dyn_lock = g_mutex_new ();
1732 rtpbin->latency_ms = DEFAULT_LATENCY_MS;
1733 rtpbin->latency_ns = DEFAULT_LATENCY_MS * GST_MSECOND;
1734 rtpbin->do_lost = DEFAULT_DO_LOST;
1735 rtpbin->ignore_pt = DEFAULT_IGNORE_PT;
1736 rtpbin->ntp_sync = DEFAULT_NTP_SYNC;
1737 rtpbin->rtcp_sync_interval = DEFAULT_RTCP_SYNC_INTERVAL;
1738 rtpbin->priv->autoremove = DEFAULT_AUTOREMOVE;
1739 rtpbin->buffer_mode = DEFAULT_BUFFER_MODE;
1740 rtpbin->use_pipeline_clock = DEFAULT_USE_PIPELINE_CLOCK;
1742 /* some default SDES entries */
1743 str = g_strdup_printf ("%s@%s", g_get_user_name (), g_get_host_name ());
1744 rtpbin->sdes = gst_structure_new ("application/x-rtp-source-sdes",
1745 "cname", G_TYPE_STRING, str,
1746 "name", G_TYPE_STRING, g_get_real_name (),
1747 "tool", G_TYPE_STRING, "GStreamer", NULL);
1752 gst_rtp_bin_dispose (GObject * object)
1756 rtpbin = GST_RTP_BIN (object);
1758 GST_DEBUG_OBJECT (object, "freeing sessions");
1759 g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin);
1760 g_slist_free (rtpbin->sessions);
1761 rtpbin->sessions = NULL;
1762 GST_DEBUG_OBJECT (object, "freeing clients");
1763 g_slist_foreach (rtpbin->clients, (GFunc) free_client, rtpbin);
1764 g_slist_free (rtpbin->clients);
1765 rtpbin->clients = NULL;
1767 G_OBJECT_CLASS (parent_class)->dispose (object);
1771 gst_rtp_bin_finalize (GObject * object)
1775 rtpbin = GST_RTP_BIN (object);
1778 gst_structure_free (rtpbin->sdes);
1780 g_mutex_free (rtpbin->priv->bin_lock);
1781 g_mutex_free (rtpbin->priv->dyn_lock);
1783 G_OBJECT_CLASS (parent_class)->finalize (object);
1788 gst_rtp_bin_set_sdes_struct (GstRtpBin * bin, const GstStructure * sdes)
1795 GST_RTP_BIN_LOCK (bin);
1797 GST_OBJECT_LOCK (bin);
1799 gst_structure_free (bin->sdes);
1800 bin->sdes = gst_structure_copy (sdes);
1801 GST_OBJECT_UNLOCK (bin);
1803 /* store in all sessions */
1804 for (item = bin->sessions; item; item = g_slist_next (item)) {
1805 GstRtpBinSession *session = item->data;
1806 g_object_set (session->session, "sdes", sdes, NULL);
1809 GST_RTP_BIN_UNLOCK (bin);
1812 static GstStructure *
1813 gst_rtp_bin_get_sdes_struct (GstRtpBin * bin)
1815 GstStructure *result;
1817 GST_OBJECT_LOCK (bin);
1818 result = gst_structure_copy (bin->sdes);
1819 GST_OBJECT_UNLOCK (bin);
1825 gst_rtp_bin_set_property (GObject * object, guint prop_id,
1826 const GValue * value, GParamSpec * pspec)
1830 rtpbin = GST_RTP_BIN (object);
1834 GST_RTP_BIN_LOCK (rtpbin);
1835 rtpbin->latency_ms = g_value_get_uint (value);
1836 rtpbin->latency_ns = rtpbin->latency_ms * GST_MSECOND;
1837 GST_RTP_BIN_UNLOCK (rtpbin);
1838 /* propagate the property down to the jitterbuffer */
1839 gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "latency", value);
1842 gst_rtp_bin_set_sdes_struct (rtpbin, g_value_get_boxed (value));
1845 GST_RTP_BIN_LOCK (rtpbin);
1846 rtpbin->do_lost = g_value_get_boolean (value);
1847 GST_RTP_BIN_UNLOCK (rtpbin);
1848 gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "do-lost", value);
1851 rtpbin->ntp_sync = g_value_get_boolean (value);
1853 case PROP_RTCP_SYNC_INTERVAL:
1854 rtpbin->rtcp_sync_interval = g_value_get_uint (value);
1856 case PROP_IGNORE_PT:
1857 rtpbin->ignore_pt = g_value_get_boolean (value);
1859 case PROP_AUTOREMOVE:
1860 rtpbin->priv->autoremove = g_value_get_boolean (value);
1862 case PROP_USE_PIPELINE_CLOCK:
1865 GST_RTP_BIN_LOCK (rtpbin);
1866 rtpbin->use_pipeline_clock = g_value_get_boolean (value);
1867 for (sessions = rtpbin->sessions; sessions;
1868 sessions = g_slist_next (sessions)) {
1869 GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
1871 g_object_set (G_OBJECT (session->session),
1872 "use-pipeline-clock", rtpbin->use_pipeline_clock, NULL);
1874 GST_RTP_BIN_UNLOCK (rtpbin);
1877 case PROP_BUFFER_MODE:
1878 GST_RTP_BIN_LOCK (rtpbin);
1879 rtpbin->buffer_mode = g_value_get_enum (value);
1880 GST_RTP_BIN_UNLOCK (rtpbin);
1881 /* propagate the property down to the jitterbuffer */
1882 gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "mode", value);
1885 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1891 gst_rtp_bin_get_property (GObject * object, guint prop_id,
1892 GValue * value, GParamSpec * pspec)
1896 rtpbin = GST_RTP_BIN (object);
1900 GST_RTP_BIN_LOCK (rtpbin);
1901 g_value_set_uint (value, rtpbin->latency_ms);
1902 GST_RTP_BIN_UNLOCK (rtpbin);
1905 g_value_take_boxed (value, gst_rtp_bin_get_sdes_struct (rtpbin));
1908 GST_RTP_BIN_LOCK (rtpbin);
1909 g_value_set_boolean (value, rtpbin->do_lost);
1910 GST_RTP_BIN_UNLOCK (rtpbin);
1912 case PROP_IGNORE_PT:
1913 g_value_set_boolean (value, rtpbin->ignore_pt);
1916 g_value_set_boolean (value, rtpbin->ntp_sync);
1918 case PROP_RTCP_SYNC_INTERVAL:
1919 g_value_set_uint (value, rtpbin->rtcp_sync_interval);
1921 case PROP_AUTOREMOVE:
1922 g_value_set_boolean (value, rtpbin->priv->autoremove);
1924 case PROP_BUFFER_MODE:
1925 g_value_set_enum (value, rtpbin->buffer_mode);
1927 case PROP_USE_PIPELINE_CLOCK:
1928 g_value_set_boolean (value, rtpbin->use_pipeline_clock);
1931 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1937 gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
1941 rtpbin = GST_RTP_BIN (bin);
1943 switch (GST_MESSAGE_TYPE (message)) {
1944 case GST_MESSAGE_ELEMENT:
1946 const GstStructure *s = gst_message_get_structure (message);
1948 /* we change the structure name and add the session ID to it */
1949 if (gst_structure_has_name (s, "application/x-rtp-source-sdes")) {
1950 GstRtpBinSession *sess;
1952 /* find the session we set it as object data */
1953 sess = g_object_get_data (G_OBJECT (GST_MESSAGE_SRC (message)),
1954 "GstRTPBin.session");
1956 if (G_LIKELY (sess)) {
1957 message = gst_message_make_writable (message);
1958 s = gst_message_get_structure (message);
1959 gst_structure_set ((GstStructure *) s, "session", G_TYPE_UINT,
1963 GST_BIN_CLASS (parent_class)->handle_message (bin, message);
1966 case GST_MESSAGE_BUFFERING:
1969 gint min_percent = 100;
1970 GSList *sessions, *streams;
1971 GstRtpBinStream *stream;
1972 gboolean change = FALSE, active = FALSE;
1973 GstClockTime min_out_time;
1974 GstBufferingMode mode;
1975 gint avg_in, avg_out;
1976 gint64 buffering_left;
1978 gst_message_parse_buffering (message, &percent);
1979 gst_message_parse_buffering_stats (message, &mode, &avg_in, &avg_out,
1983 g_object_get_data (G_OBJECT (GST_MESSAGE_SRC (message)),
1984 "GstRTPBin.stream");
1986 GST_DEBUG_OBJECT (bin, "got percent %d from stream %p", percent, stream);
1988 /* get the stream */
1989 if (G_LIKELY (stream)) {
1990 GST_RTP_BIN_LOCK (rtpbin);
1991 /* fill in the percent */
1992 stream->percent = percent;
1994 /* calculate the min value for all streams */
1995 for (sessions = rtpbin->sessions; sessions;
1996 sessions = g_slist_next (sessions)) {
1997 GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
1999 GST_RTP_SESSION_LOCK (session);
2000 if (session->streams) {
2001 for (streams = session->streams; streams;
2002 streams = g_slist_next (streams)) {
2003 GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
2005 GST_DEBUG_OBJECT (bin, "stream %p percent %d", stream,
2008 /* find min percent */
2009 if (min_percent > stream->percent)
2010 min_percent = stream->percent;
2013 GST_INFO_OBJECT (bin,
2014 "session has no streams, setting min_percent to 0");
2017 GST_RTP_SESSION_UNLOCK (session);
2019 GST_DEBUG_OBJECT (bin, "min percent %d", min_percent);
2021 if (rtpbin->buffering) {
2022 if (min_percent == 100) {
2023 rtpbin->buffering = FALSE;
2028 if (min_percent < 100) {
2029 /* pause the streams */
2030 rtpbin->buffering = TRUE;
2035 GST_RTP_BIN_UNLOCK (rtpbin);
2037 gst_message_unref (message);
2039 /* make a new buffering message with the min value */
2041 gst_message_new_buffering (GST_OBJECT_CAST (bin), min_percent);
2042 gst_message_set_buffering_stats (message, mode, avg_in, avg_out,
2045 if (G_UNLIKELY (change)) {
2047 guint64 running_time = 0;
2050 /* figure out the running time when we have a clock */
2051 if (G_LIKELY ((clock =
2052 gst_element_get_clock (GST_ELEMENT_CAST (bin))))) {
2053 guint64 now, base_time;
2055 now = gst_clock_get_time (clock);
2056 base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bin));
2057 running_time = now - base_time;
2059 GST_DEBUG_OBJECT (bin,
2060 "running time now %" GST_TIME_FORMAT,
2061 GST_TIME_ARGS (running_time));
2063 GST_RTP_BIN_LOCK (rtpbin);
2065 /* when we reactivate, calculate the offsets so that all streams have
2066 * an output time that is at least as big as the running_time */
2069 if (running_time > rtpbin->buffer_start) {
2070 offset = running_time - rtpbin->buffer_start;
2071 if (offset >= rtpbin->latency_ns)
2072 offset -= rtpbin->latency_ns;
2078 /* pause all streams */
2080 for (sessions = rtpbin->sessions; sessions;
2081 sessions = g_slist_next (sessions)) {
2082 GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
2084 GST_RTP_SESSION_LOCK (session);
2085 for (streams = session->streams; streams;
2086 streams = g_slist_next (streams)) {
2087 GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
2088 GstElement *element = stream->buffer;
2091 g_signal_emit_by_name (element, "set-active", active, offset,
2095 g_object_get (element, "percent", &stream->percent, NULL);
2099 if (min_out_time == -1 || last_out < min_out_time)
2100 min_out_time = last_out;
2103 GST_DEBUG_OBJECT (bin,
2104 "setting %p to %d, offset %" GST_TIME_FORMAT ", last %"
2105 GST_TIME_FORMAT ", percent %d", element, active,
2106 GST_TIME_ARGS (offset), GST_TIME_ARGS (last_out),
2109 GST_RTP_SESSION_UNLOCK (session);
2111 GST_DEBUG_OBJECT (bin,
2112 "min out time %" GST_TIME_FORMAT, GST_TIME_ARGS (min_out_time));
2114 /* the buffer_start is the min out time of all paused jitterbuffers */
2116 rtpbin->buffer_start = min_out_time;
2118 GST_RTP_BIN_UNLOCK (rtpbin);
2121 GST_BIN_CLASS (parent_class)->handle_message (bin, message);
2126 GST_BIN_CLASS (parent_class)->handle_message (bin, message);
2132 static GstStateChangeReturn
2133 gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
2135 GstStateChangeReturn res;
2137 GstRtpBinPrivate *priv;
2139 rtpbin = GST_RTP_BIN (element);
2140 priv = rtpbin->priv;
2142 switch (transition) {
2143 case GST_STATE_CHANGE_NULL_TO_READY:
2145 case GST_STATE_CHANGE_READY_TO_PAUSED:
2146 priv->last_unix = 0;
2147 GST_LOG_OBJECT (rtpbin, "clearing shutdown flag");
2148 g_atomic_int_set (&priv->shutdown, 0);
2150 case GST_STATE_CHANGE_PAUSED_TO_READY:
2151 GST_LOG_OBJECT (rtpbin, "setting shutdown flag");
2152 g_atomic_int_set (&priv->shutdown, 1);
2153 /* wait for all callbacks to end by taking the lock. No new callbacks will
2154 * be able to happen as we set the shutdown flag. */
2155 GST_RTP_BIN_DYN_LOCK (rtpbin);
2156 GST_LOG_OBJECT (rtpbin, "dynamic lock taken, we can continue shutdown");
2157 GST_RTP_BIN_DYN_UNLOCK (rtpbin);
2163 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2165 switch (transition) {
2166 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2168 case GST_STATE_CHANGE_PAUSED_TO_READY:
2170 case GST_STATE_CHANGE_READY_TO_NULL:
2178 /* a new pad (SSRC) was created in @session. This signal is emited from the
2179 * payload demuxer. */
2181 new_payload_found (GstElement * element, guint pt, GstPad * pad,
2182 GstRtpBinStream * stream)
2185 GstElementClass *klass;
2186 GstPadTemplate *templ;
2190 rtpbin = stream->bin;
2192 GST_DEBUG ("new payload pad %d", pt);
2194 GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
2196 /* ghost the pad to the parent */
2197 klass = GST_ELEMENT_GET_CLASS (rtpbin);
2198 templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
2199 padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
2200 stream->session->id, stream->ssrc, pt);
2201 gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
2203 g_object_set_data (G_OBJECT (pad), "GstRTPBin.ghostpad", gpad);
2205 gst_pad_set_caps (gpad, GST_PAD_CAPS (pad));
2206 gst_pad_set_active (gpad, TRUE);
2207 GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
2209 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
2215 GST_DEBUG ("ignoring, we are shutting down");
2221 payload_pad_removed (GstElement * element, GstPad * pad,
2222 GstRtpBinStream * stream)
2227 rtpbin = stream->bin;
2229 GST_DEBUG ("payload pad removed");
2231 GST_RTP_BIN_DYN_LOCK (rtpbin);
2232 if ((gpad = g_object_get_data (G_OBJECT (pad), "GstRTPBin.ghostpad"))) {
2233 g_object_set_data (G_OBJECT (pad), "GstRTPBin.ghostpad", NULL);
2235 gst_pad_set_active (gpad, FALSE);
2236 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), gpad);
2238 GST_RTP_BIN_DYN_UNLOCK (rtpbin);
2242 pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
2247 rtpbin = session->bin;
2249 GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
2252 caps = get_pt_map (session, pt);
2261 GST_DEBUG_OBJECT (rtpbin, "could not get caps");
2267 payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
2269 GST_DEBUG_OBJECT (session->bin,
2270 "emiting signal for pt type changed to %d in session %d", pt,
2273 g_signal_emit (session->bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
2274 0, session->id, pt);
2277 /* emited when caps changed for the session */
2279 caps_changed (GstPad * pad, GParamSpec * pspec, GstRtpBinSession * session)
2284 const GstStructure *s;
2288 g_object_get (pad, "caps", &caps, NULL);
2293 GST_DEBUG_OBJECT (bin, "got caps %" GST_PTR_FORMAT, caps);
2295 s = gst_caps_get_structure (caps, 0);
2297 /* get payload, finish when it's not there */
2298 if (!gst_structure_get_int (s, "payload", &payload))
2301 GST_RTP_SESSION_LOCK (session);
2302 GST_DEBUG_OBJECT (bin, "insert caps for payload %d", payload);
2303 g_hash_table_insert (session->ptmap, GINT_TO_POINTER (payload), caps);
2304 GST_RTP_SESSION_UNLOCK (session);
2307 /* a new pad (SSRC) was created in @session */
2309 new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
2310 GstRtpBinSession * session)
2313 GstRtpBinStream *stream;
2314 GstPad *sinkpad, *srcpad;
2317 rtpbin = session->bin;
2319 GST_DEBUG_OBJECT (rtpbin, "new SSRC pad %08x, %s:%s", ssrc,
2320 GST_DEBUG_PAD_NAME (pad));
2322 GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
2324 GST_RTP_SESSION_LOCK (session);
2326 /* create new stream */
2327 stream = create_stream (session, ssrc);
2331 /* get pad and link */
2332 GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTP");
2333 padname = g_strdup_printf ("src_%d", ssrc);
2334 srcpad = gst_element_get_static_pad (element, padname);
2336 sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
2337 gst_pad_link (srcpad, sinkpad);
2338 gst_object_unref (sinkpad);
2339 gst_object_unref (srcpad);
2341 GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTCP");
2342 padname = g_strdup_printf ("rtcp_src_%d", ssrc);
2343 srcpad = gst_element_get_static_pad (element, padname);
2345 sinkpad = gst_element_get_request_pad (stream->buffer, "sink_rtcp");
2346 gst_pad_link (srcpad, sinkpad);
2347 gst_object_unref (sinkpad);
2348 gst_object_unref (srcpad);
2350 /* connect to the RTCP sync signal from the jitterbuffer */
2351 GST_DEBUG_OBJECT (rtpbin, "connecting sync signal");
2352 stream->buffer_handlesync_sig = g_signal_connect (stream->buffer,
2353 "handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream);
2355 if (stream->demux) {
2356 /* connect to the new-pad signal of the payload demuxer, this will expose the
2357 * new pad by ghosting it. */
2358 stream->demux_newpad_sig = g_signal_connect (stream->demux,
2359 "new-payload-type", (GCallback) new_payload_found, stream);
2360 stream->demux_padremoved_sig = g_signal_connect (stream->demux,
2361 "pad-removed", (GCallback) payload_pad_removed, stream);
2363 /* connect to the request-pt-map signal. This signal will be emited by the
2364 * demuxer so that it can apply a proper caps on the buffers for the
2366 stream->demux_ptreq_sig = g_signal_connect (stream->demux,
2367 "request-pt-map", (GCallback) pt_map_requested, session);
2368 /* connect to the signal so it can be forwarded. */
2369 stream->demux_ptchange_sig = g_signal_connect (stream->demux,
2370 "payload-type-change", (GCallback) payload_type_change, session);
2372 /* add gstrtpjitterbuffer src pad to pads */
2373 GstElementClass *klass;
2374 GstPadTemplate *templ;
2378 pad = gst_element_get_static_pad (stream->buffer, "src");
2380 /* ghost the pad to the parent */
2381 klass = GST_ELEMENT_GET_CLASS (rtpbin);
2382 templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
2383 padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
2384 stream->session->id, stream->ssrc, 255);
2385 gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
2388 gst_pad_set_caps (gpad, GST_PAD_CAPS (pad));
2389 gst_pad_set_active (gpad, TRUE);
2390 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
2392 gst_object_unref (pad);
2395 GST_RTP_SESSION_UNLOCK (session);
2396 GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
2403 GST_DEBUG_OBJECT (rtpbin, "we are shutting down");
2408 GST_RTP_SESSION_UNLOCK (session);
2409 GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
2410 GST_DEBUG_OBJECT (rtpbin, "could not create stream");
2415 /* Create a pad for receiving RTP for the session in @name. Must be called with
2419 create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2423 GstRtpBinSession *session;
2424 GstPadLinkReturn lres;
2426 /* first get the session number */
2427 if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
2430 GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
2432 /* get or create session */
2433 session = find_session_by_id (rtpbin, sessid);
2435 GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
2436 /* create session now */
2437 session = create_session (rtpbin, sessid);
2438 if (session == NULL)
2442 /* check if pad was requested */
2443 if (session->recv_rtp_sink_ghost != NULL)
2444 return session->recv_rtp_sink_ghost;
2446 GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
2447 /* get recv_rtp pad and store */
2448 session->recv_rtp_sink =
2449 gst_element_get_request_pad (session->session, "recv_rtp_sink");
2450 if (session->recv_rtp_sink == NULL)
2453 g_signal_connect (session->recv_rtp_sink, "notify::caps",
2454 (GCallback) caps_changed, session);
2456 GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
2457 /* get srcpad, link to SSRCDemux */
2458 session->recv_rtp_src =
2459 gst_element_get_static_pad (session->session, "recv_rtp_src");
2460 if (session->recv_rtp_src == NULL)
2463 GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTP sink pad");
2464 sinkdpad = gst_element_get_static_pad (session->demux, "sink");
2465 GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
2466 lres = gst_pad_link (session->recv_rtp_src, sinkdpad);
2467 gst_object_unref (sinkdpad);
2468 if (lres != GST_PAD_LINK_OK)
2471 /* connect to the new-ssrc-pad signal of the SSRC demuxer */
2472 session->demux_newpad_sig = g_signal_connect (session->demux,
2473 "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
2474 session->demux_padremoved_sig = g_signal_connect (session->demux,
2475 "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
2477 GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
2478 session->recv_rtp_sink_ghost =
2479 gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
2480 gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
2481 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
2483 return session->recv_rtp_sink_ghost;
2488 g_warning ("gstrtpbin: invalid name given");
2493 /* create_session already warned */
2498 g_warning ("gstrtpbin: failed to get session pad");
2503 g_warning ("gstrtpbin: failed to link pads");
2509 remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2511 if (session->demux_newpad_sig) {
2512 g_signal_handler_disconnect (session->demux, session->demux_newpad_sig);
2513 session->demux_newpad_sig = 0;
2515 if (session->demux_padremoved_sig) {
2516 g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
2517 session->demux_padremoved_sig = 0;
2519 if (session->recv_rtp_src) {
2520 gst_object_unref (session->recv_rtp_src);
2521 session->recv_rtp_src = NULL;
2523 if (session->recv_rtp_sink) {
2524 gst_element_release_request_pad (session->session, session->recv_rtp_sink);
2525 gst_object_unref (session->recv_rtp_sink);
2526 session->recv_rtp_sink = NULL;
2528 if (session->recv_rtp_sink_ghost) {
2529 gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE);
2530 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2531 session->recv_rtp_sink_ghost);
2532 session->recv_rtp_sink_ghost = NULL;
2536 /* Create a pad for receiving RTCP for the session in @name. Must be called with
2540 create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
2544 GstRtpBinSession *session;
2546 GstPadLinkReturn lres;
2548 /* first get the session number */
2549 if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
2552 GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
2554 /* get or create the session */
2555 session = find_session_by_id (rtpbin, sessid);
2557 GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
2558 /* create session now */
2559 session = create_session (rtpbin, sessid);
2560 if (session == NULL)
2564 /* check if pad was requested */
2565 if (session->recv_rtcp_sink_ghost != NULL)
2566 return session->recv_rtcp_sink_ghost;
2568 /* get recv_rtp pad and store */
2569 GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
2570 session->recv_rtcp_sink =
2571 gst_element_get_request_pad (session->session, "recv_rtcp_sink");
2572 if (session->recv_rtcp_sink == NULL)
2575 /* get srcpad, link to SSRCDemux */
2576 GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
2577 session->sync_src = gst_element_get_static_pad (session->session, "sync_src");
2578 if (session->sync_src == NULL)
2581 GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTCP sink pad");
2582 sinkdpad = gst_element_get_static_pad (session->demux, "rtcp_sink");
2583 lres = gst_pad_link (session->sync_src, sinkdpad);
2584 gst_object_unref (sinkdpad);
2585 if (lres != GST_PAD_LINK_OK)
2588 session->recv_rtcp_sink_ghost =
2589 gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
2590 gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
2591 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
2592 session->recv_rtcp_sink_ghost);
2594 return session->recv_rtcp_sink_ghost;
2599 g_warning ("gstrtpbin: invalid name given");
2604 /* create_session already warned */
2609 g_warning ("gstrtpbin: failed to get session pad");
2614 g_warning ("gstrtpbin: failed to link pads");
2620 remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2622 if (session->recv_rtcp_sink_ghost) {
2623 gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE);
2624 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2625 session->recv_rtcp_sink_ghost);
2626 session->recv_rtcp_sink_ghost = NULL;
2628 if (session->sync_src) {
2629 /* releasing the request pad should also unref the sync pad */
2630 gst_object_unref (session->sync_src);
2631 session->sync_src = NULL;
2633 if (session->recv_rtcp_sink) {
2634 gst_element_release_request_pad (session->session, session->recv_rtcp_sink);
2635 gst_object_unref (session->recv_rtcp_sink);
2636 session->recv_rtcp_sink = NULL;
2640 /* Create a pad for sending RTP for the session in @name. Must be called with
2644 create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2648 GstRtpBinSession *session;
2649 GstElementClass *klass;
2651 /* first get the session number */
2652 if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
2655 /* get or create session */
2656 session = find_session_by_id (rtpbin, sessid);
2658 /* create session now */
2659 session = create_session (rtpbin, sessid);
2660 if (session == NULL)
2664 /* check if pad was requested */
2665 if (session->send_rtp_sink_ghost != NULL)
2666 return session->send_rtp_sink_ghost;
2668 /* get send_rtp pad and store */
2669 session->send_rtp_sink =
2670 gst_element_get_request_pad (session->session, "send_rtp_sink");
2671 if (session->send_rtp_sink == NULL)
2674 session->send_rtp_sink_ghost =
2675 gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
2676 gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
2677 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
2680 session->send_rtp_src =
2681 gst_element_get_static_pad (session->session, "send_rtp_src");
2682 if (session->send_rtp_src == NULL)
2685 /* ghost the new source pad */
2686 klass = GST_ELEMENT_GET_CLASS (rtpbin);
2687 gname = g_strdup_printf ("send_rtp_src_%d", sessid);
2688 templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
2689 session->send_rtp_src_ghost =
2690 gst_ghost_pad_new_from_template (gname, session->send_rtp_src, templ);
2691 gst_pad_set_active (session->send_rtp_src_ghost, TRUE);
2692 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost);
2695 return session->send_rtp_sink_ghost;
2700 g_warning ("gstrtpbin: invalid name given");
2705 /* create_session already warned */
2710 g_warning ("gstrtpbin: failed to get session pad for session %d", sessid);
2715 g_warning ("gstrtpbin: failed to get rtp source pad for session %d",
2722 remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2724 if (session->send_rtp_src_ghost) {
2725 gst_pad_set_active (session->send_rtp_src_ghost, FALSE);
2726 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2727 session->send_rtp_src_ghost);
2728 session->send_rtp_src_ghost = NULL;
2730 if (session->send_rtp_src) {
2731 gst_object_unref (session->send_rtp_src);
2732 session->send_rtp_src = NULL;
2734 if (session->send_rtp_sink) {
2735 gst_element_release_request_pad (GST_ELEMENT_CAST (session->session),
2736 session->send_rtp_sink);
2737 gst_object_unref (session->send_rtp_sink);
2738 session->send_rtp_sink = NULL;
2740 if (session->send_rtp_sink_ghost) {
2741 gst_pad_set_active (session->send_rtp_sink_ghost, FALSE);
2742 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2743 session->send_rtp_sink_ghost);
2744 session->send_rtp_sink_ghost = NULL;
2748 /* Create a pad for sending RTCP for the session in @name. Must be called with
2752 create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2755 GstRtpBinSession *session;
2757 /* first get the session number */
2758 if (name == NULL || sscanf (name, "send_rtcp_src_%d", &sessid) != 1)
2761 /* get or create session */
2762 session = find_session_by_id (rtpbin, sessid);
2766 /* check if pad was requested */
2767 if (session->send_rtcp_src_ghost != NULL)
2768 return session->send_rtcp_src_ghost;
2770 /* get rtcp_src pad and store */
2771 session->send_rtcp_src =
2772 gst_element_get_request_pad (session->session, "send_rtcp_src");
2773 if (session->send_rtcp_src == NULL)
2776 session->send_rtcp_src_ghost =
2777 gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ);
2778 gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
2779 gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
2781 return session->send_rtcp_src_ghost;
2786 g_warning ("gstrtpbin: invalid name given");
2791 g_warning ("gstrtpbin: session with id %d does not exist", sessid);
2796 g_warning ("gstrtpbin: failed to get rtcp pad for session %d", sessid);
2802 remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2804 if (session->send_rtcp_src_ghost) {
2805 gst_pad_set_active (session->send_rtcp_src_ghost, FALSE);
2806 gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2807 session->send_rtcp_src_ghost);
2808 session->send_rtcp_src_ghost = NULL;
2810 if (session->send_rtcp_src) {
2811 gst_element_release_request_pad (session->session, session->send_rtcp_src);
2812 gst_object_unref (session->send_rtcp_src);
2813 session->send_rtcp_src = NULL;
2817 /* If the requested name is NULL we should create a name with
2818 * the session number assuming we want the lowest posible session
2819 * with a free pad like the template */
2821 gst_rtp_bin_get_free_pad_name (GstElement * element, GstPadTemplate * templ)
2823 gboolean name_found = FALSE;
2825 GstIterator *pad_it = NULL;
2826 gchar *pad_name = NULL;
2828 GST_DEBUG_OBJECT (element, "find a free pad name for template");
2829 while (!name_found) {
2830 gboolean done = FALSE;
2832 pad_name = g_strdup_printf (templ->name_template, session++);
2833 pad_it = gst_element_iterate_pads (GST_ELEMENT (element));
2838 switch (gst_iterator_next (pad_it, &data)) {
2839 case GST_ITERATOR_OK:
2844 pad = GST_PAD_CAST (data);
2845 name = gst_pad_get_name (pad);
2847 if (strcmp (name, pad_name) == 0) {
2852 gst_object_unref (pad);
2855 case GST_ITERATOR_ERROR:
2856 case GST_ITERATOR_RESYNC:
2857 /* restart iteration */
2862 case GST_ITERATOR_DONE:
2867 gst_iterator_free (pad_it);
2870 GST_DEBUG_OBJECT (element, "free pad name found: '%s'", pad_name);
2877 gst_rtp_bin_request_new_pad (GstElement * element,
2878 GstPadTemplate * templ, const gchar * name)
2881 GstElementClass *klass;
2884 gchar *pad_name = NULL;
2886 g_return_val_if_fail (templ != NULL, NULL);
2887 g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
2889 rtpbin = GST_RTP_BIN (element);
2890 klass = GST_ELEMENT_GET_CLASS (element);
2892 GST_RTP_BIN_LOCK (rtpbin);
2895 /* use a free pad name */
2896 pad_name = gst_rtp_bin_get_free_pad_name (element, templ);
2898 /* use the provided name */
2899 pad_name = g_strdup (name);
2902 GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name);
2904 /* figure out the template */
2905 if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
2906 result = create_recv_rtp (rtpbin, templ, pad_name);
2907 } else if (templ == gst_element_class_get_pad_template (klass,
2908 "recv_rtcp_sink_%d")) {
2909 result = create_recv_rtcp (rtpbin, templ, pad_name);
2910 } else if (templ == gst_element_class_get_pad_template (klass,
2911 "send_rtp_sink_%d")) {
2912 result = create_send_rtp (rtpbin, templ, pad_name);
2913 } else if (templ == gst_element_class_get_pad_template (klass,
2914 "send_rtcp_src_%d")) {
2915 result = create_rtcp (rtpbin, templ, pad_name);
2917 goto wrong_template;
2920 GST_RTP_BIN_UNLOCK (rtpbin);
2928 GST_RTP_BIN_UNLOCK (rtpbin);
2929 g_warning ("gstrtpbin: this is not our template");
2935 gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
2937 GstRtpBinSession *session;
2940 g_return_if_fail (GST_IS_GHOST_PAD (pad));
2941 g_return_if_fail (GST_IS_RTP_BIN (element));
2943 rtpbin = GST_RTP_BIN (element);
2945 GST_RTP_BIN_LOCK (rtpbin);
2946 GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s",
2947 GST_DEBUG_PAD_NAME (pad));
2949 if (!(session = find_session_by_pad (rtpbin, pad)))
2952 if (session->recv_rtp_sink_ghost == pad) {
2953 remove_recv_rtp (rtpbin, session);
2954 } else if (session->recv_rtcp_sink_ghost == pad) {
2955 remove_recv_rtcp (rtpbin, session);
2956 } else if (session->send_rtp_sink_ghost == pad) {
2957 remove_send_rtp (rtpbin, session);
2958 } else if (session->send_rtcp_src_ghost == pad) {
2959 remove_rtcp (rtpbin, session);
2962 /* no more request pads, free the complete session */
2963 if (session->recv_rtp_sink_ghost == NULL
2964 && session->recv_rtcp_sink_ghost == NULL
2965 && session->send_rtp_sink_ghost == NULL
2966 && session->send_rtcp_src_ghost == NULL) {
2967 GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session);
2968 rtpbin->sessions = g_slist_remove (rtpbin->sessions, session);
2969 free_session (session, rtpbin);
2971 GST_RTP_BIN_UNLOCK (rtpbin);
2978 GST_RTP_BIN_UNLOCK (rtpbin);
2979 g_warning ("gstrtpbin: %s:%s is not one of our request pads",
2980 GST_DEBUG_PAD_NAME (pad));