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