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