Document locking and its order
[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  *
963  * Get the current range as a string. @media must be prepared with
964  * gst_rtsp_media_prepare ().
965  *
966  * Returns: The range as a string, g_free() after usage.
967  */
968 gchar *
969 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
970 {
971   GstRTSPMediaPrivate *priv;
972   gchar *result;
973   GstRTSPTimeRange range;
974
975   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
976
977   priv = media->priv;
978
979   g_rec_mutex_lock (&priv->state_lock);
980   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
981     goto not_prepared;
982
983   g_mutex_lock (&priv->lock);
984   /* make copy */
985   range = priv->range;
986
987   if (!play && priv->n_active > 0) {
988     range.min.type = GST_RTSP_TIME_NOW;
989     range.min.seconds = -1;
990   }
991   g_mutex_unlock (&priv->lock);
992   g_rec_mutex_unlock (&priv->state_lock);
993
994   result = gst_rtsp_range_to_string (&range);
995
996   return result;
997
998   /* ERRORS */
999 not_prepared:
1000   {
1001     GST_WARNING ("media %p was not prepared", media);
1002     g_rec_mutex_unlock (&priv->state_lock);
1003     return NULL;
1004   }
1005 }
1006
1007 /**
1008  * gst_rtsp_media_seek:
1009  * @media: a #GstRTSPMedia
1010  * @range: a #GstRTSPTimeRange
1011  *
1012  * Seek the pipeline of @media to @range. @media must be prepared with
1013  * gst_rtsp_media_prepare().
1014  *
1015  * Returns: %TRUE on success.
1016  */
1017 gboolean
1018 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
1019 {
1020   GstRTSPMediaPrivate *priv;
1021   GstSeekFlags flags;
1022   gboolean res;
1023   GstClockTime start, stop;
1024   GstSeekType start_type, stop_type;
1025
1026   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1027   g_return_val_if_fail (range != NULL, FALSE);
1028
1029   priv = media->priv;
1030
1031   g_rec_mutex_lock (&priv->state_lock);
1032   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1033     goto not_prepared;
1034
1035   if (!priv->seekable)
1036     goto not_seekable;
1037
1038   /* depends on the current playing state of the pipeline. We might need to
1039    * queue this until we get EOS. */
1040   flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
1041
1042   start_type = stop_type = GST_SEEK_TYPE_NONE;
1043
1044   if (!gst_rtsp_range_get_times (range, &start, &stop))
1045     goto not_supported;
1046
1047   GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1048       GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1049   GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1050       GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
1051
1052   if (priv->range_start == start)
1053     start = GST_CLOCK_TIME_NONE;
1054   else if (start != GST_CLOCK_TIME_NONE)
1055     start_type = GST_SEEK_TYPE_SET;
1056
1057   if (priv->range_stop == stop)
1058     stop = GST_CLOCK_TIME_NONE;
1059   else if (stop != GST_CLOCK_TIME_NONE)
1060     stop_type = GST_SEEK_TYPE_SET;
1061
1062   if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
1063     GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1064         GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1065
1066     res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
1067         flags, start_type, start, stop_type, stop);
1068
1069     /* and block for the seek to complete */
1070     GST_INFO ("done seeking %d", res);
1071     gst_element_get_state (priv->pipeline, NULL, NULL, -1);
1072     GST_INFO ("prerolled again");
1073
1074     collect_media_stats (media);
1075   } else {
1076     GST_INFO ("no seek needed");
1077     res = TRUE;
1078   }
1079   g_rec_mutex_unlock (&priv->state_lock);
1080
1081   return res;
1082
1083   /* ERRORS */
1084 not_prepared:
1085   {
1086     g_rec_mutex_unlock (&priv->state_lock);
1087     GST_INFO ("media %p is not prepared", media);
1088     return FALSE;
1089   }
1090 not_seekable:
1091   {
1092     g_rec_mutex_unlock (&priv->state_lock);
1093     GST_INFO ("pipeline is not seekable");
1094     return TRUE;
1095   }
1096 not_supported:
1097   {
1098     g_rec_mutex_unlock (&priv->state_lock);
1099     GST_WARNING ("seek unit %d not supported", range->unit);
1100     return FALSE;
1101   }
1102 }
1103
1104 static void
1105 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1106 {
1107   GstRTSPMediaPrivate *priv = media->priv;
1108
1109   g_mutex_lock (&priv->lock);
1110   priv->status = status;
1111   GST_DEBUG ("setting new status to %d", status);
1112   g_cond_broadcast (&priv->cond);
1113   g_mutex_unlock (&priv->lock);
1114 }
1115
1116 /**
1117  * gst_rtsp_media_get_status:
1118  * @media: a #GstRTSPMedia
1119  *
1120  * Get the status of @media. When @media is busy preparing, this function waits
1121  * until @media is prepared or in error.
1122  *
1123  * Returns: the status of @media.
1124  */
1125 GstRTSPMediaStatus
1126 gst_rtsp_media_get_status (GstRTSPMedia * media)
1127 {
1128   GstRTSPMediaPrivate *priv = media->priv;
1129   GstRTSPMediaStatus result;
1130   gint64 end_time;
1131
1132   g_mutex_lock (&priv->lock);
1133   end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
1134   /* while we are preparing, wait */
1135   while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1136     GST_DEBUG ("waiting for status change");
1137     if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
1138       GST_DEBUG ("timeout, assuming error status");
1139       priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
1140     }
1141   }
1142   /* could be success or error */
1143   result = priv->status;
1144   GST_DEBUG ("got status %d", result);
1145   g_mutex_unlock (&priv->lock);
1146
1147   return result;
1148 }
1149
1150 /* called with state-lock */
1151 static gboolean
1152 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1153 {
1154   GstRTSPMediaPrivate *priv = media->priv;
1155   GstMessageType type;
1156
1157   type = GST_MESSAGE_TYPE (message);
1158
1159   switch (type) {
1160     case GST_MESSAGE_STATE_CHANGED:
1161       break;
1162     case GST_MESSAGE_BUFFERING:
1163     {
1164       gint percent;
1165
1166       gst_message_parse_buffering (message, &percent);
1167
1168       /* no state management needed for live pipelines */
1169       if (priv->is_live)
1170         break;
1171
1172       if (percent == 100) {
1173         /* a 100% message means buffering is done */
1174         priv->buffering = FALSE;
1175         /* if the desired state is playing, go back */
1176         if (priv->target_state == GST_STATE_PLAYING) {
1177           GST_INFO ("Buffering done, setting pipeline to PLAYING");
1178           gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1179         } else {
1180           GST_INFO ("Buffering done");
1181         }
1182       } else {
1183         /* buffering busy */
1184         if (priv->buffering == FALSE) {
1185           if (priv->target_state == GST_STATE_PLAYING) {
1186             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
1187             GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1188             gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1189           } else {
1190             GST_INFO ("Buffering ...");
1191           }
1192         }
1193         priv->buffering = TRUE;
1194       }
1195       break;
1196     }
1197     case GST_MESSAGE_LATENCY:
1198     {
1199       gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
1200       break;
1201     }
1202     case GST_MESSAGE_ERROR:
1203     {
1204       GError *gerror;
1205       gchar *debug;
1206
1207       gst_message_parse_error (message, &gerror, &debug);
1208       GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1209       g_error_free (gerror);
1210       g_free (debug);
1211
1212       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1213       break;
1214     }
1215     case GST_MESSAGE_WARNING:
1216     {
1217       GError *gerror;
1218       gchar *debug;
1219
1220       gst_message_parse_warning (message, &gerror, &debug);
1221       GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1222       g_error_free (gerror);
1223       g_free (debug);
1224       break;
1225     }
1226     case GST_MESSAGE_ELEMENT:
1227       break;
1228     case GST_MESSAGE_STREAM_STATUS:
1229       break;
1230     case GST_MESSAGE_ASYNC_DONE:
1231       if (!priv->adding) {
1232         /* when we are dynamically adding pads, the addition of the udpsrc will
1233          * temporarily produce ASYNC_DONE messages. We have to ignore them and
1234          * wait for the final ASYNC_DONE after everything prerolled */
1235         GST_INFO ("%p: got ASYNC_DONE", media);
1236         collect_media_stats (media);
1237
1238         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1239           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1240       } else {
1241         GST_INFO ("%p: ignoring ASYNC_DONE", media);
1242       }
1243       break;
1244     case GST_MESSAGE_EOS:
1245       GST_INFO ("%p: got EOS", media);
1246
1247       if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1248         GST_DEBUG ("shutting down after EOS");
1249         finish_unprepare (media);
1250       }
1251       break;
1252     default:
1253       GST_INFO ("%p: got message type %d (%s)", media, type,
1254           gst_message_type_get_name (type));
1255       break;
1256   }
1257   return TRUE;
1258 }
1259
1260 static gboolean
1261 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1262 {
1263   GstRTSPMediaPrivate *priv = media->priv;
1264   GstRTSPMediaClass *klass;
1265   gboolean ret;
1266
1267   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1268
1269   g_rec_mutex_lock (&priv->state_lock);
1270   if (klass->handle_message)
1271     ret = klass->handle_message (media, message);
1272   else
1273     ret = FALSE;
1274   g_rec_mutex_unlock (&priv->state_lock);
1275
1276   return ret;
1277 }
1278
1279 static void
1280 watch_destroyed (GstRTSPMedia * media)
1281 {
1282   GST_DEBUG_OBJECT (media, "source destroyed");
1283   g_object_unref (media);
1284 }
1285
1286 /* called from streaming threads */
1287 static void
1288 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1289 {
1290   GstRTSPMediaPrivate *priv = media->priv;
1291   GstRTSPStream *stream;
1292
1293   /* FIXME, element is likely not a payloader, find the payloader here */
1294   stream = gst_rtsp_media_create_stream (media, element, pad);
1295
1296   GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1297
1298   g_rec_mutex_lock (&priv->state_lock);
1299   /* we will be adding elements below that will cause ASYNC_DONE to be
1300    * posted in the bus. We want to ignore those messages until the
1301    * pipeline really prerolled. */
1302   priv->adding = TRUE;
1303
1304   /* join the element in the PAUSED state because this callback is
1305    * called from the streaming thread and it is PAUSED */
1306   gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1307       priv->rtpbin, GST_STATE_PAUSED);
1308
1309   priv->adding = FALSE;
1310   g_rec_mutex_unlock (&priv->state_lock);
1311 }
1312
1313 static void
1314 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1315 {
1316   GstRTSPMediaPrivate *priv = media->priv;
1317   GstElement *fakesink;
1318
1319   g_mutex_lock (&priv->lock);
1320   GST_INFO ("no more pads");
1321   if ((fakesink = priv->fakesink)) {
1322     gst_object_ref (fakesink);
1323     priv->fakesink = NULL;
1324     g_mutex_unlock (&priv->lock);
1325
1326     gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
1327     gst_element_set_state (fakesink, GST_STATE_NULL);
1328     gst_object_unref (fakesink);
1329     GST_INFO ("removed fakesink");
1330   }
1331 }
1332
1333 /**
1334  * gst_rtsp_media_prepare:
1335  * @media: a #GstRTSPMedia
1336  *
1337  * Prepare @media for streaming. This function will create the pipeline and
1338  * other objects to manage the streaming.
1339  *
1340  * It will preroll the pipeline and collect vital information about the streams
1341  * such as the duration.
1342  *
1343  * Returns: %TRUE on success.
1344  */
1345 gboolean
1346 gst_rtsp_media_prepare (GstRTSPMedia * media)
1347 {
1348   GstRTSPMediaPrivate *priv;
1349   GstStateChangeReturn ret;
1350   GstRTSPMediaStatus status;
1351   guint i;
1352   GstRTSPMediaClass *klass;
1353   GstBus *bus;
1354   GList *walk;
1355
1356   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1357
1358   priv = media->priv;
1359
1360   g_rec_mutex_lock (&priv->state_lock);
1361   priv->prepare_count++;
1362
1363   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1364     goto was_prepared;
1365
1366   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1367     goto wait_status;
1368
1369   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
1370     goto not_unprepared;
1371
1372   if (!priv->reusable && priv->reused)
1373     goto is_reused;
1374
1375   priv->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1376   if (priv->rtpbin == NULL)
1377     goto no_rtpbin;
1378
1379   GST_INFO ("preparing media %p", media);
1380
1381   /* reset some variables */
1382   priv->is_live = FALSE;
1383   priv->seekable = FALSE;
1384   priv->buffering = FALSE;
1385   /* we're preparing now */
1386   priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1387
1388   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
1389
1390   /* add the pipeline bus to our custom mainloop */
1391   priv->source = gst_bus_create_watch (bus);
1392   gst_object_unref (bus);
1393
1394   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
1395       g_object_ref (media), (GDestroyNotify) watch_destroyed);
1396
1397   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1398   priv->id = g_source_attach (priv->source, klass->context);
1399
1400   /* add stuff to the bin */
1401   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
1402
1403   /* link streams we already have, other streams might appear when we have
1404    * dynamic elements */
1405   for (i = 0; i < priv->streams->len; i++) {
1406     GstRTSPStream *stream;
1407
1408     stream = g_ptr_array_index (priv->streams, i);
1409
1410     gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1411         priv->rtpbin, GST_STATE_NULL);
1412   }
1413
1414   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
1415     GstElement *elem = walk->data;
1416
1417     GST_INFO ("adding callbacks for dynamic element %p", elem);
1418
1419     g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1420     g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1421
1422     /* we add a fakesink here in order to make the state change async. We remove
1423      * the fakesink again in the no-more-pads callback. */
1424     priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1425     gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
1426   }
1427
1428   GST_INFO ("setting pipeline to PAUSED for media %p", media);
1429   /* first go to PAUSED */
1430   ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1431   priv->target_state = GST_STATE_PAUSED;
1432
1433   switch (ret) {
1434     case GST_STATE_CHANGE_SUCCESS:
1435       GST_INFO ("SUCCESS state change for media %p", media);
1436       priv->seekable = TRUE;
1437       break;
1438     case GST_STATE_CHANGE_ASYNC:
1439       GST_INFO ("ASYNC state change for media %p", media);
1440       priv->seekable = TRUE;
1441       break;
1442     case GST_STATE_CHANGE_NO_PREROLL:
1443       /* we need to go to PLAYING */
1444       GST_INFO ("NO_PREROLL state change: live media %p", media);
1445       /* FIXME we disable seeking for live streams for now. We should perform a
1446        * seeking query in preroll instead */
1447       priv->seekable = FALSE;
1448       priv->is_live = TRUE;
1449       ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1450       if (ret == GST_STATE_CHANGE_FAILURE)
1451         goto state_failed;
1452       break;
1453     case GST_STATE_CHANGE_FAILURE:
1454       goto state_failed;
1455   }
1456 wait_status:
1457   g_rec_mutex_unlock (&priv->state_lock);
1458
1459   /* now wait for all pads to be prerolled, FIXME, we should somehow be
1460    * able to do this async so that we don't block the server thread. */
1461   status = gst_rtsp_media_get_status (media);
1462   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1463     goto state_failed;
1464
1465   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1466
1467   GST_INFO ("object %p is prerolled", media);
1468
1469   return TRUE;
1470
1471   /* OK */
1472 was_prepared:
1473   {
1474     GST_LOG ("media %p was prepared", media);
1475     g_rec_mutex_unlock (&priv->state_lock);
1476     return TRUE;
1477   }
1478   /* ERRORS */
1479 not_unprepared:
1480   {
1481     GST_WARNING ("media %p was not unprepared", media);
1482     priv->prepare_count--;
1483     g_rec_mutex_unlock (&priv->state_lock);
1484     return FALSE;
1485   }
1486 is_reused:
1487   {
1488     priv->prepare_count--;
1489     g_rec_mutex_unlock (&priv->state_lock);
1490     GST_WARNING ("can not reuse media %p", media);
1491     return FALSE;
1492   }
1493 no_rtpbin:
1494   {
1495     priv->prepare_count--;
1496     g_rec_mutex_unlock (&priv->state_lock);
1497     GST_WARNING ("no rtpbin element");
1498     g_warning ("failed to create element 'rtpbin', check your installation");
1499     return FALSE;
1500   }
1501 state_failed:
1502   {
1503     GST_WARNING ("failed to preroll pipeline");
1504     gst_rtsp_media_unprepare (media);
1505     g_rec_mutex_unlock (&priv->state_lock);
1506     return FALSE;
1507   }
1508 }
1509
1510 /* must be called with state-lock */
1511 static void
1512 finish_unprepare (GstRTSPMedia * media)
1513 {
1514   GstRTSPMediaPrivate *priv = media->priv;
1515   gint i;
1516
1517   GST_DEBUG ("shutting down");
1518
1519   gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1520
1521   for (i = 0; i < priv->streams->len; i++) {
1522     GstRTSPStream *stream;
1523
1524     GST_INFO ("Removing elements of stream %d from pipeline", i);
1525
1526     stream = g_ptr_array_index (priv->streams, i);
1527
1528     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1529   }
1530   g_ptr_array_set_size (priv->streams, 0);
1531
1532   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
1533   priv->rtpbin = NULL;
1534
1535   gst_object_unref (priv->pipeline);
1536   priv->pipeline = NULL;
1537
1538   priv->reused = TRUE;
1539   priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1540
1541   /* when the media is not reusable, this will effectively unref the media and
1542    * recreate it */
1543   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1544
1545   /* the source has the last ref to the media */
1546   if (priv->source) {
1547     GST_DEBUG ("destroy source");
1548     g_source_destroy (priv->source);
1549     g_source_unref (priv->source);
1550   }
1551 }
1552
1553 /* called with state-lock */
1554 static gboolean
1555 default_unprepare (GstRTSPMedia * media)
1556 {
1557   GstRTSPMediaPrivate *priv = media->priv;
1558
1559   if (priv->eos_shutdown) {
1560     GST_DEBUG ("sending EOS for shutdown");
1561     /* ref so that we don't disappear */
1562     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
1563     /* we need to go to playing again for the EOS to propagate, normally in this
1564      * state, nothing is receiving data from us anymore so this is ok. */
1565     gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1566     priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1567   } else {
1568     finish_unprepare (media);
1569   }
1570   return TRUE;
1571 }
1572
1573 /**
1574  * gst_rtsp_media_unprepare:
1575  * @media: a #GstRTSPMedia
1576  *
1577  * Unprepare @media. After this call, the media should be prepared again before
1578  * it can be used again. If the media is set to be non-reusable, a new instance
1579  * must be created.
1580  *
1581  * Returns: %TRUE on success.
1582  */
1583 gboolean
1584 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1585 {
1586   GstRTSPMediaPrivate *priv;
1587   gboolean success;
1588
1589   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1590
1591   priv = media->priv;
1592
1593   g_rec_mutex_lock (&priv->state_lock);
1594   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1595     goto was_unprepared;
1596
1597   priv->prepare_count--;
1598   if (priv->prepare_count > 0)
1599     goto is_busy;
1600
1601   GST_INFO ("unprepare media %p", media);
1602   priv->target_state = GST_STATE_NULL;
1603   success = TRUE;
1604
1605   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1606     GstRTSPMediaClass *klass;
1607
1608     klass = GST_RTSP_MEDIA_GET_CLASS (media);
1609     if (klass->unprepare)
1610       success = klass->unprepare (media);
1611   } else {
1612     finish_unprepare (media);
1613   }
1614   g_rec_mutex_unlock (&priv->state_lock);
1615
1616   return success;
1617
1618 was_unprepared:
1619   {
1620     g_rec_mutex_unlock (&priv->state_lock);
1621     GST_INFO ("media %p was already unprepared", media);
1622     return TRUE;
1623   }
1624 is_busy:
1625   {
1626     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
1627     g_rec_mutex_unlock (&priv->state_lock);
1628     return TRUE;
1629   }
1630 }
1631
1632 /**
1633  * gst_rtsp_media_set_state:
1634  * @media: a #GstRTSPMedia
1635  * @state: the target state of the media
1636  * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers
1637  *
1638  * Set the state of @media to @state and for the transports in @transports.
1639  *
1640  * @media must be prepared with gst_rtsp_media_prepare();
1641  *
1642  * Returns: %TRUE on success.
1643  */
1644 gboolean
1645 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1646     GPtrArray * transports)
1647 {
1648   GstRTSPMediaPrivate *priv;
1649   gint i;
1650   gboolean activate, deactivate, do_state;
1651   gint old_active;
1652
1653   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1654   g_return_val_if_fail (transports != NULL, FALSE);
1655
1656   priv = media->priv;
1657
1658   g_rec_mutex_lock (&priv->state_lock);
1659   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1660     goto not_prepared;
1661
1662   /* NULL and READY are the same */
1663   if (state == GST_STATE_READY)
1664     state = GST_STATE_NULL;
1665
1666   activate = deactivate = FALSE;
1667
1668   GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1669       media);
1670
1671   switch (state) {
1672     case GST_STATE_NULL:
1673     case GST_STATE_PAUSED:
1674       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
1675       if (priv->target_state == GST_STATE_PLAYING)
1676         deactivate = TRUE;
1677       break;
1678     case GST_STATE_PLAYING:
1679       /* we're going to PLAYING, activate */
1680       activate = TRUE;
1681       break;
1682     default:
1683       break;
1684   }
1685   old_active = priv->n_active;
1686
1687   for (i = 0; i < transports->len; i++) {
1688     GstRTSPStreamTransport *trans;
1689
1690     /* we need a non-NULL entry in the array */
1691     trans = g_ptr_array_index (transports, i);
1692     if (trans == NULL)
1693       continue;
1694
1695     if (activate) {
1696       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
1697         priv->n_active++;
1698     } else if (deactivate) {
1699       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
1700         priv->n_active--;
1701     }
1702   }
1703
1704   /* we just activated the first media, do the playing state change */
1705   if (old_active == 0 && activate)
1706     do_state = TRUE;
1707   /* if we have no more active media, do the downward state changes */
1708   else if (priv->n_active == 0)
1709     do_state = TRUE;
1710   else
1711     do_state = FALSE;
1712
1713   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
1714       media, do_state);
1715
1716   if (priv->target_state != state) {
1717     if (do_state) {
1718       if (state == GST_STATE_NULL) {
1719         gst_rtsp_media_unprepare (media);
1720       } else {
1721         GST_INFO ("state %s media %p", gst_element_state_get_name (state),
1722             media);
1723         priv->target_state = state;
1724         gst_element_set_state (priv->pipeline, state);
1725       }
1726     }
1727     g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
1728         NULL);
1729   }
1730
1731   /* remember where we are */
1732   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
1733           old_active != priv->n_active))
1734     collect_media_stats (media);
1735
1736   g_rec_mutex_unlock (&priv->state_lock);
1737
1738   return TRUE;
1739
1740   /* ERRORS */
1741 not_prepared:
1742   {
1743     GST_WARNING ("media %p was not prepared", media);
1744     g_rec_mutex_unlock (&priv->state_lock);
1745     return FALSE;
1746   }
1747 }