factory: add profile property and pass to media and streams
[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: 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: 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: 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
1198       GST_INFO ("found dynamic element %d, %p", i, elem);
1199
1200       g_mutex_lock (&priv->lock);
1201       priv->dynamic = g_list_prepend (priv->dynamic, elem);
1202       g_mutex_unlock (&priv->lock);
1203
1204       have_elem = TRUE;
1205     }
1206     g_free (name);
1207   }
1208 }
1209
1210 /**
1211  * gst_rtsp_media_create_stream:
1212  * @media: a #GstRTSPMedia
1213  * @payloader: a #GstElement
1214  * @srcpad: a source #GstPad
1215  *
1216  * Create a new stream in @media that provides RTP data on @srcpad.
1217  * @srcpad should be a pad of an element inside @media->element.
1218  *
1219  * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
1220  *          as @media exists.
1221  */
1222 GstRTSPStream *
1223 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
1224     GstPad * pad)
1225 {
1226   GstRTSPMediaPrivate *priv;
1227   GstRTSPStream *stream;
1228   GstPad *srcpad;
1229   gchar *name;
1230   gint idx;
1231
1232   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1233   g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
1234   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1235   g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
1236
1237   priv = media->priv;
1238
1239   g_mutex_lock (&priv->lock);
1240   idx = priv->streams->len;
1241
1242   GST_DEBUG ("media %p: creating stream with index %d", media, idx);
1243
1244   name = g_strdup_printf ("src_%u", idx);
1245   srcpad = gst_ghost_pad_new (name, pad);
1246   gst_pad_set_active (srcpad, TRUE);
1247   gst_element_add_pad (priv->element, srcpad);
1248   g_free (name);
1249
1250   stream = gst_rtsp_stream_new (idx, payloader, srcpad);
1251   if (priv->pool)
1252     gst_rtsp_stream_set_address_pool (stream, priv->pool);
1253   gst_rtsp_stream_set_profiles (stream, priv->profiles);
1254   gst_rtsp_stream_set_protocols (stream, priv->protocols);
1255
1256   g_ptr_array_add (priv->streams, stream);
1257   g_mutex_unlock (&priv->lock);
1258
1259   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
1260       NULL);
1261
1262   return stream;
1263 }
1264
1265 static void
1266 gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream)
1267 {
1268   GstRTSPMediaPrivate *priv;
1269   GstPad *srcpad;
1270
1271   priv = media->priv;
1272
1273   g_mutex_lock (&priv->lock);
1274   /* remove the ghostpad */
1275   srcpad = gst_rtsp_stream_get_srcpad (stream);
1276   gst_element_remove_pad (priv->element, srcpad);
1277   gst_object_unref (srcpad);
1278   /* now remove the stream */
1279   g_object_ref (stream);
1280   g_ptr_array_remove (priv->streams, stream);
1281   g_mutex_unlock (&priv->lock);
1282
1283   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM], 0,
1284       stream, NULL);
1285
1286   g_object_unref (stream);
1287 }
1288
1289 /**
1290  * gst_rtsp_media_n_streams:
1291  * @media: a #GstRTSPMedia
1292  *
1293  * Get the number of streams in this media.
1294  *
1295  * Returns: The number of streams.
1296  */
1297 guint
1298 gst_rtsp_media_n_streams (GstRTSPMedia * media)
1299 {
1300   GstRTSPMediaPrivate *priv;
1301   guint res;
1302
1303   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
1304
1305   priv = media->priv;
1306
1307   g_mutex_lock (&priv->lock);
1308   res = priv->streams->len;
1309   g_mutex_unlock (&priv->lock);
1310
1311   return res;
1312 }
1313
1314 /**
1315  * gst_rtsp_media_get_stream:
1316  * @media: a #GstRTSPMedia
1317  * @idx: the stream index
1318  *
1319  * Retrieve the stream with index @idx from @media.
1320  *
1321  * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with
1322  * that index did not exist.
1323  */
1324 GstRTSPStream *
1325 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
1326 {
1327   GstRTSPMediaPrivate *priv;
1328   GstRTSPStream *res;
1329
1330   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1331
1332   priv = media->priv;
1333
1334   g_mutex_lock (&priv->lock);
1335   if (idx < priv->streams->len)
1336     res = g_ptr_array_index (priv->streams, idx);
1337   else
1338     res = NULL;
1339   g_mutex_unlock (&priv->lock);
1340
1341   return res;
1342 }
1343
1344 /**
1345  * gst_rtsp_media_find_stream:
1346  * @media: a #GstRTSPMedia
1347  * @control: the control of the stream
1348  *
1349  * Find a stream in @media with @control as the control uri.
1350  *
1351  * Returns: (transfer none): the #GstRTSPStream with control uri @control
1352  * or %NULL when a stream with that control did not exist.
1353  */
1354 GstRTSPStream *
1355 gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control)
1356 {
1357   GstRTSPMediaPrivate *priv;
1358   GstRTSPStream *res;
1359   gint i;
1360
1361   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1362   g_return_val_if_fail (control != NULL, NULL);
1363
1364   priv = media->priv;
1365
1366   res = NULL;
1367
1368   g_mutex_lock (&priv->lock);
1369   for (i = 0; i < priv->streams->len; i++) {
1370     GstRTSPStream *test;
1371
1372     test = g_ptr_array_index (priv->streams, i);
1373     if (gst_rtsp_stream_has_control (test, control)) {
1374       res = test;
1375       break;
1376     }
1377   }
1378   g_mutex_unlock (&priv->lock);
1379
1380   return res;
1381 }
1382
1383 /* called with state-lock */
1384 static gboolean
1385 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
1386     GstRTSPRangeUnit unit)
1387 {
1388   return gst_rtsp_range_convert_units (range, unit);
1389 }
1390
1391 /**
1392  * gst_rtsp_media_get_range_string:
1393  * @media: a #GstRTSPMedia
1394  * @play: for the PLAY request
1395  * @unit: the unit to use for the string
1396  *
1397  * Get the current range as a string. @media must be prepared with
1398  * gst_rtsp_media_prepare ().
1399  *
1400  * Returns: The range as a string, g_free() after usage.
1401  */
1402 gchar *
1403 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play,
1404     GstRTSPRangeUnit unit)
1405 {
1406   GstRTSPMediaClass *klass;
1407   GstRTSPMediaPrivate *priv;
1408   gchar *result;
1409   GstRTSPTimeRange range;
1410
1411   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1412   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1413   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1414
1415   priv = media->priv;
1416
1417   g_rec_mutex_lock (&priv->state_lock);
1418   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
1419       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
1420     goto not_prepared;
1421
1422   g_mutex_lock (&priv->lock);
1423
1424   /* Update the range value with current position/duration */
1425   collect_media_stats (media);
1426
1427   /* make copy */
1428   range = priv->range;
1429
1430   if (!play && priv->n_active > 0) {
1431     range.min.type = GST_RTSP_TIME_NOW;
1432     range.min.seconds = -1;
1433   }
1434   g_mutex_unlock (&priv->lock);
1435   g_rec_mutex_unlock (&priv->state_lock);
1436
1437   if (!klass->convert_range (media, &range, unit))
1438     goto conversion_failed;
1439
1440   result = gst_rtsp_range_to_string (&range);
1441
1442   return result;
1443
1444   /* ERRORS */
1445 not_prepared:
1446   {
1447     GST_WARNING ("media %p was not prepared", media);
1448     g_rec_mutex_unlock (&priv->state_lock);
1449     return NULL;
1450   }
1451 conversion_failed:
1452   {
1453     GST_WARNING ("range conversion to unit %d failed", unit);
1454     return NULL;
1455   }
1456 }
1457
1458 static void
1459 stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
1460 {
1461   gst_rtsp_stream_set_blocked (stream, media->priv->blocked);
1462 }
1463
1464 static void
1465 media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked)
1466 {
1467   GstRTSPMediaPrivate *priv = media->priv;
1468
1469   GST_DEBUG ("media %p set blocked %d", media, blocked);
1470   priv->blocked = blocked;
1471   g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media);
1472 }
1473
1474 /**
1475  * gst_rtsp_media_seek:
1476  * @media: a #GstRTSPMedia
1477  * @range: a #GstRTSPTimeRange
1478  *
1479  * Seek the pipeline of @media to @range. @media must be prepared with
1480  * gst_rtsp_media_prepare().
1481  *
1482  * Returns: %TRUE on success.
1483  */
1484 gboolean
1485 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
1486 {
1487   GstRTSPMediaClass *klass;
1488   GstRTSPMediaPrivate *priv;
1489   gboolean res;
1490   GstClockTime start, stop;
1491   GstSeekType start_type, stop_type;
1492   GstQuery *query;
1493
1494   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1495
1496   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1497   g_return_val_if_fail (range != NULL, FALSE);
1498   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
1499
1500   priv = media->priv;
1501
1502   g_rec_mutex_lock (&priv->state_lock);
1503   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
1504     goto not_prepared;
1505
1506   /* Update the seekable state of the pipeline in case it changed */
1507   query = gst_query_new_seeking (GST_FORMAT_TIME);
1508   if (gst_element_query (priv->pipeline, query)) {
1509     GstFormat format;
1510     gboolean seekable;
1511     gint64 start, end;
1512
1513     gst_query_parse_seeking (query, &format, &seekable, &start, &end);
1514     priv->seekable = seekable;
1515   }
1516   gst_query_unref (query);
1517
1518   if (!priv->seekable)
1519     goto not_seekable;
1520
1521   start_type = stop_type = GST_SEEK_TYPE_NONE;
1522
1523   if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
1524     goto not_supported;
1525   gst_rtsp_range_get_times (range, &start, &stop);
1526
1527   GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1528       GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1529   GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1530       GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
1531
1532   if (start != GST_CLOCK_TIME_NONE)
1533     start_type = GST_SEEK_TYPE_SET;
1534
1535   if (priv->range_stop == stop)
1536     stop = GST_CLOCK_TIME_NONE;
1537   else if (stop != GST_CLOCK_TIME_NONE)
1538     stop_type = GST_SEEK_TYPE_SET;
1539
1540   if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
1541     GstSeekFlags flags;
1542
1543     GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1544         GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1545
1546     priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1547     if (priv->blocked)
1548       media_streams_set_blocked (media, TRUE);
1549
1550     /* depends on the current playing state of the pipeline. We might need to
1551      * queue this until we get EOS. */
1552     flags = GST_SEEK_FLAG_FLUSH;
1553
1554     /* if range start was not supplied we must continue from current position.
1555      * but since we're doing a flushing seek, let us query the current position
1556      * so we end up at exactly the same position after the seek. */
1557     if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */
1558       gint64 position;
1559       gboolean ret = FALSE;
1560
1561       if (klass->query_position)
1562         ret = klass->query_position (media, &position);
1563
1564       if (!ret) {
1565         GST_WARNING ("position query failed");
1566       } else {
1567         GST_DEBUG ("doing accurate seek to %" GST_TIME_FORMAT,
1568             GST_TIME_ARGS (position));
1569         start = position;
1570         start_type = GST_SEEK_TYPE_SET;
1571         flags |= GST_SEEK_FLAG_ACCURATE;
1572       }
1573     } else {
1574       /* only set keyframe flag when modifying start */
1575       if (start_type != GST_SEEK_TYPE_NONE)
1576         flags |= GST_SEEK_FLAG_KEY_UNIT;
1577     }
1578
1579     /* FIXME, we only do forwards */
1580     res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
1581         flags, start_type, start, stop_type, stop);
1582
1583     /* and block for the seek to complete */
1584     GST_INFO ("done seeking %d", res);
1585     g_rec_mutex_unlock (&priv->state_lock);
1586
1587     /* wait until pipeline is prerolled again, this will also collect stats */
1588     if (!wait_preroll (media))
1589       goto preroll_failed;
1590
1591     g_rec_mutex_lock (&priv->state_lock);
1592     GST_INFO ("prerolled again");
1593   } else {
1594     GST_INFO ("no seek needed");
1595     res = TRUE;
1596   }
1597   g_rec_mutex_unlock (&priv->state_lock);
1598
1599   return res;
1600
1601   /* ERRORS */
1602 not_prepared:
1603   {
1604     g_rec_mutex_unlock (&priv->state_lock);
1605     GST_INFO ("media %p is not prepared", media);
1606     return FALSE;
1607   }
1608 not_seekable:
1609   {
1610     g_rec_mutex_unlock (&priv->state_lock);
1611     GST_INFO ("pipeline is not seekable");
1612     return FALSE;
1613   }
1614 not_supported:
1615   {
1616     g_rec_mutex_unlock (&priv->state_lock);
1617     GST_WARNING ("conversion to npt not supported");
1618     return FALSE;
1619   }
1620 preroll_failed:
1621   {
1622     GST_WARNING ("failed to preroll after seek");
1623     return FALSE;
1624   }
1625 }
1626
1627 static void
1628 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1629 {
1630   GstRTSPMediaPrivate *priv = media->priv;
1631
1632   g_mutex_lock (&priv->lock);
1633   priv->status = status;
1634   GST_DEBUG ("setting new status to %d", status);
1635   g_cond_broadcast (&priv->cond);
1636   g_mutex_unlock (&priv->lock);
1637 }
1638
1639 /**
1640  * gst_rtsp_media_get_status:
1641  * @media: a #GstRTSPMedia
1642  *
1643  * Get the status of @media. When @media is busy preparing, this function waits
1644  * until @media is prepared or in error.
1645  *
1646  * Returns: the status of @media.
1647  */
1648 GstRTSPMediaStatus
1649 gst_rtsp_media_get_status (GstRTSPMedia * media)
1650 {
1651   GstRTSPMediaPrivate *priv = media->priv;
1652   GstRTSPMediaStatus result;
1653   gint64 end_time;
1654
1655   g_mutex_lock (&priv->lock);
1656   end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
1657   /* while we are preparing, wait */
1658   while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1659     GST_DEBUG ("waiting for status change");
1660     if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
1661       GST_DEBUG ("timeout, assuming error status");
1662       priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
1663     }
1664   }
1665   /* could be success or error */
1666   result = priv->status;
1667   GST_DEBUG ("got status %d", result);
1668   g_mutex_unlock (&priv->lock);
1669
1670   return result;
1671 }
1672
1673 static void
1674 stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
1675 {
1676   *blocked &= gst_rtsp_stream_is_blocking (stream);
1677 }
1678
1679 static gboolean
1680 media_streams_blocking (GstRTSPMedia * media)
1681 {
1682   gboolean blocking = TRUE;
1683
1684   g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_blocking,
1685       &blocking);
1686
1687   return blocking;
1688 }
1689
1690 static GstStateChangeReturn
1691 set_state (GstRTSPMedia * media, GstState state)
1692 {
1693   GstRTSPMediaPrivate *priv = media->priv;
1694   GstStateChangeReturn ret;
1695
1696   GST_INFO ("set state to %s for media %p", gst_element_state_get_name (state),
1697       media);
1698   ret = gst_element_set_state (priv->pipeline, state);
1699
1700   return ret;
1701 }
1702
1703 static GstStateChangeReturn
1704 set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
1705 {
1706   GstRTSPMediaPrivate *priv = media->priv;
1707   GstStateChangeReturn ret;
1708
1709   GST_INFO ("set target state to %s for media %p",
1710       gst_element_state_get_name (state), media);
1711   priv->target_state = state;
1712
1713   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0,
1714       priv->target_state, NULL);
1715
1716   if (do_state)
1717     ret = set_state (media, state);
1718   else
1719     ret = GST_STATE_CHANGE_SUCCESS;
1720
1721   return ret;
1722 }
1723
1724 /* called with state-lock */
1725 static gboolean
1726 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1727 {
1728   GstRTSPMediaPrivate *priv = media->priv;
1729   GstMessageType type;
1730
1731   type = GST_MESSAGE_TYPE (message);
1732
1733   switch (type) {
1734     case GST_MESSAGE_STATE_CHANGED:
1735       break;
1736     case GST_MESSAGE_BUFFERING:
1737     {
1738       gint percent;
1739
1740       gst_message_parse_buffering (message, &percent);
1741
1742       /* no state management needed for live pipelines */
1743       if (priv->is_live)
1744         break;
1745
1746       if (percent == 100) {
1747         /* a 100% message means buffering is done */
1748         priv->buffering = FALSE;
1749         /* if the desired state is playing, go back */
1750         if (priv->target_state == GST_STATE_PLAYING) {
1751           GST_INFO ("Buffering done, setting pipeline to PLAYING");
1752           set_state (media, GST_STATE_PLAYING);
1753         } else {
1754           GST_INFO ("Buffering done");
1755         }
1756       } else {
1757         /* buffering busy */
1758         if (priv->buffering == FALSE) {
1759           if (priv->target_state == GST_STATE_PLAYING) {
1760             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
1761             GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1762             set_state (media, GST_STATE_PAUSED);
1763           } else {
1764             GST_INFO ("Buffering ...");
1765           }
1766         }
1767         priv->buffering = TRUE;
1768       }
1769       break;
1770     }
1771     case GST_MESSAGE_LATENCY:
1772     {
1773       gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
1774       break;
1775     }
1776     case GST_MESSAGE_ERROR:
1777     {
1778       GError *gerror;
1779       gchar *debug;
1780
1781       gst_message_parse_error (message, &gerror, &debug);
1782       GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1783       g_error_free (gerror);
1784       g_free (debug);
1785
1786       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1787       break;
1788     }
1789     case GST_MESSAGE_WARNING:
1790     {
1791       GError *gerror;
1792       gchar *debug;
1793
1794       gst_message_parse_warning (message, &gerror, &debug);
1795       GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1796       g_error_free (gerror);
1797       g_free (debug);
1798       break;
1799     }
1800     case GST_MESSAGE_ELEMENT:
1801     {
1802       const GstStructure *s;
1803
1804       s = gst_message_get_structure (message);
1805       if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) {
1806         GST_DEBUG ("media received blocking message");
1807         if (priv->blocked && media_streams_blocking (media)) {
1808           GST_DEBUG ("media is blocking");
1809           collect_media_stats (media);
1810
1811           if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1812             gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1813         }
1814       }
1815       break;
1816     }
1817     case GST_MESSAGE_STREAM_STATUS:
1818       break;
1819     case GST_MESSAGE_ASYNC_DONE:
1820       if (priv->adding) {
1821         /* when we are dynamically adding pads, the addition of the udpsrc will
1822          * temporarily produce ASYNC_DONE messages. We have to ignore them and
1823          * wait for the final ASYNC_DONE after everything prerolled */
1824         GST_INFO ("%p: ignoring ASYNC_DONE", media);
1825       } else {
1826         GST_INFO ("%p: got ASYNC_DONE", media);
1827         collect_media_stats (media);
1828
1829         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1830           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1831       }
1832       break;
1833     case GST_MESSAGE_EOS:
1834       GST_INFO ("%p: got EOS", media);
1835
1836       if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1837         GST_DEBUG ("shutting down after EOS");
1838         finish_unprepare (media);
1839       }
1840       break;
1841     default:
1842       GST_INFO ("%p: got message type %d (%s)", media, type,
1843           gst_message_type_get_name (type));
1844       break;
1845   }
1846   return TRUE;
1847 }
1848
1849 static gboolean
1850 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1851 {
1852   GstRTSPMediaPrivate *priv = media->priv;
1853   GstRTSPMediaClass *klass;
1854   gboolean ret;
1855
1856   klass = GST_RTSP_MEDIA_GET_CLASS (media);
1857
1858   g_rec_mutex_lock (&priv->state_lock);
1859   if (klass->handle_message)
1860     ret = klass->handle_message (media, message);
1861   else
1862     ret = FALSE;
1863   g_rec_mutex_unlock (&priv->state_lock);
1864
1865   return ret;
1866 }
1867
1868 static void
1869 watch_destroyed (GstRTSPMedia * media)
1870 {
1871   GST_DEBUG_OBJECT (media, "source destroyed");
1872   g_object_unref (media);
1873 }
1874
1875 static GstElement *
1876 find_payload_element (GstElement * payloader)
1877 {
1878   GstElement *pay = NULL;
1879
1880   if (GST_IS_BIN (payloader)) {
1881     GstIterator *iter;
1882     GValue item = { 0 };
1883
1884     iter = gst_bin_iterate_recurse (GST_BIN (payloader));
1885     while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) {
1886       GstElement *element = (GstElement *) g_value_get_object (&item);
1887       GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element);
1888       const gchar *klass;
1889
1890       klass =
1891           gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS);
1892       if (klass == NULL)
1893         continue;
1894
1895       if (strstr (klass, "Payloader") && strstr (klass, "RTP")) {
1896         pay = gst_object_ref (element);
1897         g_value_unset (&item);
1898         break;
1899       }
1900       g_value_unset (&item);
1901     }
1902     gst_iterator_free (iter);
1903   } else {
1904     pay = g_object_ref (payloader);
1905   }
1906
1907   return pay;
1908 }
1909
1910 /* called from streaming threads */
1911 static void
1912 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1913 {
1914   GstRTSPMediaPrivate *priv = media->priv;
1915   GstRTSPStream *stream;
1916   GstElement *pay;
1917
1918   /* find the real payload element */
1919   pay = find_payload_element (element);
1920   stream = gst_rtsp_media_create_stream (media, pay, pad);
1921   gst_object_unref (pay);
1922
1923   g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream);
1924
1925   GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1926
1927   g_rec_mutex_lock (&priv->state_lock);
1928   /* we will be adding elements below that will cause ASYNC_DONE to be
1929    * posted in the bus. We want to ignore those messages until the
1930    * pipeline really prerolled. */
1931   priv->adding = TRUE;
1932
1933   /* join the element in the PAUSED state because this callback is
1934    * called from the streaming thread and it is PAUSED */
1935   gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
1936       priv->rtpbin, GST_STATE_PAUSED);
1937
1938   priv->adding = FALSE;
1939   g_rec_mutex_unlock (&priv->state_lock);
1940 }
1941
1942 static void
1943 pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1944 {
1945   GstRTSPMediaPrivate *priv = media->priv;
1946   GstRTSPStream *stream;
1947
1948   stream = g_object_get_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream");
1949   if (stream == NULL)
1950     return;
1951
1952   GST_INFO ("pad removed %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
1953
1954   g_rec_mutex_lock (&priv->state_lock);
1955   gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
1956   g_rec_mutex_unlock (&priv->state_lock);
1957
1958   gst_rtsp_media_remove_stream (media, stream);
1959 }
1960
1961 static void
1962 remove_fakesink (GstRTSPMediaPrivate * priv)
1963 {
1964   GstElement *fakesink;
1965
1966   g_mutex_lock (&priv->lock);
1967   if ((fakesink = priv->fakesink))
1968     gst_object_ref (fakesink);
1969   priv->fakesink = NULL;
1970   g_mutex_unlock (&priv->lock);
1971
1972   if (fakesink) {
1973     gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
1974     gst_element_set_state (fakesink, GST_STATE_NULL);
1975     gst_object_unref (fakesink);
1976     GST_INFO ("removed fakesink");
1977   }
1978 }
1979
1980 static void
1981 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1982 {
1983   GstRTSPMediaPrivate *priv = media->priv;
1984
1985   GST_INFO ("no more pads");
1986   remove_fakesink (priv);
1987 }
1988
1989 typedef struct _DynPaySignalHandlers DynPaySignalHandlers;
1990
1991 struct _DynPaySignalHandlers
1992 {
1993   gulong pad_added_handler;
1994   gulong pad_removed_handler;
1995   gulong no_more_pads_handler;
1996 };
1997
1998 static gboolean
1999 start_preroll (GstRTSPMedia * media)
2000 {
2001   GstRTSPMediaPrivate *priv = media->priv;
2002   GstStateChangeReturn ret;
2003
2004   GST_INFO ("setting pipeline to PAUSED for media %p", media);
2005   /* first go to PAUSED */
2006   ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
2007
2008   switch (ret) {
2009     case GST_STATE_CHANGE_SUCCESS:
2010       GST_INFO ("SUCCESS state change for media %p", media);
2011       priv->seekable = TRUE;
2012       break;
2013     case GST_STATE_CHANGE_ASYNC:
2014       GST_INFO ("ASYNC state change for media %p", media);
2015       priv->seekable = TRUE;
2016       break;
2017     case GST_STATE_CHANGE_NO_PREROLL:
2018       /* we need to go to PLAYING */
2019       GST_INFO ("NO_PREROLL state change: live media %p", media);
2020       /* FIXME we disable seeking for live streams for now. We should perform a
2021        * seeking query in preroll instead */
2022       priv->seekable = FALSE;
2023       priv->is_live = TRUE;
2024       /* start blocked  to make sure nothing goes to the sink */
2025       media_streams_set_blocked (media, TRUE);
2026       ret = set_state (media, GST_STATE_PLAYING);
2027       if (ret == GST_STATE_CHANGE_FAILURE)
2028         goto state_failed;
2029       break;
2030     case GST_STATE_CHANGE_FAILURE:
2031       goto state_failed;
2032   }
2033
2034   return TRUE;
2035
2036 state_failed:
2037   {
2038     GST_WARNING ("failed to preroll pipeline");
2039     return FALSE;
2040   }
2041 }
2042
2043 static gboolean
2044 wait_preroll (GstRTSPMedia * media)
2045 {
2046   GstRTSPMediaStatus status;
2047
2048   GST_DEBUG ("wait to preroll pipeline");
2049
2050   /* wait until pipeline is prerolled */
2051   status = gst_rtsp_media_get_status (media);
2052   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
2053     goto preroll_failed;
2054
2055   return TRUE;
2056
2057 preroll_failed:
2058   {
2059     GST_WARNING ("failed to preroll pipeline");
2060     return FALSE;
2061   }
2062 }
2063
2064 static gboolean
2065 start_prepare (GstRTSPMedia * media)
2066 {
2067   GstRTSPMediaPrivate *priv = media->priv;
2068   guint i;
2069   GList *walk;
2070
2071   /* link streams we already have, other streams might appear when we have
2072    * dynamic elements */
2073   for (i = 0; i < priv->streams->len; i++) {
2074     GstRTSPStream *stream;
2075
2076     stream = g_ptr_array_index (priv->streams, i);
2077
2078     gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
2079         priv->rtpbin, GST_STATE_NULL);
2080   }
2081
2082   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
2083     GstElement *elem = walk->data;
2084     DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
2085
2086     GST_INFO ("adding callbacks for dynamic element %p", elem);
2087
2088     handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
2089         (GCallback) pad_added_cb, media);
2090     handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
2091         (GCallback) pad_removed_cb, media);
2092     handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
2093         (GCallback) no_more_pads_cb, media);
2094
2095     g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
2096
2097     /* we add a fakesink here in order to make the state change async. We remove
2098      * the fakesink again in the no-more-pads callback. */
2099     priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
2100     gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
2101   }
2102
2103   if (!start_preroll (media))
2104     goto preroll_failed;
2105
2106   return FALSE;
2107
2108 preroll_failed:
2109   {
2110     GST_WARNING ("failed to preroll pipeline");
2111     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2112     return FALSE;
2113   }
2114 }
2115
2116 /**
2117  * gst_rtsp_media_prepare:
2118  * @media: a #GstRTSPMedia
2119  * @thread: a #GstRTSPThread to run the bus handler or %NULL
2120  *
2121  * Prepare @media for streaming. This function will create the objects
2122  * to manage the streaming. A pipeline must have been set on @media with
2123  * gst_rtsp_media_take_pipeline().
2124  *
2125  * It will preroll the pipeline and collect vital information about the streams
2126  * such as the duration.
2127  *
2128  * Returns: %TRUE on success.
2129  */
2130 gboolean
2131 gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
2132 {
2133   GstRTSPMediaPrivate *priv;
2134   GstBus *bus;
2135   GSource *source;
2136   GstRTSPMediaClass *klass;
2137
2138   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2139   g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE);
2140
2141   priv = media->priv;
2142
2143   g_rec_mutex_lock (&priv->state_lock);
2144   priv->prepare_count++;
2145
2146   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED ||
2147       priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED)
2148     goto was_prepared;
2149
2150   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
2151     goto wait_status;
2152
2153   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
2154     goto not_unprepared;
2155
2156   if (!priv->reusable && priv->reused)
2157     goto is_reused;
2158
2159   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2160
2161   if (!klass->create_rtpbin)
2162     goto no_create_rtpbin;
2163
2164   priv->rtpbin = klass->create_rtpbin (media);
2165   if (priv->rtpbin != NULL) {
2166     gboolean success = TRUE;
2167
2168     if (klass->setup_rtpbin)
2169       success = klass->setup_rtpbin (media, priv->rtpbin);
2170
2171     if (success == FALSE) {
2172       gst_object_unref (priv->rtpbin);
2173       priv->rtpbin = NULL;
2174     }
2175   }
2176   if (priv->rtpbin == NULL)
2177     goto no_rtpbin;
2178
2179   GST_INFO ("preparing media %p", media);
2180
2181   /* reset some variables */
2182   priv->is_live = FALSE;
2183   priv->seekable = FALSE;
2184   priv->buffering = FALSE;
2185   priv->thread = thread;
2186   /* we're preparing now */
2187   priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
2188
2189   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
2190
2191   /* add the pipeline bus to our custom mainloop */
2192   priv->source = gst_bus_create_watch (bus);
2193   gst_object_unref (bus);
2194
2195   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
2196       g_object_ref (media), (GDestroyNotify) watch_destroyed);
2197
2198   priv->id = g_source_attach (priv->source, thread->context);
2199
2200   /* add stuff to the bin */
2201   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
2202
2203   /* do remainder in context */
2204   source = g_idle_source_new ();
2205   g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
2206   g_source_attach (source, thread->context);
2207   g_source_unref (source);
2208
2209 wait_status:
2210   g_rec_mutex_unlock (&priv->state_lock);
2211
2212   /* now wait for all pads to be prerolled, FIXME, we should somehow be
2213    * able to do this async so that we don't block the server thread. */
2214   if (!wait_preroll (media))
2215     goto preroll_failed;
2216
2217   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
2218
2219   GST_INFO ("object %p is prerolled", media);
2220
2221   return TRUE;
2222
2223   /* OK */
2224 was_prepared:
2225   {
2226     GST_LOG ("media %p was prepared", media);
2227     /* we are not going to use the giving thread, so stop it. */
2228     gst_rtsp_thread_stop (thread);
2229     g_rec_mutex_unlock (&priv->state_lock);
2230     return TRUE;
2231   }
2232   /* ERRORS */
2233 not_unprepared:
2234   {
2235     GST_WARNING ("media %p was not unprepared", media);
2236     priv->prepare_count--;
2237     g_rec_mutex_unlock (&priv->state_lock);
2238     return FALSE;
2239   }
2240 is_reused:
2241   {
2242     priv->prepare_count--;
2243     g_rec_mutex_unlock (&priv->state_lock);
2244     GST_WARNING ("can not reuse media %p", media);
2245     return FALSE;
2246   }
2247 no_create_rtpbin:
2248   {
2249     priv->prepare_count--;
2250     g_rec_mutex_unlock (&priv->state_lock);
2251     GST_ERROR ("no create_rtpbin function");
2252     g_critical ("no create_rtpbin vmethod function set");
2253     return FALSE;
2254   }
2255 no_rtpbin:
2256   {
2257     priv->prepare_count--;
2258     g_rec_mutex_unlock (&priv->state_lock);
2259     GST_WARNING ("no rtpbin element");
2260     g_warning ("failed to create element 'rtpbin', check your installation");
2261     return FALSE;
2262   }
2263 preroll_failed:
2264   {
2265     GST_WARNING ("failed to preroll pipeline");
2266     gst_rtsp_media_unprepare (media);
2267     return FALSE;
2268   }
2269 }
2270
2271 /* must be called with state-lock */
2272 static void
2273 finish_unprepare (GstRTSPMedia * media)
2274 {
2275   GstRTSPMediaPrivate *priv = media->priv;
2276   gint i;
2277   GList *walk;
2278
2279   GST_DEBUG ("shutting down");
2280
2281   set_state (media, GST_STATE_NULL);
2282   remove_fakesink (priv);
2283
2284   for (i = 0; i < priv->streams->len; i++) {
2285     GstRTSPStream *stream;
2286
2287     GST_INFO ("Removing elements of stream %d from pipeline", i);
2288
2289     stream = g_ptr_array_index (priv->streams, i);
2290
2291     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
2292   }
2293
2294   /* remove the pad signal handlers */
2295   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
2296     GstElement *elem = walk->data;
2297     DynPaySignalHandlers *handlers;
2298
2299     handlers =
2300         g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers");
2301     g_assert (handlers != NULL);
2302
2303     g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler);
2304     g_signal_handler_disconnect (G_OBJECT (elem),
2305         handlers->pad_removed_handler);
2306     g_signal_handler_disconnect (G_OBJECT (elem),
2307         handlers->no_more_pads_handler);
2308
2309     g_slice_free (DynPaySignalHandlers, handlers);
2310   }
2311
2312   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
2313   priv->rtpbin = NULL;
2314
2315   if (priv->nettime)
2316     gst_object_unref (priv->nettime);
2317   priv->nettime = NULL;
2318
2319   priv->reused = TRUE;
2320   priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
2321
2322   /* when the media is not reusable, this will effectively unref the media and
2323    * recreate it */
2324   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
2325
2326   /* the source has the last ref to the media */
2327   if (priv->source) {
2328     GST_DEBUG ("destroy source");
2329     g_source_destroy (priv->source);
2330     g_source_unref (priv->source);
2331   }
2332   if (priv->thread) {
2333     GST_DEBUG ("stop thread");
2334     gst_rtsp_thread_stop (priv->thread);
2335   }
2336 }
2337
2338 /* called with state-lock */
2339 static gboolean
2340 default_unprepare (GstRTSPMedia * media)
2341 {
2342   GstRTSPMediaPrivate *priv = media->priv;
2343
2344   if (priv->eos_shutdown) {
2345     GST_DEBUG ("sending EOS for shutdown");
2346     /* ref so that we don't disappear */
2347     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
2348     /* we need to go to playing again for the EOS to propagate, normally in this
2349      * state, nothing is receiving data from us anymore so this is ok. */
2350     set_state (media, GST_STATE_PLAYING);
2351     priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
2352   } else {
2353     finish_unprepare (media);
2354   }
2355   return TRUE;
2356 }
2357
2358 /**
2359  * gst_rtsp_media_unprepare:
2360  * @media: a #GstRTSPMedia
2361  *
2362  * Unprepare @media. After this call, the media should be prepared again before
2363  * it can be used again. If the media is set to be non-reusable, a new instance
2364  * must be created.
2365  *
2366  * Returns: %TRUE on success.
2367  */
2368 gboolean
2369 gst_rtsp_media_unprepare (GstRTSPMedia * media)
2370 {
2371   GstRTSPMediaPrivate *priv;
2372   gboolean success;
2373
2374   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2375
2376   priv = media->priv;
2377
2378   g_rec_mutex_lock (&priv->state_lock);
2379   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
2380     goto was_unprepared;
2381
2382   priv->prepare_count--;
2383   if (priv->prepare_count > 0)
2384     goto is_busy;
2385
2386   GST_INFO ("unprepare media %p", media);
2387   set_target_state (media, GST_STATE_NULL, FALSE);
2388   success = TRUE;
2389
2390   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
2391     GstRTSPMediaClass *klass;
2392
2393     klass = GST_RTSP_MEDIA_GET_CLASS (media);
2394     if (klass->unprepare)
2395       success = klass->unprepare (media);
2396   } else {
2397     finish_unprepare (media);
2398   }
2399   g_rec_mutex_unlock (&priv->state_lock);
2400
2401   return success;
2402
2403 was_unprepared:
2404   {
2405     g_rec_mutex_unlock (&priv->state_lock);
2406     GST_INFO ("media %p was already unprepared", media);
2407     return TRUE;
2408   }
2409 is_busy:
2410   {
2411     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
2412     g_rec_mutex_unlock (&priv->state_lock);
2413     return TRUE;
2414   }
2415 }
2416
2417 /* should be called with state-lock */
2418 static GstClock *
2419 get_clock_unlocked (GstRTSPMedia * media)
2420 {
2421   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
2422     GST_DEBUG_OBJECT (media, "media was not prepared");
2423     return NULL;
2424   }
2425   return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
2426 }
2427
2428 /**
2429  * gst_rtsp_media_get_clock:
2430  * @media: a #GstRTSPMedia
2431  *
2432  * Get the clock that is used by the pipeline in @media.
2433  *
2434  * @media must be prepared before this method returns a valid clock object.
2435  *
2436  * Returns: (transfer full): the #GstClock used by @media. unref after usage.
2437  */
2438 GstClock *
2439 gst_rtsp_media_get_clock (GstRTSPMedia * media)
2440 {
2441   GstClock *clock;
2442   GstRTSPMediaPrivate *priv;
2443
2444   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2445
2446   priv = media->priv;
2447
2448   g_rec_mutex_lock (&priv->state_lock);
2449   clock = get_clock_unlocked (media);
2450   g_rec_mutex_unlock (&priv->state_lock);
2451
2452   return clock;
2453 }
2454
2455 /**
2456  * gst_rtsp_media_get_base_time:
2457  * @media: a #GstRTSPMedia
2458  *
2459  * Get the base_time that is used by the pipeline in @media.
2460  *
2461  * @media must be prepared before this method returns a valid base_time.
2462  *
2463  * Returns: the base_time used by @media.
2464  */
2465 GstClockTime
2466 gst_rtsp_media_get_base_time (GstRTSPMedia * media)
2467 {
2468   GstClockTime result;
2469   GstRTSPMediaPrivate *priv;
2470
2471   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE);
2472
2473   priv = media->priv;
2474
2475   g_rec_mutex_lock (&priv->state_lock);
2476   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2477     goto not_prepared;
2478
2479   result = gst_element_get_base_time (media->priv->pipeline);
2480   g_rec_mutex_unlock (&priv->state_lock);
2481
2482   return result;
2483
2484   /* ERRORS */
2485 not_prepared:
2486   {
2487     g_rec_mutex_unlock (&priv->state_lock);
2488     GST_DEBUG_OBJECT (media, "media was not prepared");
2489     return GST_CLOCK_TIME_NONE;
2490   }
2491 }
2492
2493 /**
2494  * gst_rtsp_media_get_time_provider:
2495  * @media: a #GstRTSPMedia
2496  * @address: an address or %NULL
2497  * @port: a port or 0
2498  *
2499  * Get the #GstNetTimeProvider for the clock used by @media. The time provider
2500  * will listen on @address and @port for client time requests.
2501  *
2502  * Returns: (transfer full): the #GstNetTimeProvider of @media.
2503  */
2504 GstNetTimeProvider *
2505 gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
2506     guint16 port)
2507 {
2508   GstRTSPMediaPrivate *priv;
2509   GstNetTimeProvider *provider = NULL;
2510
2511   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2512
2513   priv = media->priv;
2514
2515   g_rec_mutex_lock (&priv->state_lock);
2516   if (priv->time_provider) {
2517     if ((provider = priv->nettime) == NULL) {
2518       GstClock *clock;
2519
2520       if (priv->time_provider && (clock = get_clock_unlocked (media))) {
2521         provider = gst_net_time_provider_new (clock, address, port);
2522         gst_object_unref (clock);
2523
2524         priv->nettime = provider;
2525       }
2526     }
2527   }
2528   g_rec_mutex_unlock (&priv->state_lock);
2529
2530   if (provider)
2531     gst_object_ref (provider);
2532
2533   return provider;
2534 }
2535
2536 static gboolean
2537 default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info)
2538 {
2539   return gst_rtsp_sdp_from_media (sdp, info, media);
2540 }
2541
2542 /**
2543  * gst_rtsp_media_setup_sdp:
2544  * @sdp: a #GstSDPMessage
2545  * @info: info
2546  * @media: a #GstRTSPMedia
2547  *
2548  * Add @media specific info to @sdp. @info is used to configure the connection
2549  * information in the SDP.
2550  *
2551  * Returns: TRUE on success.
2552  */
2553 gboolean
2554 gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
2555     GstSDPInfo * info)
2556 {
2557   GstRTSPMediaPrivate *priv;
2558   GstRTSPMediaClass *klass;
2559   gboolean res;
2560
2561   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2562   g_return_val_if_fail (sdp != NULL, FALSE);
2563   g_return_val_if_fail (info != NULL, FALSE);
2564
2565   priv = media->priv;
2566
2567   g_rec_mutex_lock (&priv->state_lock);
2568
2569   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2570
2571   if (!klass->setup_sdp)
2572     goto no_setup_sdp;
2573
2574   res = klass->setup_sdp (media, sdp, info);
2575
2576   g_rec_mutex_unlock (&priv->state_lock);
2577
2578   return res;
2579
2580   /* ERRORS */
2581 no_setup_sdp:
2582   {
2583     g_rec_mutex_unlock (&priv->state_lock);
2584     GST_ERROR ("no setup_sdp function");
2585     g_critical ("no setup_sdp vmethod function set");
2586     return FALSE;
2587   }
2588 }
2589
2590 /**
2591  * gst_rtsp_media_suspend:
2592  * @media: a #GstRTSPMedia
2593  *
2594  * Suspend @media. The state of the pipeline managed by @media is set to
2595  * GST_STATE_NULL but all streams are kept. @media can be prepared again
2596  * with gst_rtsp_media_undo_reset()
2597  *
2598  * @media must be prepared with gst_rtsp_media_prepare();
2599  *
2600  * Returns: %TRUE on success.
2601  */
2602 gboolean
2603 gst_rtsp_media_suspend (GstRTSPMedia * media)
2604 {
2605   GstRTSPMediaPrivate *priv = media->priv;
2606   GstStateChangeReturn ret;
2607
2608   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2609
2610   GST_FIXME ("suspend for dynamic pipelines needs fixing");
2611
2612   g_rec_mutex_lock (&priv->state_lock);
2613   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2614     goto not_prepared;
2615
2616   /* don't attempt to suspend when something is busy */
2617   if (priv->n_active > 0)
2618     goto done;
2619
2620   switch (priv->suspend_mode) {
2621     case GST_RTSP_SUSPEND_MODE_NONE:
2622       GST_DEBUG ("media %p no suspend", media);
2623       break;
2624     case GST_RTSP_SUSPEND_MODE_PAUSE:
2625       GST_DEBUG ("media %p suspend to PAUSED", media);
2626       ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
2627       if (ret == GST_STATE_CHANGE_FAILURE)
2628         goto state_failed;
2629       break;
2630     case GST_RTSP_SUSPEND_MODE_RESET:
2631       GST_DEBUG ("media %p suspend to NULL", media);
2632       ret = set_target_state (media, GST_STATE_NULL, TRUE);
2633       if (ret == GST_STATE_CHANGE_FAILURE)
2634         goto state_failed;
2635       break;
2636     default:
2637       break;
2638   }
2639   /* let the streams do the state changes freely, if any */
2640   media_streams_set_blocked (media, FALSE);
2641   priv->status = GST_RTSP_MEDIA_STATUS_SUSPENDED;
2642 done:
2643   g_rec_mutex_unlock (&priv->state_lock);
2644
2645   return TRUE;
2646
2647   /* ERRORS */
2648 not_prepared:
2649   {
2650     g_rec_mutex_unlock (&priv->state_lock);
2651     GST_WARNING ("media %p was not prepared", media);
2652     return FALSE;
2653   }
2654 state_failed:
2655   {
2656     g_rec_mutex_unlock (&priv->state_lock);
2657     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2658     GST_WARNING ("failed changing pipeline's state for media %p", media);
2659     return FALSE;
2660   }
2661 }
2662
2663 /**
2664  * gst_rtsp_media_unsuspend:
2665  * @media: a #GstRTSPMedia
2666  *
2667  * Unsuspend @media if it was in a suspended state. This method does nothing
2668  * when the media was not in the suspended state.
2669  *
2670  * Returns: %TRUE on success.
2671  */
2672 gboolean
2673 gst_rtsp_media_unsuspend (GstRTSPMedia * media)
2674 {
2675   GstRTSPMediaPrivate *priv = media->priv;
2676
2677   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2678
2679   g_rec_mutex_lock (&priv->state_lock);
2680   if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
2681     goto done;
2682
2683   switch (priv->suspend_mode) {
2684     case GST_RTSP_SUSPEND_MODE_NONE:
2685       priv->status = GST_RTSP_MEDIA_STATUS_PREPARED;
2686       break;
2687     case GST_RTSP_SUSPEND_MODE_PAUSE:
2688       priv->status = GST_RTSP_MEDIA_STATUS_PREPARED;
2689       break;
2690     case GST_RTSP_SUSPEND_MODE_RESET:
2691     {
2692       priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
2693       if (!start_preroll (media))
2694         goto start_failed;
2695       g_rec_mutex_unlock (&priv->state_lock);
2696
2697       if (!wait_preroll (media))
2698         goto preroll_failed;
2699
2700       g_rec_mutex_lock (&priv->state_lock);
2701     }
2702     default:
2703       break;
2704   }
2705 done:
2706   g_rec_mutex_unlock (&priv->state_lock);
2707
2708   return TRUE;
2709
2710   /* ERRORS */
2711 start_failed:
2712   {
2713     g_rec_mutex_unlock (&priv->state_lock);
2714     GST_WARNING ("failed to preroll pipeline");
2715     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2716     return FALSE;
2717   }
2718 preroll_failed:
2719   {
2720     GST_WARNING ("failed to preroll pipeline");
2721     return FALSE;
2722   }
2723 }
2724
2725 /* must be called with state-lock */
2726 static void
2727 media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
2728 {
2729   GstRTSPMediaPrivate *priv = media->priv;
2730
2731   if (state == GST_STATE_NULL) {
2732     gst_rtsp_media_unprepare (media);
2733   } else {
2734     GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
2735     set_target_state (media, state, FALSE);
2736     /* when we are buffering, don't update the state yet, this will be done
2737      * when buffering finishes */
2738     if (priv->buffering) {
2739       GST_INFO ("Buffering busy, delay state change");
2740     } else {
2741       if (state == GST_STATE_PLAYING)
2742         /* make sure pads are not blocking anymore when going to PLAYING */
2743         media_streams_set_blocked (media, FALSE);
2744
2745       set_state (media, state);
2746
2747       /* and suspend after pause */
2748       if (state == GST_STATE_PAUSED)
2749         gst_rtsp_media_suspend (media);
2750     }
2751   }
2752 }
2753
2754 /**
2755  * gst_rtsp_media_set_pipeline_state:
2756  * @media: a #GstRTSPMedia
2757  * @state: the target state of the pipeline
2758  *
2759  * Set the state of the pipeline managed by @media to @state
2760  */
2761 void
2762 gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state)
2763 {
2764   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
2765
2766   g_rec_mutex_lock (&media->priv->state_lock);
2767   media_set_pipeline_state_locked (media, state);
2768   g_rec_mutex_unlock (&media->priv->state_lock);
2769 }
2770
2771 /**
2772  * gst_rtsp_media_set_state:
2773  * @media: a #GstRTSPMedia
2774  * @state: the target state of the media
2775  * @transports: (element-type GstRtspServer.RTSPStreamTransport): a #GPtrArray
2776  * of #GstRTSPStreamTransport pointers
2777  *
2778  * Set the state of @media to @state and for the transports in @transports.
2779  *
2780  * @media must be prepared with gst_rtsp_media_prepare();
2781  *
2782  * Returns: %TRUE on success.
2783  */
2784 gboolean
2785 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
2786     GPtrArray * transports)
2787 {
2788   GstRTSPMediaPrivate *priv;
2789   gint i;
2790   gboolean activate, deactivate, do_state;
2791   gint old_active;
2792
2793   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2794   g_return_val_if_fail (transports != NULL, FALSE);
2795
2796   priv = media->priv;
2797
2798   g_rec_mutex_lock (&priv->state_lock);
2799   if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR)
2800     goto error_status;
2801   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
2802       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
2803     goto not_prepared;
2804
2805   /* NULL and READY are the same */
2806   if (state == GST_STATE_READY)
2807     state = GST_STATE_NULL;
2808
2809   activate = deactivate = FALSE;
2810
2811   GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
2812       media);
2813
2814   switch (state) {
2815     case GST_STATE_NULL:
2816     case GST_STATE_PAUSED:
2817       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
2818       if (priv->target_state == GST_STATE_PLAYING)
2819         deactivate = TRUE;
2820       break;
2821     case GST_STATE_PLAYING:
2822       /* we're going to PLAYING, activate */
2823       activate = TRUE;
2824       break;
2825     default:
2826       break;
2827   }
2828   old_active = priv->n_active;
2829
2830   for (i = 0; i < transports->len; i++) {
2831     GstRTSPStreamTransport *trans;
2832
2833     /* we need a non-NULL entry in the array */
2834     trans = g_ptr_array_index (transports, i);
2835     if (trans == NULL)
2836       continue;
2837
2838     if (activate) {
2839       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
2840         priv->n_active++;
2841     } else if (deactivate) {
2842       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
2843         priv->n_active--;
2844     }
2845   }
2846
2847   /* we just activated the first media, do the playing state change */
2848   if (old_active == 0 && activate)
2849     do_state = TRUE;
2850   /* if we have no more active media, do the downward state changes */
2851   else if (priv->n_active == 0)
2852     do_state = TRUE;
2853   else
2854     do_state = FALSE;
2855
2856   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
2857       media, do_state);
2858
2859   if (priv->target_state != state) {
2860     if (do_state)
2861       media_set_pipeline_state_locked (media, state);
2862
2863     g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2864         NULL);
2865   }
2866
2867   /* remember where we are */
2868   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
2869           old_active != priv->n_active))
2870     collect_media_stats (media);
2871
2872   g_rec_mutex_unlock (&priv->state_lock);
2873
2874   return TRUE;
2875
2876   /* ERRORS */
2877 not_prepared:
2878   {
2879     GST_WARNING ("media %p was not prepared", media);
2880     g_rec_mutex_unlock (&priv->state_lock);
2881     return FALSE;
2882   }
2883 error_status:
2884   {
2885     GST_WARNING ("media %p in error status while changing to state %d",
2886         media, state);
2887     if (state == GST_STATE_NULL) {
2888       for (i = 0; i < transports->len; i++) {
2889         GstRTSPStreamTransport *trans;
2890
2891         /* we need a non-NULL entry in the array */
2892         trans = g_ptr_array_index (transports, i);
2893         if (trans == NULL)
2894           continue;
2895
2896         gst_rtsp_stream_transport_set_active (trans, FALSE);
2897       }
2898       priv->n_active = 0;
2899     }
2900     g_rec_mutex_unlock (&priv->state_lock);
2901     return FALSE;
2902   }
2903 }