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