media: start media pipeline in context
[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 static gboolean
1560 start_prepare (GstRTSPMedia * media)
1561 {
1562   GstRTSPMediaPrivate *priv = media->priv;
1563   GstStateChangeReturn ret;
1564   guint i;
1565   GList *walk;
1566
1567   /* link streams we already have, other streams might appear when we have
1568    * dynamic elements */
1569   for (i = 0; i < priv->streams->len; i++) {
1570     GstRTSPStream *stream;
1571
1572     stream = g_ptr_array_index (priv->streams, i);
1573
1574     gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1575         priv->rtpbin, GST_STATE_NULL);
1576   }
1577
1578   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1579     GstElement *elem = walk->data;
1580     DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
1581
1582     GST_INFO ("adding callbacks for dynamic element %p", elem);
1583
1584     handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
1585         (GCallback) pad_added_cb, media);
1586     handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
1587         (GCallback) pad_removed_cb, media);
1588     handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
1589         (GCallback) no_more_pads_cb, media);
1590
1591     g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
1592
1593     /* we add a fakesink here in order to make the state change async. We remove
1594      * the fakesink again in the no-more-pads callback. */
1595     priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1596     gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
1597   }
1598
1599   GST_INFO ("setting pipeline to PAUSED for media %p", media);
1600   /* first go to PAUSED */
1601   ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1602   priv->target_state = GST_STATE_PAUSED;
1603
1604   switch (ret) {
1605     case GST_STATE_CHANGE_SUCCESS:
1606       GST_INFO ("SUCCESS state change for media %p", media);
1607       priv->seekable = TRUE;
1608       break;
1609     case GST_STATE_CHANGE_ASYNC:
1610       GST_INFO ("ASYNC state change for media %p", media);
1611       priv->seekable = TRUE;
1612       break;
1613     case GST_STATE_CHANGE_NO_PREROLL:
1614       /* we need to go to PLAYING */
1615       GST_INFO ("NO_PREROLL state change: live media %p", media);
1616       /* FIXME we disable seeking for live streams for now. We should perform a
1617        * seeking query in preroll instead */
1618       priv->seekable = FALSE;
1619       priv->is_live = TRUE;
1620       ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1621       if (ret == GST_STATE_CHANGE_FAILURE)
1622         goto state_failed;
1623       break;
1624     case GST_STATE_CHANGE_FAILURE:
1625       goto state_failed;
1626   }
1627
1628   return FALSE;
1629
1630 state_failed:
1631   {
1632     GST_WARNING ("failed to preroll pipeline");
1633     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1634     return FALSE;
1635   }
1636 }
1637
1638 /**
1639  * gst_rtsp_media_prepare:
1640  * @media: a #GstRTSPMedia
1641  * @context: a #GMainContext to run the bus handler or %NULL
1642  *
1643  * Prepare @media for streaming. This function will create the objects
1644  * to manage the streaming. A pipeline must have been set on @media with
1645  * gst_rtsp_media_take_pipeline().
1646  *
1647  * It will preroll the pipeline and collect vital information about the streams
1648  * such as the duration.
1649  *
1650  * Returns: %TRUE on success.
1651  */
1652 gboolean
1653 gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context)
1654 {
1655   GstRTSPMediaPrivate *priv;
1656   GstRTSPMediaStatus status;
1657   GstRTSPMediaClass *klass;
1658   GstBus *bus;
1659   GSource *source;
1660
1661   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1662
1663   priv = media->priv;
1664
1665   g_rec_mutex_lock (&priv->state_lock);
1666   priv->prepare_count++;
1667
1668   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1669     goto was_prepared;
1670
1671   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1672     goto wait_status;
1673
1674   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
1675     goto not_unprepared;
1676
1677   if (!priv->reusable && priv->reused)
1678     goto is_reused;
1679
1680   priv->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1681   if (priv->rtpbin == NULL)
1682     goto no_rtpbin;
1683
1684   GST_INFO ("preparing media %p", media);
1685
1686   /* reset some variables */
1687   priv->is_live = FALSE;
1688   priv->seekable = FALSE;
1689   priv->buffering = FALSE;
1690   /* we're preparing now */
1691   priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1692
1693   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1694
1695   if (context == NULL)
1696     context = klass->context;
1697
1698   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
1699
1700   /* add the pipeline bus to our custom mainloop */
1701   priv->source = gst_bus_create_watch (bus);
1702   gst_object_unref (bus);
1703
1704   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
1705       g_object_ref (media), (GDestroyNotify) watch_destroyed);
1706
1707   priv->id = g_source_attach (priv->source, context);
1708
1709   /* add stuff to the bin */
1710   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
1711
1712   /* do remainder in context */
1713   source = g_idle_source_new ();
1714   g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
1715   g_source_attach (source, context);
1716   g_source_unref (source);
1717
1718 wait_status:
1719   g_rec_mutex_unlock (&priv->state_lock);
1720
1721   /* now wait for all pads to be prerolled, FIXME, we should somehow be
1722    * able to do this async so that we don't block the server thread. */
1723   status = gst_rtsp_media_get_status (media);
1724   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1725     goto state_failed;
1726
1727   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1728
1729   GST_INFO ("object %p is prerolled", media);
1730
1731   return TRUE;
1732
1733   /* OK */
1734 was_prepared:
1735   {
1736     GST_LOG ("media %p was prepared", media);
1737     g_rec_mutex_unlock (&priv->state_lock);
1738     return TRUE;
1739   }
1740   /* ERRORS */
1741 not_unprepared:
1742   {
1743     GST_WARNING ("media %p was not unprepared", media);
1744     priv->prepare_count--;
1745     g_rec_mutex_unlock (&priv->state_lock);
1746     return FALSE;
1747   }
1748 is_reused:
1749   {
1750     priv->prepare_count--;
1751     g_rec_mutex_unlock (&priv->state_lock);
1752     GST_WARNING ("can not reuse media %p", media);
1753     return FALSE;
1754   }
1755 no_rtpbin:
1756   {
1757     priv->prepare_count--;
1758     g_rec_mutex_unlock (&priv->state_lock);
1759     GST_WARNING ("no rtpbin element");
1760     g_warning ("failed to create element 'rtpbin', check your installation");
1761     return FALSE;
1762   }
1763 state_failed:
1764   {
1765     GST_WARNING ("failed to preroll pipeline");
1766     gst_rtsp_media_unprepare (media);
1767     return FALSE;
1768   }
1769 }
1770
1771 /* must be called with state-lock */
1772 static void
1773 finish_unprepare (GstRTSPMedia * media)
1774 {
1775   GstRTSPMediaPrivate *priv = media->priv;
1776   gint i;
1777   GList *walk;
1778
1779   GST_DEBUG ("shutting down");
1780
1781   gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1782   remove_fakesink (priv);
1783
1784   for (i = 0; i < priv->streams->len; i++) {
1785     GstRTSPStream *stream;
1786
1787     GST_INFO ("Removing elements of stream %d from pipeline", i);
1788
1789     stream = g_ptr_array_index (priv->streams, i);
1790
1791     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1792   }
1793
1794   /* remove the pad signal handlers */
1795   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1796     GstElement *elem = walk->data;
1797     DynPaySignalHandlers *handlers;
1798
1799     handlers =
1800         g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers");
1801     g_assert (handlers != NULL);
1802
1803     g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler);
1804     g_signal_handler_disconnect (G_OBJECT (elem),
1805         handlers->pad_removed_handler);
1806     g_signal_handler_disconnect (G_OBJECT (elem),
1807         handlers->no_more_pads_handler);
1808
1809     g_slice_free (DynPaySignalHandlers, handlers);
1810   }
1811
1812   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
1813   priv->rtpbin = NULL;
1814
1815   if (priv->nettime)
1816     gst_object_unref (priv->nettime);
1817   priv->nettime = NULL;
1818
1819   priv->reused = TRUE;
1820   priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1821
1822   /* when the media is not reusable, this will effectively unref the media and
1823    * recreate it */
1824   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1825
1826   /* the source has the last ref to the media */
1827   if (priv->source) {
1828     GST_DEBUG ("destroy source");
1829     g_source_destroy (priv->source);
1830     g_source_unref (priv->source);
1831   }
1832 }
1833
1834 /* called with state-lock */
1835 static gboolean
1836 default_unprepare (GstRTSPMedia * media)
1837 {
1838   GstRTSPMediaPrivate *priv = media->priv;
1839
1840   if (priv->eos_shutdown) {
1841     GST_DEBUG ("sending EOS for shutdown");
1842     /* ref so that we don't disappear */
1843     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
1844     /* we need to go to playing again for the EOS to propagate, normally in this
1845      * state, nothing is receiving data from us anymore so this is ok. */
1846     gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1847     priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1848   } else {
1849     finish_unprepare (media);
1850   }
1851   return TRUE;
1852 }
1853
1854 /**
1855  * gst_rtsp_media_unprepare:
1856  * @media: a #GstRTSPMedia
1857  *
1858  * Unprepare @media. After this call, the media should be prepared again before
1859  * it can be used again. If the media is set to be non-reusable, a new instance
1860  * must be created.
1861  *
1862  * Returns: %TRUE on success.
1863  */
1864 gboolean
1865 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1866 {
1867   GstRTSPMediaPrivate *priv;
1868   gboolean success;
1869
1870   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1871
1872   priv = media->priv;
1873
1874   g_rec_mutex_lock (&priv->state_lock);
1875   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1876     goto was_unprepared;
1877
1878   priv->prepare_count--;
1879   if (priv->prepare_count > 0)
1880     goto is_busy;
1881
1882   GST_INFO ("unprepare media %p", media);
1883   priv->target_state = GST_STATE_NULL;
1884   success = TRUE;
1885
1886   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1887     GstRTSPMediaClass *klass;
1888
1889     klass = GST_RTSP_MEDIA_GET_CLASS (media);
1890     if (klass->unprepare)
1891       success = klass->unprepare (media);
1892   } else {
1893     finish_unprepare (media);
1894   }
1895   g_rec_mutex_unlock (&priv->state_lock);
1896
1897   return success;
1898
1899 was_unprepared:
1900   {
1901     g_rec_mutex_unlock (&priv->state_lock);
1902     GST_INFO ("media %p was already unprepared", media);
1903     return TRUE;
1904   }
1905 is_busy:
1906   {
1907     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
1908     g_rec_mutex_unlock (&priv->state_lock);
1909     return TRUE;
1910   }
1911 }
1912
1913 /* should be called with state-lock */
1914 static GstClock *
1915 get_clock_unlocked (GstRTSPMedia * media)
1916 {
1917   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
1918     GST_DEBUG_OBJECT (media, "media was not prepared");
1919     return NULL;
1920   }
1921   return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
1922 }
1923
1924 /**
1925  * gst_rtsp_media_get_clock:
1926  * @media: a #GstRTSPMedia
1927  *
1928  * Get the clock that is used by the pipeline in @media.
1929  *
1930  * @media must be prepared before this method returns a valid clock object.
1931  *
1932  * Returns: the #GstClock used by @media. unref after usage.
1933  */
1934 GstClock *
1935 gst_rtsp_media_get_clock (GstRTSPMedia * media)
1936 {
1937   GstClock *clock;
1938   GstRTSPMediaPrivate *priv;
1939
1940   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1941
1942   priv = media->priv;
1943
1944   g_rec_mutex_lock (&priv->state_lock);
1945   clock = get_clock_unlocked (media);
1946   g_rec_mutex_unlock (&priv->state_lock);
1947
1948   return clock;
1949 }
1950
1951 /**
1952  * gst_rtsp_media_get_base_time:
1953  * @media: a #GstRTSPMedia
1954  *
1955  * Get the base_time that is used by the pipeline in @media.
1956  *
1957  * @media must be prepared before this method returns a valid base_time.
1958  *
1959  * Returns: the base_time used by @media.
1960  */
1961 GstClockTime
1962 gst_rtsp_media_get_base_time (GstRTSPMedia * media)
1963 {
1964   GstClockTime result;
1965   GstRTSPMediaPrivate *priv;
1966
1967   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE);
1968
1969   priv = media->priv;
1970
1971   g_rec_mutex_lock (&priv->state_lock);
1972   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1973     goto not_prepared;
1974
1975   result = gst_element_get_base_time (media->priv->pipeline);
1976   g_rec_mutex_unlock (&priv->state_lock);
1977
1978   return result;
1979
1980   /* ERRORS */
1981 not_prepared:
1982   {
1983     g_rec_mutex_unlock (&priv->state_lock);
1984     GST_DEBUG_OBJECT (media, "media was not prepared");
1985     return GST_CLOCK_TIME_NONE;
1986   }
1987 }
1988
1989 /**
1990  * gst_rtsp_media_get_time_provider:
1991  * @media: a #GstRTSPMedia
1992  * @address: an address or NULL
1993  * @port: a port or 0
1994  *
1995  * Get the #GstNetTimeProvider for the clock used by @media. The time provider
1996  * will listen on @address and @port for client time requests.
1997  *
1998  * Returns: the #GstNetTimeProvider of @media.
1999  */
2000 GstNetTimeProvider *
2001 gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
2002     guint16 port)
2003 {
2004   GstRTSPMediaPrivate *priv;
2005   GstNetTimeProvider *provider = NULL;
2006
2007   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2008
2009   priv = media->priv;
2010
2011   g_rec_mutex_lock (&priv->state_lock);
2012   if (priv->time_provider) {
2013     if ((provider = priv->nettime) == NULL) {
2014       GstClock *clock;
2015
2016       if (priv->time_provider && (clock = get_clock_unlocked (media))) {
2017         provider = gst_net_time_provider_new (clock, address, port);
2018         gst_object_unref (clock);
2019
2020         priv->nettime = provider;
2021       }
2022     }
2023   }
2024   g_rec_mutex_unlock (&priv->state_lock);
2025
2026   if (provider)
2027     gst_object_ref (provider);
2028
2029   return provider;
2030 }
2031
2032 /**
2033  * gst_rtsp_media_set_state:
2034  * @media: a #GstRTSPMedia
2035  * @state: the target state of the media
2036  * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers
2037  *
2038  * Set the state of @media to @state and for the transports in @transports.
2039  *
2040  * @media must be prepared with gst_rtsp_media_prepare();
2041  *
2042  * Returns: %TRUE on success.
2043  */
2044 gboolean
2045 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
2046     GPtrArray * transports)
2047 {
2048   GstRTSPMediaPrivate *priv;
2049   gint i;
2050   gboolean activate, deactivate, do_state;
2051   gint old_active;
2052
2053   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2054   g_return_val_if_fail (transports != NULL, FALSE);
2055
2056   priv = media->priv;
2057
2058   g_rec_mutex_lock (&priv->state_lock);
2059   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2060     goto not_prepared;
2061
2062   /* NULL and READY are the same */
2063   if (state == GST_STATE_READY)
2064     state = GST_STATE_NULL;
2065
2066   activate = deactivate = FALSE;
2067
2068   GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
2069       media);
2070
2071   switch (state) {
2072     case GST_STATE_NULL:
2073     case GST_STATE_PAUSED:
2074       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
2075       if (priv->target_state == GST_STATE_PLAYING)
2076         deactivate = TRUE;
2077       break;
2078     case GST_STATE_PLAYING:
2079       /* we're going to PLAYING, activate */
2080       activate = TRUE;
2081       break;
2082     default:
2083       break;
2084   }
2085   old_active = priv->n_active;
2086
2087   for (i = 0; i < transports->len; i++) {
2088     GstRTSPStreamTransport *trans;
2089
2090     /* we need a non-NULL entry in the array */
2091     trans = g_ptr_array_index (transports, i);
2092     if (trans == NULL)
2093       continue;
2094
2095     if (activate) {
2096       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
2097         priv->n_active++;
2098     } else if (deactivate) {
2099       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
2100         priv->n_active--;
2101     }
2102   }
2103
2104   /* we just activated the first media, do the playing state change */
2105   if (old_active == 0 && activate)
2106     do_state = TRUE;
2107   /* if we have no more active media, do the downward state changes */
2108   else if (priv->n_active == 0)
2109     do_state = TRUE;
2110   else
2111     do_state = FALSE;
2112
2113   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
2114       media, do_state);
2115
2116   if (priv->target_state != state) {
2117     if (do_state) {
2118       if (state == GST_STATE_NULL) {
2119         gst_rtsp_media_unprepare (media);
2120       } else {
2121         GST_INFO ("state %s media %p", gst_element_state_get_name (state),
2122             media);
2123         priv->target_state = state;
2124         /* when we are buffering, don't update the state yet, this will be done
2125          * when buffering finishes */
2126         if (priv->buffering) {
2127           GST_INFO ("Buffering busy, delay state change");
2128         } else {
2129           gst_element_set_state (priv->pipeline, state);
2130         }
2131       }
2132     }
2133     g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2134         NULL);
2135   }
2136
2137   /* remember where we are */
2138   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
2139           old_active != priv->n_active))
2140     collect_media_stats (media);
2141
2142   g_rec_mutex_unlock (&priv->state_lock);
2143
2144   return TRUE;
2145
2146   /* ERRORS */
2147 not_prepared:
2148   {
2149     GST_WARNING ("media %p was not prepared", media);
2150     g_rec_mutex_unlock (&priv->state_lock);
2151     return FALSE;
2152   }
2153 }
2154
2155 /* called with state-lock */
2156 static gboolean
2157 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
2158     GstRTSPRangeUnit unit)
2159 {
2160   return gst_rtsp_range_convert_units (range, unit);
2161 }
2162
2163 static gboolean
2164 default_query_position (GstRTSPMedia * media, gint64 * position)
2165 {
2166   return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME,
2167       position);
2168 }
2169
2170 static gboolean
2171 default_query_stop (GstRTSPMedia * media, gint64 * stop)
2172 {
2173   GstQuery *query;
2174   gboolean res;
2175
2176   query = gst_query_new_segment (GST_FORMAT_TIME);
2177   if ((res = gst_element_query (media->priv->pipeline, query))) {
2178     GstFormat format;
2179     gst_query_parse_segment (query, NULL, &format, NULL, stop);
2180     if (format != GST_FORMAT_TIME)
2181       *stop = -1;
2182   }
2183   gst_query_unref (query);
2184   return res;
2185 }