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