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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include <gst/app/gstappsrc.h>
24 #include <gst/app/gstappsink.h>
26 #include "rtsp-media.h"
28 #define GST_RTSP_MEDIA_GET_PRIVATE(obj) \
29 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate))
31 struct _GstRTSPMediaPrivate
38 GstRTSPLowerTrans protocols;
40 gboolean eos_shutdown;
43 GstRTSPAddressPool *pool;
49 GstRTSPMediaStatus status;
53 /* the pipeline for the media */
62 GstState target_state;
64 /* RTP session manager */
67 /* the range of media */
68 GstRTSPTimeRange range;
69 GstClockTime range_start;
70 GstClockTime range_stop;
73 #define DEFAULT_SHARED FALSE
74 #define DEFAULT_REUSABLE FALSE
75 #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
76 //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
77 #define DEFAULT_EOS_SHUTDOWN FALSE
78 #define DEFAULT_BUFFER_SIZE 0x80000
80 /* define to dump received RTCP packets */
103 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
104 #define GST_CAT_DEFAULT rtsp_media_debug
106 static void gst_rtsp_media_get_property (GObject * object, guint propid,
107 GValue * value, GParamSpec * pspec);
108 static void gst_rtsp_media_set_property (GObject * object, guint propid,
109 const GValue * value, GParamSpec * pspec);
110 static void gst_rtsp_media_finalize (GObject * obj);
112 static gpointer do_loop (GstRTSPMediaClass * klass);
113 static gboolean default_handle_message (GstRTSPMedia * media,
114 GstMessage * message);
115 static void finish_unprepare (GstRTSPMedia * media);
116 static gboolean default_unprepare (GstRTSPMedia * media);
118 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
120 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
123 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
125 GObjectClass *gobject_class;
127 g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate));
129 gobject_class = G_OBJECT_CLASS (klass);
131 gobject_class->get_property = gst_rtsp_media_get_property;
132 gobject_class->set_property = gst_rtsp_media_set_property;
133 gobject_class->finalize = gst_rtsp_media_finalize;
135 g_object_class_install_property (gobject_class, PROP_SHARED,
136 g_param_spec_boolean ("shared", "Shared",
137 "If this media pipeline can be shared", DEFAULT_SHARED,
138 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
140 g_object_class_install_property (gobject_class, PROP_REUSABLE,
141 g_param_spec_boolean ("reusable", "Reusable",
142 "If this media pipeline can be reused after an unprepare",
143 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
145 g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
146 g_param_spec_flags ("protocols", "Protocols",
147 "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
148 DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
151 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
152 "Send an EOS event to the pipeline before unpreparing",
153 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
156 g_param_spec_uint ("buffer-size", "Buffer Size",
157 "The kernel UDP buffer size to use", 0, G_MAXUINT,
158 DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
160 gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
161 g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
162 G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
163 g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM);
165 gst_rtsp_media_signals[SIGNAL_PREPARED] =
166 g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
167 G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
168 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
170 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
171 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
172 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
173 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
175 gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
176 g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
177 G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
178 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
180 klass->context = g_main_context_new ();
181 klass->loop = g_main_loop_new (klass->context, TRUE);
183 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
185 klass->thread = g_thread_new ("Bus Thread", (GThreadFunc) do_loop, klass);
187 klass->handle_message = default_handle_message;
188 klass->unprepare = default_unprepare;
192 gst_rtsp_media_init (GstRTSPMedia * media)
194 GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media);
198 priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
199 g_mutex_init (&priv->lock);
200 g_cond_init (&priv->cond);
201 g_rec_mutex_init (&priv->state_lock);
203 priv->shared = DEFAULT_SHARED;
204 priv->reusable = DEFAULT_REUSABLE;
205 priv->protocols = DEFAULT_PROTOCOLS;
206 priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
207 priv->buffer_size = DEFAULT_BUFFER_SIZE;
211 gst_rtsp_media_finalize (GObject * obj)
213 GstRTSPMediaPrivate *priv;
216 media = GST_RTSP_MEDIA (obj);
219 GST_INFO ("finalize media %p", media);
221 gst_rtsp_media_unprepare (media);
223 g_ptr_array_unref (priv->streams);
225 g_list_free_full (priv->dynamic, gst_object_unref);
228 gst_object_unref (priv->pipeline);
230 g_object_unref (priv->auth);
232 g_object_unref (priv->pool);
233 g_mutex_clear (&priv->lock);
234 g_cond_clear (&priv->cond);
235 g_rec_mutex_clear (&priv->state_lock);
237 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
241 gst_rtsp_media_get_property (GObject * object, guint propid,
242 GValue * value, GParamSpec * pspec)
244 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
248 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
251 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
254 g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
256 case PROP_EOS_SHUTDOWN:
257 g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
259 case PROP_BUFFER_SIZE:
260 g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
263 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
268 gst_rtsp_media_set_property (GObject * object, guint propid,
269 const GValue * value, GParamSpec * pspec)
271 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
275 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
278 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
281 gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
283 case PROP_EOS_SHUTDOWN:
284 gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
286 case PROP_BUFFER_SIZE:
287 gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
290 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
295 do_loop (GstRTSPMediaClass * klass)
297 GST_INFO ("enter mainloop");
298 g_main_loop_run (klass->loop);
299 GST_INFO ("exit mainloop");
304 /* must be called with state lock */
306 collect_media_stats (GstRTSPMedia * media)
308 GstRTSPMediaPrivate *priv = media->priv;
309 gint64 position, duration;
311 priv->range.unit = GST_RTSP_RANGE_NPT;
313 GST_INFO ("collect media stats");
316 priv->range.min.type = GST_RTSP_TIME_NOW;
317 priv->range.min.seconds = -1;
318 priv->range_start = -1;
319 priv->range.max.type = GST_RTSP_TIME_END;
320 priv->range.max.seconds = -1;
321 priv->range_stop = -1;
323 /* get the position */
324 if (!gst_element_query_position (priv->pipeline, GST_FORMAT_TIME,
326 GST_INFO ("position query failed");
330 /* get the duration */
331 if (!gst_element_query_duration (priv->pipeline, GST_FORMAT_TIME,
333 GST_INFO ("duration query failed");
337 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
338 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
340 if (position == -1) {
341 priv->range.min.type = GST_RTSP_TIME_NOW;
342 priv->range.min.seconds = -1;
343 priv->range_start = -1;
345 priv->range.min.type = GST_RTSP_TIME_SECONDS;
346 priv->range.min.seconds = ((gdouble) position) / GST_SECOND;
347 priv->range_start = position;
349 if (duration == -1) {
350 priv->range.max.type = GST_RTSP_TIME_END;
351 priv->range.max.seconds = -1;
352 priv->range_stop = -1;
354 priv->range.max.type = GST_RTSP_TIME_SECONDS;
355 priv->range.max.seconds = ((gdouble) duration) / GST_SECOND;
356 priv->range_stop = duration;
362 * gst_rtsp_media_new:
363 * @element: (transfer full): a #GstElement
365 * Create a new #GstRTSPMedia instance. @element is the bin element that
366 * provides the different streams. The #GstRTSPMedia object contains the
367 * element to produce RTP data for one or more related (audio/video/..)
370 * Ownership is taken of @element.
372 * Returns: a new #GstRTSPMedia object.
375 gst_rtsp_media_new (GstElement * element)
377 GstRTSPMedia *result;
379 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
381 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
382 result->priv->element = element;
388 * gst_rtsp_media_take_element:
389 * @media: a #GstRTSPMedia
390 * @pipeline: (transfer full): a #GstPipeline
392 * Set @pipeline as the #GstPipeline for @media. Ownership is
393 * taken of @pipeline.
396 gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
398 GstRTSPMediaPrivate *priv;
401 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
402 g_return_if_fail (GST_IS_PIPELINE (pipeline));
406 g_mutex_lock (&priv->lock);
407 old = priv->pipeline;
408 priv->pipeline = GST_ELEMENT_CAST (pipeline);
409 g_mutex_unlock (&priv->lock);
412 gst_object_unref (old);
414 gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
418 * gst_rtsp_media_set_shared:
419 * @media: a #GstRTSPMedia
420 * @shared: the new value
422 * Set or unset if the pipeline for @media can be shared will multiple clients.
423 * When @shared is %TRUE, client requests for this media will share the media
427 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
429 GstRTSPMediaPrivate *priv;
431 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
435 g_mutex_lock (&priv->lock);
436 priv->shared = shared;
437 g_mutex_unlock (&priv->lock);
441 * gst_rtsp_media_is_shared:
442 * @media: a #GstRTSPMedia
444 * Check if the pipeline for @media can be shared between multiple clients.
446 * Returns: %TRUE if the media can be shared between clients.
449 gst_rtsp_media_is_shared (GstRTSPMedia * media)
451 GstRTSPMediaPrivate *priv;
454 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
458 g_mutex_lock (&priv->lock);
460 g_mutex_unlock (&priv->lock);
466 * gst_rtsp_media_set_reusable:
467 * @media: a #GstRTSPMedia
468 * @reusable: the new value
470 * Set or unset if the pipeline for @media can be reused after the pipeline has
474 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
476 GstRTSPMediaPrivate *priv;
478 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
482 g_mutex_lock (&priv->lock);
483 priv->reusable = reusable;
484 g_mutex_unlock (&priv->lock);
488 * gst_rtsp_media_is_reusable:
489 * @media: a #GstRTSPMedia
491 * Check if the pipeline for @media can be reused after an unprepare.
493 * Returns: %TRUE if the media can be reused
496 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
498 GstRTSPMediaPrivate *priv;
501 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
505 g_mutex_lock (&priv->lock);
506 res = priv->reusable;
507 g_mutex_unlock (&priv->lock);
513 * gst_rtsp_media_set_protocols:
514 * @media: a #GstRTSPMedia
515 * @protocols: the new flags
517 * Configure the allowed lower transport for @media.
520 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
522 GstRTSPMediaPrivate *priv;
524 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
528 g_mutex_lock (&priv->lock);
529 priv->protocols = protocols;
530 g_mutex_unlock (&priv->lock);
534 * gst_rtsp_media_get_protocols:
535 * @media: a #GstRTSPMedia
537 * Get the allowed protocols of @media.
539 * Returns: a #GstRTSPLowerTrans
542 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
544 GstRTSPMediaPrivate *priv;
545 GstRTSPLowerTrans res;
547 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
548 GST_RTSP_LOWER_TRANS_UNKNOWN);
552 g_mutex_lock (&priv->lock);
553 res = priv->protocols;
554 g_mutex_unlock (&priv->lock);
560 * gst_rtsp_media_set_eos_shutdown:
561 * @media: a #GstRTSPMedia
562 * @eos_shutdown: the new value
564 * Set or unset if an EOS event will be sent to the pipeline for @media before
568 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
570 GstRTSPMediaPrivate *priv;
572 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
576 g_mutex_lock (&priv->lock);
577 priv->eos_shutdown = eos_shutdown;
578 g_mutex_unlock (&priv->lock);
582 * gst_rtsp_media_is_eos_shutdown:
583 * @media: a #GstRTSPMedia
585 * Check if the pipeline for @media will send an EOS down the pipeline before
588 * Returns: %TRUE if the media will send EOS before unpreparing.
591 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
593 GstRTSPMediaPrivate *priv;
596 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
600 g_mutex_lock (&priv->lock);
601 res = priv->eos_shutdown;
602 g_mutex_unlock (&priv->lock);
608 * gst_rtsp_media_set_buffer_size:
609 * @media: a #GstRTSPMedia
610 * @size: the new value
612 * Set the kernel UDP buffer size.
615 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
617 GstRTSPMediaPrivate *priv;
619 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
621 GST_LOG_OBJECT (media, "set buffer size %u", size);
625 g_mutex_lock (&priv->lock);
626 priv->buffer_size = size;
627 g_mutex_unlock (&priv->lock);
631 * gst_rtsp_media_get_buffer_size:
632 * @media: a #GstRTSPMedia
634 * Get the kernel UDP buffer size.
636 * Returns: the kernel UDP buffer size.
639 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
641 GstRTSPMediaPrivate *priv;
644 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
648 g_mutex_unlock (&priv->lock);
649 res = priv->buffer_size;
650 g_mutex_unlock (&priv->lock);
656 * gst_rtsp_media_set_auth:
657 * @media: a #GstRTSPMedia
658 * @auth: a #GstRTSPAuth
660 * configure @auth to be used as the authentication manager of @media.
663 gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
665 GstRTSPMediaPrivate *priv;
668 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
672 GST_LOG_OBJECT (media, "set auth %p", auth);
674 g_mutex_lock (&priv->lock);
675 if ((old = priv->auth) != auth)
676 priv->auth = auth ? g_object_ref (auth) : NULL;
679 g_mutex_unlock (&priv->lock);
682 g_object_unref (old);
686 * gst_rtsp_media_get_auth:
687 * @media: a #GstRTSPMedia
689 * Get the #GstRTSPAuth used as the authentication manager of @media.
691 * Returns: (transfer full): the #GstRTSPAuth of @media. g_object_unref() after
695 gst_rtsp_media_get_auth (GstRTSPMedia * media)
697 GstRTSPMediaPrivate *priv;
700 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
704 g_mutex_lock (&priv->lock);
705 if ((result = priv->auth))
706 g_object_ref (result);
707 g_mutex_unlock (&priv->lock);
713 * gst_rtsp_media_set_address_pool:
714 * @media: a #GstRTSPMedia
715 * @pool: a #GstRTSPAddressPool
717 * configure @pool to be used as the address pool of @media.
720 gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
721 GstRTSPAddressPool * pool)
723 GstRTSPMediaPrivate *priv;
724 GstRTSPAddressPool *old;
726 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
730 GST_LOG_OBJECT (media, "set address pool %p", pool);
732 g_mutex_lock (&priv->lock);
733 if ((old = priv->pool) != pool)
734 priv->pool = pool ? g_object_ref (pool) : NULL;
737 g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool,
739 g_mutex_unlock (&priv->lock);
742 g_object_unref (old);
746 * gst_rtsp_media_get_address_pool:
747 * @media: a #GstRTSPMedia
749 * Get the #GstRTSPAddressPool used as the address pool of @media.
751 * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after
755 gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
757 GstRTSPMediaPrivate *priv;
758 GstRTSPAddressPool *result;
760 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
764 g_mutex_lock (&priv->lock);
765 if ((result = priv->pool))
766 g_object_ref (result);
767 g_mutex_unlock (&priv->lock);
773 * gst_rtsp_media_collect_streams:
774 * @media: a #GstRTSPMedia
776 * Find all payloader elements, they should be named pay%d in the
777 * element of @media, and create #GstRTSPStreams for them.
779 * Collect all dynamic elements, named dynpay%d, and add them to
780 * the list of dynamic elements.
783 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
785 GstRTSPMediaPrivate *priv;
786 GstElement *element, *elem;
791 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
794 element = priv->element;
797 for (i = 0; have_elem; i++) {
802 name = g_strdup_printf ("pay%d", i);
803 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
804 GST_INFO ("found stream %d with payloader %p", i, elem);
806 /* take the pad of the payloader */
807 pad = gst_element_get_static_pad (elem, "src");
808 /* create the stream */
809 gst_rtsp_media_create_stream (media, elem, pad);
810 gst_object_unref (pad);
811 gst_object_unref (elem);
817 name = g_strdup_printf ("dynpay%d", i);
818 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
819 /* a stream that will dynamically create pads to provide RTP packets */
821 GST_INFO ("found dynamic element %d, %p", i, elem);
823 g_mutex_lock (&priv->lock);
824 priv->dynamic = g_list_prepend (priv->dynamic, elem);
825 g_mutex_unlock (&priv->lock);
834 * gst_rtsp_media_create_stream:
835 * @media: a #GstRTSPMedia
836 * @payloader: a #GstElement
837 * @srcpad: a source #GstPad
839 * Create a new stream in @media that provides RTP data on @srcpad.
840 * @srcpad should be a pad of an element inside @media->element.
842 * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
846 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
849 GstRTSPMediaPrivate *priv;
850 GstRTSPStream *stream;
855 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
856 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
857 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
858 g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
862 g_mutex_lock (&priv->lock);
863 idx = priv->streams->len;
865 GST_DEBUG ("media %p: creating stream with index %d", media, idx);
867 name = g_strdup_printf ("src_%u", idx);
868 srcpad = gst_ghost_pad_new (name, pad);
869 gst_pad_set_active (srcpad, TRUE);
870 gst_element_add_pad (priv->element, srcpad);
873 stream = gst_rtsp_stream_new (idx, payloader, srcpad);
875 gst_rtsp_stream_set_address_pool (stream, priv->pool);
877 g_ptr_array_add (priv->streams, stream);
878 g_mutex_unlock (&priv->lock);
880 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
887 * gst_rtsp_media_n_streams:
888 * @media: a #GstRTSPMedia
890 * Get the number of streams in this media.
892 * Returns: The number of streams.
895 gst_rtsp_media_n_streams (GstRTSPMedia * media)
897 GstRTSPMediaPrivate *priv;
900 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
904 g_mutex_lock (&priv->lock);
905 res = priv->streams->len;
906 g_mutex_unlock (&priv->lock);
912 * gst_rtsp_media_get_stream:
913 * @media: a #GstRTSPMedia
914 * @idx: the stream index
916 * Retrieve the stream with index @idx from @media.
918 * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with
919 * that index did not exist.
922 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
924 GstRTSPMediaPrivate *priv;
927 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
931 g_mutex_lock (&priv->lock);
932 if (idx < priv->streams->len)
933 res = g_ptr_array_index (priv->streams, idx);
936 g_mutex_unlock (&priv->lock);
942 * gst_rtsp_media_get_range_string:
943 * @media: a #GstRTSPMedia
944 * @play: for the PLAY request
946 * Get the current range as a string. @media must be prepared with
947 * gst_rtsp_media_prepare ().
949 * Returns: The range as a string, g_free() after usage.
952 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
954 GstRTSPMediaPrivate *priv;
956 GstRTSPTimeRange range;
958 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
962 g_rec_mutex_lock (&priv->state_lock);
963 if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
966 g_mutex_lock (&priv->lock);
970 if (!play && priv->n_active > 0) {
971 range.min.type = GST_RTSP_TIME_NOW;
972 range.min.seconds = -1;
974 g_mutex_unlock (&priv->lock);
975 g_rec_mutex_unlock (&priv->state_lock);
977 result = gst_rtsp_range_to_string (&range);
984 GST_WARNING ("media %p was not prepared", media);
985 g_rec_mutex_unlock (&priv->state_lock);
991 * gst_rtsp_media_seek:
992 * @media: a #GstRTSPMedia
993 * @range: a #GstRTSPTimeRange
995 * Seek the pipeline of @media to @range. @media must be prepared with
996 * gst_rtsp_media_prepare().
998 * Returns: %TRUE on success.
1001 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
1003 GstRTSPMediaPrivate *priv;
1006 GstClockTime start, stop;
1007 GstSeekType start_type, stop_type;
1009 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1010 g_return_val_if_fail (range != NULL, FALSE);
1014 g_rec_mutex_lock (&priv->state_lock);
1015 if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1018 if (!priv->seekable)
1021 /* depends on the current playing state of the pipeline. We might need to
1022 * queue this until we get EOS. */
1023 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
1025 start_type = stop_type = GST_SEEK_TYPE_NONE;
1027 if (!gst_rtsp_range_get_times (range, &start, &stop))
1030 GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1031 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1032 GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1033 GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
1035 if (priv->range_start == start)
1036 start = GST_CLOCK_TIME_NONE;
1037 else if (start != GST_CLOCK_TIME_NONE)
1038 start_type = GST_SEEK_TYPE_SET;
1040 if (priv->range_stop == stop)
1041 stop = GST_CLOCK_TIME_NONE;
1042 else if (stop != GST_CLOCK_TIME_NONE)
1043 stop_type = GST_SEEK_TYPE_SET;
1045 if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
1046 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1047 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1049 res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
1050 flags, start_type, start, stop_type, stop);
1052 /* and block for the seek to complete */
1053 GST_INFO ("done seeking %d", res);
1054 gst_element_get_state (priv->pipeline, NULL, NULL, -1);
1055 GST_INFO ("prerolled again");
1057 collect_media_stats (media);
1059 GST_INFO ("no seek needed");
1062 g_rec_mutex_unlock (&priv->state_lock);
1069 g_rec_mutex_unlock (&priv->state_lock);
1070 GST_INFO ("media %p is not prepared", media);
1075 g_rec_mutex_unlock (&priv->state_lock);
1076 GST_INFO ("pipeline is not seekable");
1081 g_rec_mutex_unlock (&priv->state_lock);
1082 GST_WARNING ("seek unit %d not supported", range->unit);
1088 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1090 GstRTSPMediaPrivate *priv = media->priv;
1092 g_mutex_lock (&priv->lock);
1093 /* never overwrite the error status */
1094 if (priv->status != GST_RTSP_MEDIA_STATUS_ERROR)
1095 priv->status = status;
1096 GST_DEBUG ("setting new status to %d", status);
1097 g_cond_broadcast (&priv->cond);
1098 g_mutex_unlock (&priv->lock);
1102 * gst_rtsp_media_get_status:
1103 * @media: a #GstRTSPMedia
1105 * Get the status of @media. When @media is busy preparing, this function waits
1106 * until @media is prepared or in error.
1108 * Returns: the status of @media.
1111 gst_rtsp_media_get_status (GstRTSPMedia * media)
1113 GstRTSPMediaPrivate *priv = media->priv;
1114 GstRTSPMediaStatus result;
1117 g_mutex_lock (&priv->lock);
1118 end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
1119 /* while we are preparing, wait */
1120 while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1121 GST_DEBUG ("waiting for status change");
1122 if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
1123 GST_DEBUG ("timeout, assuming error status");
1124 priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
1127 /* could be success or error */
1128 result = priv->status;
1129 GST_DEBUG ("got status %d", result);
1130 g_mutex_unlock (&priv->lock);
1135 /* called with state-lock */
1137 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1139 GstRTSPMediaPrivate *priv = media->priv;
1140 GstMessageType type;
1142 type = GST_MESSAGE_TYPE (message);
1145 case GST_MESSAGE_STATE_CHANGED:
1147 case GST_MESSAGE_BUFFERING:
1151 gst_message_parse_buffering (message, &percent);
1153 /* no state management needed for live pipelines */
1157 if (percent == 100) {
1158 /* a 100% message means buffering is done */
1159 priv->buffering = FALSE;
1160 /* if the desired state is playing, go back */
1161 if (priv->target_state == GST_STATE_PLAYING) {
1162 GST_INFO ("Buffering done, setting pipeline to PLAYING");
1163 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1165 GST_INFO ("Buffering done");
1168 /* buffering busy */
1169 if (priv->buffering == FALSE) {
1170 if (priv->target_state == GST_STATE_PLAYING) {
1171 /* we were not buffering but PLAYING, PAUSE the pipeline. */
1172 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1173 gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1175 GST_INFO ("Buffering ...");
1178 priv->buffering = TRUE;
1182 case GST_MESSAGE_LATENCY:
1184 gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
1187 case GST_MESSAGE_ERROR:
1192 gst_message_parse_error (message, &gerror, &debug);
1193 GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1194 g_error_free (gerror);
1197 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1200 case GST_MESSAGE_WARNING:
1205 gst_message_parse_warning (message, &gerror, &debug);
1206 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1207 g_error_free (gerror);
1211 case GST_MESSAGE_ELEMENT:
1213 case GST_MESSAGE_STREAM_STATUS:
1215 case GST_MESSAGE_ASYNC_DONE:
1216 if (!priv->adding) {
1217 /* when we are dynamically adding pads, the addition of the udpsrc will
1218 * temporarily produce ASYNC_DONE messages. We have to ignore them and
1219 * wait for the final ASYNC_DONE after everything prerolled */
1220 GST_INFO ("%p: got ASYNC_DONE", media);
1221 collect_media_stats (media);
1223 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1225 GST_INFO ("%p: ignoring ASYNC_DONE", media);
1228 case GST_MESSAGE_EOS:
1229 GST_INFO ("%p: got EOS", media);
1231 if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1232 GST_DEBUG ("shutting down after EOS");
1233 finish_unprepare (media);
1234 g_object_unref (media);
1238 GST_INFO ("%p: got message type %s", media,
1239 gst_message_type_get_name (type));
1246 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1248 GstRTSPMediaPrivate *priv = media->priv;
1249 GstRTSPMediaClass *klass;
1252 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1254 g_rec_mutex_lock (&priv->state_lock);
1255 if (klass->handle_message)
1256 ret = klass->handle_message (media, message);
1259 g_rec_mutex_unlock (&priv->state_lock);
1265 watch_destroyed (GstRTSPMedia * media)
1267 GST_DEBUG_OBJECT (media, "source destroyed");
1268 gst_object_unref (media);
1271 /* called from streaming threads */
1273 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1275 GstRTSPMediaPrivate *priv = media->priv;
1276 GstRTSPStream *stream;
1278 /* FIXME, element is likely not a payloader, find the payloader here */
1279 stream = gst_rtsp_media_create_stream (media, element, pad);
1281 GST_INFO ("pad added %s:%s, stream %s", GST_DEBUG_PAD_NAME (pad), stream);
1283 g_rec_mutex_lock (&priv->state_lock);
1284 /* we will be adding elements below that will cause ASYNC_DONE to be
1285 * posted in the bus. We want to ignore those messages until the
1286 * pipeline really prerolled. */
1287 priv->adding = TRUE;
1289 /* join the element in the PAUSED state because this callback is
1290 * called from the streaming thread and it is PAUSED */
1291 gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1292 priv->rtpbin, GST_STATE_PAUSED);
1294 priv->adding = FALSE;
1295 g_rec_mutex_unlock (&priv->state_lock);
1299 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1301 GstRTSPMediaPrivate *priv = media->priv;
1302 GstElement *fakesink;
1304 g_mutex_lock (&priv->lock);
1305 GST_INFO ("no more pads");
1306 if ((fakesink = priv->fakesink)) {
1307 gst_object_ref (fakesink);
1308 priv->fakesink = NULL;
1309 g_mutex_unlock (&priv->lock);
1311 gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
1312 gst_element_set_state (fakesink, GST_STATE_NULL);
1313 gst_object_unref (fakesink);
1314 GST_INFO ("removed fakesink");
1319 * gst_rtsp_media_prepare:
1320 * @media: a #GstRTSPMedia
1322 * Prepare @media for streaming. This function will create the pipeline and
1323 * other objects to manage the streaming.
1325 * It will preroll the pipeline and collect vital information about the streams
1326 * such as the duration.
1328 * Returns: %TRUE on success.
1331 gst_rtsp_media_prepare (GstRTSPMedia * media)
1333 GstRTSPMediaPrivate *priv;
1334 GstStateChangeReturn ret;
1335 GstRTSPMediaStatus status;
1337 GstRTSPMediaClass *klass;
1341 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1345 g_rec_mutex_lock (&priv->state_lock);
1346 if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1349 if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1352 if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
1353 goto not_unprepared;
1355 if (!priv->reusable && priv->reused)
1358 priv->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1359 if (priv->rtpbin == NULL)
1362 GST_INFO ("preparing media %p", media);
1364 /* reset some variables */
1365 priv->is_live = FALSE;
1366 priv->seekable = FALSE;
1367 priv->buffering = FALSE;
1368 /* we're preparing now */
1369 priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1371 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
1373 /* add the pipeline bus to our custom mainloop */
1374 priv->source = gst_bus_create_watch (bus);
1375 gst_object_unref (bus);
1377 g_source_set_callback (priv->source, (GSourceFunc) bus_message,
1378 gst_object_ref (media), (GDestroyNotify) watch_destroyed);
1380 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1381 priv->id = g_source_attach (priv->source, klass->context);
1383 /* add stuff to the bin */
1384 gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
1386 /* link streams we already have, other streams might appear when we have
1387 * dynamic elements */
1388 for (i = 0; i < priv->streams->len; i++) {
1389 GstRTSPStream *stream;
1391 stream = g_ptr_array_index (priv->streams, i);
1393 gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1394 priv->rtpbin, GST_STATE_NULL);
1397 for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1398 GstElement *elem = walk->data;
1400 GST_INFO ("adding callbacks for dynamic element %p", elem);
1402 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1403 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1405 /* we add a fakesink here in order to make the state change async. We remove
1406 * the fakesink again in the no-more-pads callback. */
1407 priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1408 gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
1411 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1412 /* first go to PAUSED */
1413 ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1414 priv->target_state = GST_STATE_PAUSED;
1417 case GST_STATE_CHANGE_SUCCESS:
1418 GST_INFO ("SUCCESS state change for media %p", media);
1419 priv->seekable = TRUE;
1421 case GST_STATE_CHANGE_ASYNC:
1422 GST_INFO ("ASYNC state change for media %p", media);
1423 priv->seekable = TRUE;
1425 case GST_STATE_CHANGE_NO_PREROLL:
1426 /* we need to go to PLAYING */
1427 GST_INFO ("NO_PREROLL state change: live media %p", media);
1428 /* FIXME we disable seeking for live streams for now. We should perform a
1429 * seeking query in preroll instead */
1430 priv->seekable = FALSE;
1431 priv->is_live = TRUE;
1432 ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1433 if (ret == GST_STATE_CHANGE_FAILURE)
1436 case GST_STATE_CHANGE_FAILURE:
1440 g_rec_mutex_unlock (&priv->state_lock);
1442 /* now wait for all pads to be prerolled, FIXME, we should somehow be
1443 * able to do this async so that we don't block the server thread. */
1444 status = gst_rtsp_media_get_status (media);
1445 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1448 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1450 GST_INFO ("object %p is prerolled", media);
1457 GST_LOG ("media %p was prepared", media);
1458 g_rec_mutex_unlock (&priv->state_lock);
1464 GST_WARNING ("media %p was not unprepared", media);
1465 g_rec_mutex_unlock (&priv->state_lock);
1470 g_rec_mutex_unlock (&priv->state_lock);
1471 GST_WARNING ("can not reuse media %p", media);
1476 g_rec_mutex_unlock (&priv->state_lock);
1477 GST_WARNING ("no rtpbin element");
1478 g_warning ("failed to create element 'rtpbin', check your installation");
1483 GST_WARNING ("failed to preroll pipeline");
1484 gst_rtsp_media_unprepare (media);
1485 g_rec_mutex_unlock (&priv->state_lock);
1490 /* must be called with state-lock */
1492 finish_unprepare (GstRTSPMedia * media)
1494 GstRTSPMediaPrivate *priv = media->priv;
1497 GST_DEBUG ("shutting down");
1499 gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1501 for (i = 0; i < priv->streams->len; i++) {
1502 GstRTSPStream *stream;
1504 GST_INFO ("Removing elements of stream %d from pipeline", i);
1506 stream = g_ptr_array_index (priv->streams, i);
1508 gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1510 g_ptr_array_set_size (priv->streams, 0);
1512 gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
1513 priv->rtpbin = NULL;
1515 gst_object_unref (priv->pipeline);
1516 priv->pipeline = NULL;
1518 priv->reused = TRUE;
1519 priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1522 g_source_destroy (priv->source);
1523 g_source_unref (priv->source);
1524 priv->source = NULL;
1527 /* when the media is not reusable, this will effectively unref the media and
1529 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1532 /* called with state-lock */
1534 default_unprepare (GstRTSPMedia * media)
1536 GstRTSPMediaPrivate *priv = media->priv;
1538 if (priv->eos_shutdown) {
1539 GST_DEBUG ("sending EOS for shutdown");
1540 /* ref so that we don't disappear */
1541 g_object_ref (media);
1542 gst_element_send_event (priv->pipeline, gst_event_new_eos ());
1543 /* we need to go to playing again for the EOS to propagate, normally in this
1544 * state, nothing is receiving data from us anymore so this is ok. */
1545 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1546 priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1548 finish_unprepare (media);
1554 * gst_rtsp_media_unprepare:
1555 * @media: a #GstRTSPMedia
1557 * Unprepare @media. After this call, the media should be prepared again before
1558 * it can be used again. If the media is set to be non-reusable, a new instance
1561 * Returns: %TRUE on success.
1564 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1566 GstRTSPMediaPrivate *priv;
1569 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1573 g_rec_mutex_lock (&priv->state_lock);
1574 if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1575 goto was_unprepared;
1577 GST_INFO ("unprepare media %p", media);
1578 priv->target_state = GST_STATE_NULL;
1581 if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1582 GstRTSPMediaClass *klass;
1584 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1585 if (klass->unprepare)
1586 success = klass->unprepare (media);
1588 finish_unprepare (media);
1590 g_rec_mutex_unlock (&priv->state_lock);
1596 g_rec_mutex_unlock (&priv->state_lock);
1597 GST_INFO ("media %p was already unprepared", media);
1603 * gst_rtsp_media_set_state:
1604 * @media: a #GstRTSPMedia
1605 * @state: the target state of the media
1606 * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers
1608 * Set the state of @media to @state and for the transports in @transports.
1610 * @media must be prepared with gst_rtsp_media_prepare();
1612 * Returns: %TRUE on success.
1615 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1616 GPtrArray * transports)
1618 GstRTSPMediaPrivate *priv;
1620 gboolean activate, deactivate, do_state;
1623 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1624 g_return_val_if_fail (transports != NULL, FALSE);
1628 g_rec_mutex_lock (&priv->state_lock);
1629 if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1632 /* NULL and READY are the same */
1633 if (state == GST_STATE_READY)
1634 state = GST_STATE_NULL;
1636 activate = deactivate = FALSE;
1638 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1642 case GST_STATE_NULL:
1643 case GST_STATE_PAUSED:
1644 /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
1645 if (priv->target_state == GST_STATE_PLAYING)
1648 case GST_STATE_PLAYING:
1649 /* we're going to PLAYING, activate */
1655 old_active = priv->n_active;
1657 for (i = 0; i < transports->len; i++) {
1658 GstRTSPStreamTransport *trans;
1660 /* we need a non-NULL entry in the array */
1661 trans = g_ptr_array_index (transports, i);
1666 if (gst_rtsp_stream_transport_set_active (trans, TRUE))
1668 } else if (deactivate) {
1669 if (gst_rtsp_stream_transport_set_active (trans, FALSE))
1674 /* we just activated the first media, do the playing state change */
1675 if (old_active == 0 && activate)
1677 /* if we have no more active media, do the downward state changes */
1678 else if (priv->n_active == 0)
1683 GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
1686 if (priv->target_state != state) {
1688 if (state == GST_STATE_NULL) {
1689 gst_rtsp_media_unprepare (media);
1691 GST_INFO ("state %s media %p", gst_element_state_get_name (state),
1693 priv->target_state = state;
1694 gst_element_set_state (priv->pipeline, state);
1697 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
1701 /* remember where we are */
1702 if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
1703 old_active != priv->n_active))
1704 collect_media_stats (media);
1706 g_rec_mutex_unlock (&priv->state_lock);
1713 GST_WARNING ("media %p was not prepared", media);
1714 g_rec_mutex_unlock (&priv->state_lock);