client: Add drop-backlog property
[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  * SECTION:rtsp-media
21  * @short_description: The media pipeline
22  * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession,
23  *     #GstRTSPSessionMedia
24  *
25  * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the
26  * streaming to the clients. The actual data transfer is done by the
27  * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
28  *
29  * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the
30  * client does a DESCRIBE or SETUP of a resource.
31  *
32  * A media is created with gst_rtsp_media_new() that takes the element that will
33  * provide the streaming elements. For each of the streams, a new #GstRTSPStream
34  * object needs to be made with the gst_rtsp_media_create_stream() which takes
35  * the payloader element and the source pad that produces the RTP stream.
36  *
37  * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The
38  * prepare method will add rtpbin and sinks and sources to send and receive RTP
39  * and RTCP packets from the clients. Each stream srcpad is connected to an
40  * input into the internal rtpbin.
41  *
42  * It is also possible to dynamically create #GstRTSPStream objects during the
43  * prepare phase. With gst_rtsp_media_get_status() you can check the status of
44  * the prepare phase.
45  *
46  * After the media is prepared, it is ready for streaming. It will usually be
47  * managed in a session with gst_rtsp_session_manage_media(). See
48  * #GstRTSPSession and #GstRTSPSessionMedia.
49  *
50  * The state of the media can be controlled with gst_rtsp_media_set_state ().
51  * Seeking can be done with gst_rtsp_media_seek().
52  *
53  * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
54  * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
55  * cleanly shut down.
56  *
57  * With gst_rtsp_media_set_shared(), the media can be shared between multiple
58  * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline
59  * can be prepared again after an unprepare.
60  *
61  * Last reviewed on 2013-07-11 (1.0.0)
62  */
63
64 #include <string.h>
65 #include <stdlib.h>
66
67 #include <gst/app/gstappsrc.h>
68 #include <gst/app/gstappsink.h>
69
70 #include "rtsp-media.h"
71
72 #define GST_RTSP_MEDIA_GET_PRIVATE(obj)  \
73      (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate))
74
75 struct _GstRTSPMediaPrivate
76 {
77   GMutex lock;
78   GCond cond;
79
80   /* protected by lock */
81   GstRTSPPermissions *permissions;
82   gboolean shared;
83   gboolean suspend_mode;
84   gboolean reusable;
85   GstRTSPProfile profiles;
86   GstRTSPLowerTrans protocols;
87   gboolean reused;
88   gboolean eos_shutdown;
89   guint buffer_size;
90   GstRTSPAddressPool *pool;
91   gboolean blocked;
92
93   GstElement *element;
94   GRecMutex state_lock;         /* locking order: state lock, lock */
95   GPtrArray *streams;           /* protected by lock */
96   GList *dynamic;               /* protected by lock */
97   GstRTSPMediaStatus status;    /* protected by lock */
98   gint prepare_count;
99   gint n_active;
100   gboolean adding;
101
102   /* the pipeline for the media */
103   GstElement *pipeline;
104   GstElement *fakesink;         /* protected by lock */
105   GSource *source;
106   guint id;
107   GstRTSPThread *thread;
108
109   gboolean time_provider;
110   GstNetTimeProvider *nettime;
111
112   gboolean is_live;
113   gboolean seekable;
114   gboolean buffering;
115   GstState target_state;
116
117   /* RTP session manager */
118   GstElement *rtpbin;
119
120   /* the range of media */
121   GstRTSPTimeRange range;       /* protected by lock */
122   GstClockTime range_start;
123   GstClockTime range_stop;
124 };
125
126 #define DEFAULT_SHARED          FALSE
127 #define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
128 #define DEFAULT_REUSABLE        FALSE
129 #define DEFAULT_PROFILES        GST_RTSP_PROFILE_AVP
130 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
131                                         GST_RTSP_LOWER_TRANS_TCP
132 #define DEFAULT_EOS_SHUTDOWN    FALSE
133 #define DEFAULT_BUFFER_SIZE     0x80000
134 #define DEFAULT_TIME_PROVIDER   FALSE
135
136 /* define to dump received RTCP packets */
137 #undef DUMP_STATS
138
139 enum
140 {
141   PROP_0,
142   PROP_SHARED,
143   PROP_SUSPEND_MODE,
144   PROP_REUSABLE,
145   PROP_PROFILES,
146   PROP_PROTOCOLS,
147   PROP_EOS_SHUTDOWN,
148   PROP_BUFFER_SIZE,
149   PROP_ELEMENT,
150   PROP_TIME_PROVIDER,
151   PROP_LAST
152 };
153
154 enum
155 {
156   SIGNAL_NEW_STREAM,
157   SIGNAL_REMOVED_STREAM,
158   SIGNAL_PREPARED,
159   SIGNAL_UNPREPARED,
160   SIGNAL_TARGET_STATE,
161   SIGNAL_NEW_STATE,
162   SIGNAL_LAST
163 };
164
165 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
166 #define GST_CAT_DEFAULT rtsp_media_debug
167
168 static void gst_rtsp_media_get_property (GObject * object, guint propid,
169     GValue * value, GParamSpec * pspec);
170 static void gst_rtsp_media_set_property (GObject * object, guint propid,
171     const GValue * value, GParamSpec * pspec);
172 static void gst_rtsp_media_finalize (GObject * obj);
173
174 static gboolean default_handle_message (GstRTSPMedia * media,
175     GstMessage * message);
176 static void finish_unprepare (GstRTSPMedia * media);
177 static gboolean default_unprepare (GstRTSPMedia * media);
178 static gboolean default_convert_range (GstRTSPMedia * media,
179     GstRTSPTimeRange * range, GstRTSPRangeUnit unit);
180 static gboolean default_query_position (GstRTSPMedia * media,
181     gint64 * position);
182 static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop);
183 static GstElement *default_create_rtpbin (GstRTSPMedia * media);
184 static gboolean default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
185     GstSDPInfo * info);
186
187 static gboolean wait_preroll (GstRTSPMedia * media);
188
189 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
190
191 #define C_ENUM(v) ((gint) v)
192
193 #define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type())
194 GType
195 gst_rtsp_suspend_mode_get_type (void)
196 {
197   static gsize id = 0;
198   static const GEnumValue values[] = {
199     {C_ENUM (GST_RTSP_SUSPEND_MODE_NONE), "GST_RTSP_SUSPEND_MODE_NONE", "none"},
200     {C_ENUM (GST_RTSP_SUSPEND_MODE_PAUSE), "GST_RTSP_SUSPEND_MODE_PAUSE",
201         "pause"},
202     {C_ENUM (GST_RTSP_SUSPEND_MODE_RESET), "GST_RTSP_SUSPEND_MODE_RESET",
203         "reset"},
204     {0, NULL, NULL}
205   };
206
207   if (g_once_init_enter (&id)) {
208     GType tmp = g_enum_register_static ("GstRTSPSuspendMode", values);
209     g_once_init_leave (&id, tmp);
210   }
211   return (GType) id;
212 }
213
214 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
215
216 static void
217 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
218 {
219   GObjectClass *gobject_class;
220
221   g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate));
222
223   gobject_class = G_OBJECT_CLASS (klass);
224
225   gobject_class->get_property = gst_rtsp_media_get_property;
226   gobject_class->set_property = gst_rtsp_media_set_property;
227   gobject_class->finalize = gst_rtsp_media_finalize;
228
229   g_object_class_install_property (gobject_class, PROP_SHARED,
230       g_param_spec_boolean ("shared", "Shared",
231           "If this media pipeline can be shared", DEFAULT_SHARED,
232           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
233
234   g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
235       g_param_spec_enum ("suspend-mode", "Suspend Mode",
236           "How to suspend the media in PAUSED", GST_TYPE_RTSP_SUSPEND_MODE,
237           DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
238
239   g_object_class_install_property (gobject_class, PROP_REUSABLE,
240       g_param_spec_boolean ("reusable", "Reusable",
241           "If this media pipeline can be reused after an unprepare",
242           DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243
244   g_object_class_install_property (gobject_class, PROP_PROFILES,
245       g_param_spec_flags ("profiles", "Profiles",
246           "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE,
247           DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
248
249   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
250       g_param_spec_flags ("protocols", "Protocols",
251           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
252           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253
254   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
255       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
256           "Send an EOS event to the pipeline before unpreparing",
257           DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
258
259   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
260       g_param_spec_uint ("buffer-size", "Buffer Size",
261           "The kernel UDP buffer size to use", 0, G_MAXUINT,
262           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
263
264   g_object_class_install_property (gobject_class, PROP_ELEMENT,
265       g_param_spec_object ("element", "The Element",
266           "The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
267           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
268
269   g_object_class_install_property (gobject_class, PROP_TIME_PROVIDER,
270       g_param_spec_boolean ("time-provider", "Time Provider",
271           "Use a NetTimeProvider for clients",
272           DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
273
274   gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
275       g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
276       G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
277       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM);
278
279   gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM] =
280       g_signal_new ("removed-stream", G_TYPE_FROM_CLASS (klass),
281       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, removed_stream),
282       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
283       GST_TYPE_RTSP_STREAM);
284
285   gst_rtsp_media_signals[SIGNAL_PREPARED] =
286       g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
287       G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
288       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
289
290   gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
291       g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
292       G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
293       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
294
295   gst_rtsp_media_signals[SIGNAL_TARGET_STATE] =
296       g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass),
297       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL,
298       NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
299
300   gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
301       g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
302       G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
303       g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
304
305   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
306
307   klass->handle_message = default_handle_message;
308   klass->unprepare = default_unprepare;
309   klass->convert_range = default_convert_range;
310   klass->query_position = default_query_position;
311   klass->query_stop = default_query_stop;
312   klass->create_rtpbin = default_create_rtpbin;
313   klass->setup_sdp = default_setup_sdp;
314 }
315
316 static void
317 gst_rtsp_media_init (GstRTSPMedia * media)
318 {
319   GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media);
320
321   media->priv = priv;
322
323   priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
324   g_mutex_init (&priv->lock);
325   g_cond_init (&priv->cond);
326   g_rec_mutex_init (&priv->state_lock);
327
328   priv->shared = DEFAULT_SHARED;
329   priv->suspend_mode = DEFAULT_SUSPEND_MODE;
330   priv->reusable = DEFAULT_REUSABLE;
331   priv->profiles = DEFAULT_PROFILES;
332   priv->protocols = DEFAULT_PROTOCOLS;
333   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
334   priv->buffer_size = DEFAULT_BUFFER_SIZE;
335   priv->time_provider = DEFAULT_TIME_PROVIDER;
336 }
337
338 static void
339 gst_rtsp_media_finalize (GObject * obj)
340 {
341   GstRTSPMediaPrivate *priv;
342   GstRTSPMedia *media;
343
344   media = GST_RTSP_MEDIA (obj);
345   priv = media->priv;
346
347   GST_INFO ("finalize media %p", media);
348
349   if (priv->permissions)
350     gst_rtsp_permissions_unref (priv->permissions);
351
352   g_ptr_array_unref (priv->streams);
353
354   g_list_free_full (priv->dynamic, gst_object_unref);
355
356   if (priv->pipeline)
357     gst_object_unref (priv->pipeline);
358   if (priv->nettime)
359     gst_object_unref (priv->nettime);
360   gst_object_unref (priv->element);
361   if (priv->pool)
362     g_object_unref (priv->pool);
363   g_mutex_clear (&priv->lock);
364   g_cond_clear (&priv->cond);
365   g_rec_mutex_clear (&priv->state_lock);
366
367   G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
368 }
369
370 static void
371 gst_rtsp_media_get_property (GObject * object, guint propid,
372     GValue * value, GParamSpec * pspec)
373 {
374   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
375
376   switch (propid) {
377     case PROP_ELEMENT:
378       g_value_set_object (value, media->priv->element);
379       break;
380     case PROP_SHARED:
381       g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
382       break;
383     case PROP_SUSPEND_MODE:
384       g_value_set_enum (value, gst_rtsp_media_get_suspend_mode (media));
385       break;
386     case PROP_REUSABLE:
387       g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
388       break;
389     case PROP_PROFILES:
390       g_value_set_flags (value, gst_rtsp_media_get_profiles (media));
391       break;
392     case PROP_PROTOCOLS:
393       g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
394       break;
395     case PROP_EOS_SHUTDOWN:
396       g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
397       break;
398     case PROP_BUFFER_SIZE:
399       g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
400       break;
401     case PROP_TIME_PROVIDER:
402       g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media));
403       break;
404     default:
405       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
406   }
407 }
408
409 static void
410 gst_rtsp_media_set_property (GObject * object, guint propid,
411     const GValue * value, GParamSpec * pspec)
412 {
413   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
414
415   switch (propid) {
416     case PROP_ELEMENT:
417       media->priv->element = g_value_get_object (value);
418       gst_object_ref_sink (media->priv->element);
419       break;
420     case PROP_SHARED:
421       gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
422       break;
423     case PROP_SUSPEND_MODE:
424       gst_rtsp_media_set_suspend_mode (media, g_value_get_enum (value));
425       break;
426     case PROP_REUSABLE:
427       gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
428       break;
429     case PROP_PROFILES:
430       gst_rtsp_media_set_profiles (media, g_value_get_flags (value));
431       break;
432     case PROP_PROTOCOLS:
433       gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
434       break;
435     case PROP_EOS_SHUTDOWN:
436       gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
437       break;
438     case PROP_BUFFER_SIZE:
439       gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
440       break;
441     case PROP_TIME_PROVIDER:
442       gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value));
443       break;
444     default:
445       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
446   }
447 }
448
449 static gboolean
450 default_query_position (GstRTSPMedia * media, gint64 * position)
451 {
452   return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME,
453       position);
454 }
455
456 static gboolean
457 default_query_stop (GstRTSPMedia * media, gint64 * stop)
458 {
459   GstQuery *query;
460   gboolean res;
461
462   query = gst_query_new_segment (GST_FORMAT_TIME);
463   if ((res = gst_element_query (media->priv->pipeline, query))) {
464     GstFormat format;
465     gst_query_parse_segment (query, NULL, &format, NULL, stop);
466     if (format != GST_FORMAT_TIME)
467       *stop = -1;
468   }
469   gst_query_unref (query);
470   return res;
471 }
472
473 static GstElement *
474 default_create_rtpbin (GstRTSPMedia * media)
475 {
476   GstElement *rtpbin;
477
478   rtpbin = gst_element_factory_make ("rtpbin", NULL);
479
480   return rtpbin;
481 }
482
483 /* must be called with state lock */
484 static void
485 collect_media_stats (GstRTSPMedia * media)
486 {
487   GstRTSPMediaPrivate *priv = media->priv;
488   gint64 position, stop;
489
490   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
491       priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
492     return;
493
494   priv->range.unit = GST_RTSP_RANGE_NPT;
495
496   GST_INFO ("collect media stats");
497
498   if (priv->is_live) {
499     priv->range.min.type = GST_RTSP_TIME_NOW;
500     priv->range.min.seconds = -1;
501     priv->range_start = -1;
502     priv->range.max.type = GST_RTSP_TIME_END;
503     priv->range.max.seconds = -1;
504     priv->range_stop = -1;
505   } else {
506     GstRTSPMediaClass *klass;
507     gboolean ret;
508
509     klass = GST_RTSP_MEDIA_GET_CLASS (media);
510
511     /* get the position */
512     ret = FALSE;
513     if (klass->query_position)
514       ret = klass->query_position (media, &position);
515
516     if (!ret) {
517       GST_INFO ("position query failed");
518       position = 0;
519     }
520
521     /* get the current segment stop */
522     ret = FALSE;
523     if (klass->query_stop)
524       ret = klass->query_stop (media, &stop);
525
526     if (!ret) {
527       GST_INFO ("stop query failed");
528       stop = -1;
529     }
530
531     GST_INFO ("stats: position %" GST_TIME_FORMAT ", stop %"
532         GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (stop));
533
534     if (position == -1) {
535       priv->range.min.type = GST_RTSP_TIME_NOW;
536       priv->range.min.seconds = -1;
537       priv->range_start = -1;
538     } else {
539       priv->range.min.type = GST_RTSP_TIME_SECONDS;
540       priv->range.min.seconds = ((gdouble) position) / GST_SECOND;
541       priv->range_start = position;
542     }
543     if (stop == -1) {
544       priv->range.max.type = GST_RTSP_TIME_END;
545       priv->range.max.seconds = -1;
546       priv->range_stop = -1;
547     } else {
548       priv->range.max.type = GST_RTSP_TIME_SECONDS;
549       priv->range.max.seconds = ((gdouble) stop) / GST_SECOND;
550       priv->range_stop = stop;
551     }
552   }
553 }
554
555 /**
556  * gst_rtsp_media_new:
557  * @element: (transfer full): a #GstElement
558  *
559  * Create a new #GstRTSPMedia instance. @element is the bin element that
560  * provides the different streams. The #GstRTSPMedia object contains the
561  * element to produce RTP data for one or more related (audio/video/..)
562  * streams.
563  *
564  * Ownership is taken of @element.
565  *
566  * Returns: (transfer full): a new #GstRTSPMedia object.
567  */
568 GstRTSPMedia *
569 gst_rtsp_media_new (GstElement * element)
570 {
571   GstRTSPMedia *result;
572
573   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
574
575   result = g_object_new (GST_TYPE_RTSP_MEDIA, "element", element, NULL);
576
577   return result;
578 }
579
580 /**
581  * gst_rtsp_media_get_element:
582  * @media: a #GstRTSPMedia
583  *
584  * Get the element that was used when constructing @media.
585  *
586  * Returns: (transfer full): a #GstElement. Unref after usage.
587  */
588 GstElement *
589 gst_rtsp_media_get_element (GstRTSPMedia * media)
590 {
591   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
592
593   return gst_object_ref (media->priv->element);
594 }
595
596 /**
597  * gst_rtsp_media_take_pipeline:
598  * @media: a #GstRTSPMedia
599  * @pipeline: (transfer full): a #GstPipeline
600  *
601  * Set @pipeline as the #GstPipeline for @media. Ownership is
602  * taken of @pipeline.
603  */
604 void
605 gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
606 {
607   GstRTSPMediaPrivate *priv;
608   GstElement *old;
609   GstNetTimeProvider *nettime;
610
611   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
612   g_return_if_fail (GST_IS_PIPELINE (pipeline));
613
614   priv = media->priv;
615
616   g_mutex_lock (&priv->lock);
617   old = priv->pipeline;
618   priv->pipeline = GST_ELEMENT_CAST (pipeline);
619   nettime = priv->nettime;
620   priv->nettime = NULL;
621   g_mutex_unlock (&priv->lock);
622
623   if (old)
624     gst_object_unref (old);
625
626   if (nettime)
627     gst_object_unref (nettime);
628
629   gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
630 }
631
632 /**
633  * gst_rtsp_media_set_permissions:
634  * @media: a #GstRTSPMedia
635  * @permissions: (transfer none): a #GstRTSPPermissions
636  *
637  * Set @permissions on @media.
638  */
639 void
640 gst_rtsp_media_set_permissions (GstRTSPMedia * media,
641     GstRTSPPermissions * permissions)
642 {
643   GstRTSPMediaPrivate *priv;
644
645   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
646
647   priv = media->priv;
648
649   g_mutex_lock (&priv->lock);
650   if (priv->permissions)
651     gst_rtsp_permissions_unref (priv->permissions);
652   if ((priv->permissions = permissions))
653     gst_rtsp_permissions_ref (permissions);
654   g_mutex_unlock (&priv->lock);
655 }
656
657 /**
658  * gst_rtsp_media_get_permissions:
659  * @media: a #GstRTSPMedia
660  *
661  * Get the permissions object from @media.
662  *
663  * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage.
664  */
665 GstRTSPPermissions *
666 gst_rtsp_media_get_permissions (GstRTSPMedia * media)
667 {
668   GstRTSPMediaPrivate *priv;
669   GstRTSPPermissions *result;
670
671   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
672
673   priv = media->priv;
674
675   g_mutex_lock (&priv->lock);
676   if ((result = priv->permissions))
677     gst_rtsp_permissions_ref (result);
678   g_mutex_unlock (&priv->lock);
679
680   return result;
681 }
682
683 /**
684  * gst_rtsp_media_set_suspend_mode:
685  * @media: a #GstRTSPMedia
686  * @mode: the new #GstRTSPSuspendMode
687  *
688  * Control how @ media will be suspended after the SDP has been generated and
689  * after a PAUSE request has been performed.
690  *
691  * Media must be unprepared when setting the suspend mode.
692  */
693 void
694 gst_rtsp_media_set_suspend_mode (GstRTSPMedia * media, GstRTSPSuspendMode mode)
695 {
696   GstRTSPMediaPrivate *priv;
697
698   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
699
700   priv = media->priv;
701
702   g_rec_mutex_lock (&priv->state_lock);
703   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
704     goto was_prepared;
705   priv->suspend_mode = mode;
706   g_rec_mutex_unlock (&priv->state_lock);
707
708   return;
709
710   /* ERRORS */
711 was_prepared:
712   {
713     GST_WARNING ("media %p was prepared", media);
714     g_rec_mutex_unlock (&priv->state_lock);
715   }
716 }
717
718 /**
719  * gst_rtsp_media_get_suspend_mode:
720  * @media: a #GstRTSPMedia
721  *
722  * Get how @media will be suspended.
723  *
724  * Returns: #GstRTSPSuspendMode.
725  */
726 GstRTSPSuspendMode
727 gst_rtsp_media_get_suspend_mode (GstRTSPMedia * media)
728 {
729   GstRTSPMediaPrivate *priv;
730   GstRTSPSuspendMode res;
731
732   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_SUSPEND_MODE_NONE);
733
734   priv = media->priv;
735
736   g_rec_mutex_lock (&priv->state_lock);
737   res = priv->suspend_mode;
738   g_rec_mutex_unlock (&priv->state_lock);
739
740   return res;
741 }
742
743 /**
744  * gst_rtsp_media_set_shared:
745  * @media: a #GstRTSPMedia
746  * @shared: the new value
747  *
748  * Set or unset if the pipeline for @media can be shared will multiple clients.
749  * When @shared is %TRUE, client requests for this media will share the media
750  * pipeline.
751  */
752 void
753 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
754 {
755   GstRTSPMediaPrivate *priv;
756
757   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
758
759   priv = media->priv;
760
761   g_mutex_lock (&priv->lock);
762   priv->shared = shared;
763   g_mutex_unlock (&priv->lock);
764 }
765
766 /**
767  * gst_rtsp_media_is_shared:
768  * @media: a #GstRTSPMedia
769  *
770  * Check if the pipeline for @media can be shared between multiple clients.
771  *
772  * Returns: %TRUE if the media can be shared between clients.
773  */
774 gboolean
775 gst_rtsp_media_is_shared (GstRTSPMedia * media)
776 {
777   GstRTSPMediaPrivate *priv;
778   gboolean res;
779
780   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
781
782   priv = media->priv;
783
784   g_mutex_lock (&priv->lock);
785   res = priv->shared;
786   g_mutex_unlock (&priv->lock);
787
788   return res;
789 }
790
791 /**
792  * gst_rtsp_media_set_reusable:
793  * @media: a #GstRTSPMedia
794  * @reusable: the new value
795  *
796  * Set or unset if the pipeline for @media can be reused after the pipeline has
797  * been unprepared.
798  */
799 void
800 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
801 {
802   GstRTSPMediaPrivate *priv;
803
804   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
805
806   priv = media->priv;
807
808   g_mutex_lock (&priv->lock);
809   priv->reusable = reusable;
810   g_mutex_unlock (&priv->lock);
811 }
812
813 /**
814  * gst_rtsp_media_is_reusable:
815  * @media: a #GstRTSPMedia
816  *
817  * Check if the pipeline for @media can be reused after an unprepare.
818  *
819  * Returns: %TRUE if the media can be reused
820  */
821 gboolean
822 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
823 {
824   GstRTSPMediaPrivate *priv;
825   gboolean res;
826
827   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
828
829   priv = media->priv;
830
831   g_mutex_lock (&priv->lock);
832   res = priv->reusable;
833   g_mutex_unlock (&priv->lock);
834
835   return res;
836 }
837
838 static void
839 do_set_profiles (GstRTSPStream * stream, GstRTSPProfile * profiles)
840 {
841   gst_rtsp_stream_set_profiles (stream, *profiles);
842 }
843
844 /**
845  * gst_rtsp_media_set_profiles:
846  * @media: a #GstRTSPMedia
847  * @profiles: the new flags
848  *
849  * Configure the allowed lower transport for @media.
850  */
851 void
852 gst_rtsp_media_set_profiles (GstRTSPMedia * media, GstRTSPProfile profiles)
853 {
854   GstRTSPMediaPrivate *priv;
855
856   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
857
858   priv = media->priv;
859
860   g_mutex_lock (&priv->lock);
861   priv->profiles = profiles;
862   g_ptr_array_foreach (priv->streams, (GFunc) do_set_profiles, &profiles);
863   g_mutex_unlock (&priv->lock);
864 }
865
866 /**
867  * gst_rtsp_media_get_profiles:
868  * @media: a #GstRTSPMedia
869  *
870  * Get the allowed profiles of @media.
871  *
872  * Returns: a #GstRTSPProfile
873  */
874 GstRTSPProfile
875 gst_rtsp_media_get_profiles (GstRTSPMedia * media)
876 {
877   GstRTSPMediaPrivate *priv;
878   GstRTSPProfile res;
879
880   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_PROFILE_UNKNOWN);
881
882   priv = media->priv;
883
884   g_mutex_lock (&priv->lock);
885   res = priv->profiles;
886   g_mutex_unlock (&priv->lock);
887
888   return res;
889 }
890
891 static void
892 do_set_protocols (GstRTSPStream * stream, GstRTSPLowerTrans * protocols)
893 {
894   gst_rtsp_stream_set_protocols (stream, *protocols);
895 }
896
897 /**
898  * gst_rtsp_media_set_protocols:
899  * @media: a #GstRTSPMedia
900  * @protocols: the new flags
901  *
902  * Configure the allowed lower transport for @media.
903  */
904 void
905 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
906 {
907   GstRTSPMediaPrivate *priv;
908
909   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
910
911   priv = media->priv;
912
913   g_mutex_lock (&priv->lock);
914   priv->protocols = protocols;
915   g_ptr_array_foreach (priv->streams, (GFunc) do_set_protocols, &protocols);
916   g_mutex_unlock (&priv->lock);
917 }
918
919 /**
920  * gst_rtsp_media_get_protocols:
921  * @media: a #GstRTSPMedia
922  *
923  * Get the allowed protocols of @media.
924  *
925  * Returns: a #GstRTSPLowerTrans
926  */
927 GstRTSPLowerTrans
928 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
929 {
930   GstRTSPMediaPrivate *priv;
931   GstRTSPLowerTrans res;
932
933   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
934       GST_RTSP_LOWER_TRANS_UNKNOWN);
935
936   priv = media->priv;
937
938   g_mutex_lock (&priv->lock);
939   res = priv->protocols;
940   g_mutex_unlock (&priv->lock);
941
942   return res;
943 }
944
945 /**
946  * gst_rtsp_media_set_eos_shutdown:
947  * @media: a #GstRTSPMedia
948  * @eos_shutdown: the new value
949  *
950  * Set or unset if an EOS event will be sent to the pipeline for @media before
951  * it is unprepared.
952  */
953 void
954 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
955 {
956   GstRTSPMediaPrivate *priv;
957
958   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
959
960   priv = media->priv;
961
962   g_mutex_lock (&priv->lock);
963   priv->eos_shutdown = eos_shutdown;
964   g_mutex_unlock (&priv->lock);
965 }
966
967 /**
968  * gst_rtsp_media_is_eos_shutdown:
969  * @media: a #GstRTSPMedia
970  *
971  * Check if the pipeline for @media will send an EOS down the pipeline before
972  * unpreparing.
973  *
974  * Returns: %TRUE if the media will send EOS before unpreparing.
975  */
976 gboolean
977 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
978 {
979   GstRTSPMediaPrivate *priv;
980   gboolean res;
981
982   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
983
984   priv = media->priv;
985
986   g_mutex_lock (&priv->lock);
987   res = priv->eos_shutdown;
988   g_mutex_unlock (&priv->lock);
989
990   return res;
991 }
992
993 /**
994  * gst_rtsp_media_set_buffer_size:
995  * @media: a #GstRTSPMedia
996  * @size: the new value
997  *
998  * Set the kernel UDP buffer size.
999  */
1000 void
1001 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
1002 {
1003   GstRTSPMediaPrivate *priv;
1004
1005   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1006
1007   GST_LOG_OBJECT (media, "set buffer size %u", size);
1008
1009   priv = media->priv;
1010
1011   g_mutex_lock (&priv->lock);
1012   priv->buffer_size = size;
1013   g_mutex_unlock (&priv->lock);
1014 }
1015
1016 /**
1017  * gst_rtsp_media_get_buffer_size:
1018  * @media: a #GstRTSPMedia
1019  *
1020  * Get the kernel UDP buffer size.
1021  *
1022  * Returns: the kernel UDP buffer size.
1023  */
1024 guint
1025 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
1026 {
1027   GstRTSPMediaPrivate *priv;
1028   guint res;
1029
1030   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1031
1032   priv = media->priv;
1033
1034   g_mutex_unlock (&priv->lock);
1035   res = priv->buffer_size;
1036   g_mutex_unlock (&priv->lock);
1037
1038   return res;
1039 }
1040
1041 /**
1042  * gst_rtsp_media_use_time_provider:
1043  * @media: a #GstRTSPMedia
1044  * @time_provider: if a #GstNetTimeProvider should be used
1045  *
1046  * Set @media to provide a #GstNetTimeProvider.
1047  */
1048 void
1049 gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider)
1050 {
1051   GstRTSPMediaPrivate *priv;
1052
1053   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1054
1055   priv = media->priv;
1056
1057   g_mutex_lock (&priv->lock);
1058   priv->time_provider = time_provider;
1059   g_mutex_unlock (&priv->lock);
1060 }
1061
1062 /**
1063  * gst_rtsp_media_is_time_provider:
1064  * @media: a #GstRTSPMedia
1065  *
1066  * Check if @media can provide a #GstNetTimeProvider for its pipeline clock.
1067  *
1068  * Use gst_rtsp_media_get_time_provider() to get the network clock.
1069  *
1070  * Returns: %TRUE if @media can provide a #GstNetTimeProvider.
1071  */
1072 gboolean
1073 gst_rtsp_media_is_time_provider (GstRTSPMedia * media)
1074 {
1075   GstRTSPMediaPrivate *priv;
1076   gboolean res;
1077
1078   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1079
1080   priv = media->priv;
1081
1082   g_mutex_unlock (&priv->lock);
1083   res = priv->time_provider;
1084   g_mutex_unlock (&priv->lock);
1085
1086   return res;
1087 }
1088
1089 /**
1090  * gst_rtsp_media_set_address_pool:
1091  * @media: a #GstRTSPMedia
1092  * @pool: (transfer none): a #GstRTSPAddressPool
1093  *
1094  * configure @pool to be used as the address pool of @media.
1095  */
1096 void
1097 gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
1098     GstRTSPAddressPool * pool)
1099 {
1100   GstRTSPMediaPrivate *priv;
1101   GstRTSPAddressPool *old;
1102
1103   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1104
1105   priv = media->priv;
1106
1107   GST_LOG_OBJECT (media, "set address pool %p", pool);
1108
1109   g_mutex_lock (&priv->lock);
1110   if ((old = priv->pool) != pool)
1111     priv->pool = pool ? g_object_ref (pool) : NULL;
1112   else
1113     old = NULL;
1114   g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool,
1115       pool);
1116   g_mutex_unlock (&priv->lock);
1117
1118   if (old)
1119     g_object_unref (old);
1120 }
1121
1122 /**
1123  * gst_rtsp_media_get_address_pool:
1124  * @media: a #GstRTSPMedia
1125  *
1126  * Get the #GstRTSPAddressPool used as the address pool of @media.
1127  *
1128  * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after
1129  * usage.
1130  */
1131 GstRTSPAddressPool *
1132 gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
1133 {
1134   GstRTSPMediaPrivate *priv;
1135   GstRTSPAddressPool *result;
1136
1137   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1138
1139   priv = media->priv;
1140
1141   g_mutex_lock (&priv->lock);
1142   if ((result = priv->pool))
1143     g_object_ref (result);
1144   g_mutex_unlock (&priv->lock);
1145
1146   return result;
1147 }
1148
1149 /**
1150  * gst_rtsp_media_collect_streams:
1151  * @media: a #GstRTSPMedia
1152  *
1153  * Find all payloader elements, they should be named pay\%d in the
1154  * element of @media, and create #GstRTSPStreams for them.
1155  *
1156  * Collect all dynamic elements, named dynpay\%d, and add them to
1157  * the list of dynamic elements.
1158  */
1159 void
1160 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
1161 {
1162   GstRTSPMediaPrivate *priv;
1163   GstElement *element, *elem;
1164   GstPad *pad;
1165   gint i;
1166   gboolean have_elem;
1167
1168   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1169
1170   priv = media->priv;
1171   element = priv->element;
1172
1173   have_elem = TRUE;
1174   for (i = 0; have_elem; i++) {
1175     gchar *name;
1176
1177     have_elem = FALSE;
1178
1179     name = g_strdup_printf ("pay%d", i);
1180     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
1181       GST_INFO ("found stream %d with payloader %p", i, elem);
1182
1183       /* take the pad of the payloader */
1184       pad = gst_element_get_static_pad (elem, "src");
1185       /* create the stream */
1186       gst_rtsp_media_create_stream (media, elem, pad);
1187       gst_object_unref (pad);
1188       gst_object_unref (elem);
1189
1190       have_elem = TRUE;
1191     }
1192     g_free (name);
1193
1194     name = g_strdup_printf ("dynpay%d", i);
1195     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
1196       /* a stream that will dynamically create pads to provide RTP packets */
1197       GST_INFO ("found dynamic element %d, %p", i, elem);
1198
1199       g_mutex_lock (&priv->lock);
1200       priv->dynamic = g_list_prepend (priv->dynamic, elem);
1201       g_mutex_unlock (&priv->lock);
1202
1203       have_elem = TRUE;
1204     }
1205     g_free (name);
1206   }
1207 }
1208
1209 /**
1210  * gst_rtsp_media_create_stream:
1211  * @media: a #GstRTSPMedia
1212  * @payloader: a #GstElement
1213  * @srcpad: a source #GstPad
1214  *
1215  * Create a new stream in @media that provides RTP data on @srcpad.
1216  * @srcpad should be a pad of an element inside @media->element.
1217  *
1218  * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
1219  * as @media exists.
1220  */
1221 GstRTSPStream *
1222 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
1223     GstPad * pad)
1224 {
1225   GstRTSPMediaPrivate *priv;
1226   GstRTSPStream *stream;
1227   GstPad *srcpad;
1228   gchar *name;
1229   gint idx;
1230
1231   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1232   g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
1233   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1234   g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
1235
1236   priv = media->priv;
1237
1238   g_mutex_lock (&priv->lock);
1239   idx = priv->streams->len;
1240
1241   GST_DEBUG ("media %p: creating stream with index %d", media, idx);
1242
1243   name = g_strdup_printf ("src_%u", idx);
1244   srcpad = gst_ghost_pad_new (name, pad);
1245   gst_pad_set_active (srcpad, TRUE);
1246   gst_element_add_pad (priv->element, srcpad);
1247   g_free (name);
1248
1249   stream = gst_rtsp_stream_new (idx, payloader, srcpad);
1250   if (priv->pool)
1251     gst_rtsp_stream_set_address_pool (stream, priv->pool);
1252   gst_rtsp_stream_set_profiles (stream, priv->profiles);
1253   gst_rtsp_stream_set_protocols (stream, priv->protocols);
1254
1255   g_ptr_array_add (priv->streams, stream);
1256   g_mutex_unlock (&priv->lock);
1257
1258   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
1259       NULL);
1260
1261   return stream;
1262 }
1263
1264 static void
1265 gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream)
1266 {
1267   GstRTSPMediaPrivate *priv;
1268   GstPad *srcpad;
1269
1270   priv = media->priv;
1271
1272   g_mutex_lock (&priv->lock);
1273   /* remove the ghostpad */
1274   srcpad = gst_rtsp_stream_get_srcpad (stream);
1275   gst_element_remove_pad (priv->element, srcpad);
1276   gst_object_unref (srcpad);
1277   /* now remove the stream */
1278   g_object_ref (stream);
1279   g_ptr_array_remove (priv->streams, stream);
1280   g_mutex_unlock (&priv->lock);
1281
1282   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM], 0,
1283       stream, NULL);
1284
1285   g_object_unref (stream);
1286 }
1287
1288 /**
1289  * gst_rtsp_media_n_streams:
1290  * @media: a #GstRTSPMedia
1291  *
1292  * Get the number of streams in this media.
1293  *
1294  * Returns: The number of streams.
1295  */
1296 guint
1297 gst_rtsp_media_n_streams (GstRTSPMedia * media)
1298 {
1299   GstRTSPMediaPrivate *priv;
1300   guint res;
1301
1302   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
1303
1304   priv = media->priv;
1305
1306   g_mutex_lock (&priv->lock);
1307   res = priv->streams->len;
1308   g_mutex_unlock (&priv->lock);
1309
1310   return res;
1311 }
1312
1313 /**
1314  * gst_rtsp_media_get_stream:
1315  * @media: a #GstRTSPMedia
1316  * @idx: the stream index
1317  *
1318  * Retrieve the stream with index @idx from @media.
1319  *
1320  * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with
1321  * that index did not exist.
1322  */
1323 GstRTSPStream *
1324 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
1325 {
1326   GstRTSPMediaPrivate *priv;
1327   GstRTSPStream *res;
1328
1329   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1330
1331   priv = media->priv;
1332
1333   g_mutex_lock (&priv->lock);
1334   if (idx < priv->streams->len)
1335     res = g_ptr_array_index (priv->streams, idx);
1336   else
1337     res = NULL;
1338   g_mutex_unlock (&priv->lock);
1339
1340   return res;
1341 }
1342
1343 /**
1344  * gst_rtsp_media_find_stream:
1345  * @media: a #GstRTSPMedia
1346  * @control: the control of the stream
1347  *
1348  * Find a stream in @media with @control as the control uri.
1349  *
1350  * Returns: (transfer none): the #GstRTSPStream with control uri @control
1351  * or %NULL when a stream with that control did not exist.
1352  */
1353 GstRTSPStream *
1354 gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control)
1355 {
1356   GstRTSPMediaPrivate *priv;
1357   GstRTSPStream *res;
1358   gint i;
1359
1360   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1361   g_return_val_if_fail (control != NULL, NULL);
1362
1363   priv = media->priv;
1364
1365   res = NULL;
1366
1367   g_mutex_lock (&priv->lock);
1368   for (i = 0; i < priv->streams->len; i++) {
1369     GstRTSPStream *test;
1370
1371     test = g_ptr_array_index (priv->streams, i);
1372     if (gst_rtsp_stream_has_control (test, control)) {
1373       res = test;
1374       break;
1375     }
1376   }
1377   g_mutex_unlock (&priv->lock);
1378
1379   return res;
1380 }
1381
1382 /* called with state-lock */
1383 static gboolean
1384 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
1385     GstRTSPRangeUnit unit)
1386 {
1387   return gst_rtsp_range_convert_units (range, unit);
1388 }
1389
1390 /**
1391  * gst_rtsp_media_get_range_string:
1392  * @media: a #GstRTSPMedia
1393  * @play: for the PLAY request
1394  * @unit: the unit to use for the string
1395  *
1396  * Get the current range as a string. @media must be prepared with
1397  * gst_rtsp_media_prepare ().
1398  *
1399  * Returns: (transfer full): The range as a string, g_free() after usage.
1400  */
1401 gchar *
1402 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play,
1403     GstRTSPRangeUnit unit)
1404 {
1405   GstRTSPMediaClass *klass;
1406   GstRTSPMediaPrivate *priv;
1407   gchar *result;
1408   GstRTSPTimeRange range;
1409
1410   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1411   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1412   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1413
1414   priv = media->priv;
1415
1416   g_rec_mutex_lock (&priv->state_lock);
1417   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
1418       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
1419     goto not_prepared;
1420
1421   g_mutex_lock (&priv->lock);
1422
1423   /* Update the range value with current position/duration */
1424   collect_media_stats (media);
1425
1426   /* make copy */
1427   range = priv->range;
1428
1429   if (!play && priv->n_active > 0) {
1430     range.min.type = GST_RTSP_TIME_NOW;
1431     range.min.seconds = -1;
1432   }
1433   g_mutex_unlock (&priv->lock);
1434   g_rec_mutex_unlock (&priv->state_lock);
1435
1436   if (!klass->convert_range (media, &range, unit))
1437     goto conversion_failed;
1438
1439   result = gst_rtsp_range_to_string (&range);
1440
1441   return result;
1442
1443   /* ERRORS */
1444 not_prepared:
1445   {
1446     GST_WARNING ("media %p was not prepared", media);
1447     g_rec_mutex_unlock (&priv->state_lock);
1448     return NULL;
1449   }
1450 conversion_failed:
1451   {
1452     GST_WARNING ("range conversion to unit %d failed", unit);
1453     return NULL;
1454   }
1455 }
1456
1457 static void
1458 stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
1459 {
1460   gst_rtsp_stream_set_blocked (stream, media->priv->blocked);
1461 }
1462
1463 static void
1464 media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked)
1465 {
1466   GstRTSPMediaPrivate *priv = media->priv;
1467
1468   GST_DEBUG ("media %p set blocked %d", media, blocked);
1469   priv->blocked = blocked;
1470   g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media);
1471 }
1472
1473 static void
1474 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1475 {
1476   GstRTSPMediaPrivate *priv = media->priv;
1477
1478   g_mutex_lock (&priv->lock);
1479   priv->status = status;
1480   GST_DEBUG ("setting new status to %d", status);
1481   g_cond_broadcast (&priv->cond);
1482   g_mutex_unlock (&priv->lock);
1483 }
1484
1485 /**
1486  * gst_rtsp_media_get_status:
1487  * @media: a #GstRTSPMedia
1488  *
1489  * Get the status of @media. When @media is busy preparing, this function waits
1490  * until @media is prepared or in error.
1491  *
1492  * Returns: the status of @media.
1493  */
1494 GstRTSPMediaStatus
1495 gst_rtsp_media_get_status (GstRTSPMedia * media)
1496 {
1497   GstRTSPMediaPrivate *priv = media->priv;
1498   GstRTSPMediaStatus result;
1499   gint64 end_time;
1500
1501   g_mutex_lock (&priv->lock);
1502   end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
1503   /* while we are preparing, wait */
1504   while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1505     GST_DEBUG ("waiting for status change");
1506     if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
1507       GST_DEBUG ("timeout, assuming error status");
1508       priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
1509     }
1510   }
1511   /* could be success or error */
1512   result = priv->status;
1513   GST_DEBUG ("got status %d", result);
1514   g_mutex_unlock (&priv->lock);
1515
1516   return result;
1517 }
1518
1519 /**
1520  * gst_rtsp_media_seek:
1521  * @media: a #GstRTSPMedia
1522  * @range: (transfer none): a #GstRTSPTimeRange
1523  *
1524  * Seek the pipeline of @media to @range. @media must be prepared with
1525  * gst_rtsp_media_prepare().
1526  *
1527  * Returns: %TRUE on success.
1528  */
1529 gboolean
1530 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
1531 {
1532   GstRTSPMediaClass *klass;
1533   GstRTSPMediaPrivate *priv;
1534   gboolean res;
1535   GstClockTime start, stop;
1536   GstSeekType start_type, stop_type;
1537   GstQuery *query;
1538
1539   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1540
1541   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1542   g_return_val_if_fail (range != NULL, FALSE);
1543   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1544
1545   priv = media->priv;
1546
1547   g_rec_mutex_lock (&priv->state_lock);
1548   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1549     goto not_prepared;
1550
1551   /* Update the seekable state of the pipeline in case it changed */
1552   query = gst_query_new_seeking (GST_FORMAT_TIME);
1553   if (gst_element_query (priv->pipeline, query)) {
1554     GstFormat format;
1555     gboolean seekable;
1556     gint64 start, end;
1557
1558     gst_query_parse_seeking (query, &format, &seekable, &start, &end);
1559     priv->seekable = seekable;
1560   }
1561   gst_query_unref (query);
1562
1563   if (!priv->seekable)
1564     goto not_seekable;
1565
1566   start_type = stop_type = GST_SEEK_TYPE_NONE;
1567
1568   if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
1569     goto not_supported;
1570   gst_rtsp_range_get_times (range, &start, &stop);
1571
1572   GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1573       GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1574   GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1575       GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
1576
1577   if (start != GST_CLOCK_TIME_NONE)
1578     start_type = GST_SEEK_TYPE_SET;
1579
1580   if (priv->range_stop == stop)
1581     stop = GST_CLOCK_TIME_NONE;
1582   else if (stop != GST_CLOCK_TIME_NONE)
1583     stop_type = GST_SEEK_TYPE_SET;
1584
1585   if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
1586     GstSeekFlags flags;
1587
1588     GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1589         GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1590
1591     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
1592     if (priv->blocked)
1593       media_streams_set_blocked (media, TRUE);
1594
1595     /* depends on the current playing state of the pipeline. We might need to
1596      * queue this until we get EOS. */
1597     flags = GST_SEEK_FLAG_FLUSH;
1598
1599     /* if range start was not supplied we must continue from current position.
1600      * but since we're doing a flushing seek, let us query the current position
1601      * so we end up at exactly the same position after the seek. */
1602     if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */
1603       gint64 position;
1604       gboolean ret = FALSE;
1605
1606       if (klass->query_position)
1607         ret = klass->query_position (media, &position);
1608
1609       if (!ret) {
1610         GST_WARNING ("position query failed");
1611       } else {
1612         GST_DEBUG ("doing accurate seek to %" GST_TIME_FORMAT,
1613             GST_TIME_ARGS (position));
1614         start = position;
1615         start_type = GST_SEEK_TYPE_SET;
1616         flags |= GST_SEEK_FLAG_ACCURATE;
1617       }
1618     } else {
1619       /* only set keyframe flag when modifying start */
1620       if (start_type != GST_SEEK_TYPE_NONE)
1621         flags |= GST_SEEK_FLAG_KEY_UNIT;
1622     }
1623
1624     /* FIXME, we only do forwards */
1625     res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
1626         flags, start_type, start, stop_type, stop);
1627
1628     /* and block for the seek to complete */
1629     GST_INFO ("done seeking %d", res);
1630     g_rec_mutex_unlock (&priv->state_lock);
1631
1632     /* wait until pipeline is prerolled again, this will also collect stats */
1633     if (!wait_preroll (media))
1634       goto preroll_failed;
1635
1636     g_rec_mutex_lock (&priv->state_lock);
1637     GST_INFO ("prerolled again");
1638   } else {
1639     GST_INFO ("no seek needed");
1640     res = TRUE;
1641   }
1642   g_rec_mutex_unlock (&priv->state_lock);
1643
1644   return res;
1645
1646   /* ERRORS */
1647 not_prepared:
1648   {
1649     g_rec_mutex_unlock (&priv->state_lock);
1650     GST_INFO ("media %p is not prepared", media);
1651     return FALSE;
1652   }
1653 not_seekable:
1654   {
1655     g_rec_mutex_unlock (&priv->state_lock);
1656     GST_INFO ("pipeline is not seekable");
1657     return FALSE;
1658   }
1659 not_supported:
1660   {
1661     g_rec_mutex_unlock (&priv->state_lock);
1662     GST_WARNING ("conversion to npt not supported");
1663     return FALSE;
1664   }
1665 preroll_failed:
1666   {
1667     GST_WARNING ("failed to preroll after seek");
1668     return FALSE;
1669   }
1670 }
1671
1672 static void
1673 stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
1674 {
1675   *blocked &= gst_rtsp_stream_is_blocking (stream);
1676 }
1677
1678 static gboolean
1679 media_streams_blocking (GstRTSPMedia * media)
1680 {
1681   gboolean blocking = TRUE;
1682
1683   g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_blocking,
1684       &blocking);
1685
1686   return blocking;
1687 }
1688
1689 static GstStateChangeReturn
1690 set_state (GstRTSPMedia * media, GstState state)
1691 {
1692   GstRTSPMediaPrivate *priv = media->priv;
1693   GstStateChangeReturn ret;
1694
1695   GST_INFO ("set state to %s for media %p", gst_element_state_get_name (state),
1696       media);
1697   ret = gst_element_set_state (priv->pipeline, state);
1698
1699   return ret;
1700 }
1701
1702 static GstStateChangeReturn
1703 set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
1704 {
1705   GstRTSPMediaPrivate *priv = media->priv;
1706   GstStateChangeReturn ret;
1707
1708   GST_INFO ("set target state to %s for media %p",
1709       gst_element_state_get_name (state), media);
1710   priv->target_state = state;
1711
1712   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0,
1713       priv->target_state, NULL);
1714
1715   if (do_state)
1716     ret = set_state (media, state);
1717   else
1718     ret = GST_STATE_CHANGE_SUCCESS;
1719
1720   return ret;
1721 }
1722
1723 /* called with state-lock */
1724 static gboolean
1725 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1726 {
1727   GstRTSPMediaPrivate *priv = media->priv;
1728   GstMessageType type;
1729
1730   type = GST_MESSAGE_TYPE (message);
1731
1732   switch (type) {
1733     case GST_MESSAGE_STATE_CHANGED:
1734       break;
1735     case GST_MESSAGE_BUFFERING:
1736     {
1737       gint percent;
1738
1739       gst_message_parse_buffering (message, &percent);
1740
1741       /* no state management needed for live pipelines */
1742       if (priv->is_live)
1743         break;
1744
1745       if (percent == 100) {
1746         /* a 100% message means buffering is done */
1747         priv->buffering = FALSE;
1748         /* if the desired state is playing, go back */
1749         if (priv->target_state == GST_STATE_PLAYING) {
1750           GST_INFO ("Buffering done, setting pipeline to PLAYING");
1751           set_state (media, GST_STATE_PLAYING);
1752         } else {
1753           GST_INFO ("Buffering done");
1754         }
1755       } else {
1756         /* buffering busy */
1757         if (priv->buffering == FALSE) {
1758           if (priv->target_state == GST_STATE_PLAYING) {
1759             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
1760             GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1761             set_state (media, GST_STATE_PAUSED);
1762           } else {
1763             GST_INFO ("Buffering ...");
1764           }
1765         }
1766         priv->buffering = TRUE;
1767       }
1768       break;
1769     }
1770     case GST_MESSAGE_LATENCY:
1771     {
1772       gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
1773       break;
1774     }
1775     case GST_MESSAGE_ERROR:
1776     {
1777       GError *gerror;
1778       gchar *debug;
1779
1780       gst_message_parse_error (message, &gerror, &debug);
1781       GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1782       g_error_free (gerror);
1783       g_free (debug);
1784
1785       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1786       break;
1787     }
1788     case GST_MESSAGE_WARNING:
1789     {
1790       GError *gerror;
1791       gchar *debug;
1792
1793       gst_message_parse_warning (message, &gerror, &debug);
1794       GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1795       g_error_free (gerror);
1796       g_free (debug);
1797       break;
1798     }
1799     case GST_MESSAGE_ELEMENT:
1800     {
1801       const GstStructure *s;
1802
1803       s = gst_message_get_structure (message);
1804       if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) {
1805         GST_DEBUG ("media received blocking message");
1806         if (priv->blocked && media_streams_blocking (media)) {
1807           GST_DEBUG ("media is blocking");
1808           collect_media_stats (media);
1809
1810           if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1811             gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1812         }
1813       }
1814       break;
1815     }
1816     case GST_MESSAGE_STREAM_STATUS:
1817       break;
1818     case GST_MESSAGE_ASYNC_DONE:
1819       if (priv->adding) {
1820         /* when we are dynamically adding pads, the addition of the udpsrc will
1821          * temporarily produce ASYNC_DONE messages. We have to ignore them and
1822          * wait for the final ASYNC_DONE after everything prerolled */
1823         GST_INFO ("%p: ignoring ASYNC_DONE", media);
1824       } else {
1825         GST_INFO ("%p: got ASYNC_DONE", media);
1826         collect_media_stats (media);
1827
1828         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1829           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1830       }
1831       break;
1832     case GST_MESSAGE_EOS:
1833       GST_INFO ("%p: got EOS", media);
1834
1835       if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1836         GST_DEBUG ("shutting down after EOS");
1837         finish_unprepare (media);
1838       }
1839       break;
1840     default:
1841       GST_INFO ("%p: got message type %d (%s)", media, type,
1842           gst_message_type_get_name (type));
1843       break;
1844   }
1845   return TRUE;
1846 }
1847
1848 static gboolean
1849 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1850 {
1851   GstRTSPMediaPrivate *priv = media->priv;
1852   GstRTSPMediaClass *klass;
1853   gboolean ret;
1854
1855   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1856
1857   g_rec_mutex_lock (&priv->state_lock);
1858   if (klass->handle_message)
1859     ret = klass->handle_message (media, message);
1860   else
1861     ret = FALSE;
1862   g_rec_mutex_unlock (&priv->state_lock);
1863
1864   return ret;
1865 }
1866
1867 static void
1868 watch_destroyed (GstRTSPMedia * media)
1869 {
1870   GST_DEBUG_OBJECT (media, "source destroyed");
1871   g_object_unref (media);
1872 }
1873
1874 static GstElement *
1875 find_payload_element (GstElement * payloader)
1876 {
1877   GstElement *pay = NULL;
1878
1879   if (GST_IS_BIN (payloader)) {
1880     GstIterator *iter;
1881     GValue item = { 0 };
1882
1883     iter = gst_bin_iterate_recurse (GST_BIN (payloader));
1884     while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) {
1885       GstElement *element = (GstElement *) g_value_get_object (&item);
1886       GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element);
1887       const gchar *klass;
1888
1889       klass =
1890           gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS);
1891       if (klass == NULL)
1892         continue;
1893
1894       if (strstr (klass, "Payloader") && strstr (klass, "RTP")) {
1895         pay = gst_object_ref (element);
1896         g_value_unset (&item);
1897         break;
1898       }
1899       g_value_unset (&item);
1900     }
1901     gst_iterator_free (iter);
1902   } else {
1903     pay = g_object_ref (payloader);
1904   }
1905
1906   return pay;
1907 }
1908
1909 /* called from streaming threads */
1910 static void
1911 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1912 {
1913   GstRTSPMediaPrivate *priv = media->priv;
1914   GstRTSPStream *stream;
1915   GstElement *pay;
1916
1917   /* find the real payload element */
1918   pay = find_payload_element (element);
1919   stream = gst_rtsp_media_create_stream (media, pay, pad);
1920   gst_object_unref (pay);
1921
1922   GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1923
1924   g_rec_mutex_lock (&priv->state_lock);
1925   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
1926     goto not_preparing;
1927
1928   g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream);
1929
1930   /* we will be adding elements below that will cause ASYNC_DONE to be
1931    * posted in the bus. We want to ignore those messages until the
1932    * pipeline really prerolled. */
1933   priv->adding = TRUE;
1934
1935   /* join the element in the PAUSED state because this callback is
1936    * called from the streaming thread and it is PAUSED */
1937   if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1938           priv->rtpbin, GST_STATE_PAUSED)) {
1939     GST_WARNING ("failed to join bin element");
1940   }
1941
1942   priv->adding = FALSE;
1943   g_rec_mutex_unlock (&priv->state_lock);
1944
1945   return;
1946
1947   /* ERRORS */
1948 not_preparing:
1949   {
1950     gst_rtsp_media_remove_stream (media, stream);
1951     g_rec_mutex_unlock (&priv->state_lock);
1952     GST_INFO ("ignore pad because we are not preparing");
1953     return;
1954   }
1955 }
1956
1957 static void
1958 pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1959 {
1960   GstRTSPMediaPrivate *priv = media->priv;
1961   GstRTSPStream *stream;
1962
1963   stream = g_object_get_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream");
1964   if (stream == NULL)
1965     return;
1966
1967   GST_INFO ("pad removed %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1968
1969   g_rec_mutex_lock (&priv->state_lock);
1970   gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1971   g_rec_mutex_unlock (&priv->state_lock);
1972
1973   gst_rtsp_media_remove_stream (media, stream);
1974 }
1975
1976 static void
1977 remove_fakesink (GstRTSPMediaPrivate * priv)
1978 {
1979   GstElement *fakesink;
1980
1981   g_mutex_lock (&priv->lock);
1982   if ((fakesink = priv->fakesink))
1983     gst_object_ref (fakesink);
1984   priv->fakesink = NULL;
1985   g_mutex_unlock (&priv->lock);
1986
1987   if (fakesink) {
1988     gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
1989     gst_element_set_state (fakesink, GST_STATE_NULL);
1990     gst_object_unref (fakesink);
1991     GST_INFO ("removed fakesink");
1992   }
1993 }
1994
1995 static void
1996 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1997 {
1998   GstRTSPMediaPrivate *priv = media->priv;
1999
2000   GST_INFO ("no more pads");
2001   remove_fakesink (priv);
2002 }
2003
2004 typedef struct _DynPaySignalHandlers DynPaySignalHandlers;
2005
2006 struct _DynPaySignalHandlers
2007 {
2008   gulong pad_added_handler;
2009   gulong pad_removed_handler;
2010   gulong no_more_pads_handler;
2011 };
2012
2013 static gboolean
2014 start_preroll (GstRTSPMedia * media)
2015 {
2016   GstRTSPMediaPrivate *priv = media->priv;
2017   GstStateChangeReturn ret;
2018
2019   GST_INFO ("setting pipeline to PAUSED for media %p", media);
2020   /* first go to PAUSED */
2021   ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
2022
2023   switch (ret) {
2024     case GST_STATE_CHANGE_SUCCESS:
2025       GST_INFO ("SUCCESS state change for media %p", media);
2026       priv->seekable = TRUE;
2027       break;
2028     case GST_STATE_CHANGE_ASYNC:
2029       GST_INFO ("ASYNC state change for media %p", media);
2030       priv->seekable = TRUE;
2031       break;
2032     case GST_STATE_CHANGE_NO_PREROLL:
2033       /* we need to go to PLAYING */
2034       GST_INFO ("NO_PREROLL state change: live media %p", media);
2035       /* FIXME we disable seeking for live streams for now. We should perform a
2036        * seeking query in preroll instead */
2037       priv->seekable = FALSE;
2038       priv->is_live = TRUE;
2039       /* start blocked  to make sure nothing goes to the sink */
2040       media_streams_set_blocked (media, TRUE);
2041       ret = set_state (media, GST_STATE_PLAYING);
2042       if (ret == GST_STATE_CHANGE_FAILURE)
2043         goto state_failed;
2044       break;
2045     case GST_STATE_CHANGE_FAILURE:
2046       goto state_failed;
2047   }
2048
2049   return TRUE;
2050
2051 state_failed:
2052   {
2053     GST_WARNING ("failed to preroll pipeline");
2054     return FALSE;
2055   }
2056 }
2057
2058 static gboolean
2059 wait_preroll (GstRTSPMedia * media)
2060 {
2061   GstRTSPMediaStatus status;
2062
2063   GST_DEBUG ("wait to preroll pipeline");
2064
2065   /* wait until pipeline is prerolled */
2066   status = gst_rtsp_media_get_status (media);
2067   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
2068     goto preroll_failed;
2069
2070   return TRUE;
2071
2072 preroll_failed:
2073   {
2074     GST_WARNING ("failed to preroll pipeline");
2075     return FALSE;
2076   }
2077 }
2078
2079 static gboolean
2080 start_prepare (GstRTSPMedia * media)
2081 {
2082   GstRTSPMediaPrivate *priv = media->priv;
2083   guint i;
2084   GList *walk;
2085
2086   /* link streams we already have, other streams might appear when we have
2087    * dynamic elements */
2088   for (i = 0; i < priv->streams->len; i++) {
2089     GstRTSPStream *stream;
2090
2091     stream = g_ptr_array_index (priv->streams, i);
2092
2093     if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
2094             priv->rtpbin, GST_STATE_NULL)) {
2095       goto join_bin_failed;
2096     }
2097   }
2098
2099   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
2100     GstElement *elem = walk->data;
2101     DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
2102
2103     GST_INFO ("adding callbacks for dynamic element %p", elem);
2104
2105     handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
2106         (GCallback) pad_added_cb, media);
2107     handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
2108         (GCallback) pad_removed_cb, media);
2109     handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
2110         (GCallback) no_more_pads_cb, media);
2111
2112     g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
2113
2114     /* we add a fakesink here in order to make the state change async. We remove
2115      * the fakesink again in the no-more-pads callback. */
2116     priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
2117     gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
2118   }
2119
2120   if (!start_preroll (media))
2121     goto preroll_failed;
2122
2123   return FALSE;
2124
2125 join_bin_failed:
2126   {
2127     GST_WARNING ("failed to join bin element");
2128     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2129     return FALSE;
2130   }
2131 preroll_failed:
2132   {
2133     GST_WARNING ("failed to preroll pipeline");
2134     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2135     return FALSE;
2136   }
2137 }
2138
2139 /**
2140  * gst_rtsp_media_prepare:
2141  * @media: a #GstRTSPMedia
2142  * @thread: (transfer full): a #GstRTSPThread to run the bus handler or %NULL
2143  *
2144  * Prepare @media for streaming. This function will create the objects
2145  * to manage the streaming. A pipeline must have been set on @media with
2146  * gst_rtsp_media_take_pipeline().
2147  *
2148  * It will preroll the pipeline and collect vital information about the streams
2149  * such as the duration.
2150  *
2151  * Returns: %TRUE on success.
2152  */
2153 gboolean
2154 gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
2155 {
2156   GstRTSPMediaPrivate *priv;
2157   GstBus *bus;
2158   GSource *source;
2159   GstRTSPMediaClass *klass;
2160
2161   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2162   g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE);
2163
2164   priv = media->priv;
2165
2166   g_rec_mutex_lock (&priv->state_lock);
2167   priv->prepare_count++;
2168
2169   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED ||
2170       priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED)
2171     goto was_prepared;
2172
2173   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
2174     goto wait_status;
2175
2176   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
2177     goto not_unprepared;
2178
2179   if (!priv->reusable && priv->reused)
2180     goto is_reused;
2181
2182   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2183
2184   if (!klass->create_rtpbin)
2185     goto no_create_rtpbin;
2186
2187   priv->rtpbin = klass->create_rtpbin (media);
2188   if (priv->rtpbin != NULL) {
2189     gboolean success = TRUE;
2190
2191     if (klass->setup_rtpbin)
2192       success = klass->setup_rtpbin (media, priv->rtpbin);
2193
2194     if (success == FALSE) {
2195       gst_object_unref (priv->rtpbin);
2196       priv->rtpbin = NULL;
2197     }
2198   }
2199   if (priv->rtpbin == NULL)
2200     goto no_rtpbin;
2201
2202   GST_INFO ("preparing media %p", media);
2203
2204   /* reset some variables */
2205   priv->is_live = FALSE;
2206   priv->seekable = FALSE;
2207   priv->buffering = FALSE;
2208   priv->thread = thread;
2209   /* we're preparing now */
2210   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
2211
2212   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
2213
2214   /* add the pipeline bus to our custom mainloop */
2215   priv->source = gst_bus_create_watch (bus);
2216   gst_object_unref (bus);
2217
2218   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
2219       g_object_ref (media), (GDestroyNotify) watch_destroyed);
2220
2221   priv->id = g_source_attach (priv->source, thread->context);
2222
2223   /* add stuff to the bin */
2224   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
2225
2226   /* do remainder in context */
2227   source = g_idle_source_new ();
2228   g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
2229   g_source_attach (source, thread->context);
2230   g_source_unref (source);
2231
2232 wait_status:
2233   g_rec_mutex_unlock (&priv->state_lock);
2234
2235   /* now wait for all pads to be prerolled, FIXME, we should somehow be
2236    * able to do this async so that we don't block the server thread. */
2237   if (!wait_preroll (media))
2238     goto preroll_failed;
2239
2240   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
2241
2242   GST_INFO ("object %p is prerolled", media);
2243
2244   return TRUE;
2245
2246   /* OK */
2247 was_prepared:
2248   {
2249     GST_LOG ("media %p was prepared", media);
2250     /* we are not going to use the giving thread, so stop it. */
2251     gst_rtsp_thread_stop (thread);
2252     g_rec_mutex_unlock (&priv->state_lock);
2253     return TRUE;
2254   }
2255   /* ERRORS */
2256 not_unprepared:
2257   {
2258     GST_WARNING ("media %p was not unprepared", media);
2259     priv->prepare_count--;
2260     g_rec_mutex_unlock (&priv->state_lock);
2261     return FALSE;
2262   }
2263 is_reused:
2264   {
2265     priv->prepare_count--;
2266     g_rec_mutex_unlock (&priv->state_lock);
2267     GST_WARNING ("can not reuse media %p", media);
2268     return FALSE;
2269   }
2270 no_create_rtpbin:
2271   {
2272     priv->prepare_count--;
2273     g_rec_mutex_unlock (&priv->state_lock);
2274     GST_ERROR ("no create_rtpbin function");
2275     g_critical ("no create_rtpbin vmethod function set");
2276     return FALSE;
2277   }
2278 no_rtpbin:
2279   {
2280     priv->prepare_count--;
2281     g_rec_mutex_unlock (&priv->state_lock);
2282     GST_WARNING ("no rtpbin element");
2283     g_warning ("failed to create element 'rtpbin', check your installation");
2284     return FALSE;
2285   }
2286 preroll_failed:
2287   {
2288     GST_WARNING ("failed to preroll pipeline");
2289     gst_rtsp_media_unprepare (media);
2290     return FALSE;
2291   }
2292 }
2293
2294 /* must be called with state-lock */
2295 static void
2296 finish_unprepare (GstRTSPMedia * media)
2297 {
2298   GstRTSPMediaPrivate *priv = media->priv;
2299   gint i;
2300   GList *walk;
2301
2302   GST_DEBUG ("shutting down");
2303
2304   /* release the lock on shutdown, otherwise pad_added_cb might try to
2305    * acquire the lock and then we deadlock */
2306   g_rec_mutex_unlock (&priv->state_lock);
2307   set_state (media, GST_STATE_NULL);
2308   g_rec_mutex_lock (&priv->state_lock);
2309   remove_fakesink (priv);
2310
2311   for (i = 0; i < priv->streams->len; i++) {
2312     GstRTSPStream *stream;
2313
2314     GST_INFO ("Removing elements of stream %d from pipeline", i);
2315
2316     stream = g_ptr_array_index (priv->streams, i);
2317
2318     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
2319   }
2320
2321   /* remove the pad signal handlers */
2322   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
2323     GstElement *elem = walk->data;
2324     DynPaySignalHandlers *handlers;
2325
2326     handlers =
2327         g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers");
2328     g_assert (handlers != NULL);
2329
2330     g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler);
2331     g_signal_handler_disconnect (G_OBJECT (elem),
2332         handlers->pad_removed_handler);
2333     g_signal_handler_disconnect (G_OBJECT (elem),
2334         handlers->no_more_pads_handler);
2335
2336     g_slice_free (DynPaySignalHandlers, handlers);
2337   }
2338
2339   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
2340   priv->rtpbin = NULL;
2341
2342   if (priv->nettime)
2343     gst_object_unref (priv->nettime);
2344   priv->nettime = NULL;
2345
2346   priv->reused = TRUE;
2347   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARED);
2348
2349   /* when the media is not reusable, this will effectively unref the media and
2350    * recreate it */
2351   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
2352
2353   /* the source has the last ref to the media */
2354   if (priv->source) {
2355     GST_DEBUG ("destroy source");
2356     g_source_destroy (priv->source);
2357     g_source_unref (priv->source);
2358   }
2359   if (priv->thread) {
2360     GST_DEBUG ("stop thread");
2361     gst_rtsp_thread_stop (priv->thread);
2362   }
2363 }
2364
2365 /* called with state-lock */
2366 static gboolean
2367 default_unprepare (GstRTSPMedia * media)
2368 {
2369   GstRTSPMediaPrivate *priv = media->priv;
2370
2371   if (priv->eos_shutdown) {
2372     GST_DEBUG ("sending EOS for shutdown");
2373     /* ref so that we don't disappear */
2374     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
2375     /* we need to go to playing again for the EOS to propagate, normally in this
2376      * state, nothing is receiving data from us anymore so this is ok. */
2377     set_state (media, GST_STATE_PLAYING);
2378   } else {
2379     finish_unprepare (media);
2380   }
2381   return TRUE;
2382 }
2383
2384 /**
2385  * gst_rtsp_media_unprepare:
2386  * @media: a #GstRTSPMedia
2387  *
2388  * Unprepare @media. After this call, the media should be prepared again before
2389  * it can be used again. If the media is set to be non-reusable, a new instance
2390  * must be created.
2391  *
2392  * Returns: %TRUE on success.
2393  */
2394 gboolean
2395 gst_rtsp_media_unprepare (GstRTSPMedia * media)
2396 {
2397   GstRTSPMediaPrivate *priv;
2398   gboolean success;
2399
2400   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2401
2402   priv = media->priv;
2403
2404   g_rec_mutex_lock (&priv->state_lock);
2405   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
2406     goto was_unprepared;
2407
2408   priv->prepare_count--;
2409   if (priv->prepare_count > 0)
2410     goto is_busy;
2411
2412   GST_INFO ("unprepare media %p", media);
2413   if (priv->blocked)
2414     media_streams_set_blocked (media, FALSE);
2415   set_target_state (media, GST_STATE_NULL, FALSE);
2416   success = TRUE;
2417
2418   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING);
2419
2420   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
2421     GstRTSPMediaClass *klass;
2422
2423     klass = GST_RTSP_MEDIA_GET_CLASS (media);
2424     if (klass->unprepare)
2425       success = klass->unprepare (media);
2426   } else {
2427     finish_unprepare (media);
2428   }
2429   g_rec_mutex_unlock (&priv->state_lock);
2430
2431   return success;
2432
2433 was_unprepared:
2434   {
2435     g_rec_mutex_unlock (&priv->state_lock);
2436     GST_INFO ("media %p was already unprepared", media);
2437     return TRUE;
2438   }
2439 is_busy:
2440   {
2441     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
2442     g_rec_mutex_unlock (&priv->state_lock);
2443     return TRUE;
2444   }
2445 }
2446
2447 /* should be called with state-lock */
2448 static GstClock *
2449 get_clock_unlocked (GstRTSPMedia * media)
2450 {
2451   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
2452     GST_DEBUG_OBJECT (media, "media was not prepared");
2453     return NULL;
2454   }
2455   return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
2456 }
2457
2458 /**
2459  * gst_rtsp_media_get_clock:
2460  * @media: a #GstRTSPMedia
2461  *
2462  * Get the clock that is used by the pipeline in @media.
2463  *
2464  * @media must be prepared before this method returns a valid clock object.
2465  *
2466  * Returns: (transfer full): the #GstClock used by @media. unref after usage.
2467  */
2468 GstClock *
2469 gst_rtsp_media_get_clock (GstRTSPMedia * media)
2470 {
2471   GstClock *clock;
2472   GstRTSPMediaPrivate *priv;
2473
2474   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2475
2476   priv = media->priv;
2477
2478   g_rec_mutex_lock (&priv->state_lock);
2479   clock = get_clock_unlocked (media);
2480   g_rec_mutex_unlock (&priv->state_lock);
2481
2482   return clock;
2483 }
2484
2485 /**
2486  * gst_rtsp_media_get_base_time:
2487  * @media: a #GstRTSPMedia
2488  *
2489  * Get the base_time that is used by the pipeline in @media.
2490  *
2491  * @media must be prepared before this method returns a valid base_time.
2492  *
2493  * Returns: the base_time used by @media.
2494  */
2495 GstClockTime
2496 gst_rtsp_media_get_base_time (GstRTSPMedia * media)
2497 {
2498   GstClockTime result;
2499   GstRTSPMediaPrivate *priv;
2500
2501   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE);
2502
2503   priv = media->priv;
2504
2505   g_rec_mutex_lock (&priv->state_lock);
2506   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2507     goto not_prepared;
2508
2509   result = gst_element_get_base_time (media->priv->pipeline);
2510   g_rec_mutex_unlock (&priv->state_lock);
2511
2512   return result;
2513
2514   /* ERRORS */
2515 not_prepared:
2516   {
2517     g_rec_mutex_unlock (&priv->state_lock);
2518     GST_DEBUG_OBJECT (media, "media was not prepared");
2519     return GST_CLOCK_TIME_NONE;
2520   }
2521 }
2522
2523 /**
2524  * gst_rtsp_media_get_time_provider:
2525  * @media: a #GstRTSPMedia
2526  * @address: an address or %NULL
2527  * @port: a port or 0
2528  *
2529  * Get the #GstNetTimeProvider for the clock used by @media. The time provider
2530  * will listen on @address and @port for client time requests.
2531  *
2532  * Returns: (transfer full): the #GstNetTimeProvider of @media.
2533  */
2534 GstNetTimeProvider *
2535 gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
2536     guint16 port)
2537 {
2538   GstRTSPMediaPrivate *priv;
2539   GstNetTimeProvider *provider = NULL;
2540
2541   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2542
2543   priv = media->priv;
2544
2545   g_rec_mutex_lock (&priv->state_lock);
2546   if (priv->time_provider) {
2547     if ((provider = priv->nettime) == NULL) {
2548       GstClock *clock;
2549
2550       if (priv->time_provider && (clock = get_clock_unlocked (media))) {
2551         provider = gst_net_time_provider_new (clock, address, port);
2552         gst_object_unref (clock);
2553
2554         priv->nettime = provider;
2555       }
2556     }
2557   }
2558   g_rec_mutex_unlock (&priv->state_lock);
2559
2560   if (provider)
2561     gst_object_ref (provider);
2562
2563   return provider;
2564 }
2565
2566 static gboolean
2567 default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info)
2568 {
2569   return gst_rtsp_sdp_from_media (sdp, info, media);
2570 }
2571
2572 /**
2573  * gst_rtsp_media_setup_sdp:
2574  * @media: a #GstRTSPMedia
2575  * @sdp: (transfer none): a #GstSDPMessage
2576  * @info: (transfer none): a #GstSDPInfo
2577  *
2578  * Add @media specific info to @sdp. @info is used to configure the connection
2579  * information in the SDP.
2580  *
2581  * Returns: TRUE on success.
2582  */
2583 gboolean
2584 gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
2585     GstSDPInfo * info)
2586 {
2587   GstRTSPMediaPrivate *priv;
2588   GstRTSPMediaClass *klass;
2589   gboolean res;
2590
2591   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2592   g_return_val_if_fail (sdp != NULL, FALSE);
2593   g_return_val_if_fail (info != NULL, FALSE);
2594
2595   priv = media->priv;
2596
2597   g_rec_mutex_lock (&priv->state_lock);
2598
2599   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2600
2601   if (!klass->setup_sdp)
2602     goto no_setup_sdp;
2603
2604   res = klass->setup_sdp (media, sdp, info);
2605
2606   g_rec_mutex_unlock (&priv->state_lock);
2607
2608   return res;
2609
2610   /* ERRORS */
2611 no_setup_sdp:
2612   {
2613     g_rec_mutex_unlock (&priv->state_lock);
2614     GST_ERROR ("no setup_sdp function");
2615     g_critical ("no setup_sdp vmethod function set");
2616     return FALSE;
2617   }
2618 }
2619
2620 /**
2621  * gst_rtsp_media_suspend:
2622  * @media: a #GstRTSPMedia
2623  *
2624  * Suspend @media. The state of the pipeline managed by @media is set to
2625  * GST_STATE_NULL but all streams are kept. @media can be prepared again
2626  * with gst_rtsp_media_unsuspend()
2627  *
2628  * @media must be prepared with gst_rtsp_media_prepare();
2629  *
2630  * Returns: %TRUE on success.
2631  */
2632 gboolean
2633 gst_rtsp_media_suspend (GstRTSPMedia * media)
2634 {
2635   GstRTSPMediaPrivate *priv = media->priv;
2636   GstStateChangeReturn ret;
2637
2638   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2639
2640   GST_FIXME ("suspend for dynamic pipelines needs fixing");
2641
2642   g_rec_mutex_lock (&priv->state_lock);
2643   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2644     goto not_prepared;
2645
2646   /* don't attempt to suspend when something is busy */
2647   if (priv->n_active > 0)
2648     goto done;
2649
2650   switch (priv->suspend_mode) {
2651     case GST_RTSP_SUSPEND_MODE_NONE:
2652       GST_DEBUG ("media %p no suspend", media);
2653       break;
2654     case GST_RTSP_SUSPEND_MODE_PAUSE:
2655       GST_DEBUG ("media %p suspend to PAUSED", media);
2656       ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
2657       if (ret == GST_STATE_CHANGE_FAILURE)
2658         goto state_failed;
2659       break;
2660     case GST_RTSP_SUSPEND_MODE_RESET:
2661       GST_DEBUG ("media %p suspend to NULL", media);
2662       ret = set_target_state (media, GST_STATE_NULL, TRUE);
2663       if (ret == GST_STATE_CHANGE_FAILURE)
2664         goto state_failed;
2665       break;
2666     default:
2667       break;
2668   }
2669   /* let the streams do the state changes freely, if any */
2670   media_streams_set_blocked (media, FALSE);
2671   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_SUSPENDED);
2672 done:
2673   g_rec_mutex_unlock (&priv->state_lock);
2674
2675   return TRUE;
2676
2677   /* ERRORS */
2678 not_prepared:
2679   {
2680     g_rec_mutex_unlock (&priv->state_lock);
2681     GST_WARNING ("media %p was not prepared", media);
2682     return FALSE;
2683   }
2684 state_failed:
2685   {
2686     g_rec_mutex_unlock (&priv->state_lock);
2687     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2688     GST_WARNING ("failed changing pipeline's state for media %p", media);
2689     return FALSE;
2690   }
2691 }
2692
2693 /**
2694  * gst_rtsp_media_unsuspend:
2695  * @media: a #GstRTSPMedia
2696  *
2697  * Unsuspend @media if it was in a suspended state. This method does nothing
2698  * when the media was not in the suspended state.
2699  *
2700  * Returns: %TRUE on success.
2701  */
2702 gboolean
2703 gst_rtsp_media_unsuspend (GstRTSPMedia * media)
2704 {
2705   GstRTSPMediaPrivate *priv = media->priv;
2706
2707   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2708
2709   g_rec_mutex_lock (&priv->state_lock);
2710   if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
2711     goto done;
2712
2713   switch (priv->suspend_mode) {
2714     case GST_RTSP_SUSPEND_MODE_NONE:
2715       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
2716       break;
2717     case GST_RTSP_SUSPEND_MODE_PAUSE:
2718       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
2719       break;
2720     case GST_RTSP_SUSPEND_MODE_RESET:
2721     {
2722       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
2723       if (!start_preroll (media))
2724         goto start_failed;
2725       g_rec_mutex_unlock (&priv->state_lock);
2726
2727       if (!wait_preroll (media))
2728         goto preroll_failed;
2729
2730       g_rec_mutex_lock (&priv->state_lock);
2731     }
2732     default:
2733       break;
2734   }
2735 done:
2736   g_rec_mutex_unlock (&priv->state_lock);
2737
2738   return TRUE;
2739
2740   /* ERRORS */
2741 start_failed:
2742   {
2743     g_rec_mutex_unlock (&priv->state_lock);
2744     GST_WARNING ("failed to preroll pipeline");
2745     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2746     return FALSE;
2747   }
2748 preroll_failed:
2749   {
2750     GST_WARNING ("failed to preroll pipeline");
2751     return FALSE;
2752   }
2753 }
2754
2755 /* must be called with state-lock */
2756 static void
2757 media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
2758 {
2759   GstRTSPMediaPrivate *priv = media->priv;
2760
2761   if (state == GST_STATE_NULL) {
2762     gst_rtsp_media_unprepare (media);
2763   } else {
2764     GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
2765     set_target_state (media, state, FALSE);
2766     /* when we are buffering, don't update the state yet, this will be done
2767      * when buffering finishes */
2768     if (priv->buffering) {
2769       GST_INFO ("Buffering busy, delay state change");
2770     } else {
2771       if (state == GST_STATE_PLAYING)
2772         /* make sure pads are not blocking anymore when going to PLAYING */
2773         media_streams_set_blocked (media, FALSE);
2774
2775       set_state (media, state);
2776
2777       /* and suspend after pause */
2778       if (state == GST_STATE_PAUSED)
2779         gst_rtsp_media_suspend (media);
2780     }
2781   }
2782 }
2783
2784 /**
2785  * gst_rtsp_media_set_pipeline_state:
2786  * @media: a #GstRTSPMedia
2787  * @state: the target state of the pipeline
2788  *
2789  * Set the state of the pipeline managed by @media to @state
2790  */
2791 void
2792 gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state)
2793 {
2794   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
2795
2796   g_rec_mutex_lock (&media->priv->state_lock);
2797   media_set_pipeline_state_locked (media, state);
2798   g_rec_mutex_unlock (&media->priv->state_lock);
2799 }
2800
2801 /**
2802  * gst_rtsp_media_set_state:
2803  * @media: a #GstRTSPMedia
2804  * @state: the target state of the media
2805  * @transports: (transfer none) (element-type GstRtspServer.RTSPStreamTransport):
2806  * a #GPtrArray of #GstRTSPStreamTransport pointers
2807  *
2808  * Set the state of @media to @state and for the transports in @transports.
2809  *
2810  * @media must be prepared with gst_rtsp_media_prepare();
2811  *
2812  * Returns: %TRUE on success.
2813  */
2814 gboolean
2815 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
2816     GPtrArray * transports)
2817 {
2818   GstRTSPMediaPrivate *priv;
2819   gint i;
2820   gboolean activate, deactivate, do_state;
2821   gint old_active;
2822
2823   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2824   g_return_val_if_fail (transports != NULL, FALSE);
2825
2826   priv = media->priv;
2827
2828   g_rec_mutex_lock (&priv->state_lock);
2829   if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR)
2830     goto error_status;
2831   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
2832       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
2833     goto not_prepared;
2834
2835   /* NULL and READY are the same */
2836   if (state == GST_STATE_READY)
2837     state = GST_STATE_NULL;
2838
2839   activate = deactivate = FALSE;
2840
2841   GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
2842       media);
2843
2844   switch (state) {
2845     case GST_STATE_NULL:
2846     case GST_STATE_PAUSED:
2847       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
2848       if (priv->target_state == GST_STATE_PLAYING)
2849         deactivate = TRUE;
2850       break;
2851     case GST_STATE_PLAYING:
2852       /* we're going to PLAYING, activate */
2853       activate = TRUE;
2854       break;
2855     default:
2856       break;
2857   }
2858   old_active = priv->n_active;
2859
2860   for (i = 0; i < transports->len; i++) {
2861     GstRTSPStreamTransport *trans;
2862
2863     /* we need a non-NULL entry in the array */
2864     trans = g_ptr_array_index (transports, i);
2865     if (trans == NULL)
2866       continue;
2867
2868     if (activate) {
2869       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
2870         priv->n_active++;
2871     } else if (deactivate) {
2872       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
2873         priv->n_active--;
2874     }
2875   }
2876
2877   /* we just activated the first media, do the playing state change */
2878   if (old_active == 0 && activate)
2879     do_state = TRUE;
2880   /* if we have no more active media, do the downward state changes */
2881   else if (priv->n_active == 0)
2882     do_state = TRUE;
2883   else
2884     do_state = FALSE;
2885
2886   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
2887       media, do_state);
2888
2889   if (priv->target_state != state) {
2890     if (do_state)
2891       media_set_pipeline_state_locked (media, state);
2892
2893     g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2894         NULL);
2895   }
2896
2897   /* remember where we are */
2898   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
2899           old_active != priv->n_active))
2900     collect_media_stats (media);
2901
2902   g_rec_mutex_unlock (&priv->state_lock);
2903
2904   return TRUE;
2905
2906   /* ERRORS */
2907 not_prepared:
2908   {
2909     GST_WARNING ("media %p was not prepared", media);
2910     g_rec_mutex_unlock (&priv->state_lock);
2911     return FALSE;
2912   }
2913 error_status:
2914   {
2915     GST_WARNING ("media %p in error status while changing to state %d",
2916         media, state);
2917     if (state == GST_STATE_NULL) {
2918       for (i = 0; i < transports->len; i++) {
2919         GstRTSPStreamTransport *trans;
2920
2921         /* we need a non-NULL entry in the array */
2922         trans = g_ptr_array_index (transports, i);
2923         if (trans == NULL)
2924           continue;
2925
2926         gst_rtsp_stream_transport_set_active (trans, FALSE);
2927       }
2928       priv->n_active = 0;
2929     }
2930     g_rec_mutex_unlock (&priv->state_lock);
2931     return FALSE;
2932   }
2933 }