rtsp-media: remove transports if media is in error status
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-media.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 /**
20  * SECTION:rtsp-media
21  * @short_description: The media pipeline
22  * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession,
23  *     #GstRTSPSessionMedia
24  *
25  * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the
26  * streaming to the clients. The actual data transfer is done by the
27  * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
28  *
29  * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the
30  * client does a DESCRIBE or SETUP of a resource.
31  *
32  * A media is created with gst_rtsp_media_new() that takes the element that will
33  * provide the streaming elements. For each of the streams, a new #GstRTSPStream
34  * object needs to be made with the gst_rtsp_media_create_stream() which takes
35  * the payloader element and the source pad that produces the RTP stream.
36  *
37  * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The
38  * prepare method will add rtpbin and sinks and sources to send and receive RTP
39  * and RTCP packets from the clients. Each stream srcpad is connected to an
40  * input into the internal rtpbin.
41  *
42  * It is also possible to dynamically create #GstRTSPStream objects during the
43  * prepare phase. With gst_rtsp_media_get_status() you can check the status of
44  * the prepare phase.
45  *
46  * After the media is prepared, it is ready for streaming. It will usually be
47  * managed in a session with gst_rtsp_session_manage_media(). See
48  * #GstRTSPSession and #GstRTSPSessionMedia.
49  *
50  * The state of the media can be controlled with gst_rtsp_media_set_state ().
51  * Seeking can be done with gst_rtsp_media_seek().
52  *
53  * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
54  * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
55  * cleanly shut down.
56  *
57  * With gst_rtsp_media_set_shared(), the media can be shared between multiple
58  * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline
59  * can be prepared again after an unprepare.
60  *
61  * Last reviewed on 2013-07-11 (1.0.0)
62  */
63
64 #include <string.h>
65 #include <stdlib.h>
66
67 #include <gst/app/gstappsrc.h>
68 #include <gst/app/gstappsink.h>
69
70 #include "rtsp-media.h"
71
72 #define GST_RTSP_MEDIA_GET_PRIVATE(obj)  \
73      (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate))
74
75 struct _GstRTSPMediaPrivate
76 {
77   GMutex lock;
78   GCond cond;
79
80   /* protected by lock */
81   GstRTSPPermissions *permissions;
82   gboolean shared;
83   gboolean reusable;
84   GstRTSPLowerTrans protocols;
85   gboolean reused;
86   gboolean eos_shutdown;
87   guint buffer_size;
88   GstRTSPAddressPool *pool;
89
90   GstElement *element;
91   GRecMutex state_lock;         /* locking order: state lock, lock */
92   GPtrArray *streams;           /* protected by lock */
93   GList *dynamic;               /* protected by lock */
94   GstRTSPMediaStatus status;    /* protected by lock */
95   gint prepare_count;
96   gint n_active;
97   gboolean adding;
98
99   /* the pipeline for the media */
100   GstElement *pipeline;
101   GstElement *fakesink;         /* protected by lock */
102   GSource *source;
103   guint id;
104   GstRTSPThread *thread;
105
106   gboolean time_provider;
107   GstNetTimeProvider *nettime;
108
109   gboolean is_live;
110   gboolean seekable;
111   gboolean buffering;
112   GstState target_state;
113
114   /* RTP session manager */
115   GstElement *rtpbin;
116
117   /* the range of media */
118   GstRTSPTimeRange range;       /* protected by lock */
119   GstClockTime range_start;
120   GstClockTime range_stop;
121 };
122
123 #define DEFAULT_SHARED          FALSE
124 #define DEFAULT_REUSABLE        FALSE
125 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
126                                         GST_RTSP_LOWER_TRANS_TCP
127 #define DEFAULT_EOS_SHUTDOWN    FALSE
128 #define DEFAULT_BUFFER_SIZE     0x80000
129 #define DEFAULT_TIME_PROVIDER   FALSE
130
131 /* define to dump received RTCP packets */
132 #undef DUMP_STATS
133
134 enum
135 {
136   PROP_0,
137   PROP_SHARED,
138   PROP_REUSABLE,
139   PROP_PROTOCOLS,
140   PROP_EOS_SHUTDOWN,
141   PROP_BUFFER_SIZE,
142   PROP_ELEMENT,
143   PROP_TIME_PROVIDER,
144   PROP_LAST
145 };
146
147 enum
148 {
149   SIGNAL_NEW_STREAM,
150   SIGNAL_REMOVED_STREAM,
151   SIGNAL_PREPARED,
152   SIGNAL_UNPREPARED,
153   SIGNAL_NEW_STATE,
154   SIGNAL_LAST
155 };
156
157 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
158 #define GST_CAT_DEFAULT rtsp_media_debug
159
160 static void gst_rtsp_media_get_property (GObject * object, guint propid,
161     GValue * value, GParamSpec * pspec);
162 static void gst_rtsp_media_set_property (GObject * object, guint propid,
163     const GValue * value, GParamSpec * pspec);
164 static void gst_rtsp_media_finalize (GObject * obj);
165
166 static gboolean default_handle_message (GstRTSPMedia * media,
167     GstMessage * message);
168 static void finish_unprepare (GstRTSPMedia * media);
169 static gboolean default_unprepare (GstRTSPMedia * media);
170 static gboolean
171 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
172     GstRTSPRangeUnit unit);
173 static gboolean default_query_position (GstRTSPMedia * media,
174     gint64 * position);
175 static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop);
176
177 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
178
179 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
180
181 static void
182 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
183 {
184   GObjectClass *gobject_class;
185
186   g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate));
187
188   gobject_class = G_OBJECT_CLASS (klass);
189
190   gobject_class->get_property = gst_rtsp_media_get_property;
191   gobject_class->set_property = gst_rtsp_media_set_property;
192   gobject_class->finalize = gst_rtsp_media_finalize;
193
194   g_object_class_install_property (gobject_class, PROP_SHARED,
195       g_param_spec_boolean ("shared", "Shared",
196           "If this media pipeline can be shared", DEFAULT_SHARED,
197           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198
199   g_object_class_install_property (gobject_class, PROP_REUSABLE,
200       g_param_spec_boolean ("reusable", "Reusable",
201           "If this media pipeline can be reused after an unprepare",
202           DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
203
204   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
205       g_param_spec_flags ("protocols", "Protocols",
206           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
207           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208
209   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
210       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
211           "Send an EOS event to the pipeline before unpreparing",
212           DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213
214   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
215       g_param_spec_uint ("buffer-size", "Buffer Size",
216           "The kernel UDP buffer size to use", 0, G_MAXUINT,
217           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218
219   g_object_class_install_property (gobject_class, PROP_ELEMENT,
220       g_param_spec_object ("element", "The Element",
221           "The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
222           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
223
224   g_object_class_install_property (gobject_class, PROP_TIME_PROVIDER,
225       g_param_spec_boolean ("time-provider", "Time Provider",
226           "Use a NetTimeProvider for clients",
227           DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
228
229   gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
230       g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
231       G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
232       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM);
233
234   gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM] =
235       g_signal_new ("removed-stream", G_TYPE_FROM_CLASS (klass),
236       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, removed_stream),
237       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
238       GST_TYPE_RTSP_STREAM);
239
240   gst_rtsp_media_signals[SIGNAL_PREPARED] =
241       g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
242       G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
243       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
244
245   gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
246       g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
247       G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
248       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
249
250   gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
251       g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
252       G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
253       g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
254
255   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
256
257   klass->handle_message = default_handle_message;
258   klass->unprepare = default_unprepare;
259   klass->convert_range = default_convert_range;
260   klass->query_position = default_query_position;
261   klass->query_stop = default_query_stop;
262 }
263
264 static void
265 gst_rtsp_media_init (GstRTSPMedia * media)
266 {
267   GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media);
268
269   media->priv = priv;
270
271   priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
272   g_mutex_init (&priv->lock);
273   g_cond_init (&priv->cond);
274   g_rec_mutex_init (&priv->state_lock);
275
276   priv->shared = DEFAULT_SHARED;
277   priv->reusable = DEFAULT_REUSABLE;
278   priv->protocols = DEFAULT_PROTOCOLS;
279   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
280   priv->buffer_size = DEFAULT_BUFFER_SIZE;
281   priv->time_provider = DEFAULT_TIME_PROVIDER;
282 }
283
284 static void
285 gst_rtsp_media_finalize (GObject * obj)
286 {
287   GstRTSPMediaPrivate *priv;
288   GstRTSPMedia *media;
289
290   media = GST_RTSP_MEDIA (obj);
291   priv = media->priv;
292
293   GST_INFO ("finalize media %p", media);
294
295   if (priv->permissions)
296     gst_rtsp_permissions_unref (priv->permissions);
297
298   g_ptr_array_unref (priv->streams);
299
300   g_list_free_full (priv->dynamic, gst_object_unref);
301
302   if (priv->pipeline)
303     gst_object_unref (priv->pipeline);
304   if (priv->nettime)
305     gst_object_unref (priv->nettime);
306   gst_object_unref (priv->element);
307   if (priv->pool)
308     g_object_unref (priv->pool);
309   g_mutex_clear (&priv->lock);
310   g_cond_clear (&priv->cond);
311   g_rec_mutex_clear (&priv->state_lock);
312
313   G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
314 }
315
316 static void
317 gst_rtsp_media_get_property (GObject * object, guint propid,
318     GValue * value, GParamSpec * pspec)
319 {
320   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
321
322   switch (propid) {
323     case PROP_ELEMENT:
324       g_value_set_object (value, media->priv->element);
325       break;
326     case PROP_SHARED:
327       g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
328       break;
329     case PROP_REUSABLE:
330       g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
331       break;
332     case PROP_PROTOCOLS:
333       g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
334       break;
335     case PROP_EOS_SHUTDOWN:
336       g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
337       break;
338     case PROP_BUFFER_SIZE:
339       g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
340       break;
341     case PROP_TIME_PROVIDER:
342       g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media));
343       break;
344     default:
345       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
346   }
347 }
348
349 static void
350 gst_rtsp_media_set_property (GObject * object, guint propid,
351     const GValue * value, GParamSpec * pspec)
352 {
353   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
354
355   switch (propid) {
356     case PROP_ELEMENT:
357       media->priv->element = g_value_get_object (value);
358       gst_object_ref_sink (media->priv->element);
359       break;
360     case PROP_SHARED:
361       gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
362       break;
363     case PROP_REUSABLE:
364       gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
365       break;
366     case PROP_PROTOCOLS:
367       gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
368       break;
369     case PROP_EOS_SHUTDOWN:
370       gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
371       break;
372     case PROP_BUFFER_SIZE:
373       gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
374       break;
375     case PROP_TIME_PROVIDER:
376       gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value));
377       break;
378     default:
379       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
380   }
381 }
382
383 /* must be called with state lock */
384 static void
385 collect_media_stats (GstRTSPMedia * media)
386 {
387   GstRTSPMediaPrivate *priv = media->priv;
388   gint64 position, stop;
389
390   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
391       priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
392     return;
393
394   priv->range.unit = GST_RTSP_RANGE_NPT;
395
396   GST_INFO ("collect media stats");
397
398   if (priv->is_live) {
399     priv->range.min.type = GST_RTSP_TIME_NOW;
400     priv->range.min.seconds = -1;
401     priv->range_start = -1;
402     priv->range.max.type = GST_RTSP_TIME_END;
403     priv->range.max.seconds = -1;
404     priv->range_stop = -1;
405   } else {
406     GstRTSPMediaClass *klass;
407     gboolean ret;
408
409     klass = GST_RTSP_MEDIA_GET_CLASS (media);
410
411     /* get the position */
412     ret = FALSE;
413     if (klass->query_position)
414       ret = klass->query_position (media, &position);
415
416     if (!ret) {
417       GST_INFO ("position query failed");
418       position = 0;
419     }
420
421     /* get the current segment stop */
422     ret = FALSE;
423     if (klass->query_stop)
424       ret = klass->query_stop (media, &stop);
425
426     if (!ret) {
427       GST_INFO ("stop query failed");
428       stop = -1;
429     }
430
431     GST_INFO ("stats: position %" GST_TIME_FORMAT ", stop %"
432         GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (stop));
433
434     if (position == -1) {
435       priv->range.min.type = GST_RTSP_TIME_NOW;
436       priv->range.min.seconds = -1;
437       priv->range_start = -1;
438     } else {
439       priv->range.min.type = GST_RTSP_TIME_SECONDS;
440       priv->range.min.seconds = ((gdouble) position) / GST_SECOND;
441       priv->range_start = position;
442     }
443     if (stop == -1) {
444       priv->range.max.type = GST_RTSP_TIME_END;
445       priv->range.max.seconds = -1;
446       priv->range_stop = -1;
447     } else {
448       priv->range.max.type = GST_RTSP_TIME_SECONDS;
449       priv->range.max.seconds = ((gdouble) stop) / GST_SECOND;
450       priv->range_stop = stop;
451     }
452   }
453 }
454
455 /**
456  * gst_rtsp_media_new:
457  * @element: (transfer full): a #GstElement
458  *
459  * Create a new #GstRTSPMedia instance. @element is the bin element that
460  * provides the different streams. The #GstRTSPMedia object contains the
461  * element to produce RTP data for one or more related (audio/video/..)
462  * streams.
463  *
464  * Ownership is taken of @element.
465  *
466  * Returns: a new #GstRTSPMedia object.
467  */
468 GstRTSPMedia *
469 gst_rtsp_media_new (GstElement * element)
470 {
471   GstRTSPMedia *result;
472
473   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
474
475   result = g_object_new (GST_TYPE_RTSP_MEDIA, "element", element, NULL);
476
477   return result;
478 }
479
480 /**
481  * gst_rtsp_media_get_element:
482  * @media: a #GstRTSPMedia
483  *
484  * Get the element that was used when constructing @media.
485  *
486  * Returns: (transfer full): a #GstElement. Unref after usage.
487  */
488 GstElement *
489 gst_rtsp_media_get_element (GstRTSPMedia * media)
490 {
491   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
492
493   return gst_object_ref (media->priv->element);
494 }
495
496 /**
497  * gst_rtsp_media_take_pipeline:
498  * @media: a #GstRTSPMedia
499  * @pipeline: (transfer full): a #GstPipeline
500  *
501  * Set @pipeline as the #GstPipeline for @media. Ownership is
502  * taken of @pipeline.
503  */
504 void
505 gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
506 {
507   GstRTSPMediaPrivate *priv;
508   GstElement *old;
509   GstNetTimeProvider *nettime;
510
511   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
512   g_return_if_fail (GST_IS_PIPELINE (pipeline));
513
514   priv = media->priv;
515
516   g_mutex_lock (&priv->lock);
517   old = priv->pipeline;
518   priv->pipeline = GST_ELEMENT_CAST (pipeline);
519   nettime = priv->nettime;
520   priv->nettime = NULL;
521   g_mutex_unlock (&priv->lock);
522
523   if (old)
524     gst_object_unref (old);
525
526   if (nettime)
527     gst_object_unref (nettime);
528
529   gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
530 }
531
532 /**
533  * gst_rtsp_media_set_permissions:
534  * @media: a #GstRTSPMedia
535  * @permissions: a #GstRTSPPermissions
536  *
537  * Set @permissions on @media.
538  */
539 void
540 gst_rtsp_media_set_permissions (GstRTSPMedia * media,
541     GstRTSPPermissions * permissions)
542 {
543   GstRTSPMediaPrivate *priv;
544
545   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
546
547   priv = media->priv;
548
549   g_mutex_lock (&priv->lock);
550   if (priv->permissions)
551     gst_rtsp_permissions_unref (priv->permissions);
552   if ((priv->permissions = permissions))
553     gst_rtsp_permissions_ref (permissions);
554   g_mutex_unlock (&priv->lock);
555 }
556
557 /**
558  * gst_rtsp_media_get_permissions:
559  * @media: a #GstRTSPMedia
560  *
561  * Get the permissions object from @media.
562  *
563  * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage.
564  */
565 GstRTSPPermissions *
566 gst_rtsp_media_get_permissions (GstRTSPMedia * media)
567 {
568   GstRTSPMediaPrivate *priv;
569   GstRTSPPermissions *result;
570
571   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
572
573   priv = media->priv;
574
575   g_mutex_lock (&priv->lock);
576   if ((result = priv->permissions))
577     gst_rtsp_permissions_ref (result);
578   g_mutex_unlock (&priv->lock);
579
580   return result;
581 }
582
583 /**
584  * gst_rtsp_media_set_shared:
585  * @media: a #GstRTSPMedia
586  * @shared: the new value
587  *
588  * Set or unset if the pipeline for @media can be shared will multiple clients.
589  * When @shared is %TRUE, client requests for this media will share the media
590  * pipeline.
591  */
592 void
593 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
594 {
595   GstRTSPMediaPrivate *priv;
596
597   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
598
599   priv = media->priv;
600
601   g_mutex_lock (&priv->lock);
602   priv->shared = shared;
603   g_mutex_unlock (&priv->lock);
604 }
605
606 /**
607  * gst_rtsp_media_is_shared:
608  * @media: a #GstRTSPMedia
609  *
610  * Check if the pipeline for @media can be shared between multiple clients.
611  *
612  * Returns: %TRUE if the media can be shared between clients.
613  */
614 gboolean
615 gst_rtsp_media_is_shared (GstRTSPMedia * media)
616 {
617   GstRTSPMediaPrivate *priv;
618   gboolean res;
619
620   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
621
622   priv = media->priv;
623
624   g_mutex_lock (&priv->lock);
625   res = priv->shared;
626   g_mutex_unlock (&priv->lock);
627
628   return res;
629 }
630
631 /**
632  * gst_rtsp_media_set_reusable:
633  * @media: a #GstRTSPMedia
634  * @reusable: the new value
635  *
636  * Set or unset if the pipeline for @media can be reused after the pipeline has
637  * been unprepared.
638  */
639 void
640 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
641 {
642   GstRTSPMediaPrivate *priv;
643
644   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
645
646   priv = media->priv;
647
648   g_mutex_lock (&priv->lock);
649   priv->reusable = reusable;
650   g_mutex_unlock (&priv->lock);
651 }
652
653 /**
654  * gst_rtsp_media_is_reusable:
655  * @media: a #GstRTSPMedia
656  *
657  * Check if the pipeline for @media can be reused after an unprepare.
658  *
659  * Returns: %TRUE if the media can be reused
660  */
661 gboolean
662 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
663 {
664   GstRTSPMediaPrivate *priv;
665   gboolean res;
666
667   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
668
669   priv = media->priv;
670
671   g_mutex_lock (&priv->lock);
672   res = priv->reusable;
673   g_mutex_unlock (&priv->lock);
674
675   return res;
676 }
677
678 static void
679 do_set_protocols (GstRTSPStream * stream, GstRTSPLowerTrans * protocols)
680 {
681   gst_rtsp_stream_set_protocols (stream, *protocols);
682 }
683
684 /**
685  * gst_rtsp_media_set_protocols:
686  * @media: a #GstRTSPMedia
687  * @protocols: the new flags
688  *
689  * Configure the allowed lower transport for @media.
690  */
691 void
692 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
693 {
694   GstRTSPMediaPrivate *priv;
695
696   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
697
698   priv = media->priv;
699
700   g_mutex_lock (&priv->lock);
701   priv->protocols = protocols;
702   g_ptr_array_foreach (priv->streams, (GFunc) do_set_protocols, &protocols);
703   g_mutex_unlock (&priv->lock);
704 }
705
706 /**
707  * gst_rtsp_media_get_protocols:
708  * @media: a #GstRTSPMedia
709  *
710  * Get the allowed protocols of @media.
711  *
712  * Returns: a #GstRTSPLowerTrans
713  */
714 GstRTSPLowerTrans
715 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
716 {
717   GstRTSPMediaPrivate *priv;
718   GstRTSPLowerTrans res;
719
720   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
721       GST_RTSP_LOWER_TRANS_UNKNOWN);
722
723   priv = media->priv;
724
725   g_mutex_lock (&priv->lock);
726   res = priv->protocols;
727   g_mutex_unlock (&priv->lock);
728
729   return res;
730 }
731
732 /**
733  * gst_rtsp_media_set_eos_shutdown:
734  * @media: a #GstRTSPMedia
735  * @eos_shutdown: the new value
736  *
737  * Set or unset if an EOS event will be sent to the pipeline for @media before
738  * it is unprepared.
739  */
740 void
741 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
742 {
743   GstRTSPMediaPrivate *priv;
744
745   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
746
747   priv = media->priv;
748
749   g_mutex_lock (&priv->lock);
750   priv->eos_shutdown = eos_shutdown;
751   g_mutex_unlock (&priv->lock);
752 }
753
754 /**
755  * gst_rtsp_media_is_eos_shutdown:
756  * @media: a #GstRTSPMedia
757  *
758  * Check if the pipeline for @media will send an EOS down the pipeline before
759  * unpreparing.
760  *
761  * Returns: %TRUE if the media will send EOS before unpreparing.
762  */
763 gboolean
764 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
765 {
766   GstRTSPMediaPrivate *priv;
767   gboolean res;
768
769   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
770
771   priv = media->priv;
772
773   g_mutex_lock (&priv->lock);
774   res = priv->eos_shutdown;
775   g_mutex_unlock (&priv->lock);
776
777   return res;
778 }
779
780 /**
781  * gst_rtsp_media_set_buffer_size:
782  * @media: a #GstRTSPMedia
783  * @size: the new value
784  *
785  * Set the kernel UDP buffer size.
786  */
787 void
788 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
789 {
790   GstRTSPMediaPrivate *priv;
791
792   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
793
794   GST_LOG_OBJECT (media, "set buffer size %u", size);
795
796   priv = media->priv;
797
798   g_mutex_lock (&priv->lock);
799   priv->buffer_size = size;
800   g_mutex_unlock (&priv->lock);
801 }
802
803 /**
804  * gst_rtsp_media_get_buffer_size:
805  * @media: a #GstRTSPMedia
806  *
807  * Get the kernel UDP buffer size.
808  *
809  * Returns: the kernel UDP buffer size.
810  */
811 guint
812 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
813 {
814   GstRTSPMediaPrivate *priv;
815   guint res;
816
817   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
818
819   priv = media->priv;
820
821   g_mutex_unlock (&priv->lock);
822   res = priv->buffer_size;
823   g_mutex_unlock (&priv->lock);
824
825   return res;
826 }
827
828 /**
829  * gst_rtsp_media_use_time_provider:
830  * @media: a #GstRTSPMedia
831  * @time_provider: if a #GstNetTimeProvider should be used
832  *
833  * Set @media to provide a #GstNetTimeProvider.
834  */
835 void
836 gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider)
837 {
838   GstRTSPMediaPrivate *priv;
839
840   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
841
842   priv = media->priv;
843
844   g_mutex_lock (&priv->lock);
845   priv->time_provider = time_provider;
846   g_mutex_unlock (&priv->lock);
847 }
848
849 /**
850  * gst_rtsp_media_is_time_provider:
851  * @media: a #GstRTSPMedia
852  *
853  * Check if @media can provide a #GstNetTimeProvider for its pipeline clock.
854  *
855  * Use gst_rtsp_media_get_time_provider() to get the network clock.
856  *
857  * Returns: %TRUE if @media can provide a #GstNetTimeProvider.
858  */
859 gboolean
860 gst_rtsp_media_is_time_provider (GstRTSPMedia * media)
861 {
862   GstRTSPMediaPrivate *priv;
863   gboolean res;
864
865   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
866
867   priv = media->priv;
868
869   g_mutex_unlock (&priv->lock);
870   res = priv->time_provider;
871   g_mutex_unlock (&priv->lock);
872
873   return res;
874 }
875
876 /**
877  * gst_rtsp_media_set_address_pool:
878  * @media: a #GstRTSPMedia
879  * @pool: a #GstRTSPAddressPool
880  *
881  * configure @pool to be used as the address pool of @media.
882  */
883 void
884 gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
885     GstRTSPAddressPool * pool)
886 {
887   GstRTSPMediaPrivate *priv;
888   GstRTSPAddressPool *old;
889
890   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
891
892   priv = media->priv;
893
894   GST_LOG_OBJECT (media, "set address pool %p", pool);
895
896   g_mutex_lock (&priv->lock);
897   if ((old = priv->pool) != pool)
898     priv->pool = pool ? g_object_ref (pool) : NULL;
899   else
900     old = NULL;
901   g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool,
902       pool);
903   g_mutex_unlock (&priv->lock);
904
905   if (old)
906     g_object_unref (old);
907 }
908
909 /**
910  * gst_rtsp_media_get_address_pool:
911  * @media: a #GstRTSPMedia
912  *
913  * Get the #GstRTSPAddressPool used as the address pool of @media.
914  *
915  * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after
916  * usage.
917  */
918 GstRTSPAddressPool *
919 gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
920 {
921   GstRTSPMediaPrivate *priv;
922   GstRTSPAddressPool *result;
923
924   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
925
926   priv = media->priv;
927
928   g_mutex_lock (&priv->lock);
929   if ((result = priv->pool))
930     g_object_ref (result);
931   g_mutex_unlock (&priv->lock);
932
933   return result;
934 }
935
936 /**
937  * gst_rtsp_media_collect_streams:
938  * @media: a #GstRTSPMedia
939  *
940  * Find all payloader elements, they should be named pay%d in the
941  * element of @media, and create #GstRTSPStreams for them.
942  *
943  * Collect all dynamic elements, named dynpay%d, and add them to
944  * the list of dynamic elements.
945  */
946 void
947 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
948 {
949   GstRTSPMediaPrivate *priv;
950   GstElement *element, *elem;
951   GstPad *pad;
952   gint i;
953   gboolean have_elem;
954
955   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
956
957   priv = media->priv;
958   element = priv->element;
959
960   have_elem = TRUE;
961   for (i = 0; have_elem; i++) {
962     gchar *name;
963
964     have_elem = FALSE;
965
966     name = g_strdup_printf ("pay%d", i);
967     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
968       GST_INFO ("found stream %d with payloader %p", i, elem);
969
970       /* take the pad of the payloader */
971       pad = gst_element_get_static_pad (elem, "src");
972       /* create the stream */
973       gst_rtsp_media_create_stream (media, elem, pad);
974       gst_object_unref (pad);
975       gst_object_unref (elem);
976
977       have_elem = TRUE;
978     }
979     g_free (name);
980
981     name = g_strdup_printf ("dynpay%d", i);
982     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
983       /* a stream that will dynamically create pads to provide RTP packets */
984
985       GST_INFO ("found dynamic element %d, %p", i, elem);
986
987       g_mutex_lock (&priv->lock);
988       priv->dynamic = g_list_prepend (priv->dynamic, elem);
989       g_mutex_unlock (&priv->lock);
990
991       have_elem = TRUE;
992     }
993     g_free (name);
994   }
995 }
996
997 /**
998  * gst_rtsp_media_create_stream:
999  * @media: a #GstRTSPMedia
1000  * @payloader: a #GstElement
1001  * @srcpad: a source #GstPad
1002  *
1003  * Create a new stream in @media that provides RTP data on @srcpad.
1004  * @srcpad should be a pad of an element inside @media->element.
1005  *
1006  * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
1007  *          as @media exists.
1008  */
1009 GstRTSPStream *
1010 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
1011     GstPad * pad)
1012 {
1013   GstRTSPMediaPrivate *priv;
1014   GstRTSPStream *stream;
1015   GstPad *srcpad;
1016   gchar *name;
1017   gint idx;
1018
1019   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1020   g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
1021   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1022   g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
1023
1024   priv = media->priv;
1025
1026   g_mutex_lock (&priv->lock);
1027   idx = priv->streams->len;
1028
1029   GST_DEBUG ("media %p: creating stream with index %d", media, idx);
1030
1031   name = g_strdup_printf ("src_%u", idx);
1032   srcpad = gst_ghost_pad_new (name, pad);
1033   gst_pad_set_active (srcpad, TRUE);
1034   gst_element_add_pad (priv->element, srcpad);
1035   g_free (name);
1036
1037   stream = gst_rtsp_stream_new (idx, payloader, srcpad);
1038   if (priv->pool)
1039     gst_rtsp_stream_set_address_pool (stream, priv->pool);
1040   gst_rtsp_stream_set_protocols (stream, priv->protocols);
1041
1042   g_ptr_array_add (priv->streams, stream);
1043   g_mutex_unlock (&priv->lock);
1044
1045   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
1046       NULL);
1047
1048   return stream;
1049 }
1050
1051 static void
1052 gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream)
1053 {
1054   GstRTSPMediaPrivate *priv;
1055   GstPad *srcpad;
1056
1057   priv = media->priv;
1058
1059   g_mutex_lock (&priv->lock);
1060   /* remove the ghostpad */
1061   srcpad = gst_rtsp_stream_get_srcpad (stream);
1062   gst_element_remove_pad (priv->element, srcpad);
1063   gst_object_unref (srcpad);
1064   /* now remove the stream */
1065   g_object_ref (stream);
1066   g_ptr_array_remove (priv->streams, stream);
1067   g_mutex_unlock (&priv->lock);
1068
1069   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM], 0,
1070       stream, NULL);
1071
1072   g_object_unref (stream);
1073 }
1074
1075 /**
1076  * gst_rtsp_media_n_streams:
1077  * @media: a #GstRTSPMedia
1078  *
1079  * Get the number of streams in this media.
1080  *
1081  * Returns: The number of streams.
1082  */
1083 guint
1084 gst_rtsp_media_n_streams (GstRTSPMedia * media)
1085 {
1086   GstRTSPMediaPrivate *priv;
1087   guint res;
1088
1089   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
1090
1091   priv = media->priv;
1092
1093   g_mutex_lock (&priv->lock);
1094   res = priv->streams->len;
1095   g_mutex_unlock (&priv->lock);
1096
1097   return res;
1098 }
1099
1100 /**
1101  * gst_rtsp_media_get_stream:
1102  * @media: a #GstRTSPMedia
1103  * @idx: the stream index
1104  *
1105  * Retrieve the stream with index @idx from @media.
1106  *
1107  * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with
1108  * that index did not exist.
1109  */
1110 GstRTSPStream *
1111 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
1112 {
1113   GstRTSPMediaPrivate *priv;
1114   GstRTSPStream *res;
1115
1116   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1117
1118   priv = media->priv;
1119
1120   g_mutex_lock (&priv->lock);
1121   if (idx < priv->streams->len)
1122     res = g_ptr_array_index (priv->streams, idx);
1123   else
1124     res = NULL;
1125   g_mutex_unlock (&priv->lock);
1126
1127   return res;
1128 }
1129
1130 /**
1131  * gst_rtsp_media_find_stream:
1132  * @media: a #GstRTSPMedia
1133  * @control: the control of the stream
1134  *
1135  * Find a stream in @media with @control as the control uri.
1136  *
1137  * Returns: (transfer none): the #GstRTSPStream with control uri @control
1138  * or %NULL when a stream with that control did not exist.
1139  */
1140 GstRTSPStream *
1141 gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control)
1142 {
1143   GstRTSPMediaPrivate *priv;
1144   GstRTSPStream *res;
1145   gint i;
1146
1147   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1148   g_return_val_if_fail (control != NULL, NULL);
1149
1150   priv = media->priv;
1151
1152   res = NULL;
1153
1154   g_mutex_lock (&priv->lock);
1155   for (i = 0; i < priv->streams->len; i++) {
1156     GstRTSPStream *test;
1157
1158     test = g_ptr_array_index (priv->streams, i);
1159     if (gst_rtsp_stream_has_control (test, control)) {
1160       res = test;
1161       break;
1162     }
1163   }
1164   g_mutex_unlock (&priv->lock);
1165
1166   return res;
1167 }
1168
1169 /**
1170  * gst_rtsp_media_get_range_string:
1171  * @media: a #GstRTSPMedia
1172  * @play: for the PLAY request
1173  * @unit: the unit to use for the string
1174  *
1175  * Get the current range as a string. @media must be prepared with
1176  * gst_rtsp_media_prepare ().
1177  *
1178  * Returns: The range as a string, g_free() after usage.
1179  */
1180 gchar *
1181 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play,
1182     GstRTSPRangeUnit unit)
1183 {
1184   GstRTSPMediaClass *klass;
1185   GstRTSPMediaPrivate *priv;
1186   gchar *result;
1187   GstRTSPTimeRange range;
1188
1189   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1190   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1191   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1192
1193   priv = media->priv;
1194
1195   g_rec_mutex_lock (&priv->state_lock);
1196   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1197     goto not_prepared;
1198
1199   g_mutex_lock (&priv->lock);
1200
1201   /* Update the range value with current position/duration */
1202   collect_media_stats (media);
1203
1204   /* make copy */
1205   range = priv->range;
1206
1207   if (!play && priv->n_active > 0) {
1208     range.min.type = GST_RTSP_TIME_NOW;
1209     range.min.seconds = -1;
1210   }
1211   g_mutex_unlock (&priv->lock);
1212   g_rec_mutex_unlock (&priv->state_lock);
1213
1214   if (!klass->convert_range (media, &range, unit))
1215     goto conversion_failed;
1216
1217   result = gst_rtsp_range_to_string (&range);
1218
1219   return result;
1220
1221   /* ERRORS */
1222 not_prepared:
1223   {
1224     GST_WARNING ("media %p was not prepared", media);
1225     g_rec_mutex_unlock (&priv->state_lock);
1226     return NULL;
1227   }
1228 conversion_failed:
1229   {
1230     GST_WARNING ("range conversion to unit %d failed", unit);
1231     return NULL;
1232   }
1233 }
1234
1235 /**
1236  * gst_rtsp_media_seek:
1237  * @media: a #GstRTSPMedia
1238  * @range: a #GstRTSPTimeRange
1239  *
1240  * Seek the pipeline of @media to @range. @media must be prepared with
1241  * gst_rtsp_media_prepare().
1242  *
1243  * Returns: %TRUE on success.
1244  */
1245 gboolean
1246 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
1247 {
1248   GstRTSPMediaClass *klass;
1249   GstRTSPMediaPrivate *priv;
1250   GstSeekFlags flags;
1251   gboolean res;
1252   GstClockTime start, stop;
1253   GstSeekType start_type, stop_type;
1254   GstQuery *query;
1255
1256   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1257
1258   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1259   g_return_val_if_fail (range != NULL, FALSE);
1260   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1261
1262   priv = media->priv;
1263
1264   g_rec_mutex_lock (&priv->state_lock);
1265   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1266     goto not_prepared;
1267
1268   /* Update the seekable state of the pipeline in case it changed */
1269   query = gst_query_new_seeking (GST_FORMAT_TIME);
1270   if (gst_element_query (priv->pipeline, query)) {
1271     GstFormat format;
1272     gboolean seekable;
1273     gint64 start, end;
1274
1275     gst_query_parse_seeking (query, &format, &seekable, &start, &end);
1276     priv->seekable = seekable;
1277   }
1278   gst_query_unref (query);
1279
1280   if (!priv->seekable)
1281     goto not_seekable;
1282
1283   /* depends on the current playing state of the pipeline. We might need to
1284    * queue this until we get EOS. */
1285   flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT;
1286
1287   start_type = stop_type = GST_SEEK_TYPE_NONE;
1288
1289   if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
1290     goto not_supported;
1291   gst_rtsp_range_get_times (range, &start, &stop);
1292
1293   GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1294       GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1295   GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1296       GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
1297
1298   if (priv->range_start == start)
1299     start = GST_CLOCK_TIME_NONE;
1300   else if (start != GST_CLOCK_TIME_NONE)
1301     start_type = GST_SEEK_TYPE_SET;
1302
1303   if (priv->range_stop == stop)
1304     stop = GST_CLOCK_TIME_NONE;
1305   else if (stop != GST_CLOCK_TIME_NONE)
1306     stop_type = GST_SEEK_TYPE_SET;
1307
1308   if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
1309     GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1310         GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1311
1312     res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
1313         flags, start_type, start, stop_type, stop);
1314
1315     /* and block for the seek to complete */
1316     GST_INFO ("done seeking %d", res);
1317     gst_element_get_state (priv->pipeline, NULL, NULL, -1);
1318     GST_INFO ("prerolled again");
1319
1320     collect_media_stats (media);
1321   } else {
1322     GST_INFO ("no seek needed");
1323     res = TRUE;
1324   }
1325   g_rec_mutex_unlock (&priv->state_lock);
1326
1327   return res;
1328
1329   /* ERRORS */
1330 not_prepared:
1331   {
1332     g_rec_mutex_unlock (&priv->state_lock);
1333     GST_INFO ("media %p is not prepared", media);
1334     return FALSE;
1335   }
1336 not_seekable:
1337   {
1338     g_rec_mutex_unlock (&priv->state_lock);
1339     GST_INFO ("pipeline is not seekable");
1340     return FALSE;
1341   }
1342 not_supported:
1343   {
1344     g_rec_mutex_unlock (&priv->state_lock);
1345     GST_WARNING ("conversion to npt not supported");
1346     return FALSE;
1347   }
1348 }
1349
1350 static void
1351 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1352 {
1353   GstRTSPMediaPrivate *priv = media->priv;
1354
1355   g_mutex_lock (&priv->lock);
1356   priv->status = status;
1357   GST_DEBUG ("setting new status to %d", status);
1358   g_cond_broadcast (&priv->cond);
1359   g_mutex_unlock (&priv->lock);
1360 }
1361
1362 /**
1363  * gst_rtsp_media_get_status:
1364  * @media: a #GstRTSPMedia
1365  *
1366  * Get the status of @media. When @media is busy preparing, this function waits
1367  * until @media is prepared or in error.
1368  *
1369  * Returns: the status of @media.
1370  */
1371 GstRTSPMediaStatus
1372 gst_rtsp_media_get_status (GstRTSPMedia * media)
1373 {
1374   GstRTSPMediaPrivate *priv = media->priv;
1375   GstRTSPMediaStatus result;
1376   gint64 end_time;
1377
1378   g_mutex_lock (&priv->lock);
1379   end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
1380   /* while we are preparing, wait */
1381   while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1382     GST_DEBUG ("waiting for status change");
1383     if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
1384       GST_DEBUG ("timeout, assuming error status");
1385       priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
1386     }
1387   }
1388   /* could be success or error */
1389   result = priv->status;
1390   GST_DEBUG ("got status %d", result);
1391   g_mutex_unlock (&priv->lock);
1392
1393   return result;
1394 }
1395
1396 /* called with state-lock */
1397 static gboolean
1398 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1399 {
1400   GstRTSPMediaPrivate *priv = media->priv;
1401   GstMessageType type;
1402
1403   type = GST_MESSAGE_TYPE (message);
1404
1405   switch (type) {
1406     case GST_MESSAGE_STATE_CHANGED:
1407       break;
1408     case GST_MESSAGE_BUFFERING:
1409     {
1410       gint percent;
1411
1412       gst_message_parse_buffering (message, &percent);
1413
1414       /* no state management needed for live pipelines */
1415       if (priv->is_live)
1416         break;
1417
1418       if (percent == 100) {
1419         /* a 100% message means buffering is done */
1420         priv->buffering = FALSE;
1421         /* if the desired state is playing, go back */
1422         if (priv->target_state == GST_STATE_PLAYING) {
1423           GST_INFO ("Buffering done, setting pipeline to PLAYING");
1424           gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1425         } else {
1426           GST_INFO ("Buffering done");
1427         }
1428       } else {
1429         /* buffering busy */
1430         if (priv->buffering == FALSE) {
1431           if (priv->target_state == GST_STATE_PLAYING) {
1432             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
1433             GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1434             gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1435           } else {
1436             GST_INFO ("Buffering ...");
1437           }
1438         }
1439         priv->buffering = TRUE;
1440       }
1441       break;
1442     }
1443     case GST_MESSAGE_LATENCY:
1444     {
1445       gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
1446       break;
1447     }
1448     case GST_MESSAGE_ERROR:
1449     {
1450       GError *gerror;
1451       gchar *debug;
1452
1453       gst_message_parse_error (message, &gerror, &debug);
1454       GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1455       g_error_free (gerror);
1456       g_free (debug);
1457
1458       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1459       break;
1460     }
1461     case GST_MESSAGE_WARNING:
1462     {
1463       GError *gerror;
1464       gchar *debug;
1465
1466       gst_message_parse_warning (message, &gerror, &debug);
1467       GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1468       g_error_free (gerror);
1469       g_free (debug);
1470       break;
1471     }
1472     case GST_MESSAGE_ELEMENT:
1473       break;
1474     case GST_MESSAGE_STREAM_STATUS:
1475       break;
1476     case GST_MESSAGE_ASYNC_DONE:
1477       if (priv->adding) {
1478         /* when we are dynamically adding pads, the addition of the udpsrc will
1479          * temporarily produce ASYNC_DONE messages. We have to ignore them and
1480          * wait for the final ASYNC_DONE after everything prerolled */
1481         GST_INFO ("%p: ignoring ASYNC_DONE", media);
1482       } else {
1483         GST_INFO ("%p: got ASYNC_DONE", media);
1484         collect_media_stats (media);
1485
1486         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1487           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1488       }
1489       break;
1490     case GST_MESSAGE_EOS:
1491       GST_INFO ("%p: got EOS", media);
1492
1493       if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1494         GST_DEBUG ("shutting down after EOS");
1495         finish_unprepare (media);
1496       }
1497       break;
1498     default:
1499       GST_INFO ("%p: got message type %d (%s)", media, type,
1500           gst_message_type_get_name (type));
1501       break;
1502   }
1503   return TRUE;
1504 }
1505
1506 static gboolean
1507 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1508 {
1509   GstRTSPMediaPrivate *priv = media->priv;
1510   GstRTSPMediaClass *klass;
1511   gboolean ret;
1512
1513   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1514
1515   g_rec_mutex_lock (&priv->state_lock);
1516   if (klass->handle_message)
1517     ret = klass->handle_message (media, message);
1518   else
1519     ret = FALSE;
1520   g_rec_mutex_unlock (&priv->state_lock);
1521
1522   return ret;
1523 }
1524
1525 static void
1526 watch_destroyed (GstRTSPMedia * media)
1527 {
1528   GST_DEBUG_OBJECT (media, "source destroyed");
1529   g_object_unref (media);
1530 }
1531
1532 static GstElement *
1533 find_payload_element (GstElement * payloader)
1534 {
1535   GValue item = { 0 };
1536   GstIterator *iter;
1537   GstElement *pay = NULL;
1538
1539   iter = gst_bin_iterate_recurse (GST_BIN (payloader));
1540   while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) {
1541     GstElement *element = (GstElement *) g_value_get_object (&item);
1542     GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element);
1543     const gchar *klass;
1544
1545     klass = gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS);
1546     if (klass == NULL)
1547       continue;
1548
1549     if (strstr (klass, "Payloader") && strstr (klass, "RTP")) {
1550       pay = gst_object_ref (element);
1551       g_value_unset (&item);
1552       break;
1553     }
1554     g_value_unset (&item);
1555   }
1556   gst_iterator_free (iter);
1557
1558   return pay;
1559 }
1560
1561 /* called from streaming threads */
1562 static void
1563 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1564 {
1565   GstRTSPMediaPrivate *priv = media->priv;
1566   GstRTSPStream *stream;
1567   GstElement *pay;
1568
1569   /* find the real payload element */
1570   pay = find_payload_element (element);
1571   stream = gst_rtsp_media_create_stream (media, pay, pad);
1572   gst_object_unref (pay);
1573
1574   g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream);
1575
1576   GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1577
1578   g_rec_mutex_lock (&priv->state_lock);
1579   /* we will be adding elements below that will cause ASYNC_DONE to be
1580    * posted in the bus. We want to ignore those messages until the
1581    * pipeline really prerolled. */
1582   priv->adding = TRUE;
1583
1584   /* join the element in the PAUSED state because this callback is
1585    * called from the streaming thread and it is PAUSED */
1586   gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1587       priv->rtpbin, GST_STATE_PAUSED);
1588
1589   priv->adding = FALSE;
1590   g_rec_mutex_unlock (&priv->state_lock);
1591 }
1592
1593 static void
1594 pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1595 {
1596   GstRTSPMediaPrivate *priv = media->priv;
1597   GstRTSPStream *stream;
1598
1599   stream = g_object_get_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream");
1600   if (stream == NULL)
1601     return;
1602
1603   GST_INFO ("pad removed %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1604
1605   g_rec_mutex_lock (&priv->state_lock);
1606   gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1607   g_rec_mutex_unlock (&priv->state_lock);
1608
1609   gst_rtsp_media_remove_stream (media, stream);
1610 }
1611
1612 static void
1613 remove_fakesink (GstRTSPMediaPrivate * priv)
1614 {
1615   GstElement *fakesink;
1616
1617   g_mutex_lock (&priv->lock);
1618   if ((fakesink = priv->fakesink))
1619     gst_object_ref (fakesink);
1620   priv->fakesink = NULL;
1621   g_mutex_unlock (&priv->lock);
1622
1623   if (fakesink) {
1624     gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
1625     gst_element_set_state (fakesink, GST_STATE_NULL);
1626     gst_object_unref (fakesink);
1627     GST_INFO ("removed fakesink");
1628   }
1629 }
1630
1631 static void
1632 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1633 {
1634   GstRTSPMediaPrivate *priv = media->priv;
1635
1636   GST_INFO ("no more pads");
1637   remove_fakesink (priv);
1638 }
1639
1640 typedef struct _DynPaySignalHandlers DynPaySignalHandlers;
1641
1642 struct _DynPaySignalHandlers
1643 {
1644   gulong pad_added_handler;
1645   gulong pad_removed_handler;
1646   gulong no_more_pads_handler;
1647 };
1648
1649 static gboolean
1650 start_prepare (GstRTSPMedia * media)
1651 {
1652   GstRTSPMediaPrivate *priv = media->priv;
1653   GstStateChangeReturn ret;
1654   guint i;
1655   GList *walk;
1656
1657   /* link streams we already have, other streams might appear when we have
1658    * dynamic elements */
1659   for (i = 0; i < priv->streams->len; i++) {
1660     GstRTSPStream *stream;
1661
1662     stream = g_ptr_array_index (priv->streams, i);
1663
1664     gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1665         priv->rtpbin, GST_STATE_NULL);
1666   }
1667
1668   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1669     GstElement *elem = walk->data;
1670     DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
1671
1672     GST_INFO ("adding callbacks for dynamic element %p", elem);
1673
1674     handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
1675         (GCallback) pad_added_cb, media);
1676     handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
1677         (GCallback) pad_removed_cb, media);
1678     handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
1679         (GCallback) no_more_pads_cb, media);
1680
1681     g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
1682
1683     /* we add a fakesink here in order to make the state change async. We remove
1684      * the fakesink again in the no-more-pads callback. */
1685     priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1686     gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
1687   }
1688
1689   GST_INFO ("setting pipeline to PAUSED for media %p", media);
1690   /* first go to PAUSED */
1691   ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1692   priv->target_state = GST_STATE_PAUSED;
1693
1694   switch (ret) {
1695     case GST_STATE_CHANGE_SUCCESS:
1696       GST_INFO ("SUCCESS state change for media %p", media);
1697       priv->seekable = TRUE;
1698       break;
1699     case GST_STATE_CHANGE_ASYNC:
1700       GST_INFO ("ASYNC state change for media %p", media);
1701       priv->seekable = TRUE;
1702       break;
1703     case GST_STATE_CHANGE_NO_PREROLL:
1704       /* we need to go to PLAYING */
1705       GST_INFO ("NO_PREROLL state change: live media %p", media);
1706       /* FIXME we disable seeking for live streams for now. We should perform a
1707        * seeking query in preroll instead */
1708       priv->seekable = FALSE;
1709       priv->is_live = TRUE;
1710       ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1711       if (ret == GST_STATE_CHANGE_FAILURE)
1712         goto state_failed;
1713       break;
1714     case GST_STATE_CHANGE_FAILURE:
1715       goto state_failed;
1716   }
1717
1718   return FALSE;
1719
1720 state_failed:
1721   {
1722     GST_WARNING ("failed to preroll pipeline");
1723     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1724     return FALSE;
1725   }
1726 }
1727
1728 /**
1729  * gst_rtsp_media_prepare:
1730  * @media: a #GstRTSPMedia
1731  * @thread: a #GstRTSPThread to run the bus handler or %NULL
1732  *
1733  * Prepare @media for streaming. This function will create the objects
1734  * to manage the streaming. A pipeline must have been set on @media with
1735  * gst_rtsp_media_take_pipeline().
1736  *
1737  * It will preroll the pipeline and collect vital information about the streams
1738  * such as the duration.
1739  *
1740  * Returns: %TRUE on success.
1741  */
1742 gboolean
1743 gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
1744 {
1745   GstRTSPMediaPrivate *priv;
1746   GstRTSPMediaStatus status;
1747   GstBus *bus;
1748   GSource *source;
1749
1750   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1751   g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE);
1752
1753   priv = media->priv;
1754
1755   g_rec_mutex_lock (&priv->state_lock);
1756   priv->prepare_count++;
1757
1758   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1759     goto was_prepared;
1760
1761   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1762     goto wait_status;
1763
1764   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
1765     goto not_unprepared;
1766
1767   if (!priv->reusable && priv->reused)
1768     goto is_reused;
1769
1770   priv->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1771   if (priv->rtpbin != NULL) {
1772     GstRTSPMediaClass *klass;
1773     gboolean success = TRUE;
1774
1775     klass = GST_RTSP_MEDIA_GET_CLASS (media);
1776     if (klass->setup_rtpbin)
1777       success = klass->setup_rtpbin (media, priv->rtpbin);
1778
1779     if (success == FALSE) {
1780       gst_object_unref (priv->rtpbin);
1781       priv->rtpbin = NULL;
1782     }
1783   }
1784   if (priv->rtpbin == NULL)
1785     goto no_rtpbin;
1786
1787   GST_INFO ("preparing media %p", media);
1788
1789   /* reset some variables */
1790   priv->is_live = FALSE;
1791   priv->seekable = FALSE;
1792   priv->buffering = FALSE;
1793   priv->thread = thread;
1794   /* we're preparing now */
1795   priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1796
1797   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
1798
1799   /* add the pipeline bus to our custom mainloop */
1800   priv->source = gst_bus_create_watch (bus);
1801   gst_object_unref (bus);
1802
1803   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
1804       g_object_ref (media), (GDestroyNotify) watch_destroyed);
1805
1806   priv->id = g_source_attach (priv->source, thread->context);
1807
1808   /* add stuff to the bin */
1809   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
1810
1811   /* do remainder in context */
1812   source = g_idle_source_new ();
1813   g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
1814   g_source_attach (source, thread->context);
1815   g_source_unref (source);
1816
1817 wait_status:
1818   g_rec_mutex_unlock (&priv->state_lock);
1819
1820   /* now wait for all pads to be prerolled, FIXME, we should somehow be
1821    * able to do this async so that we don't block the server thread. */
1822   status = gst_rtsp_media_get_status (media);
1823   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1824     goto state_failed;
1825
1826   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1827
1828   GST_INFO ("object %p is prerolled", media);
1829
1830   return TRUE;
1831
1832   /* OK */
1833 was_prepared:
1834   {
1835     GST_LOG ("media %p was prepared", media);
1836     g_rec_mutex_unlock (&priv->state_lock);
1837     return TRUE;
1838   }
1839   /* ERRORS */
1840 not_unprepared:
1841   {
1842     GST_WARNING ("media %p was not unprepared", media);
1843     priv->prepare_count--;
1844     g_rec_mutex_unlock (&priv->state_lock);
1845     return FALSE;
1846   }
1847 is_reused:
1848   {
1849     priv->prepare_count--;
1850     g_rec_mutex_unlock (&priv->state_lock);
1851     GST_WARNING ("can not reuse media %p", media);
1852     return FALSE;
1853   }
1854 no_rtpbin:
1855   {
1856     priv->prepare_count--;
1857     g_rec_mutex_unlock (&priv->state_lock);
1858     GST_WARNING ("no rtpbin element");
1859     g_warning ("failed to create element 'rtpbin', check your installation");
1860     return FALSE;
1861   }
1862 state_failed:
1863   {
1864     GST_WARNING ("failed to preroll pipeline");
1865     gst_rtsp_media_unprepare (media);
1866     return FALSE;
1867   }
1868 }
1869
1870 /* must be called with state-lock */
1871 static void
1872 finish_unprepare (GstRTSPMedia * media)
1873 {
1874   GstRTSPMediaPrivate *priv = media->priv;
1875   gint i;
1876   GList *walk;
1877
1878   GST_DEBUG ("shutting down");
1879
1880   gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1881   remove_fakesink (priv);
1882
1883   for (i = 0; i < priv->streams->len; i++) {
1884     GstRTSPStream *stream;
1885
1886     GST_INFO ("Removing elements of stream %d from pipeline", i);
1887
1888     stream = g_ptr_array_index (priv->streams, i);
1889
1890     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1891   }
1892
1893   /* remove the pad signal handlers */
1894   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1895     GstElement *elem = walk->data;
1896     DynPaySignalHandlers *handlers;
1897
1898     handlers =
1899         g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers");
1900     g_assert (handlers != NULL);
1901
1902     g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler);
1903     g_signal_handler_disconnect (G_OBJECT (elem),
1904         handlers->pad_removed_handler);
1905     g_signal_handler_disconnect (G_OBJECT (elem),
1906         handlers->no_more_pads_handler);
1907
1908     g_slice_free (DynPaySignalHandlers, handlers);
1909   }
1910
1911   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
1912   priv->rtpbin = NULL;
1913
1914   if (priv->nettime)
1915     gst_object_unref (priv->nettime);
1916   priv->nettime = NULL;
1917
1918   priv->reused = TRUE;
1919   priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1920
1921   /* when the media is not reusable, this will effectively unref the media and
1922    * recreate it */
1923   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1924
1925   /* the source has the last ref to the media */
1926   if (priv->source) {
1927     GST_DEBUG ("destroy source");
1928     g_source_destroy (priv->source);
1929     g_source_unref (priv->source);
1930   }
1931   if (priv->thread) {
1932     GST_DEBUG ("stop thread");
1933     gst_rtsp_thread_stop (priv->thread);
1934   }
1935 }
1936
1937 /* called with state-lock */
1938 static gboolean
1939 default_unprepare (GstRTSPMedia * media)
1940 {
1941   GstRTSPMediaPrivate *priv = media->priv;
1942
1943   if (priv->eos_shutdown) {
1944     GST_DEBUG ("sending EOS for shutdown");
1945     /* ref so that we don't disappear */
1946     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
1947     /* we need to go to playing again for the EOS to propagate, normally in this
1948      * state, nothing is receiving data from us anymore so this is ok. */
1949     gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1950     priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1951   } else {
1952     finish_unprepare (media);
1953   }
1954   return TRUE;
1955 }
1956
1957 /**
1958  * gst_rtsp_media_unprepare:
1959  * @media: a #GstRTSPMedia
1960  *
1961  * Unprepare @media. After this call, the media should be prepared again before
1962  * it can be used again. If the media is set to be non-reusable, a new instance
1963  * must be created.
1964  *
1965  * Returns: %TRUE on success.
1966  */
1967 gboolean
1968 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1969 {
1970   GstRTSPMediaPrivate *priv;
1971   gboolean success;
1972
1973   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1974
1975   priv = media->priv;
1976
1977   g_rec_mutex_lock (&priv->state_lock);
1978   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1979     goto was_unprepared;
1980
1981   priv->prepare_count--;
1982   if (priv->prepare_count > 0)
1983     goto is_busy;
1984
1985   GST_INFO ("unprepare media %p", media);
1986   priv->target_state = GST_STATE_NULL;
1987   success = TRUE;
1988
1989   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1990     GstRTSPMediaClass *klass;
1991
1992     klass = GST_RTSP_MEDIA_GET_CLASS (media);
1993     if (klass->unprepare)
1994       success = klass->unprepare (media);
1995   } else {
1996     finish_unprepare (media);
1997   }
1998   g_rec_mutex_unlock (&priv->state_lock);
1999
2000   return success;
2001
2002 was_unprepared:
2003   {
2004     g_rec_mutex_unlock (&priv->state_lock);
2005     GST_INFO ("media %p was already unprepared", media);
2006     return TRUE;
2007   }
2008 is_busy:
2009   {
2010     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
2011     g_rec_mutex_unlock (&priv->state_lock);
2012     return TRUE;
2013   }
2014 }
2015
2016 /* should be called with state-lock */
2017 static GstClock *
2018 get_clock_unlocked (GstRTSPMedia * media)
2019 {
2020   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
2021     GST_DEBUG_OBJECT (media, "media was not prepared");
2022     return NULL;
2023   }
2024   return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
2025 }
2026
2027 /**
2028  * gst_rtsp_media_get_clock:
2029  * @media: a #GstRTSPMedia
2030  *
2031  * Get the clock that is used by the pipeline in @media.
2032  *
2033  * @media must be prepared before this method returns a valid clock object.
2034  *
2035  * Returns: (transfer full): the #GstClock used by @media. unref after usage.
2036  */
2037 GstClock *
2038 gst_rtsp_media_get_clock (GstRTSPMedia * media)
2039 {
2040   GstClock *clock;
2041   GstRTSPMediaPrivate *priv;
2042
2043   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2044
2045   priv = media->priv;
2046
2047   g_rec_mutex_lock (&priv->state_lock);
2048   clock = get_clock_unlocked (media);
2049   g_rec_mutex_unlock (&priv->state_lock);
2050
2051   return clock;
2052 }
2053
2054 /**
2055  * gst_rtsp_media_get_base_time:
2056  * @media: a #GstRTSPMedia
2057  *
2058  * Get the base_time that is used by the pipeline in @media.
2059  *
2060  * @media must be prepared before this method returns a valid base_time.
2061  *
2062  * Returns: the base_time used by @media.
2063  */
2064 GstClockTime
2065 gst_rtsp_media_get_base_time (GstRTSPMedia * media)
2066 {
2067   GstClockTime result;
2068   GstRTSPMediaPrivate *priv;
2069
2070   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE);
2071
2072   priv = media->priv;
2073
2074   g_rec_mutex_lock (&priv->state_lock);
2075   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2076     goto not_prepared;
2077
2078   result = gst_element_get_base_time (media->priv->pipeline);
2079   g_rec_mutex_unlock (&priv->state_lock);
2080
2081   return result;
2082
2083   /* ERRORS */
2084 not_prepared:
2085   {
2086     g_rec_mutex_unlock (&priv->state_lock);
2087     GST_DEBUG_OBJECT (media, "media was not prepared");
2088     return GST_CLOCK_TIME_NONE;
2089   }
2090 }
2091
2092 /**
2093  * gst_rtsp_media_get_time_provider:
2094  * @media: a #GstRTSPMedia
2095  * @address: an address or %NULL
2096  * @port: a port or 0
2097  *
2098  * Get the #GstNetTimeProvider for the clock used by @media. The time provider
2099  * will listen on @address and @port for client time requests.
2100  *
2101  * Returns: (transfer full): the #GstNetTimeProvider of @media.
2102  */
2103 GstNetTimeProvider *
2104 gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
2105     guint16 port)
2106 {
2107   GstRTSPMediaPrivate *priv;
2108   GstNetTimeProvider *provider = NULL;
2109
2110   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2111
2112   priv = media->priv;
2113
2114   g_rec_mutex_lock (&priv->state_lock);
2115   if (priv->time_provider) {
2116     if ((provider = priv->nettime) == NULL) {
2117       GstClock *clock;
2118
2119       if (priv->time_provider && (clock = get_clock_unlocked (media))) {
2120         provider = gst_net_time_provider_new (clock, address, port);
2121         gst_object_unref (clock);
2122
2123         priv->nettime = provider;
2124       }
2125     }
2126   }
2127   g_rec_mutex_unlock (&priv->state_lock);
2128
2129   if (provider)
2130     gst_object_ref (provider);
2131
2132   return provider;
2133 }
2134
2135 /**
2136  * gst_rtsp_media_set_pipeline_state:
2137  * @media: a #GstRTSPMedia
2138  * @state: the target state of the pipeline
2139  *
2140  * Set the state of the pipeline managed by @media to @state
2141  */
2142 void
2143 gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state)
2144 {
2145   GstRTSPMediaPrivate *priv = media->priv;
2146
2147   if (state == GST_STATE_NULL) {
2148     gst_rtsp_media_unprepare (media);
2149   } else {
2150     GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
2151     priv->target_state = state;
2152     /* when we are buffering, don't update the state yet, this will be done
2153      * when buffering finishes */
2154     if (priv->buffering) {
2155       GST_INFO ("Buffering busy, delay state change");
2156     } else {
2157       gst_element_set_state (priv->pipeline, state);
2158     }
2159   }
2160 }
2161
2162 /**
2163  * gst_rtsp_media_set_state:
2164  * @media: a #GstRTSPMedia
2165  * @state: the target state of the media
2166  * @transports: (element-type GstRtspServer.RTSPStreamTransport): a #GPtrArray
2167  * of #GstRTSPStreamTransport pointers
2168  *
2169  * Set the state of @media to @state and for the transports in @transports.
2170  *
2171  * @media must be prepared with gst_rtsp_media_prepare();
2172  *
2173  * Returns: %TRUE on success.
2174  */
2175 gboolean
2176 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
2177     GPtrArray * transports)
2178 {
2179   GstRTSPMediaPrivate *priv;
2180   gint i;
2181   gboolean activate, deactivate, do_state;
2182   gint old_active;
2183
2184   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2185   g_return_val_if_fail (transports != NULL, FALSE);
2186
2187   priv = media->priv;
2188
2189   g_rec_mutex_lock (&priv->state_lock);
2190   if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR)
2191     goto error_status;
2192   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2193     goto not_prepared;
2194
2195   /* NULL and READY are the same */
2196   if (state == GST_STATE_READY)
2197     state = GST_STATE_NULL;
2198
2199   activate = deactivate = FALSE;
2200
2201   GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
2202       media);
2203
2204   switch (state) {
2205     case GST_STATE_NULL:
2206     case GST_STATE_PAUSED:
2207       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
2208       if (priv->target_state == GST_STATE_PLAYING)
2209         deactivate = TRUE;
2210       break;
2211     case GST_STATE_PLAYING:
2212       /* we're going to PLAYING, activate */
2213       activate = TRUE;
2214       break;
2215     default:
2216       break;
2217   }
2218   old_active = priv->n_active;
2219
2220   for (i = 0; i < transports->len; i++) {
2221     GstRTSPStreamTransport *trans;
2222
2223     /* we need a non-NULL entry in the array */
2224     trans = g_ptr_array_index (transports, i);
2225     if (trans == NULL)
2226       continue;
2227
2228     if (activate) {
2229       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
2230         priv->n_active++;
2231     } else if (deactivate) {
2232       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
2233         priv->n_active--;
2234     }
2235   }
2236
2237   /* we just activated the first media, do the playing state change */
2238   if (old_active == 0 && activate)
2239     do_state = TRUE;
2240   /* if we have no more active media, do the downward state changes */
2241   else if (priv->n_active == 0)
2242     do_state = TRUE;
2243   else
2244     do_state = FALSE;
2245
2246   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
2247       media, do_state);
2248
2249   if (priv->target_state != state) {
2250     if (do_state)
2251       gst_rtsp_media_set_pipeline_state (media, state);
2252
2253     g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2254         NULL);
2255   }
2256
2257   /* remember where we are */
2258   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
2259           old_active != priv->n_active))
2260     collect_media_stats (media);
2261
2262   g_rec_mutex_unlock (&priv->state_lock);
2263
2264   return TRUE;
2265
2266   /* ERRORS */
2267 not_prepared:
2268   {
2269     GST_WARNING ("media %p was not prepared", media);
2270     g_rec_mutex_unlock (&priv->state_lock);
2271     return FALSE;
2272   }
2273 error_status:
2274   {
2275     GST_WARNING ("media %p in error status while changing to state %d",
2276         media, state);
2277     if (state == GST_STATE_NULL) {
2278       for (i = 0; i < transports->len; i++) {
2279         GstRTSPStreamTransport *trans;
2280
2281         /* we need a non-NULL entry in the array */
2282         trans = g_ptr_array_index (transports, i);
2283         if (trans == NULL)
2284           continue;
2285
2286         gst_rtsp_stream_transport_set_active (trans, FALSE);
2287       }
2288       priv->n_active = 0;
2289     }
2290     g_rec_mutex_unlock (&priv->state_lock);
2291     return FALSE;
2292   }
2293 }
2294
2295 /* called with state-lock */
2296 static gboolean
2297 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
2298     GstRTSPRangeUnit unit)
2299 {
2300   return gst_rtsp_range_convert_units (range, unit);
2301 }
2302
2303 static gboolean
2304 default_query_position (GstRTSPMedia * media, gint64 * position)
2305 {
2306   return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME,
2307       position);
2308 }
2309
2310 static gboolean
2311 default_query_stop (GstRTSPMedia * media, gint64 * stop)
2312 {
2313   GstQuery *query;
2314   gboolean res;
2315
2316   query = gst_query_new_segment (GST_FORMAT_TIME);
2317   if ((res = gst_element_query (media->priv->pipeline, query))) {
2318     GstFormat format;
2319     gst_query_parse_segment (query, NULL, &format, NULL, stop);
2320     if (format != GST_FORMAT_TIME)
2321       *stop = -1;
2322   }
2323   gst_query_unref (query);
2324   return res;
2325 }