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