2 * Copyright (C) 2008 Wim Taymans <wim.taymans at 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.
22 #include <gst/app/gstappsrc.h>
23 #include <gst/app/gstappsink.h>
25 #include "rtsp-media.h"
27 #define DEFAULT_SHARED FALSE
28 #define DEFAULT_REUSABLE FALSE
30 /* define to dump received RTCP packets */
47 GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug);
48 #define GST_CAT_DEFAULT rtsp_media_debug
50 static GQuark ssrc_stream_map_key;
52 static void gst_rtsp_media_get_property (GObject * object, guint propid,
53 GValue * value, GParamSpec * pspec);
54 static void gst_rtsp_media_set_property (GObject * object, guint propid,
55 const GValue * value, GParamSpec * pspec);
56 static void gst_rtsp_media_finalize (GObject * obj);
58 static gpointer do_loop (GstRTSPMediaClass * klass);
59 static gboolean default_handle_message (GstRTSPMedia * media,
60 GstMessage * message);
61 static gboolean default_unprepare (GstRTSPMedia * media);
62 static void unlock_streams (GstRTSPMedia * media);
64 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
66 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
69 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
71 GObjectClass *gobject_class;
74 gobject_class = G_OBJECT_CLASS (klass);
76 gobject_class->get_property = gst_rtsp_media_get_property;
77 gobject_class->set_property = gst_rtsp_media_set_property;
78 gobject_class->finalize = gst_rtsp_media_finalize;
80 g_object_class_install_property (gobject_class, PROP_SHARED,
81 g_param_spec_boolean ("shared", "Shared",
82 "If this media pipeline can be shared", DEFAULT_SHARED,
83 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
85 g_object_class_install_property (gobject_class, PROP_REUSABLE,
86 g_param_spec_boolean ("reusable", "Reusable",
87 "If this media pipeline can be reused after an unprepare",
88 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
90 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
91 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
92 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
93 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
95 klass->context = g_main_context_new ();
96 klass->loop = g_main_loop_new (klass->context, TRUE);
98 klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
100 g_critical ("could not start bus thread: %s", error->message);
102 klass->handle_message = default_handle_message;
103 klass->unprepare = default_unprepare;
105 ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
109 gst_rtsp_media_init (GstRTSPMedia * media)
111 media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
112 media->lock = g_mutex_new ();
113 media->cond = g_cond_new ();
117 gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
120 g_object_unref (stream->session);
123 gst_caps_unref (stream->caps);
125 if (stream->send_rtp_sink)
126 gst_object_unref (stream->send_rtp_sink);
127 if (stream->send_rtp_src)
128 gst_object_unref (stream->send_rtp_src);
129 if (stream->send_rtcp_src)
130 gst_object_unref (stream->send_rtcp_src);
131 if (stream->recv_rtcp_sink)
132 gst_object_unref (stream->recv_rtcp_sink);
133 if (stream->recv_rtp_sink)
134 gst_object_unref (stream->recv_rtp_sink);
136 g_list_free (stream->transports);
142 gst_rtsp_media_finalize (GObject * obj)
147 media = GST_RTSP_MEDIA (obj);
149 GST_INFO ("finalize media %p", media);
151 if (media->pipeline) {
152 unlock_streams (media);
153 gst_element_set_state (media->pipeline, GST_STATE_NULL);
154 gst_object_unref (media->pipeline);
157 for (i = 0; i < media->streams->len; i++) {
158 GstRTSPMediaStream *stream;
160 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
162 gst_rtsp_media_stream_free (stream);
164 g_array_free (media->streams, TRUE);
166 g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL);
167 g_list_free (media->dynamic);
170 g_source_destroy (media->source);
171 g_source_unref (media->source);
173 g_mutex_free (media->lock);
174 g_cond_free (media->cond);
176 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
180 gst_rtsp_media_get_property (GObject * object, guint propid,
181 GValue * value, GParamSpec * pspec)
183 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
187 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
190 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
198 gst_rtsp_media_set_property (GObject * object, guint propid,
199 const GValue * value, GParamSpec * pspec)
201 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
205 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
208 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
216 do_loop (GstRTSPMediaClass * klass)
218 GST_INFO ("enter mainloop");
219 g_main_loop_run (klass->loop);
220 GST_INFO ("exit mainloop");
226 collect_media_stats (GstRTSPMedia * media)
229 gint64 position, duration;
231 media->range.unit = GST_RTSP_RANGE_NPT;
233 if (media->is_live) {
234 media->range.min.type = GST_RTSP_TIME_NOW;
235 media->range.min.seconds = -1;
236 media->range.max.type = GST_RTSP_TIME_END;
237 media->range.max.seconds = -1;
239 /* get the position */
240 format = GST_FORMAT_TIME;
241 if (!gst_element_query_position (media->pipeline, &format, &position)) {
242 GST_INFO ("position query failed");
246 /* get the duration */
247 format = GST_FORMAT_TIME;
248 if (!gst_element_query_duration (media->pipeline, &format, &duration)) {
249 GST_INFO ("duration query failed");
253 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
254 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
256 if (position == -1) {
257 media->range.min.type = GST_RTSP_TIME_NOW;
258 media->range.min.seconds = -1;
260 media->range.min.type = GST_RTSP_TIME_SECONDS;
261 media->range.min.seconds = ((gdouble) position) / GST_SECOND;
263 if (duration == -1) {
264 media->range.max.type = GST_RTSP_TIME_END;
265 media->range.max.seconds = -1;
267 media->range.max.type = GST_RTSP_TIME_SECONDS;
268 media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
274 * gst_rtsp_media_new:
276 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
277 * element to produde RTP data for one or more related (audio/video/..)
280 * Returns: a new #GstRTSPMedia object.
283 gst_rtsp_media_new (void)
285 GstRTSPMedia *result;
287 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
293 * gst_rtsp_media_set_shared:
294 * @media: a #GstRTSPMedia
295 * @shared: the new value
297 * Set or unset if the pipeline for @media can be shared will multiple clients.
298 * When @shared is %TRUE, client requests for this media will share the media
302 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
304 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
306 media->shared = shared;
310 * gst_rtsp_media_is_shared:
311 * @media: a #GstRTSPMedia
313 * Check if the pipeline for @media can be shared between multiple clients.
315 * Returns: %TRUE if the media can be shared between clients.
318 gst_rtsp_media_is_shared (GstRTSPMedia * media)
320 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
322 return media->shared;
326 * gst_rtsp_media_set_reusable:
327 * @media: a #GstRTSPMedia
328 * @reusable: the new value
330 * Set or unset if the pipeline for @media can be reused after the pipeline has
334 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
336 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
338 media->reusable = reusable;
342 * gst_rtsp_media_is_reusable:
343 * @media: a #GstRTSPMedia
345 * Check if the pipeline for @media can be reused after an unprepare.
347 * Returns: %TRUE if the media can be reused
350 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
352 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
354 return media->reusable;
358 * gst_rtsp_media_n_streams:
359 * @media: a #GstRTSPMedia
361 * Get the number of streams in this media.
363 * Returns: The number of streams.
366 gst_rtsp_media_n_streams (GstRTSPMedia * media)
368 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
370 return media->streams->len;
374 * gst_rtsp_media_get_stream:
375 * @media: a #GstRTSPMedia
376 * @idx: the stream index
378 * Retrieve the stream with index @idx from @media.
380 * Returns: the #GstRTSPMediaStream at index @idx or %NULL when a stream with
381 * that index did not exist.
384 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
386 GstRTSPMediaStream *res;
388 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
390 if (idx < media->streams->len)
391 res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
399 * gst_rtsp_media_seek:
400 * @stream: a #GstRTSPMediaStream
401 * @range: a #GstRTSPTimeRange
403 * Seek the pipeline to @range.
405 * Returns: %TRUE on success.
408 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
413 GstSeekType start_type, stop_type;
415 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
416 g_return_val_if_fail (range != NULL, FALSE);
418 if (range->unit != GST_RTSP_RANGE_NPT)
421 /* depends on the current playing state of the pipeline. We might need to
422 * queue this until we get EOS. */
423 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
425 start_type = stop_type = GST_SEEK_TYPE_NONE;
427 switch (range->min.type) {
428 case GST_RTSP_TIME_NOW:
431 case GST_RTSP_TIME_SECONDS:
432 /* only seek when something changed */
433 if (media->range.min.seconds == range->min.seconds) {
436 start = range->min.seconds * GST_SECOND;
437 start_type = GST_SEEK_TYPE_SET;
440 case GST_RTSP_TIME_END:
444 switch (range->max.type) {
445 case GST_RTSP_TIME_SECONDS:
446 /* only seek when something changed */
447 if (media->range.max.seconds == range->max.seconds) {
450 stop = range->max.seconds * GST_SECOND;
451 stop_type = GST_SEEK_TYPE_SET;
454 case GST_RTSP_TIME_END:
456 stop_type = GST_SEEK_TYPE_SET;
458 case GST_RTSP_TIME_NOW:
463 if (start != -1 || stop != -1) {
464 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
465 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
467 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
468 flags, start_type, start, stop_type, stop);
470 /* and block for the seek to complete */
471 GST_INFO ("done seeking %d", res);
472 gst_element_get_state (media->pipeline, NULL, NULL, -1);
473 GST_INFO ("prerolled again");
475 GST_INFO ("no seek needed");
484 GST_WARNING ("seek unit %d not supported", range->unit);
489 GST_WARNING ("weird range type %d not supported", range->min.type);
495 * gst_rtsp_media_stream_rtp:
496 * @stream: a #GstRTSPMediaStream
497 * @buffer: a #GstBuffer
499 * Handle an RTP buffer for the stream. This method is usually called when a
500 * message has been received from a client using the TCP transport.
502 * This function takes ownership of @buffer.
504 * Returns: a GstFlowReturn.
507 gst_rtsp_media_stream_rtp (GstRTSPMediaStream * stream, GstBuffer * buffer)
511 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
517 * gst_rtsp_media_stream_rtcp:
518 * @stream: a #GstRTSPMediaStream
519 * @buffer: a #GstBuffer
521 * Handle an RTCP buffer for the stream. This method is usually called when a
522 * message has been received from a client using the TCP transport.
524 * This function takes ownership of @buffer.
526 * Returns: a GstFlowReturn.
529 gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer)
533 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
538 /* Allocate the udp ports and sockets */
540 alloc_udp_ports (GstRTSPMediaStream * stream)
542 GstStateChangeReturn ret;
543 GstElement *udpsrc0, *udpsrc1;
544 GstElement *udpsink0, *udpsink1;
545 gint tmp_rtp, tmp_rtcp;
547 gint rtpport, rtcpport, sockfd;
555 /* Start with random port */
558 /* try to allocate 2 UDP ports, the RTP port should be an even
559 * number and the RTCP port should be the next (uneven) port */
561 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
563 goto no_udp_protocol;
564 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
566 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
567 if (ret == GST_STATE_CHANGE_FAILURE) {
573 gst_element_set_state (udpsrc0, GST_STATE_NULL);
574 gst_object_unref (udpsrc0);
578 goto no_udp_protocol;
581 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
583 /* check if port is even */
584 if ((tmp_rtp & 1) != 0) {
585 /* port not even, close and allocate another */
589 gst_element_set_state (udpsrc0, GST_STATE_NULL);
590 gst_object_unref (udpsrc0);
596 /* allocate port+1 for RTCP now */
597 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
599 goto no_udp_rtcp_protocol;
602 tmp_rtcp = tmp_rtp + 1;
603 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
605 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
606 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
607 if (ret == GST_STATE_CHANGE_FAILURE) {
612 gst_element_set_state (udpsrc0, GST_STATE_NULL);
613 gst_object_unref (udpsrc0);
615 gst_element_set_state (udpsrc1, GST_STATE_NULL);
616 gst_object_unref (udpsrc1);
622 /* all fine, do port check */
623 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
624 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
626 /* this should not happen... */
627 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
630 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
632 goto no_udp_protocol;
634 g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL);
635 g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL);
636 g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL);
638 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
640 goto no_udp_protocol;
642 g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
643 g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL);
644 g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL);
645 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
646 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
648 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
649 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
650 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
651 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
653 /* we keep these elements, we configure all in configure_transport when the
654 * server told us to really use the UDP ports. */
655 stream->udpsrc[0] = udpsrc0;
656 stream->udpsrc[1] = udpsrc1;
657 stream->udpsink[0] = udpsink0;
658 stream->udpsink[1] = udpsink1;
659 stream->server_port.min = rtpport;
660 stream->server_port.max = rtcpport;
673 no_udp_rtcp_protocol:
684 gst_element_set_state (udpsrc0, GST_STATE_NULL);
685 gst_object_unref (udpsrc0);
688 gst_element_set_state (udpsrc1, GST_STATE_NULL);
689 gst_object_unref (udpsrc1);
692 gst_element_set_state (udpsink0, GST_STATE_NULL);
693 gst_object_unref (udpsink0);
696 gst_element_set_state (udpsink1, GST_STATE_NULL);
697 gst_object_unref (udpsink1);
704 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
707 GstCaps *newcaps, *oldcaps;
709 if ((newcaps = GST_PAD_CAPS (pad)))
710 gst_caps_ref (newcaps);
712 oldcaps = stream->caps;
713 stream->caps = newcaps;
716 gst_caps_unref (oldcaps);
718 capsstr = gst_caps_to_string (newcaps);
719 GST_INFO ("stream %p received caps %p, %s", stream, newcaps, capsstr);
724 dump_structure (const GstStructure * s)
728 sstr = gst_structure_to_string (s);
729 GST_INFO ("structure: %s", sstr);
733 static GstRTSPMediaTrans *
734 find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from)
737 GstRTSPMediaTrans *result = NULL;
742 if (rtcp_from == NULL)
745 tmp = g_strrstr (rtcp_from, ":");
749 port = atoi (tmp + 1);
750 dest = g_strndup (rtcp_from, tmp - rtcp_from);
752 GST_INFO ("finding %s:%d", dest, port);
754 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
755 GstRTSPMediaTrans *trans = walk->data;
758 min = trans->transport->client_port.min;
759 max = trans->transport->client_port.max;
761 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
773 on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
776 GstRTSPMediaTrans *trans;
778 GST_INFO ("%p: new source %p", stream, source);
780 /* see if we have a stream to match with the origin of the RTCP packet */
781 trans = g_object_get_qdata (source, ssrc_stream_map_key);
783 g_object_get (source, "stats", &stats, NULL);
785 const gchar *rtcp_from;
787 dump_structure (stats);
789 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
790 if ((trans = find_transport (stream, rtcp_from))) {
791 GST_INFO ("%p: found transport %p for source %p", stream, trans,
794 /* keep ref to the source */
795 trans->rtpsource = source;
797 g_object_set_qdata (source, ssrc_stream_map_key, trans);
799 gst_structure_free (stats);
802 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
807 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPMediaStream * stream)
809 GST_INFO ("%p: new SDES %p", stream, source);
813 on_ssrc_active (GObject * session, GObject * source,
814 GstRTSPMediaStream * stream)
816 GstRTSPMediaTrans *trans;
818 trans = g_object_get_qdata (source, ssrc_stream_map_key);
820 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
822 if (trans && trans->keep_alive)
823 trans->keep_alive (trans->ka_user_data);
828 g_object_get (source, "stats", &stats, NULL);
830 dump_structure (stats);
831 gst_structure_free (stats);
838 on_bye_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
840 GST_INFO ("%p: source %p bye", stream, source);
844 on_bye_timeout (GObject * session, GObject * source,
845 GstRTSPMediaStream * stream)
847 GstRTSPMediaTrans *trans;
849 GST_INFO ("%p: source %p bye timeout", stream, source);
851 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
852 trans->rtpsource = NULL;
853 trans->timeout = TRUE;
858 on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream)
860 GstRTSPMediaTrans *trans;
862 GST_INFO ("%p: source %p timeout", stream, source);
864 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
865 trans->rtpsource = NULL;
866 trans->timeout = TRUE;
871 handle_new_buffer (GstAppSink * sink, gpointer user_data)
875 GstRTSPMediaStream *stream;
877 buffer = gst_app_sink_pull_buffer (sink);
881 stream = (GstRTSPMediaStream *) user_data;
883 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
884 GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
886 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
888 tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data);
891 tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data);
894 gst_buffer_unref (buffer);
899 static GstAppSinkCallbacks sink_cb = {
900 NULL, /* not interested in EOS */
901 NULL, /* not interested in preroll buffers */
905 /* prepare the pipeline objects to handle @stream in @media */
907 setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
910 GstPad *pad, *teepad, *selpad;
911 GstPadLinkReturn ret;
914 /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2
915 * for sending RTP/RTCP. The sender and receiver ports are shared between the
917 if (!alloc_udp_ports (stream))
920 /* add the ports to the pipeline */
921 for (i = 0; i < 2; i++) {
922 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[i]);
923 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[i]);
926 /* create elements for the TCP transfer */
927 for (i = 0; i < 2; i++) {
928 stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
929 stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
930 g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
931 g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
932 g_object_set (stream->appsink[i], "preroll-queue-len", 1, NULL);
933 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]);
934 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]);
935 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
936 &sink_cb, stream, NULL);
939 /* hook up the stream to the RTP session elements. */
940 name = g_strdup_printf ("send_rtp_sink_%d", idx);
941 stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
943 name = g_strdup_printf ("send_rtp_src_%d", idx);
944 stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name);
946 name = g_strdup_printf ("send_rtcp_src_%d", idx);
947 stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name);
949 name = g_strdup_printf ("recv_rtcp_sink_%d", idx);
950 stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
952 name = g_strdup_printf ("recv_rtp_sink_%d", idx);
953 stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
956 /* get the session */
957 g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx,
960 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
962 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
964 g_signal_connect (stream->session, "on-ssrc-active",
965 (GCallback) on_ssrc_active, stream);
966 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
968 g_signal_connect (stream->session, "on-bye-timeout",
969 (GCallback) on_bye_timeout, stream);
970 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
973 /* link the RTP pad to the session manager */
974 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
975 if (ret != GST_PAD_LINK_OK)
978 /* make tee for RTP and link to stream */
979 stream->tee[0] = gst_element_factory_make ("tee", NULL);
980 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]);
982 pad = gst_element_get_static_pad (stream->tee[0], "sink");
983 gst_pad_link (stream->send_rtp_src, pad);
984 gst_object_unref (pad);
986 /* link RTP sink, we're pretty sure this will work. */
987 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
988 pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
989 gst_pad_link (teepad, pad);
990 gst_object_unref (pad);
991 gst_object_unref (teepad);
993 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
994 pad = gst_element_get_static_pad (stream->appsink[0], "sink");
995 gst_pad_link (teepad, pad);
996 gst_object_unref (pad);
997 gst_object_unref (teepad);
999 /* make tee for RTCP */
1000 stream->tee[1] = gst_element_factory_make ("tee", NULL);
1001 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]);
1003 pad = gst_element_get_static_pad (stream->tee[1], "sink");
1004 gst_pad_link (stream->send_rtcp_src, pad);
1005 gst_object_unref (pad);
1007 /* link RTCP elements */
1008 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1009 pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
1010 gst_pad_link (teepad, pad);
1011 gst_object_unref (pad);
1012 gst_object_unref (teepad);
1014 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1015 pad = gst_element_get_static_pad (stream->appsink[1], "sink");
1016 gst_pad_link (teepad, pad);
1017 gst_object_unref (pad);
1018 gst_object_unref (teepad);
1020 /* make selector for the RTP receivers */
1021 stream->selector[0] = gst_element_factory_make ("input-selector", NULL);
1022 g_object_set (stream->selector[0], "select-all", TRUE, NULL);
1023 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
1025 pad = gst_element_get_static_pad (stream->selector[0], "src");
1026 gst_pad_link (pad, stream->recv_rtp_sink);
1027 gst_object_unref (pad);
1029 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1030 pad = gst_element_get_static_pad (stream->udpsrc[0], "src");
1031 gst_pad_link (pad, selpad);
1032 gst_object_unref (pad);
1033 gst_object_unref (selpad);
1035 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1036 pad = gst_element_get_static_pad (stream->appsrc[0], "src");
1037 gst_pad_link (pad, selpad);
1038 gst_object_unref (pad);
1039 gst_object_unref (selpad);
1041 /* make selector for the RTCP receivers */
1042 stream->selector[1] = gst_element_factory_make ("input-selector", NULL);
1043 g_object_set (stream->selector[1], "select-all", TRUE, NULL);
1044 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
1046 pad = gst_element_get_static_pad (stream->selector[1], "src");
1047 gst_pad_link (pad, stream->recv_rtcp_sink);
1048 gst_object_unref (pad);
1050 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1051 pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
1052 gst_pad_link (pad, selpad);
1053 gst_object_unref (pad);
1054 gst_object_unref (selpad);
1056 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1057 pad = gst_element_get_static_pad (stream->appsrc[1], "src");
1058 gst_pad_link (pad, selpad);
1059 gst_object_unref (pad);
1060 gst_object_unref (selpad);
1062 /* we set and keep these to playing so that they don't cause NO_PREROLL return
1064 gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING);
1065 gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING);
1066 gst_element_set_locked_state (stream->udpsrc[0], TRUE);
1067 gst_element_set_locked_state (stream->udpsrc[1], TRUE);
1069 /* be notified of caps changes */
1070 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
1071 (GCallback) caps_notify, stream);
1073 stream->prepared = TRUE;
1080 GST_WARNING ("failed to link stream %d", idx);
1086 unlock_streams (GstRTSPMedia * media)
1090 /* unlock the udp src elements */
1091 n_streams = gst_rtsp_media_n_streams (media);
1092 for (i = 0; i < n_streams; i++) {
1093 GstRTSPMediaStream *stream;
1095 stream = gst_rtsp_media_get_stream (media, i);
1097 gst_element_set_locked_state (stream->udpsrc[0], FALSE);
1098 gst_element_set_locked_state (stream->udpsrc[1], FALSE);
1103 gst_rtsp_media_set_status (GstRTSPMedia *media, GstRTSPMediaStatus status)
1105 g_mutex_lock (media->lock);
1106 /* never overwrite the error status */
1107 if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
1108 media->status = status;
1109 GST_DEBUG ("setting new status to %d", status);
1110 g_cond_broadcast (media->cond);
1111 g_mutex_unlock (media->lock);
1114 static GstRTSPMediaStatus
1115 gst_rtsp_media_get_status (GstRTSPMedia *media)
1117 GstRTSPMediaStatus result;
1119 g_mutex_lock (media->lock);
1120 /* while we are preparing, wait */
1121 while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1122 GST_DEBUG ("waiting for status change");
1123 g_cond_wait (media->cond, media->lock);
1125 /* could be success or error */
1126 result = media->status;
1127 GST_DEBUG ("got status %d", result);
1128 g_mutex_unlock (media->lock);
1134 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1136 GstMessageType type;
1138 type = GST_MESSAGE_TYPE (message);
1141 case GST_MESSAGE_STATE_CHANGED:
1143 case GST_MESSAGE_BUFFERING:
1147 gst_message_parse_buffering (message, &percent);
1149 /* no state management needed for live pipelines */
1153 if (percent == 100) {
1154 /* a 100% message means buffering is done */
1155 media->buffering = FALSE;
1156 /* if the desired state is playing, go back */
1157 if (media->target_state == GST_STATE_PLAYING) {
1158 GST_INFO ("Buffering done, setting pipeline to PLAYING");
1159 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1161 GST_INFO ("Buffering done");
1164 /* buffering busy */
1165 if (media->buffering == FALSE) {
1166 if (media->target_state == GST_STATE_PLAYING) {
1167 /* we were not buffering but PLAYING, PAUSE the pipeline. */
1168 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1169 gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1171 GST_INFO ("Buffering ...");
1174 media->buffering = TRUE;
1178 case GST_MESSAGE_LATENCY:
1180 gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
1183 case GST_MESSAGE_ERROR:
1188 gst_message_parse_error (message, &gerror, &debug);
1189 GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1190 g_error_free (gerror);
1193 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1196 case GST_MESSAGE_WARNING:
1201 gst_message_parse_warning (message, &gerror, &debug);
1202 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1203 g_error_free (gerror);
1207 case GST_MESSAGE_ELEMENT:
1209 case GST_MESSAGE_STREAM_STATUS:
1211 case GST_MESSAGE_ASYNC_DONE:
1212 GST_INFO ("%p: got ASYNC_DONE", media);
1213 collect_media_stats (media);
1215 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1218 GST_INFO ("%p: got message type %s", media,
1219 gst_message_type_get_name (type));
1226 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1228 GstRTSPMediaClass *klass;
1231 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1233 if (klass->handle_message)
1234 ret = klass->handle_message (media, message);
1242 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1244 GstRTSPMediaStream *stream;
1248 i = media->streams->len + 1;
1250 GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i);
1252 stream = g_new0 (GstRTSPMediaStream, 1);
1253 stream->payloader = element;
1255 name = g_strdup_printf ("dynpay%d", i);
1257 /* ghost the pad of the payloader to the element */
1258 stream->srcpad = gst_ghost_pad_new (name, pad);
1259 gst_pad_set_active (stream->srcpad, TRUE);
1260 gst_element_add_pad (media->element, stream->srcpad);
1263 /* add stream now */
1264 g_array_append_val (media->streams, stream);
1266 setup_stream (stream, i, media);
1268 for (i = 0; i < 2; i++) {
1269 gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED);
1270 gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED);
1271 gst_element_set_state (stream->tee[i], GST_STATE_PAUSED);
1272 gst_element_set_state (stream->selector[i], GST_STATE_PAUSED);
1273 gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED);
1278 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1280 GST_INFO ("no more pads");
1281 if (media->fakesink) {
1282 gst_object_ref (media->fakesink);
1283 gst_bin_remove (GST_BIN (media->pipeline), media->fakesink);
1284 gst_element_set_state (media->fakesink, GST_STATE_NULL);
1285 gst_object_unref (media->fakesink);
1286 media->fakesink = NULL;
1287 GST_INFO ("removed fakesink");
1292 * gst_rtsp_media_prepare:
1293 * @obj: a #GstRTSPMedia
1295 * Prepare @media for streaming. This function will create the pipeline and
1296 * other objects to manage the streaming.
1298 * It will preroll the pipeline and collect vital information about the streams
1299 * such as the duration.
1301 * Returns: %TRUE on success.
1304 gst_rtsp_media_prepare (GstRTSPMedia * media)
1306 GstStateChangeReturn ret;
1307 GstRTSPMediaStatus status;
1309 GstRTSPMediaClass *klass;
1313 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1316 if (!media->reusable && media->reused)
1319 GST_INFO ("preparing media %p", media);
1321 /* reset some variables */
1322 media->is_live = FALSE;
1323 media->buffering = FALSE;
1324 /* we're preparing now */
1325 media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1327 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
1329 /* add the pipeline bus to our custom mainloop */
1330 media->source = gst_bus_create_watch (bus);
1331 gst_object_unref (bus);
1333 g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL);
1335 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1336 media->id = g_source_attach (media->source, klass->context);
1338 media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL);
1340 /* add stuff to the bin */
1341 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
1343 /* link streams we already have, other streams might appear when we have
1344 * dynamic elements */
1345 n_streams = gst_rtsp_media_n_streams (media);
1346 for (i = 0; i < n_streams; i++) {
1347 GstRTSPMediaStream *stream;
1349 stream = gst_rtsp_media_get_stream (media, i);
1351 setup_stream (stream, i, media);
1354 for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
1355 GstElement *elem = walk->data;
1357 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1358 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1360 /* we add a fakesink here in order to make the state change async. We remove
1361 * the fakesink again in the no-more-pads callback. */
1362 media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1363 gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
1366 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1367 /* first go to PAUSED */
1368 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1369 media->target_state = GST_STATE_PAUSED;
1372 case GST_STATE_CHANGE_SUCCESS:
1373 GST_INFO ("SUCCESS state change for media %p", media);
1375 case GST_STATE_CHANGE_ASYNC:
1376 GST_INFO ("ASYNC state change for media %p", media);
1378 case GST_STATE_CHANGE_NO_PREROLL:
1379 /* we need to go to PLAYING */
1380 GST_INFO ("NO_PREROLL state change: live media %p", media);
1381 media->is_live = TRUE;
1382 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1383 if (ret == GST_STATE_CHANGE_FAILURE)
1386 case GST_STATE_CHANGE_FAILURE:
1390 /* now wait for all pads to be prerolled */
1391 status = gst_rtsp_media_get_status (media);
1392 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1395 GST_INFO ("object %p is prerolled", media);
1407 GST_WARNING ("failed to preroll pipeline");
1408 unlock_streams (media);
1409 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1414 GST_WARNING ("can not reuse media %p", media);
1420 * gst_rtsp_media_unprepare:
1421 * @obj: a #GstRTSPMedia
1423 * Unprepare @media. After this call, the media should be prepared again before
1424 * it can be used again. If the media is set to be non-reusable, a new instance
1427 * Returns: %TRUE on success.
1430 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1432 GstRTSPMediaClass *klass;
1435 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1438 GST_INFO ("unprepare media %p", media);
1439 media->target_state = GST_STATE_NULL;
1441 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1442 if (klass->unprepare)
1443 success = klass->unprepare (media);
1447 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1448 media->reused = TRUE;
1450 /* when the media is not reusable, this will effectively unref the media and
1452 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1458 default_unprepare (GstRTSPMedia * media)
1460 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1466 * gst_rtsp_media_set_state:
1467 * @media: a #GstRTSPMedia
1468 * @state: the target state of the media
1469 * @transports: a GArray of #GstRTSPMediaTrans pointers
1471 * Set the state of @media to @state and for the transports in @transports.
1473 * Returns: %TRUE on success.
1476 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1477 GArray * transports)
1480 GstStateChangeReturn ret;
1481 gboolean add, remove, do_state;
1484 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1485 g_return_val_if_fail (transports != NULL, FALSE);
1487 /* NULL and READY are the same */
1488 if (state == GST_STATE_READY)
1489 state = GST_STATE_NULL;
1491 add = remove = FALSE;
1493 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1497 case GST_STATE_NULL:
1498 /* unlock the streams so that they follow the state changes from now on */
1499 unlock_streams (media);
1501 case GST_STATE_PAUSED:
1502 /* we're going from PLAYING to PAUSED, READY or NULL, remove */
1503 if (media->target_state == GST_STATE_PLAYING)
1506 case GST_STATE_PLAYING:
1507 /* we're going to PLAYING, add */
1513 old_active = media->active;
1515 for (i = 0; i < transports->len; i++) {
1516 GstRTSPMediaTrans *tr;
1517 GstRTSPMediaStream *stream;
1518 GstRTSPTransport *trans;
1520 /* we need a non-NULL entry in the array */
1521 tr = g_array_index (transports, GstRTSPMediaTrans *, i);
1525 /* we need a transport */
1526 if (!(trans = tr->transport))
1529 /* get the stream and add the destinations */
1530 stream = gst_rtsp_media_get_stream (media, tr->idx);
1531 switch (trans->lower_transport) {
1532 case GST_RTSP_LOWER_TRANS_UDP:
1533 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1538 dest = trans->destination;
1539 if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1540 min = trans->port.min;
1541 max = trans->port.max;
1543 min = trans->client_port.min;
1544 max = trans->client_port.max;
1547 if (add && !tr->active) {
1548 GST_INFO ("adding %s:%d-%d", dest, min, max);
1549 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
1550 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
1551 stream->transports = g_list_prepend (stream->transports, tr);
1554 } else if (remove && tr->active) {
1555 GST_INFO ("removing %s:%d-%d", dest, min, max);
1556 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
1557 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
1558 stream->transports = g_list_remove (stream->transports, tr);
1564 case GST_RTSP_LOWER_TRANS_TCP:
1565 if (add && !tr->active) {
1566 GST_INFO ("adding TCP %s", trans->destination);
1567 stream->transports = g_list_prepend (stream->transports, tr);
1570 } else if (remove && tr->active) {
1571 GST_INFO ("removing TCP %s", trans->destination);
1572 stream->transports = g_list_remove (stream->transports, tr);
1578 GST_INFO ("Unknown transport %d", trans->lower_transport);
1583 /* we just added the first media, do the playing state change */
1584 if (old_active == 0 && add)
1586 /* if we have no more active media, do the downward state changes */
1587 else if (media->active == 0)
1592 GST_INFO ("active %d media %p", media->active, media);
1594 if (do_state && media->target_state != state) {
1595 if (state == GST_STATE_NULL) {
1596 gst_rtsp_media_unprepare (media);
1598 GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
1599 media->target_state = state;
1600 ret = gst_element_set_state (media->pipeline, state);
1604 /* remember where we are */
1605 if (state == GST_STATE_PAUSED)
1606 collect_media_stats (media);
1612 * gst_rtsp_media_remove_elements:
1613 * @media: a #GstRTSPMedia
1615 * Remove all elements and the pipeline controlled by @media.
1618 gst_rtsp_media_remove_elements (GstRTSPMedia * media)
1622 unlock_streams (media);
1624 for (i = 0; i < media->streams->len; i++) {
1625 GstRTSPMediaStream *stream;
1627 GST_INFO ("Removing elements of stream %d from pipeline", i);
1629 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
1631 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
1633 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
1635 for (j = 0; j < 2; j++) {
1636 gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL);
1637 gst_element_set_state (stream->udpsink[j], GST_STATE_NULL);
1638 gst_element_set_state (stream->appsrc[j], GST_STATE_NULL);
1639 gst_element_set_state (stream->appsink[j], GST_STATE_NULL);
1640 gst_element_set_state (stream->tee[j], GST_STATE_NULL);
1641 gst_element_set_state (stream->selector[j], GST_STATE_NULL);
1643 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]);
1644 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]);
1645 gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]);
1646 gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]);
1647 gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]);
1648 gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]);
1651 gst_caps_unref (stream->caps);
1652 stream->caps = NULL;
1653 gst_rtsp_media_stream_free (stream);
1655 g_array_remove_range (media->streams, 0, media->streams->len);
1657 gst_element_set_state (media->rtpbin, GST_STATE_NULL);
1658 gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
1660 gst_object_unref (media->pipeline);
1661 media->pipeline = NULL;