159dd3d447201f7ec53faaf3553e4c98c6a18568
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-media.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  * Copyright (C) 2015 Centricular Ltd
4  *     Author: Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:rtsp-media
23  * @short_description: The media pipeline
24  * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession,
25  *     #GstRTSPSessionMedia
26  *
27  * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the
28  * streaming to the clients. The actual data transfer is done by the
29  * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
30  *
31  * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the
32  * client does a DESCRIBE or SETUP of a resource.
33  *
34  * A media is created with gst_rtsp_media_new() that takes the element that will
35  * provide the streaming elements. For each of the streams, a new #GstRTSPStream
36  * object needs to be made with the gst_rtsp_media_create_stream() which takes
37  * the payloader element and the source pad that produces the RTP stream.
38  *
39  * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The
40  * prepare method will add rtpbin and sinks and sources to send and receive RTP
41  * and RTCP packets from the clients. Each stream srcpad is connected to an
42  * input into the internal rtpbin.
43  *
44  * It is also possible to dynamically create #GstRTSPStream objects during the
45  * prepare phase. With gst_rtsp_media_get_status() you can check the status of
46  * the prepare phase.
47  *
48  * After the media is prepared, it is ready for streaming. It will usually be
49  * managed in a session with gst_rtsp_session_manage_media(). See
50  * #GstRTSPSession and #GstRTSPSessionMedia.
51  *
52  * The state of the media can be controlled with gst_rtsp_media_set_state ().
53  * Seeking can be done with gst_rtsp_media_seek().
54  *
55  * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
56  * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
57  * cleanly shut down.
58  *
59  * With gst_rtsp_media_set_shared(), the media can be shared between multiple
60  * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline
61  * can be prepared again after an unprepare.
62  *
63  * Last reviewed on 2013-07-11 (1.0.0)
64  */
65
66 #include <stdio.h>
67 #include <string.h>
68 #include <stdlib.h>
69
70 #include <gst/app/gstappsrc.h>
71 #include <gst/app/gstappsink.h>
72
73 #include <gst/sdp/gstmikey.h>
74 #include <gst/rtp/gstrtppayloads.h>
75
76 #define AES_128_KEY_LEN 16
77 #define AES_256_KEY_LEN 32
78
79 #define HMAC_32_KEY_LEN 4
80 #define HMAC_80_KEY_LEN 10
81
82 #include "rtsp-media.h"
83
84 #define GST_RTSP_MEDIA_GET_PRIVATE(obj)  \
85      (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate))
86
87 struct _GstRTSPMediaPrivate
88 {
89   GMutex lock;
90   GCond cond;
91
92   /* protected by lock */
93   GstRTSPPermissions *permissions;
94   gboolean shared;
95   gboolean suspend_mode;
96   gboolean reusable;
97   GstRTSPProfile profiles;
98   GstRTSPLowerTrans protocols;
99   gboolean reused;
100   gboolean eos_shutdown;
101   guint buffer_size;
102   GstRTSPAddressPool *pool;
103   gchar *multicast_iface;
104   gboolean blocked;
105   GstRTSPTransportMode transport_mode;
106   gboolean stop_on_disconnect;
107
108   GstElement *element;
109   GRecMutex state_lock;         /* locking order: state lock, lock */
110   GPtrArray *streams;           /* protected by lock */
111   GList *dynamic;               /* protected by lock */
112   GstRTSPMediaStatus status;    /* protected by lock */
113   gint prepare_count;
114   gint n_active;
115   gboolean adding;
116
117   /* the pipeline for the media */
118   GstElement *pipeline;
119   GstElement *fakesink;         /* protected by lock */
120   GSource *source;
121   guint id;
122   GstRTSPThread *thread;
123
124   gboolean time_provider;
125   GstNetTimeProvider *nettime;
126
127   gboolean is_live;
128   GstClockTimeDiff seekable;
129   gboolean buffering;
130   GstState target_state;
131
132   /* RTP session manager */
133   GstElement *rtpbin;
134
135   /* the range of media */
136   GstRTSPTimeRange range;       /* protected by lock */
137   GstClockTime range_start;
138   GstClockTime range_stop;
139
140   GList *payloads;              /* protected by lock */
141   GstClockTime rtx_time;        /* protected by lock */
142   guint latency;                /* protected by lock */
143   GstClock *clock;              /* protected by lock */
144   GstRTSPPublishClockMode publish_clock_mode;
145 };
146
147 #define DEFAULT_SHARED          FALSE
148 #define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
149 #define DEFAULT_REUSABLE        FALSE
150 #define DEFAULT_PROFILES        GST_RTSP_PROFILE_AVP
151 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
152                                         GST_RTSP_LOWER_TRANS_TCP
153 #define DEFAULT_EOS_SHUTDOWN    FALSE
154 #define DEFAULT_BUFFER_SIZE     0x80000
155 #define DEFAULT_TIME_PROVIDER   FALSE
156 #define DEFAULT_LATENCY         200
157 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
158 #define DEFAULT_STOP_ON_DISCONNECT TRUE
159
160 /* define to dump received RTCP packets */
161 #undef DUMP_STATS
162
163 enum
164 {
165   PROP_0,
166   PROP_SHARED,
167   PROP_SUSPEND_MODE,
168   PROP_REUSABLE,
169   PROP_PROFILES,
170   PROP_PROTOCOLS,
171   PROP_EOS_SHUTDOWN,
172   PROP_BUFFER_SIZE,
173   PROP_ELEMENT,
174   PROP_TIME_PROVIDER,
175   PROP_LATENCY,
176   PROP_TRANSPORT_MODE,
177   PROP_STOP_ON_DISCONNECT,
178   PROP_CLOCK,
179   PROP_LAST
180 };
181
182 enum
183 {
184   SIGNAL_NEW_STREAM,
185   SIGNAL_REMOVED_STREAM,
186   SIGNAL_PREPARED,
187   SIGNAL_UNPREPARED,
188   SIGNAL_TARGET_STATE,
189   SIGNAL_NEW_STATE,
190   SIGNAL_LAST
191 };
192
193 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
194 #define GST_CAT_DEFAULT rtsp_media_debug
195
196 static void gst_rtsp_media_get_property (GObject * object, guint propid,
197     GValue * value, GParamSpec * pspec);
198 static void gst_rtsp_media_set_property (GObject * object, guint propid,
199     const GValue * value, GParamSpec * pspec);
200 static void gst_rtsp_media_finalize (GObject * obj);
201
202 static gboolean default_handle_message (GstRTSPMedia * media,
203     GstMessage * message);
204 static void finish_unprepare (GstRTSPMedia * media);
205 static gboolean default_prepare (GstRTSPMedia * media, GstRTSPThread * thread);
206 static gboolean default_unprepare (GstRTSPMedia * media);
207 static gboolean default_suspend (GstRTSPMedia * media);
208 static gboolean default_unsuspend (GstRTSPMedia * media);
209 static gboolean default_convert_range (GstRTSPMedia * media,
210     GstRTSPTimeRange * range, GstRTSPRangeUnit unit);
211 static gboolean default_query_position (GstRTSPMedia * media,
212     gint64 * position);
213 static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop);
214 static GstElement *default_create_rtpbin (GstRTSPMedia * media);
215 static gboolean default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
216     GstSDPInfo * info);
217 static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp);
218
219 static gboolean wait_preroll (GstRTSPMedia * media);
220
221 static GstElement *find_payload_element (GstElement * payloader);
222
223 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
224
225 #define C_ENUM(v) ((gint) v)
226
227 GType
228 gst_rtsp_suspend_mode_get_type (void)
229 {
230   static gsize id = 0;
231   static const GEnumValue values[] = {
232     {C_ENUM (GST_RTSP_SUSPEND_MODE_NONE), "GST_RTSP_SUSPEND_MODE_NONE", "none"},
233     {C_ENUM (GST_RTSP_SUSPEND_MODE_PAUSE), "GST_RTSP_SUSPEND_MODE_PAUSE",
234         "pause"},
235     {C_ENUM (GST_RTSP_SUSPEND_MODE_RESET), "GST_RTSP_SUSPEND_MODE_RESET",
236         "reset"},
237     {0, NULL, NULL}
238   };
239
240   if (g_once_init_enter (&id)) {
241     GType tmp = g_enum_register_static ("GstRTSPSuspendMode", values);
242     g_once_init_leave (&id, tmp);
243   }
244   return (GType) id;
245 }
246
247 #define C_FLAGS(v) ((guint) v)
248
249 GType
250 gst_rtsp_transport_mode_get_type (void)
251 {
252   static gsize id = 0;
253   static const GFlagsValue values[] = {
254     {C_FLAGS (GST_RTSP_TRANSPORT_MODE_PLAY), "GST_RTSP_TRANSPORT_MODE_PLAY",
255         "play"},
256     {C_FLAGS (GST_RTSP_TRANSPORT_MODE_RECORD), "GST_RTSP_TRANSPORT_MODE_RECORD",
257         "record"},
258     {0, NULL, NULL}
259   };
260
261   if (g_once_init_enter (&id)) {
262     GType tmp = g_flags_register_static ("GstRTSPTransportMode", values);
263     g_once_init_leave (&id, tmp);
264   }
265   return (GType) id;
266 }
267
268 GType
269 gst_rtsp_publish_clock_mode_get_type (void)
270 {
271   static gsize id = 0;
272   static const GEnumValue values[] = {
273     {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_NONE),
274         "GST_RTSP_PUBLISH_CLOCK_MODE_NONE", "none"},
275     {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK),
276           "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK",
277         "clock"},
278     {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET),
279           "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET",
280         "clock-and-offset"},
281     {0, NULL, NULL}
282   };
283
284   if (g_once_init_enter (&id)) {
285     GType tmp = g_enum_register_static ("GstRTSPPublishClockMode", values);
286     g_once_init_leave (&id, tmp);
287   }
288   return (GType) id;
289 }
290
291 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
292
293 static void
294 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
295 {
296   GObjectClass *gobject_class;
297
298   g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate));
299
300   gobject_class = G_OBJECT_CLASS (klass);
301
302   gobject_class->get_property = gst_rtsp_media_get_property;
303   gobject_class->set_property = gst_rtsp_media_set_property;
304   gobject_class->finalize = gst_rtsp_media_finalize;
305
306   g_object_class_install_property (gobject_class, PROP_SHARED,
307       g_param_spec_boolean ("shared", "Shared",
308           "If this media pipeline can be shared", DEFAULT_SHARED,
309           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310
311   g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
312       g_param_spec_enum ("suspend-mode", "Suspend Mode",
313           "How to suspend the media in PAUSED", GST_TYPE_RTSP_SUSPEND_MODE,
314           DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
315
316   g_object_class_install_property (gobject_class, PROP_REUSABLE,
317       g_param_spec_boolean ("reusable", "Reusable",
318           "If this media pipeline can be reused after an unprepare",
319           DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320
321   g_object_class_install_property (gobject_class, PROP_PROFILES,
322       g_param_spec_flags ("profiles", "Profiles",
323           "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE,
324           DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
325
326   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
327       g_param_spec_flags ("protocols", "Protocols",
328           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
329           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
330
331   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
332       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
333           "Send an EOS event to the pipeline before unpreparing",
334           DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
335
336   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
337       g_param_spec_uint ("buffer-size", "Buffer Size",
338           "The kernel UDP buffer size to use", 0, G_MAXUINT,
339           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
340
341   g_object_class_install_property (gobject_class, PROP_ELEMENT,
342       g_param_spec_object ("element", "The Element",
343           "The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
344           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
345
346   g_object_class_install_property (gobject_class, PROP_TIME_PROVIDER,
347       g_param_spec_boolean ("time-provider", "Time Provider",
348           "Use a NetTimeProvider for clients",
349           DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
350
351   g_object_class_install_property (gobject_class, PROP_LATENCY,
352       g_param_spec_uint ("latency", "Latency",
353           "Latency used for receiving media in milliseconds", 0, G_MAXUINT,
354           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
355
356   g_object_class_install_property (gobject_class, PROP_TRANSPORT_MODE,
357       g_param_spec_flags ("transport-mode", "Transport Mode",
358           "If this media pipeline can be used for PLAY or RECORD",
359           GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
360           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
361
362   g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT,
363       g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect",
364           "If this media pipeline should be stopped "
365           "when a client disconnects without TEARDOWN",
366           DEFAULT_STOP_ON_DISCONNECT,
367           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
368
369   g_object_class_install_property (gobject_class, PROP_CLOCK,
370       g_param_spec_object ("clock", "Clock",
371           "Clock to be used by the media pipeline",
372           GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373
374   gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
375       g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
376       G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
377       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM);
378
379   gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM] =
380       g_signal_new ("removed-stream", G_TYPE_FROM_CLASS (klass),
381       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, removed_stream),
382       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
383       GST_TYPE_RTSP_STREAM);
384
385   gst_rtsp_media_signals[SIGNAL_PREPARED] =
386       g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
387       G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
388       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
389
390   gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
391       g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
392       G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
393       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
394
395   gst_rtsp_media_signals[SIGNAL_TARGET_STATE] =
396       g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass),
397       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, target_state),
398       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
399
400   gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
401       g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
402       G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
403       g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
404
405   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
406
407   klass->handle_message = default_handle_message;
408   klass->prepare = default_prepare;
409   klass->unprepare = default_unprepare;
410   klass->suspend = default_suspend;
411   klass->unsuspend = default_unsuspend;
412   klass->convert_range = default_convert_range;
413   klass->query_position = default_query_position;
414   klass->query_stop = default_query_stop;
415   klass->create_rtpbin = default_create_rtpbin;
416   klass->setup_sdp = default_setup_sdp;
417   klass->handle_sdp = default_handle_sdp;
418 }
419
420 static void
421 gst_rtsp_media_init (GstRTSPMedia * media)
422 {
423   GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media);
424
425   media->priv = priv;
426
427   priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
428   g_mutex_init (&priv->lock);
429   g_cond_init (&priv->cond);
430   g_rec_mutex_init (&priv->state_lock);
431
432   priv->shared = DEFAULT_SHARED;
433   priv->suspend_mode = DEFAULT_SUSPEND_MODE;
434   priv->reusable = DEFAULT_REUSABLE;
435   priv->profiles = DEFAULT_PROFILES;
436   priv->protocols = DEFAULT_PROTOCOLS;
437   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
438   priv->buffer_size = DEFAULT_BUFFER_SIZE;
439   priv->time_provider = DEFAULT_TIME_PROVIDER;
440   priv->transport_mode = DEFAULT_TRANSPORT_MODE;
441   priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
442   priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
443 }
444
445 static void
446 gst_rtsp_media_finalize (GObject * obj)
447 {
448   GstRTSPMediaPrivate *priv;
449   GstRTSPMedia *media;
450
451   media = GST_RTSP_MEDIA (obj);
452   priv = media->priv;
453
454   GST_INFO ("finalize media %p", media);
455
456   if (priv->permissions)
457     gst_rtsp_permissions_unref (priv->permissions);
458
459   g_ptr_array_unref (priv->streams);
460
461   g_list_free_full (priv->dynamic, gst_object_unref);
462
463   if (priv->pipeline)
464     gst_object_unref (priv->pipeline);
465   if (priv->nettime)
466     gst_object_unref (priv->nettime);
467   gst_object_unref (priv->element);
468   if (priv->pool)
469     g_object_unref (priv->pool);
470   if (priv->payloads)
471     g_list_free (priv->payloads);
472   g_free (priv->multicast_iface);
473   g_mutex_clear (&priv->lock);
474   g_cond_clear (&priv->cond);
475   g_rec_mutex_clear (&priv->state_lock);
476
477   G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
478 }
479
480 static void
481 gst_rtsp_media_get_property (GObject * object, guint propid,
482     GValue * value, GParamSpec * pspec)
483 {
484   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
485
486   switch (propid) {
487     case PROP_ELEMENT:
488       g_value_set_object (value, media->priv->element);
489       break;
490     case PROP_SHARED:
491       g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
492       break;
493     case PROP_SUSPEND_MODE:
494       g_value_set_enum (value, gst_rtsp_media_get_suspend_mode (media));
495       break;
496     case PROP_REUSABLE:
497       g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
498       break;
499     case PROP_PROFILES:
500       g_value_set_flags (value, gst_rtsp_media_get_profiles (media));
501       break;
502     case PROP_PROTOCOLS:
503       g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
504       break;
505     case PROP_EOS_SHUTDOWN:
506       g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
507       break;
508     case PROP_BUFFER_SIZE:
509       g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
510       break;
511     case PROP_TIME_PROVIDER:
512       g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media));
513       break;
514     case PROP_LATENCY:
515       g_value_set_uint (value, gst_rtsp_media_get_latency (media));
516       break;
517     case PROP_TRANSPORT_MODE:
518       g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media));
519       break;
520     case PROP_STOP_ON_DISCONNECT:
521       g_value_set_boolean (value, gst_rtsp_media_is_stop_on_disconnect (media));
522       break;
523     case PROP_CLOCK:
524       g_value_take_object (value, gst_rtsp_media_get_clock (media));
525       break;
526     default:
527       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
528   }
529 }
530
531 static void
532 gst_rtsp_media_set_property (GObject * object, guint propid,
533     const GValue * value, GParamSpec * pspec)
534 {
535   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
536
537   switch (propid) {
538     case PROP_ELEMENT:
539       media->priv->element = g_value_get_object (value);
540       gst_object_ref_sink (media->priv->element);
541       break;
542     case PROP_SHARED:
543       gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
544       break;
545     case PROP_SUSPEND_MODE:
546       gst_rtsp_media_set_suspend_mode (media, g_value_get_enum (value));
547       break;
548     case PROP_REUSABLE:
549       gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
550       break;
551     case PROP_PROFILES:
552       gst_rtsp_media_set_profiles (media, g_value_get_flags (value));
553       break;
554     case PROP_PROTOCOLS:
555       gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
556       break;
557     case PROP_EOS_SHUTDOWN:
558       gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
559       break;
560     case PROP_BUFFER_SIZE:
561       gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
562       break;
563     case PROP_TIME_PROVIDER:
564       gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value));
565       break;
566     case PROP_LATENCY:
567       gst_rtsp_media_set_latency (media, g_value_get_uint (value));
568       break;
569     case PROP_TRANSPORT_MODE:
570       gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value));
571       break;
572     case PROP_STOP_ON_DISCONNECT:
573       gst_rtsp_media_set_stop_on_disconnect (media,
574           g_value_get_boolean (value));
575       break;
576     case PROP_CLOCK:
577       gst_rtsp_media_set_clock (media, g_value_get_object (value));
578       break;
579     default:
580       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
581   }
582 }
583
584 typedef struct
585 {
586   gint64 position;
587   gboolean ret;
588 } DoQueryPositionData;
589
590 static void
591 do_query_position (GstRTSPStream * stream, DoQueryPositionData * data)
592 {
593   gint64 tmp;
594
595   if (gst_rtsp_stream_query_position (stream, &tmp)) {
596     data->position = MIN (data->position, tmp);
597     data->ret = TRUE;
598   }
599
600   GST_INFO_OBJECT (stream, "media position: %" GST_TIME_FORMAT,
601       GST_TIME_ARGS (data->position));
602 }
603
604 static gboolean
605 default_query_position (GstRTSPMedia * media, gint64 * position)
606 {
607   GstRTSPMediaPrivate *priv;
608   DoQueryPositionData data;
609
610   priv = media->priv;
611
612   data.position = G_MAXINT64;
613   data.ret = FALSE;
614
615   g_ptr_array_foreach (priv->streams, (GFunc) do_query_position, &data);
616
617   if (!data.ret)
618     *position = GST_CLOCK_TIME_NONE;
619   else
620     *position = data.position;
621
622   return data.ret;
623 }
624
625 typedef struct
626 {
627   gint64 stop;
628   gboolean ret;
629 } DoQueryStopData;
630
631 static void
632 do_query_stop (GstRTSPStream * stream, DoQueryStopData * data)
633 {
634   gint64 tmp = 0;
635
636   if (gst_rtsp_stream_query_stop (stream, &tmp)) {
637     data->stop = MAX (data->stop, tmp);
638     data->ret = TRUE;
639   }
640 }
641
642 static gboolean
643 default_query_stop (GstRTSPMedia * media, gint64 * stop)
644 {
645   GstRTSPMediaPrivate *priv;
646   DoQueryStopData data;
647
648   priv = media->priv;
649
650   data.stop = -1;
651   data.ret = FALSE;
652
653   g_ptr_array_foreach (priv->streams, (GFunc) do_query_stop, &data);
654
655   *stop = data.stop;
656
657   return data.ret;
658 }
659
660 static GstElement *
661 default_create_rtpbin (GstRTSPMedia * media)
662 {
663   GstElement *rtpbin;
664
665   rtpbin = gst_element_factory_make ("rtpbin", NULL);
666
667   return rtpbin;
668 }
669
670 /* must be called with state lock */
671 static void
672 check_seekable (GstRTSPMedia * media)
673 {
674   GstQuery *query;
675   GstRTSPMediaPrivate *priv = media->priv;
676
677   /* Update the seekable state of the pipeline in case it changed */
678   if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) {
679     /* TODO: Seeking for RECORD? */
680     priv->seekable = -1;
681   } else {
682     guint i, n = priv->streams->len;
683
684     for (i = 0; i < n; i++) {
685       GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
686
687       if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
688           GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) {
689         priv->seekable = -1;
690         return;
691       }
692     }
693   }
694
695   query = gst_query_new_seeking (GST_FORMAT_TIME);
696   if (gst_element_query (priv->pipeline, query)) {
697     GstFormat format;
698     gboolean seekable;
699     gint64 start, end;
700
701     gst_query_parse_seeking (query, &format, &seekable, &start, &end);
702     priv->seekable = seekable ? G_MAXINT64 : 0.0;
703   }
704
705   gst_query_unref (query);
706 }
707
708
709 /* must be called with state lock */
710 static void
711 collect_media_stats (GstRTSPMedia * media)
712 {
713   GstRTSPMediaPrivate *priv = media->priv;
714   gint64 position = 0, stop = -1;
715
716   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
717       priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
718     return;
719
720   priv->range.unit = GST_RTSP_RANGE_NPT;
721
722   GST_INFO ("collect media stats");
723
724   if (priv->is_live) {
725     priv->range.min.type = GST_RTSP_TIME_NOW;
726     priv->range.min.seconds = -1;
727     priv->range_start = -1;
728     priv->range.max.type = GST_RTSP_TIME_END;
729     priv->range.max.seconds = -1;
730     priv->range_stop = -1;
731   } else {
732     GstRTSPMediaClass *klass;
733     gboolean ret;
734
735     klass = GST_RTSP_MEDIA_GET_CLASS (media);
736
737     /* get the position */
738     ret = FALSE;
739     if (klass->query_position)
740       ret = klass->query_position (media, &position);
741
742     if (!ret) {
743       GST_INFO ("position query failed");
744       position = 0;
745     }
746
747     /* get the current segment stop */
748     ret = FALSE;
749     if (klass->query_stop)
750       ret = klass->query_stop (media, &stop);
751
752     if (!ret) {
753       GST_INFO ("stop query failed");
754       stop = -1;
755     }
756
757     GST_INFO ("stats: position %" GST_TIME_FORMAT ", stop %"
758         GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (stop));
759
760     if (position == -1) {
761       priv->range.min.type = GST_RTSP_TIME_NOW;
762       priv->range.min.seconds = -1;
763       priv->range_start = -1;
764     } else {
765       priv->range.min.type = GST_RTSP_TIME_SECONDS;
766       priv->range.min.seconds = ((gdouble) position) / GST_SECOND;
767       priv->range_start = position;
768     }
769     if (stop == -1) {
770       priv->range.max.type = GST_RTSP_TIME_END;
771       priv->range.max.seconds = -1;
772       priv->range_stop = -1;
773     } else {
774       priv->range.max.type = GST_RTSP_TIME_SECONDS;
775       priv->range.max.seconds = ((gdouble) stop) / GST_SECOND;
776       priv->range_stop = stop;
777     }
778
779     check_seekable (media);
780   }
781 }
782
783 /**
784  * gst_rtsp_media_new:
785  * @element: (transfer full): a #GstElement
786  *
787  * Create a new #GstRTSPMedia instance. @element is the bin element that
788  * provides the different streams. The #GstRTSPMedia object contains the
789  * element to produce RTP data for one or more related (audio/video/..)
790  * streams.
791  *
792  * Ownership is taken of @element.
793  *
794  * Returns: (transfer full): a new #GstRTSPMedia object.
795  */
796 GstRTSPMedia *
797 gst_rtsp_media_new (GstElement * element)
798 {
799   GstRTSPMedia *result;
800
801   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
802
803   result = g_object_new (GST_TYPE_RTSP_MEDIA, "element", element, NULL);
804
805   return result;
806 }
807
808 /**
809  * gst_rtsp_media_get_element:
810  * @media: a #GstRTSPMedia
811  *
812  * Get the element that was used when constructing @media.
813  *
814  * Returns: (transfer full): a #GstElement. Unref after usage.
815  */
816 GstElement *
817 gst_rtsp_media_get_element (GstRTSPMedia * media)
818 {
819   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
820
821   return gst_object_ref (media->priv->element);
822 }
823
824 /**
825  * gst_rtsp_media_take_pipeline:
826  * @media: a #GstRTSPMedia
827  * @pipeline: (transfer full): a #GstPipeline
828  *
829  * Set @pipeline as the #GstPipeline for @media. Ownership is
830  * taken of @pipeline.
831  */
832 void
833 gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
834 {
835   GstRTSPMediaPrivate *priv;
836   GstElement *old;
837   GstNetTimeProvider *nettime;
838
839   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
840   g_return_if_fail (GST_IS_PIPELINE (pipeline));
841
842   priv = media->priv;
843
844   g_mutex_lock (&priv->lock);
845   old = priv->pipeline;
846   priv->pipeline = GST_ELEMENT_CAST (pipeline);
847   nettime = priv->nettime;
848   priv->nettime = NULL;
849   g_mutex_unlock (&priv->lock);
850
851   if (old)
852     gst_object_unref (old);
853
854   if (nettime)
855     gst_object_unref (nettime);
856
857   gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
858 }
859
860 /**
861  * gst_rtsp_media_set_permissions:
862  * @media: a #GstRTSPMedia
863  * @permissions: (transfer none): a #GstRTSPPermissions
864  *
865  * Set @permissions on @media.
866  */
867 void
868 gst_rtsp_media_set_permissions (GstRTSPMedia * media,
869     GstRTSPPermissions * permissions)
870 {
871   GstRTSPMediaPrivate *priv;
872
873   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
874
875   priv = media->priv;
876
877   g_mutex_lock (&priv->lock);
878   if (priv->permissions)
879     gst_rtsp_permissions_unref (priv->permissions);
880   if ((priv->permissions = permissions))
881     gst_rtsp_permissions_ref (permissions);
882   g_mutex_unlock (&priv->lock);
883 }
884
885 /**
886  * gst_rtsp_media_get_permissions:
887  * @media: a #GstRTSPMedia
888  *
889  * Get the permissions object from @media.
890  *
891  * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage.
892  */
893 GstRTSPPermissions *
894 gst_rtsp_media_get_permissions (GstRTSPMedia * media)
895 {
896   GstRTSPMediaPrivate *priv;
897   GstRTSPPermissions *result;
898
899   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
900
901   priv = media->priv;
902
903   g_mutex_lock (&priv->lock);
904   if ((result = priv->permissions))
905     gst_rtsp_permissions_ref (result);
906   g_mutex_unlock (&priv->lock);
907
908   return result;
909 }
910
911 /**
912  * gst_rtsp_media_set_suspend_mode:
913  * @media: a #GstRTSPMedia
914  * @mode: the new #GstRTSPSuspendMode
915  *
916  * Control how @ media will be suspended after the SDP has been generated and
917  * after a PAUSE request has been performed.
918  *
919  * Media must be unprepared when setting the suspend mode.
920  */
921 void
922 gst_rtsp_media_set_suspend_mode (GstRTSPMedia * media, GstRTSPSuspendMode mode)
923 {
924   GstRTSPMediaPrivate *priv;
925
926   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
927
928   priv = media->priv;
929
930   g_rec_mutex_lock (&priv->state_lock);
931   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
932     goto was_prepared;
933   priv->suspend_mode = mode;
934   g_rec_mutex_unlock (&priv->state_lock);
935
936   return;
937
938   /* ERRORS */
939 was_prepared:
940   {
941     GST_WARNING ("media %p was prepared", media);
942     g_rec_mutex_unlock (&priv->state_lock);
943   }
944 }
945
946 /**
947  * gst_rtsp_media_get_suspend_mode:
948  * @media: a #GstRTSPMedia
949  *
950  * Get how @media will be suspended.
951  *
952  * Returns: #GstRTSPSuspendMode.
953  */
954 GstRTSPSuspendMode
955 gst_rtsp_media_get_suspend_mode (GstRTSPMedia * media)
956 {
957   GstRTSPMediaPrivate *priv;
958   GstRTSPSuspendMode res;
959
960   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_SUSPEND_MODE_NONE);
961
962   priv = media->priv;
963
964   g_rec_mutex_lock (&priv->state_lock);
965   res = priv->suspend_mode;
966   g_rec_mutex_unlock (&priv->state_lock);
967
968   return res;
969 }
970
971 /**
972  * gst_rtsp_media_set_shared:
973  * @media: a #GstRTSPMedia
974  * @shared: the new value
975  *
976  * Set or unset if the pipeline for @media can be shared will multiple clients.
977  * When @shared is %TRUE, client requests for this media will share the media
978  * pipeline.
979  */
980 void
981 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
982 {
983   GstRTSPMediaPrivate *priv;
984
985   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
986
987   priv = media->priv;
988
989   g_mutex_lock (&priv->lock);
990   priv->shared = shared;
991   g_mutex_unlock (&priv->lock);
992 }
993
994 /**
995  * gst_rtsp_media_is_shared:
996  * @media: a #GstRTSPMedia
997  *
998  * Check if the pipeline for @media can be shared between multiple clients.
999  *
1000  * Returns: %TRUE if the media can be shared between clients.
1001  */
1002 gboolean
1003 gst_rtsp_media_is_shared (GstRTSPMedia * media)
1004 {
1005   GstRTSPMediaPrivate *priv;
1006   gboolean res;
1007
1008   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1009
1010   priv = media->priv;
1011
1012   g_mutex_lock (&priv->lock);
1013   res = priv->shared;
1014   g_mutex_unlock (&priv->lock);
1015
1016   return res;
1017 }
1018
1019 /**
1020  * gst_rtsp_media_set_reusable:
1021  * @media: a #GstRTSPMedia
1022  * @reusable: the new value
1023  *
1024  * Set or unset if the pipeline for @media can be reused after the pipeline has
1025  * been unprepared.
1026  */
1027 void
1028 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
1029 {
1030   GstRTSPMediaPrivate *priv;
1031
1032   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1033
1034   priv = media->priv;
1035
1036   g_mutex_lock (&priv->lock);
1037   priv->reusable = reusable;
1038   g_mutex_unlock (&priv->lock);
1039 }
1040
1041 /**
1042  * gst_rtsp_media_is_reusable:
1043  * @media: a #GstRTSPMedia
1044  *
1045  * Check if the pipeline for @media can be reused after an unprepare.
1046  *
1047  * Returns: %TRUE if the media can be reused
1048  */
1049 gboolean
1050 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
1051 {
1052   GstRTSPMediaPrivate *priv;
1053   gboolean res;
1054
1055   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1056
1057   priv = media->priv;
1058
1059   g_mutex_lock (&priv->lock);
1060   res = priv->reusable;
1061   g_mutex_unlock (&priv->lock);
1062
1063   return res;
1064 }
1065
1066 static void
1067 do_set_profiles (GstRTSPStream * stream, GstRTSPProfile * profiles)
1068 {
1069   gst_rtsp_stream_set_profiles (stream, *profiles);
1070 }
1071
1072 /**
1073  * gst_rtsp_media_set_profiles:
1074  * @media: a #GstRTSPMedia
1075  * @profiles: the new flags
1076  *
1077  * Configure the allowed lower transport for @media.
1078  */
1079 void
1080 gst_rtsp_media_set_profiles (GstRTSPMedia * media, GstRTSPProfile profiles)
1081 {
1082   GstRTSPMediaPrivate *priv;
1083
1084   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1085
1086   priv = media->priv;
1087
1088   g_mutex_lock (&priv->lock);
1089   priv->profiles = profiles;
1090   g_ptr_array_foreach (priv->streams, (GFunc) do_set_profiles, &profiles);
1091   g_mutex_unlock (&priv->lock);
1092 }
1093
1094 /**
1095  * gst_rtsp_media_get_profiles:
1096  * @media: a #GstRTSPMedia
1097  *
1098  * Get the allowed profiles of @media.
1099  *
1100  * Returns: a #GstRTSPProfile
1101  */
1102 GstRTSPProfile
1103 gst_rtsp_media_get_profiles (GstRTSPMedia * media)
1104 {
1105   GstRTSPMediaPrivate *priv;
1106   GstRTSPProfile res;
1107
1108   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_PROFILE_UNKNOWN);
1109
1110   priv = media->priv;
1111
1112   g_mutex_lock (&priv->lock);
1113   res = priv->profiles;
1114   g_mutex_unlock (&priv->lock);
1115
1116   return res;
1117 }
1118
1119 static void
1120 do_set_protocols (GstRTSPStream * stream, GstRTSPLowerTrans * protocols)
1121 {
1122   gst_rtsp_stream_set_protocols (stream, *protocols);
1123 }
1124
1125 /**
1126  * gst_rtsp_media_set_protocols:
1127  * @media: a #GstRTSPMedia
1128  * @protocols: the new flags
1129  *
1130  * Configure the allowed lower transport for @media.
1131  */
1132 void
1133 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
1134 {
1135   GstRTSPMediaPrivate *priv;
1136
1137   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1138
1139   priv = media->priv;
1140
1141   g_mutex_lock (&priv->lock);
1142   priv->protocols = protocols;
1143   g_ptr_array_foreach (priv->streams, (GFunc) do_set_protocols, &protocols);
1144   g_mutex_unlock (&priv->lock);
1145 }
1146
1147 /**
1148  * gst_rtsp_media_get_protocols:
1149  * @media: a #GstRTSPMedia
1150  *
1151  * Get the allowed protocols of @media.
1152  *
1153  * Returns: a #GstRTSPLowerTrans
1154  */
1155 GstRTSPLowerTrans
1156 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
1157 {
1158   GstRTSPMediaPrivate *priv;
1159   GstRTSPLowerTrans res;
1160
1161   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
1162       GST_RTSP_LOWER_TRANS_UNKNOWN);
1163
1164   priv = media->priv;
1165
1166   g_mutex_lock (&priv->lock);
1167   res = priv->protocols;
1168   g_mutex_unlock (&priv->lock);
1169
1170   return res;
1171 }
1172
1173 /**
1174  * gst_rtsp_media_set_eos_shutdown:
1175  * @media: a #GstRTSPMedia
1176  * @eos_shutdown: the new value
1177  *
1178  * Set or unset if an EOS event will be sent to the pipeline for @media before
1179  * it is unprepared.
1180  */
1181 void
1182 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
1183 {
1184   GstRTSPMediaPrivate *priv;
1185
1186   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1187
1188   priv = media->priv;
1189
1190   g_mutex_lock (&priv->lock);
1191   priv->eos_shutdown = eos_shutdown;
1192   g_mutex_unlock (&priv->lock);
1193 }
1194
1195 /**
1196  * gst_rtsp_media_is_eos_shutdown:
1197  * @media: a #GstRTSPMedia
1198  *
1199  * Check if the pipeline for @media will send an EOS down the pipeline before
1200  * unpreparing.
1201  *
1202  * Returns: %TRUE if the media will send EOS before unpreparing.
1203  */
1204 gboolean
1205 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
1206 {
1207   GstRTSPMediaPrivate *priv;
1208   gboolean res;
1209
1210   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1211
1212   priv = media->priv;
1213
1214   g_mutex_lock (&priv->lock);
1215   res = priv->eos_shutdown;
1216   g_mutex_unlock (&priv->lock);
1217
1218   return res;
1219 }
1220
1221 /**
1222  * gst_rtsp_media_set_buffer_size:
1223  * @media: a #GstRTSPMedia
1224  * @size: the new value
1225  *
1226  * Set the kernel UDP buffer size.
1227  */
1228 void
1229 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
1230 {
1231   GstRTSPMediaPrivate *priv;
1232   guint i;
1233
1234   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1235
1236   GST_LOG_OBJECT (media, "set buffer size %u", size);
1237
1238   priv = media->priv;
1239
1240   g_mutex_lock (&priv->lock);
1241   priv->buffer_size = size;
1242
1243   for (i = 0; i < priv->streams->len; i++) {
1244     GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
1245     gst_rtsp_stream_set_buffer_size (stream, size);
1246   }
1247   g_mutex_unlock (&priv->lock);
1248 }
1249
1250 /**
1251  * gst_rtsp_media_get_buffer_size:
1252  * @media: a #GstRTSPMedia
1253  *
1254  * Get the kernel UDP buffer size.
1255  *
1256  * Returns: the kernel UDP buffer size.
1257  */
1258 guint
1259 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
1260 {
1261   GstRTSPMediaPrivate *priv;
1262   guint res;
1263
1264   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1265
1266   priv = media->priv;
1267
1268   g_mutex_lock (&priv->lock);
1269   res = priv->buffer_size;
1270   g_mutex_unlock (&priv->lock);
1271
1272   return res;
1273 }
1274
1275 /**
1276  * gst_rtsp_media_set_stop_on_disconnect:
1277  * @media: a #GstRTSPMedia
1278  * @stop_on_disconnect: the new value
1279  *
1280  * Set or unset if the pipeline for @media should be stopped when a
1281  * client disconnects without sending TEARDOWN.
1282  */
1283 void
1284 gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia * media,
1285     gboolean stop_on_disconnect)
1286 {
1287   GstRTSPMediaPrivate *priv;
1288
1289   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1290
1291   priv = media->priv;
1292
1293   g_mutex_lock (&priv->lock);
1294   priv->stop_on_disconnect = stop_on_disconnect;
1295   g_mutex_unlock (&priv->lock);
1296 }
1297
1298 /**
1299  * gst_rtsp_media_is_stop_on_disconnect:
1300  * @media: a #GstRTSPMedia
1301  *
1302  * Check if the pipeline for @media will be stopped when a client disconnects
1303  * without sending TEARDOWN.
1304  *
1305  * Returns: %TRUE if the media will be stopped when a client disconnects
1306  *     without sending TEARDOWN.
1307  */
1308 gboolean
1309 gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia * media)
1310 {
1311   GstRTSPMediaPrivate *priv;
1312   gboolean res;
1313
1314   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), TRUE);
1315
1316   priv = media->priv;
1317
1318   g_mutex_lock (&priv->lock);
1319   res = priv->stop_on_disconnect;
1320   g_mutex_unlock (&priv->lock);
1321
1322   return res;
1323 }
1324
1325 /**
1326  * gst_rtsp_media_set_retransmission_time:
1327  * @media: a #GstRTSPMedia
1328  * @time: the new value
1329  *
1330  * Set the amount of time to store retransmission packets.
1331  */
1332 void
1333 gst_rtsp_media_set_retransmission_time (GstRTSPMedia * media, GstClockTime time)
1334 {
1335   GstRTSPMediaPrivate *priv;
1336   guint i;
1337
1338   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1339
1340   GST_LOG_OBJECT (media, "set retransmission time %" G_GUINT64_FORMAT, time);
1341
1342   priv = media->priv;
1343
1344   g_mutex_lock (&priv->lock);
1345   priv->rtx_time = time;
1346   for (i = 0; i < priv->streams->len; i++) {
1347     GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
1348
1349     gst_rtsp_stream_set_retransmission_time (stream, time);
1350   }
1351
1352   if (priv->rtpbin)
1353     g_object_set (priv->rtpbin, "do-retransmission", time > 0, NULL);
1354   g_mutex_unlock (&priv->lock);
1355 }
1356
1357 /**
1358  * gst_rtsp_media_get_retransmission_time:
1359  * @media: a #GstRTSPMedia
1360  *
1361  * Get the amount of time to store retransmission data.
1362  *
1363  * Returns: the amount of time to store retransmission data.
1364  */
1365 GstClockTime
1366 gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media)
1367 {
1368   GstRTSPMediaPrivate *priv;
1369   GstClockTime res;
1370
1371   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1372
1373   priv = media->priv;
1374
1375   g_mutex_lock (&priv->lock);
1376   res = priv->rtx_time;
1377   g_mutex_unlock (&priv->lock);
1378
1379   return res;
1380 }
1381
1382 /**
1383  * gst_rtsp_media_set_latency:
1384  * @media: a #GstRTSPMedia
1385  * @latency: latency in milliseconds
1386  *
1387  * Configure the latency used for receiving media.
1388  */
1389 void
1390 gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency)
1391 {
1392   GstRTSPMediaPrivate *priv;
1393
1394   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1395
1396   GST_LOG_OBJECT (media, "set latency %ums", latency);
1397
1398   priv = media->priv;
1399
1400   g_mutex_lock (&priv->lock);
1401   priv->latency = latency;
1402   if (priv->rtpbin)
1403     g_object_set (priv->rtpbin, "latency", latency, NULL);
1404   g_mutex_unlock (&priv->lock);
1405 }
1406
1407 /**
1408  * gst_rtsp_media_get_latency:
1409  * @media: a #GstRTSPMedia
1410  *
1411  * Get the latency that is used for receiving media.
1412  *
1413  * Returns: latency in milliseconds
1414  */
1415 guint
1416 gst_rtsp_media_get_latency (GstRTSPMedia * media)
1417 {
1418   GstRTSPMediaPrivate *priv;
1419   guint res;
1420
1421   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1422
1423   priv = media->priv;
1424
1425   g_mutex_lock (&priv->lock);
1426   res = priv->latency;
1427   g_mutex_unlock (&priv->lock);
1428
1429   return res;
1430 }
1431
1432 /**
1433  * gst_rtsp_media_use_time_provider:
1434  * @media: a #GstRTSPMedia
1435  * @time_provider: if a #GstNetTimeProvider should be used
1436  *
1437  * Set @media to provide a #GstNetTimeProvider.
1438  */
1439 void
1440 gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider)
1441 {
1442   GstRTSPMediaPrivate *priv;
1443
1444   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1445
1446   priv = media->priv;
1447
1448   g_mutex_lock (&priv->lock);
1449   priv->time_provider = time_provider;
1450   g_mutex_unlock (&priv->lock);
1451 }
1452
1453 /**
1454  * gst_rtsp_media_is_time_provider:
1455  * @media: a #GstRTSPMedia
1456  *
1457  * Check if @media can provide a #GstNetTimeProvider for its pipeline clock.
1458  *
1459  * Use gst_rtsp_media_get_time_provider() to get the network clock.
1460  *
1461  * Returns: %TRUE if @media can provide a #GstNetTimeProvider.
1462  */
1463 gboolean
1464 gst_rtsp_media_is_time_provider (GstRTSPMedia * media)
1465 {
1466   GstRTSPMediaPrivate *priv;
1467   gboolean res;
1468
1469   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1470
1471   priv = media->priv;
1472
1473   g_mutex_lock (&priv->lock);
1474   res = priv->time_provider;
1475   g_mutex_unlock (&priv->lock);
1476
1477   return res;
1478 }
1479
1480 /**
1481  * gst_rtsp_media_set_clock:
1482  * @media: a #GstRTSPMedia
1483  * @clock: #GstClock to be used
1484  *
1485  * Configure the clock used for the media.
1486  */
1487 void
1488 gst_rtsp_media_set_clock (GstRTSPMedia * media, GstClock * clock)
1489 {
1490   GstRTSPMediaPrivate *priv;
1491
1492   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1493   g_return_if_fail (GST_IS_CLOCK (clock) || clock == NULL);
1494
1495   GST_LOG_OBJECT (media, "setting clock %" GST_PTR_FORMAT, clock);
1496
1497   priv = media->priv;
1498
1499   g_mutex_lock (&priv->lock);
1500   if (priv->clock)
1501     gst_object_unref (priv->clock);
1502   priv->clock = clock ? gst_object_ref (clock) : NULL;
1503   if (priv->pipeline) {
1504     if (clock)
1505       gst_pipeline_use_clock (GST_PIPELINE_CAST (priv->pipeline), clock);
1506     else
1507       gst_pipeline_auto_clock (GST_PIPELINE_CAST (priv->pipeline));
1508   }
1509
1510   g_mutex_unlock (&priv->lock);
1511 }
1512
1513 /**
1514  * gst_rtsp_media_set_publish_clock_mode:
1515  * @media: a #GstRTSPMedia
1516  * @mode: the clock publish mode
1517  *
1518  * Sets if and how the media clock should be published according to RFC7273.
1519  *
1520  * Since: 1.8
1521  */
1522 void
1523 gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media,
1524     GstRTSPPublishClockMode mode)
1525 {
1526   GstRTSPMediaPrivate *priv;
1527   guint i, n;
1528
1529   priv = media->priv;
1530   g_mutex_lock (&priv->lock);
1531   priv->publish_clock_mode = mode;
1532
1533   n = priv->streams->len;
1534   for (i = 0; i < n; i++) {
1535     GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
1536
1537     gst_rtsp_stream_set_publish_clock_mode (stream, mode);
1538   }
1539   g_mutex_unlock (&priv->lock);
1540 }
1541
1542 /**
1543  * gst_rtsp_media_get_publish_clock_mode:
1544  * @media: a #GstRTSPMedia
1545  *
1546  * Gets if and how the media clock should be published according to RFC7273.
1547  *
1548  * Returns: The GstRTSPPublishClockMode
1549  *
1550  * Since: 1.8
1551  */
1552 GstRTSPPublishClockMode
1553 gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media)
1554 {
1555   GstRTSPMediaPrivate *priv;
1556   GstRTSPPublishClockMode ret;
1557
1558   priv = media->priv;
1559   g_mutex_lock (&priv->lock);
1560   ret = priv->publish_clock_mode;
1561   g_mutex_unlock (&priv->lock);
1562
1563   return ret;
1564 }
1565
1566 /**
1567  * gst_rtsp_media_set_address_pool:
1568  * @media: a #GstRTSPMedia
1569  * @pool: (transfer none): a #GstRTSPAddressPool
1570  *
1571  * configure @pool to be used as the address pool of @media.
1572  */
1573 void
1574 gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
1575     GstRTSPAddressPool * pool)
1576 {
1577   GstRTSPMediaPrivate *priv;
1578   GstRTSPAddressPool *old;
1579
1580   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1581
1582   priv = media->priv;
1583
1584   GST_LOG_OBJECT (media, "set address pool %p", pool);
1585
1586   g_mutex_lock (&priv->lock);
1587   if ((old = priv->pool) != pool)
1588     priv->pool = pool ? g_object_ref (pool) : NULL;
1589   else
1590     old = NULL;
1591   g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool,
1592       pool);
1593   g_mutex_unlock (&priv->lock);
1594
1595   if (old)
1596     g_object_unref (old);
1597 }
1598
1599 /**
1600  * gst_rtsp_media_get_address_pool:
1601  * @media: a #GstRTSPMedia
1602  *
1603  * Get the #GstRTSPAddressPool used as the address pool of @media.
1604  *
1605  * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after
1606  * usage.
1607  */
1608 GstRTSPAddressPool *
1609 gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
1610 {
1611   GstRTSPMediaPrivate *priv;
1612   GstRTSPAddressPool *result;
1613
1614   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1615
1616   priv = media->priv;
1617
1618   g_mutex_lock (&priv->lock);
1619   if ((result = priv->pool))
1620     g_object_ref (result);
1621   g_mutex_unlock (&priv->lock);
1622
1623   return result;
1624 }
1625
1626 /**
1627  * gst_rtsp_media_set_multicast_iface:
1628  * @media: a #GstRTSPMedia
1629  * @multicast_iface: (transfer none): a multicast interface name
1630  *
1631  * configure @multicast_iface to be used for @media.
1632  */
1633 void
1634 gst_rtsp_media_set_multicast_iface (GstRTSPMedia * media,
1635     const gchar * multicast_iface)
1636 {
1637   GstRTSPMediaPrivate *priv;
1638   gchar *old;
1639
1640   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1641
1642   priv = media->priv;
1643
1644   GST_LOG_OBJECT (media, "set multicast interface %s", multicast_iface);
1645
1646   g_mutex_lock (&priv->lock);
1647   if ((old = priv->multicast_iface) != multicast_iface)
1648     priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL;
1649   else
1650     old = NULL;
1651   g_ptr_array_foreach (priv->streams,
1652       (GFunc) gst_rtsp_stream_set_multicast_iface, (gchar *) multicast_iface);
1653   g_mutex_unlock (&priv->lock);
1654
1655   if (old)
1656     g_free (old);
1657 }
1658
1659 /**
1660  * gst_rtsp_media_get_multicast_iface:
1661  * @media: a #GstRTSPMedia
1662  *
1663  * Get the multicast interface used for @media.
1664  *
1665  * Returns: (transfer full): the multicast interface for @media. g_free() after
1666  * usage.
1667  */
1668 gchar *
1669 gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media)
1670 {
1671   GstRTSPMediaPrivate *priv;
1672   gchar *result;
1673
1674   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1675
1676   priv = media->priv;
1677
1678   g_mutex_lock (&priv->lock);
1679   if ((result = priv->multicast_iface))
1680     result = g_strdup (result);
1681   g_mutex_unlock (&priv->lock);
1682
1683   return result;
1684 }
1685
1686 static GList *
1687 _find_payload_types (GstRTSPMedia * media)
1688 {
1689   gint i, n;
1690   GQueue queue = G_QUEUE_INIT;
1691
1692   n = media->priv->streams->len;
1693   for (i = 0; i < n; i++) {
1694     GstRTSPStream *stream = g_ptr_array_index (media->priv->streams, i);
1695     guint pt = gst_rtsp_stream_get_pt (stream);
1696
1697     g_queue_push_tail (&queue, GUINT_TO_POINTER (pt));
1698   }
1699
1700   return queue.head;
1701 }
1702
1703 static guint
1704 _next_available_pt (GList * payloads)
1705 {
1706   guint i;
1707
1708   for (i = 96; i <= 127; i++) {
1709     GList *iter = g_list_find (payloads, GINT_TO_POINTER (i));
1710     if (!iter)
1711       return GPOINTER_TO_UINT (i);
1712   }
1713
1714   return 0;
1715 }
1716
1717 /**
1718  * gst_rtsp_media_collect_streams:
1719  * @media: a #GstRTSPMedia
1720  *
1721  * Find all payloader elements, they should be named pay\%d in the
1722  * element of @media, and create #GstRTSPStreams for them.
1723  *
1724  * Collect all dynamic elements, named dynpay\%d, and add them to
1725  * the list of dynamic elements.
1726  *
1727  * Find all depayloader elements, they should be named depay\%d in the
1728  * element of @media, and create #GstRTSPStreams for them.
1729  */
1730 void
1731 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
1732 {
1733   GstRTSPMediaPrivate *priv;
1734   GstElement *element, *elem;
1735   GstPad *pad;
1736   gint i;
1737   gboolean have_elem;
1738   gboolean more_elem_remaining = TRUE;
1739   GstRTSPTransportMode mode = 0;
1740
1741   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
1742
1743   priv = media->priv;
1744   element = priv->element;
1745
1746   have_elem = FALSE;
1747   for (i = 0; more_elem_remaining; i++) {
1748     gchar *name;
1749
1750     more_elem_remaining = FALSE;
1751
1752     name = g_strdup_printf ("pay%d", i);
1753     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
1754       GstElement *pay;
1755       GST_INFO ("found stream %d with payloader %p", i, elem);
1756
1757       /* take the pad of the payloader */
1758       pad = gst_element_get_static_pad (elem, "src");
1759
1760       /* find the real payload element in case elem is a GstBin */
1761       pay = find_payload_element (elem);
1762
1763       /* create the stream */
1764       if (pay == NULL) {
1765         GST_WARNING ("could not find real payloader, using bin");
1766         gst_rtsp_media_create_stream (media, elem, pad);
1767       } else {
1768         gst_rtsp_media_create_stream (media, pay, pad);
1769         gst_object_unref (pay);
1770       }
1771
1772       gst_object_unref (pad);
1773       gst_object_unref (elem);
1774
1775       have_elem = TRUE;
1776       more_elem_remaining = TRUE;
1777       mode |= GST_RTSP_TRANSPORT_MODE_PLAY;
1778     }
1779     g_free (name);
1780
1781     name = g_strdup_printf ("dynpay%d", i);
1782     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
1783       /* a stream that will dynamically create pads to provide RTP packets */
1784       GST_INFO ("found dynamic element %d, %p", i, elem);
1785
1786       g_mutex_lock (&priv->lock);
1787       priv->dynamic = g_list_prepend (priv->dynamic, elem);
1788       g_mutex_unlock (&priv->lock);
1789
1790       have_elem = TRUE;
1791       more_elem_remaining = TRUE;
1792       mode |= GST_RTSP_TRANSPORT_MODE_PLAY;
1793     }
1794     g_free (name);
1795
1796     name = g_strdup_printf ("depay%d", i);
1797     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
1798       GST_INFO ("found stream %d with depayloader %p", i, elem);
1799
1800       /* take the pad of the payloader */
1801       pad = gst_element_get_static_pad (elem, "sink");
1802       /* create the stream */
1803       gst_rtsp_media_create_stream (media, elem, pad);
1804       gst_object_unref (pad);
1805       gst_object_unref (elem);
1806
1807       have_elem = TRUE;
1808       more_elem_remaining = TRUE;
1809       mode |= GST_RTSP_TRANSPORT_MODE_RECORD;
1810     }
1811     g_free (name);
1812   }
1813
1814   if (have_elem) {
1815     if (priv->transport_mode != mode)
1816       GST_WARNING ("found different mode than expected (0x%02x != 0x%02d)",
1817           priv->transport_mode, mode);
1818   }
1819 }
1820
1821 /**
1822  * gst_rtsp_media_create_stream:
1823  * @media: a #GstRTSPMedia
1824  * @payloader: a #GstElement
1825  * @pad: a #GstPad
1826  *
1827  * Create a new stream in @media that provides RTP data on @pad.
1828  * @pad should be a pad of an element inside @media->element.
1829  *
1830  * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
1831  * as @media exists.
1832  */
1833 GstRTSPStream *
1834 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
1835     GstPad * pad)
1836 {
1837   GstRTSPMediaPrivate *priv;
1838   GstRTSPStream *stream;
1839   GstPad *ghostpad;
1840   gchar *name;
1841   gint idx;
1842
1843   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1844   g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
1845   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1846
1847   priv = media->priv;
1848
1849   g_mutex_lock (&priv->lock);
1850   idx = priv->streams->len;
1851
1852   GST_DEBUG ("media %p: creating stream with index %d", media, idx);
1853
1854   if (GST_PAD_IS_SRC (pad))
1855     name = g_strdup_printf ("src_%u", idx);
1856   else
1857     name = g_strdup_printf ("sink_%u", idx);
1858
1859   ghostpad = gst_ghost_pad_new (name, pad);
1860   gst_pad_set_active (ghostpad, TRUE);
1861   gst_element_add_pad (priv->element, ghostpad);
1862   g_free (name);
1863
1864   stream = gst_rtsp_stream_new (idx, payloader, ghostpad);
1865   if (priv->pool)
1866     gst_rtsp_stream_set_address_pool (stream, priv->pool);
1867   gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface);
1868   gst_rtsp_stream_set_profiles (stream, priv->profiles);
1869   gst_rtsp_stream_set_protocols (stream, priv->protocols);
1870   gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
1871   gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size);
1872   gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode);
1873
1874   g_ptr_array_add (priv->streams, stream);
1875
1876   if (GST_PAD_IS_SRC (pad)) {
1877     gint i, n;
1878
1879     if (priv->payloads)
1880       g_list_free (priv->payloads);
1881     priv->payloads = _find_payload_types (media);
1882
1883     n = priv->streams->len;
1884     for (i = 0; i < n; i++) {
1885       GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
1886       guint rtx_pt = _next_available_pt (priv->payloads);
1887
1888       if (rtx_pt == 0) {
1889         GST_WARNING ("Ran out of space of dynamic payload types");
1890         break;
1891       }
1892
1893       gst_rtsp_stream_set_retransmission_pt (stream, rtx_pt);
1894
1895       priv->payloads =
1896           g_list_append (priv->payloads, GUINT_TO_POINTER (rtx_pt));
1897     }
1898   }
1899   g_mutex_unlock (&priv->lock);
1900
1901   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
1902       NULL);
1903
1904   return stream;
1905 }
1906
1907 static void
1908 gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream)
1909 {
1910   GstRTSPMediaPrivate *priv;
1911   GstPad *srcpad;
1912
1913   priv = media->priv;
1914
1915   g_mutex_lock (&priv->lock);
1916   /* remove the ghostpad */
1917   srcpad = gst_rtsp_stream_get_srcpad (stream);
1918   gst_element_remove_pad (priv->element, srcpad);
1919   gst_object_unref (srcpad);
1920   /* now remove the stream */
1921   g_object_ref (stream);
1922   g_ptr_array_remove (priv->streams, stream);
1923   g_mutex_unlock (&priv->lock);
1924
1925   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM], 0,
1926       stream, NULL);
1927
1928   g_object_unref (stream);
1929 }
1930
1931 /**
1932  * gst_rtsp_media_n_streams:
1933  * @media: a #GstRTSPMedia
1934  *
1935  * Get the number of streams in this media.
1936  *
1937  * Returns: The number of streams.
1938  */
1939 guint
1940 gst_rtsp_media_n_streams (GstRTSPMedia * media)
1941 {
1942   GstRTSPMediaPrivate *priv;
1943   guint res;
1944
1945   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
1946
1947   priv = media->priv;
1948
1949   g_mutex_lock (&priv->lock);
1950   res = priv->streams->len;
1951   g_mutex_unlock (&priv->lock);
1952
1953   return res;
1954 }
1955
1956 /**
1957  * gst_rtsp_media_get_stream:
1958  * @media: a #GstRTSPMedia
1959  * @idx: the stream index
1960  *
1961  * Retrieve the stream with index @idx from @media.
1962  *
1963  * Returns: (nullable) (transfer none): the #GstRTSPStream at index
1964  * @idx or %NULL when a stream with that index did not exist.
1965  */
1966 GstRTSPStream *
1967 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
1968 {
1969   GstRTSPMediaPrivate *priv;
1970   GstRTSPStream *res;
1971
1972   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
1973
1974   priv = media->priv;
1975
1976   g_mutex_lock (&priv->lock);
1977   if (idx < priv->streams->len)
1978     res = g_ptr_array_index (priv->streams, idx);
1979   else
1980     res = NULL;
1981   g_mutex_unlock (&priv->lock);
1982
1983   return res;
1984 }
1985
1986 /**
1987  * gst_rtsp_media_find_stream:
1988  * @media: a #GstRTSPMedia
1989  * @control: the control of the stream
1990  *
1991  * Find a stream in @media with @control as the control uri.
1992  *
1993  * Returns: (nullable) (transfer none): the #GstRTSPStream with
1994  * control uri @control or %NULL when a stream with that control did
1995  * not exist.
1996  */
1997 GstRTSPStream *
1998 gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control)
1999 {
2000   GstRTSPMediaPrivate *priv;
2001   GstRTSPStream *res;
2002   gint i;
2003
2004   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2005   g_return_val_if_fail (control != NULL, NULL);
2006
2007   priv = media->priv;
2008
2009   res = NULL;
2010
2011   g_mutex_lock (&priv->lock);
2012   for (i = 0; i < priv->streams->len; i++) {
2013     GstRTSPStream *test;
2014
2015     test = g_ptr_array_index (priv->streams, i);
2016     if (gst_rtsp_stream_has_control (test, control)) {
2017       res = test;
2018       break;
2019     }
2020   }
2021   g_mutex_unlock (&priv->lock);
2022
2023   return res;
2024 }
2025
2026 /* called with state-lock */
2027 static gboolean
2028 default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range,
2029     GstRTSPRangeUnit unit)
2030 {
2031   return gst_rtsp_range_convert_units (range, unit);
2032 }
2033
2034 /**
2035  * gst_rtsp_media_get_range_string:
2036  * @media: a #GstRTSPMedia
2037  * @play: for the PLAY request
2038  * @unit: the unit to use for the string
2039  *
2040  * Get the current range as a string. @media must be prepared with
2041  * gst_rtsp_media_prepare ().
2042  *
2043  * Returns: (transfer full): The range as a string, g_free() after usage.
2044  */
2045 gchar *
2046 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play,
2047     GstRTSPRangeUnit unit)
2048 {
2049   GstRTSPMediaClass *klass;
2050   GstRTSPMediaPrivate *priv;
2051   gchar *result;
2052   GstRTSPTimeRange range;
2053
2054   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2055   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
2056   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
2057
2058   priv = media->priv;
2059
2060   g_rec_mutex_lock (&priv->state_lock);
2061   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
2062       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
2063     goto not_prepared;
2064
2065   g_mutex_lock (&priv->lock);
2066
2067   /* Update the range value with current position/duration */
2068   collect_media_stats (media);
2069
2070   /* make copy */
2071   range = priv->range;
2072
2073   if (!play && priv->n_active > 0) {
2074     range.min.type = GST_RTSP_TIME_NOW;
2075     range.min.seconds = -1;
2076   }
2077   g_mutex_unlock (&priv->lock);
2078   g_rec_mutex_unlock (&priv->state_lock);
2079
2080   if (!klass->convert_range (media, &range, unit))
2081     goto conversion_failed;
2082
2083   result = gst_rtsp_range_to_string (&range);
2084
2085   return result;
2086
2087   /* ERRORS */
2088 not_prepared:
2089   {
2090     GST_WARNING ("media %p was not prepared", media);
2091     g_rec_mutex_unlock (&priv->state_lock);
2092     return NULL;
2093   }
2094 conversion_failed:
2095   {
2096     GST_WARNING ("range conversion to unit %d failed", unit);
2097     return NULL;
2098   }
2099 }
2100
2101 static void
2102 stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
2103 {
2104   gst_rtsp_stream_set_blocked (stream, media->priv->blocked);
2105 }
2106
2107 static void
2108 media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked)
2109 {
2110   GstRTSPMediaPrivate *priv = media->priv;
2111
2112   GST_DEBUG ("media %p set blocked %d", media, blocked);
2113   priv->blocked = blocked;
2114   g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media);
2115 }
2116
2117 static void
2118 stream_unblock (GstRTSPStream * stream, GstRTSPMedia * media)
2119 {
2120   gst_rtsp_stream_unblock_linked (stream);
2121 }
2122
2123 static void
2124 media_unblock_linked (GstRTSPMedia * media)
2125 {
2126   GstRTSPMediaPrivate *priv = media->priv;
2127
2128   GST_DEBUG ("media %p unblocking linked streams", media);
2129   g_ptr_array_foreach (priv->streams, (GFunc) stream_unblock, media);
2130 }
2131
2132 static void
2133 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
2134 {
2135   GstRTSPMediaPrivate *priv = media->priv;
2136
2137   g_mutex_lock (&priv->lock);
2138   priv->status = status;
2139   GST_DEBUG ("setting new status to %d", status);
2140   g_cond_broadcast (&priv->cond);
2141   g_mutex_unlock (&priv->lock);
2142 }
2143
2144 /**
2145  * gst_rtsp_media_get_status:
2146  * @media: a #GstRTSPMedia
2147  *
2148  * Get the status of @media. When @media is busy preparing, this function waits
2149  * until @media is prepared or in error.
2150  *
2151  * Returns: the status of @media.
2152  */
2153 GstRTSPMediaStatus
2154 gst_rtsp_media_get_status (GstRTSPMedia * media)
2155 {
2156   GstRTSPMediaPrivate *priv = media->priv;
2157   GstRTSPMediaStatus result;
2158   gint64 end_time;
2159
2160   g_mutex_lock (&priv->lock);
2161   end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
2162   /* while we are preparing, wait */
2163   while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
2164     GST_DEBUG ("waiting for status change");
2165     if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) {
2166       GST_DEBUG ("timeout, assuming error status");
2167       priv->status = GST_RTSP_MEDIA_STATUS_ERROR;
2168     }
2169   }
2170   /* could be success or error */
2171   result = priv->status;
2172   GST_DEBUG ("got status %d", result);
2173   g_mutex_unlock (&priv->lock);
2174
2175   return result;
2176 }
2177
2178 /**
2179  * gst_rtsp_media_seek_full:
2180  * @media: a #GstRTSPMedia
2181  * @range: (transfer none): a #GstRTSPTimeRange
2182  * @flags: The minimal set of #GstSeekFlags to use
2183  *
2184  * Seek the pipeline of @media to @range. @media must be prepared with
2185  * gst_rtsp_media_prepare().
2186  *
2187  * Returns: %TRUE on success.
2188  */
2189 gboolean
2190 gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
2191     GstSeekFlags flags)
2192 {
2193   GstRTSPMediaClass *klass;
2194   GstRTSPMediaPrivate *priv;
2195   gboolean res;
2196   GstClockTime start, stop;
2197   GstSeekType start_type, stop_type;
2198   gint64 current_position;
2199
2200   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2201
2202   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2203   g_return_val_if_fail (range != NULL, FALSE);
2204   g_return_val_if_fail (klass->convert_range != NULL, FALSE);
2205
2206   priv = media->priv;
2207
2208   g_rec_mutex_lock (&priv->state_lock);
2209   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
2210     goto not_prepared;
2211
2212   /* Update the seekable state of the pipeline in case it changed */
2213   check_seekable (media);
2214
2215   if (priv->seekable == 0) {
2216     GST_FIXME_OBJECT (media, "Handle going back to 0 for none live"
2217         " not seekable streams.");
2218
2219     goto not_seekable;
2220   } else if (priv->seekable < 0) {
2221     goto not_seekable;
2222   }
2223
2224   start_type = stop_type = GST_SEEK_TYPE_NONE;
2225
2226   if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
2227     goto not_supported;
2228   gst_rtsp_range_get_times (range, &start, &stop);
2229
2230   GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2231       GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
2232   GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2233       GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
2234
2235   current_position = -1;
2236   if (klass->query_position)
2237     klass->query_position (media, &current_position);
2238   GST_INFO ("current media position %" GST_TIME_FORMAT,
2239       GST_TIME_ARGS (current_position));
2240
2241   if (start != GST_CLOCK_TIME_NONE)
2242     start_type = GST_SEEK_TYPE_SET;
2243
2244   if (priv->range_stop == stop)
2245     stop = GST_CLOCK_TIME_NONE;
2246   else if (stop != GST_CLOCK_TIME_NONE)
2247     stop_type = GST_SEEK_TYPE_SET;
2248
2249   if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
2250     gboolean had_flags = flags != 0;
2251
2252     GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2253         GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
2254
2255     /* depends on the current playing state of the pipeline. We might need to
2256      * queue this until we get EOS. */
2257     if (had_flags)
2258       flags |= GST_SEEK_FLAG_FLUSH;
2259     else
2260       flags = GST_SEEK_FLAG_FLUSH;
2261
2262
2263     /* if range start was not supplied we must continue from current position.
2264      * but since we're doing a flushing seek, let us query the current position
2265      * so we end up at exactly the same position after the seek. */
2266     if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */
2267       if (current_position == -1) {
2268         GST_WARNING ("current position unknown");
2269       } else {
2270         GST_DEBUG ("doing accurate seek to %" GST_TIME_FORMAT,
2271             GST_TIME_ARGS (current_position));
2272         start = current_position;
2273         start_type = GST_SEEK_TYPE_SET;
2274         if (!had_flags)
2275           flags |= GST_SEEK_FLAG_ACCURATE;
2276       }
2277     } else {
2278       /* only set keyframe flag when modifying start */
2279       if (start_type != GST_SEEK_TYPE_NONE)
2280         if (!had_flags)
2281           flags |= GST_SEEK_FLAG_KEY_UNIT;
2282     }
2283
2284     if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) {
2285       GST_DEBUG ("not seeking because no position change");
2286       res = TRUE;
2287     } else {
2288       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
2289       if (priv->blocked)
2290         media_streams_set_blocked (media, TRUE);
2291
2292       /* FIXME, we only do forwards playback, no trick modes yet */
2293       res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
2294           flags, start_type, start, stop_type, stop);
2295
2296       /* and block for the seek to complete */
2297       GST_INFO ("done seeking %d", res);
2298       if (!res)
2299         goto seek_failed;
2300
2301       g_rec_mutex_unlock (&priv->state_lock);
2302
2303       /* wait until pipeline is prerolled again, this will also collect stats */
2304       if (!wait_preroll (media))
2305         goto preroll_failed;
2306
2307       g_rec_mutex_lock (&priv->state_lock);
2308       GST_INFO ("prerolled again");
2309     }
2310   } else {
2311     GST_INFO ("no seek needed");
2312     res = TRUE;
2313   }
2314   g_rec_mutex_unlock (&priv->state_lock);
2315
2316   return res;
2317
2318   /* ERRORS */
2319 not_prepared:
2320   {
2321     g_rec_mutex_unlock (&priv->state_lock);
2322     GST_INFO ("media %p is not prepared", media);
2323     return FALSE;
2324   }
2325 not_seekable:
2326   {
2327     g_rec_mutex_unlock (&priv->state_lock);
2328     GST_INFO ("pipeline is not seekable");
2329     return FALSE;
2330   }
2331 not_supported:
2332   {
2333     g_rec_mutex_unlock (&priv->state_lock);
2334     GST_WARNING ("conversion to npt not supported");
2335     return FALSE;
2336   }
2337 seek_failed:
2338   {
2339     g_rec_mutex_unlock (&priv->state_lock);
2340     GST_INFO ("seeking failed");
2341     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2342     return FALSE;
2343   }
2344 preroll_failed:
2345   {
2346     GST_WARNING ("failed to preroll after seek");
2347     return FALSE;
2348   }
2349 }
2350
2351
2352 /**
2353  * gst_rtsp_media_seek:
2354  * @media: a #GstRTSPMedia
2355  * @range: (transfer none): a #GstRTSPTimeRange
2356  *
2357  * Seek the pipeline of @media to @range. @media must be prepared with
2358  * gst_rtsp_media_prepare().
2359  *
2360  * Returns: %TRUE on success.
2361  */
2362 gboolean
2363 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
2364 {
2365   return gst_rtsp_media_seek_full (media, range, 0);
2366 }
2367
2368
2369 static void
2370 stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
2371 {
2372   *blocked &= gst_rtsp_stream_is_blocking (stream);
2373 }
2374
2375 static gboolean
2376 media_streams_blocking (GstRTSPMedia * media)
2377 {
2378   gboolean blocking = TRUE;
2379
2380   g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_blocking,
2381       &blocking);
2382
2383   return blocking;
2384 }
2385
2386 static GstStateChangeReturn
2387 set_state (GstRTSPMedia * media, GstState state)
2388 {
2389   GstRTSPMediaPrivate *priv = media->priv;
2390   GstStateChangeReturn ret;
2391
2392   GST_INFO ("set state to %s for media %p", gst_element_state_get_name (state),
2393       media);
2394   ret = gst_element_set_state (priv->pipeline, state);
2395
2396   return ret;
2397 }
2398
2399 static GstStateChangeReturn
2400 set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
2401 {
2402   GstRTSPMediaPrivate *priv = media->priv;
2403   GstStateChangeReturn ret;
2404
2405   GST_INFO ("set target state to %s for media %p",
2406       gst_element_state_get_name (state), media);
2407   priv->target_state = state;
2408
2409   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0,
2410       priv->target_state, NULL);
2411
2412   if (do_state)
2413     ret = set_state (media, state);
2414   else
2415     ret = GST_STATE_CHANGE_SUCCESS;
2416
2417   return ret;
2418 }
2419
2420 /* called with state-lock */
2421 static gboolean
2422 default_handle_message (GstRTSPMedia * media, GstMessage * message)
2423 {
2424   GstRTSPMediaPrivate *priv = media->priv;
2425   GstMessageType type;
2426
2427   type = GST_MESSAGE_TYPE (message);
2428
2429   switch (type) {
2430     case GST_MESSAGE_STATE_CHANGED:
2431     {
2432       GstState old, new, pending;
2433
2434       if (GST_MESSAGE_SRC (message) != GST_OBJECT (priv->pipeline))
2435         break;
2436
2437       gst_message_parse_state_changed (message, &old, &new, &pending);
2438
2439       GST_DEBUG ("%p: went from %s to %s (pending %s)", media,
2440           gst_element_state_get_name (old), gst_element_state_get_name (new),
2441           gst_element_state_get_name (pending));
2442       if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)
2443           && old == GST_STATE_READY && new == GST_STATE_PAUSED) {
2444         GST_INFO ("%p: went to PAUSED, prepared now", media);
2445         collect_media_stats (media);
2446
2447         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
2448           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
2449       }
2450
2451       break;
2452     }
2453     case GST_MESSAGE_BUFFERING:
2454     {
2455       gint percent;
2456
2457       gst_message_parse_buffering (message, &percent);
2458
2459       /* no state management needed for live pipelines */
2460       if (priv->is_live)
2461         break;
2462
2463       if (percent == 100) {
2464         /* a 100% message means buffering is done */
2465         priv->buffering = FALSE;
2466         /* if the desired state is playing, go back */
2467         if (priv->target_state == GST_STATE_PLAYING) {
2468           GST_INFO ("Buffering done, setting pipeline to PLAYING");
2469           set_state (media, GST_STATE_PLAYING);
2470         } else {
2471           GST_INFO ("Buffering done");
2472         }
2473       } else {
2474         /* buffering busy */
2475         if (priv->buffering == FALSE) {
2476           if (priv->target_state == GST_STATE_PLAYING) {
2477             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
2478             GST_INFO ("Buffering, setting pipeline to PAUSED ...");
2479             set_state (media, GST_STATE_PAUSED);
2480           } else {
2481             GST_INFO ("Buffering ...");
2482           }
2483         }
2484         priv->buffering = TRUE;
2485       }
2486       break;
2487     }
2488     case GST_MESSAGE_LATENCY:
2489     {
2490       gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline));
2491       break;
2492     }
2493     case GST_MESSAGE_ERROR:
2494     {
2495       GError *gerror;
2496       gchar *debug;
2497
2498       gst_message_parse_error (message, &gerror, &debug);
2499       GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
2500       g_error_free (gerror);
2501       g_free (debug);
2502
2503       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2504       break;
2505     }
2506     case GST_MESSAGE_WARNING:
2507     {
2508       GError *gerror;
2509       gchar *debug;
2510
2511       gst_message_parse_warning (message, &gerror, &debug);
2512       GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
2513       g_error_free (gerror);
2514       g_free (debug);
2515       break;
2516     }
2517     case GST_MESSAGE_ELEMENT:
2518     {
2519       const GstStructure *s;
2520
2521       s = gst_message_get_structure (message);
2522       if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) {
2523         GST_DEBUG ("media received blocking message");
2524         if (priv->blocked && media_streams_blocking (media)) {
2525           GST_DEBUG ("media is blocking");
2526           collect_media_stats (media);
2527
2528           if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
2529             gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
2530         }
2531       }
2532       break;
2533     }
2534     case GST_MESSAGE_STREAM_STATUS:
2535       break;
2536     case GST_MESSAGE_ASYNC_DONE:
2537       if (priv->adding) {
2538         /* when we are dynamically adding pads, the addition of the udpsrc will
2539          * temporarily produce ASYNC_DONE messages. We have to ignore them and
2540          * wait for the final ASYNC_DONE after everything prerolled */
2541         GST_INFO ("%p: ignoring ASYNC_DONE", media);
2542       } else {
2543         GST_INFO ("%p: got ASYNC_DONE", media);
2544         if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
2545           gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
2546       }
2547       break;
2548     case GST_MESSAGE_EOS:
2549       GST_INFO ("%p: got EOS", media);
2550
2551       if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
2552         GST_DEBUG ("shutting down after EOS");
2553         finish_unprepare (media);
2554       }
2555       break;
2556     default:
2557       GST_INFO ("%p: got message type %d (%s)", media, type,
2558           gst_message_type_get_name (type));
2559       break;
2560   }
2561   return TRUE;
2562 }
2563
2564 static gboolean
2565 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
2566 {
2567   GstRTSPMediaPrivate *priv = media->priv;
2568   GstRTSPMediaClass *klass;
2569   gboolean ret;
2570
2571   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2572
2573   g_rec_mutex_lock (&priv->state_lock);
2574   if (klass->handle_message)
2575     ret = klass->handle_message (media, message);
2576   else
2577     ret = FALSE;
2578   g_rec_mutex_unlock (&priv->state_lock);
2579
2580   return ret;
2581 }
2582
2583 static void
2584 watch_destroyed (GstRTSPMedia * media)
2585 {
2586   GST_DEBUG_OBJECT (media, "source destroyed");
2587   g_object_unref (media);
2588 }
2589
2590 static GstElement *
2591 find_payload_element (GstElement * payloader)
2592 {
2593   GstElement *pay = NULL;
2594
2595   if (GST_IS_BIN (payloader)) {
2596     GstIterator *iter;
2597     GValue item = { 0 };
2598
2599     iter = gst_bin_iterate_recurse (GST_BIN (payloader));
2600     while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) {
2601       GstElement *element = (GstElement *) g_value_get_object (&item);
2602       GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element);
2603       const gchar *klass;
2604
2605       klass =
2606           gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS);
2607       if (klass == NULL)
2608         continue;
2609
2610       if (strstr (klass, "Payloader") && strstr (klass, "RTP")) {
2611         pay = gst_object_ref (element);
2612         g_value_unset (&item);
2613         break;
2614       }
2615       g_value_unset (&item);
2616     }
2617     gst_iterator_free (iter);
2618   } else {
2619     pay = g_object_ref (payloader);
2620   }
2621
2622   return pay;
2623 }
2624
2625 /* called from streaming threads */
2626 static void
2627 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
2628 {
2629   GstRTSPMediaPrivate *priv = media->priv;
2630   GstRTSPStream *stream;
2631   GstElement *pay;
2632
2633   /* find the real payload element */
2634   pay = find_payload_element (element);
2635   stream = gst_rtsp_media_create_stream (media, pay, pad);
2636   gst_object_unref (pay);
2637
2638   GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
2639
2640   g_rec_mutex_lock (&priv->state_lock);
2641   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
2642     goto not_preparing;
2643
2644   g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream);
2645
2646   /* we will be adding elements below that will cause ASYNC_DONE to be
2647    * posted in the bus. We want to ignore those messages until the
2648    * pipeline really prerolled. */
2649   priv->adding = TRUE;
2650
2651   /* join the element in the PAUSED state because this callback is
2652    * called from the streaming thread and it is PAUSED */
2653   if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
2654           priv->rtpbin, GST_STATE_PAUSED)) {
2655     GST_WARNING ("failed to join bin element");
2656   }
2657
2658   if (priv->blocked)
2659     gst_rtsp_stream_set_blocked (stream, TRUE);
2660
2661   priv->adding = FALSE;
2662   g_rec_mutex_unlock (&priv->state_lock);
2663
2664   return;
2665
2666   /* ERRORS */
2667 not_preparing:
2668   {
2669     gst_rtsp_media_remove_stream (media, stream);
2670     g_rec_mutex_unlock (&priv->state_lock);
2671     GST_INFO ("ignore pad because we are not preparing");
2672     return;
2673   }
2674 }
2675
2676 static void
2677 pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
2678 {
2679   GstRTSPMediaPrivate *priv = media->priv;
2680   GstRTSPStream *stream;
2681
2682   stream = g_object_get_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream");
2683   if (stream == NULL)
2684     return;
2685
2686   GST_INFO ("pad removed %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream);
2687
2688   g_rec_mutex_lock (&priv->state_lock);
2689   gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
2690   g_rec_mutex_unlock (&priv->state_lock);
2691
2692   gst_rtsp_media_remove_stream (media, stream);
2693 }
2694
2695 static void
2696 remove_fakesink (GstRTSPMediaPrivate * priv)
2697 {
2698   GstElement *fakesink;
2699
2700   g_mutex_lock (&priv->lock);
2701   if ((fakesink = priv->fakesink))
2702     gst_object_ref (fakesink);
2703   priv->fakesink = NULL;
2704   g_mutex_unlock (&priv->lock);
2705
2706   if (fakesink) {
2707     gst_bin_remove (GST_BIN (priv->pipeline), fakesink);
2708     gst_element_set_state (fakesink, GST_STATE_NULL);
2709     gst_object_unref (fakesink);
2710     GST_INFO ("removed fakesink");
2711   }
2712 }
2713
2714 static void
2715 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
2716 {
2717   GstRTSPMediaPrivate *priv = media->priv;
2718
2719   GST_INFO ("no more pads");
2720   remove_fakesink (priv);
2721 }
2722
2723 typedef struct _DynPaySignalHandlers DynPaySignalHandlers;
2724
2725 struct _DynPaySignalHandlers
2726 {
2727   gulong pad_added_handler;
2728   gulong pad_removed_handler;
2729   gulong no_more_pads_handler;
2730 };
2731
2732 static gboolean
2733 start_preroll (GstRTSPMedia * media)
2734 {
2735   GstRTSPMediaPrivate *priv = media->priv;
2736   GstStateChangeReturn ret;
2737
2738   GST_INFO ("setting pipeline to PAUSED for media %p", media);
2739
2740   /* start blocked since it is possible that there are no sink elements yet */
2741   media_streams_set_blocked (media, TRUE);
2742   ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
2743
2744   switch (ret) {
2745     case GST_STATE_CHANGE_SUCCESS:
2746       GST_INFO ("SUCCESS state change for media %p", media);
2747       break;
2748     case GST_STATE_CHANGE_ASYNC:
2749       GST_INFO ("ASYNC state change for media %p", media);
2750       break;
2751     case GST_STATE_CHANGE_NO_PREROLL:
2752       /* we need to go to PLAYING */
2753       GST_INFO ("NO_PREROLL state change: live media %p", media);
2754       /* FIXME we disable seeking for live streams for now. We should perform a
2755        * seeking query in preroll instead */
2756       priv->seekable = -1;
2757       priv->is_live = TRUE;
2758
2759       ret = set_state (media, GST_STATE_PLAYING);
2760       if (ret == GST_STATE_CHANGE_FAILURE)
2761         goto state_failed;
2762       break;
2763     case GST_STATE_CHANGE_FAILURE:
2764       goto state_failed;
2765   }
2766
2767   return TRUE;
2768
2769 state_failed:
2770   {
2771     GST_WARNING ("failed to preroll pipeline");
2772     return FALSE;
2773   }
2774 }
2775
2776 static gboolean
2777 wait_preroll (GstRTSPMedia * media)
2778 {
2779   GstRTSPMediaStatus status;
2780
2781   GST_DEBUG ("wait to preroll pipeline");
2782
2783   /* wait until pipeline is prerolled */
2784   status = gst_rtsp_media_get_status (media);
2785   if (status == GST_RTSP_MEDIA_STATUS_ERROR)
2786     goto preroll_failed;
2787
2788   return TRUE;
2789
2790 preroll_failed:
2791   {
2792     GST_WARNING ("failed to preroll pipeline");
2793     return FALSE;
2794   }
2795 }
2796
2797 static GstElement *
2798 request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media)
2799 {
2800   GstRTSPMediaPrivate *priv = media->priv;
2801   GstRTSPStream *stream = NULL;
2802   guint i;
2803
2804   g_mutex_lock (&priv->lock);
2805   for (i = 0; i < priv->streams->len; i++) {
2806     stream = g_ptr_array_index (priv->streams, i);
2807
2808     if (sessid == gst_rtsp_stream_get_index (stream))
2809       break;
2810   }
2811   g_mutex_unlock (&priv->lock);
2812
2813   return gst_rtsp_stream_request_aux_sender (stream, sessid);
2814 }
2815
2816 static gboolean
2817 start_prepare (GstRTSPMedia * media)
2818 {
2819   GstRTSPMediaPrivate *priv = media->priv;
2820   guint i;
2821   GList *walk;
2822
2823   g_rec_mutex_lock (&priv->state_lock);
2824   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
2825     goto no_longer_preparing;
2826
2827   /* link streams we already have, other streams might appear when we have
2828    * dynamic elements */
2829   for (i = 0; i < priv->streams->len; i++) {
2830     GstRTSPStream *stream;
2831
2832     stream = g_ptr_array_index (priv->streams, i);
2833
2834     if (priv->rtx_time > 0) {
2835       /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */
2836       g_signal_connect (priv->rtpbin, "request-aux-sender",
2837           (GCallback) request_aux_sender, media);
2838     }
2839
2840     if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
2841             priv->rtpbin, GST_STATE_NULL)) {
2842       goto join_bin_failed;
2843     }
2844   }
2845
2846   if (priv->rtpbin)
2847     g_object_set (priv->rtpbin, "do-retransmission", priv->rtx_time > 0, NULL);
2848
2849   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
2850     GstElement *elem = walk->data;
2851     DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
2852
2853     GST_INFO ("adding callbacks for dynamic element %p", elem);
2854
2855     handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
2856         (GCallback) pad_added_cb, media);
2857     handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
2858         (GCallback) pad_removed_cb, media);
2859     handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
2860         (GCallback) no_more_pads_cb, media);
2861
2862     g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
2863
2864     if (!priv->fakesink) {
2865       /* we add a fakesink here in order to make the state change async. We remove
2866        * the fakesink again in the no-more-pads callback. */
2867       priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
2868       gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
2869     }
2870   }
2871
2872   if (!start_preroll (media))
2873     goto preroll_failed;
2874
2875   g_rec_mutex_unlock (&priv->state_lock);
2876
2877   return FALSE;
2878
2879 no_longer_preparing:
2880   {
2881     GST_INFO ("media is no longer preparing");
2882     g_rec_mutex_unlock (&priv->state_lock);
2883     return FALSE;
2884   }
2885 join_bin_failed:
2886   {
2887     GST_WARNING ("failed to join bin element");
2888     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2889     g_rec_mutex_unlock (&priv->state_lock);
2890     return FALSE;
2891   }
2892 preroll_failed:
2893   {
2894     GST_WARNING ("failed to preroll pipeline");
2895     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
2896     g_rec_mutex_unlock (&priv->state_lock);
2897     return FALSE;
2898   }
2899 }
2900
2901 static gboolean
2902 default_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
2903 {
2904   GstRTSPMediaPrivate *priv;
2905   GstRTSPMediaClass *klass;
2906   GstBus *bus;
2907   GMainContext *context;
2908   GSource *source;
2909
2910   priv = media->priv;
2911
2912   klass = GST_RTSP_MEDIA_GET_CLASS (media);
2913
2914   if (!klass->create_rtpbin)
2915     goto no_create_rtpbin;
2916
2917   priv->rtpbin = klass->create_rtpbin (media);
2918   if (priv->rtpbin != NULL) {
2919     gboolean success = TRUE;
2920
2921     g_object_set (priv->rtpbin, "latency", priv->latency, NULL);
2922
2923     if (klass->setup_rtpbin)
2924       success = klass->setup_rtpbin (media, priv->rtpbin);
2925
2926     if (success == FALSE) {
2927       gst_object_unref (priv->rtpbin);
2928       priv->rtpbin = NULL;
2929     }
2930   }
2931   if (priv->rtpbin == NULL)
2932     goto no_rtpbin;
2933
2934   priv->thread = thread;
2935   context = (thread != NULL) ? (thread->context) : NULL;
2936
2937   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
2938
2939   /* add the pipeline bus to our custom mainloop */
2940   priv->source = gst_bus_create_watch (bus);
2941   gst_object_unref (bus);
2942
2943   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
2944       g_object_ref (media), (GDestroyNotify) watch_destroyed);
2945
2946   priv->id = g_source_attach (priv->source, context);
2947
2948   /* add stuff to the bin */
2949   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
2950
2951   /* do remainder in context */
2952   source = g_idle_source_new ();
2953   g_source_set_callback (source, (GSourceFunc) start_prepare,
2954       g_object_ref (media), (GDestroyNotify) g_object_unref);
2955   g_source_attach (source, context);
2956   g_source_unref (source);
2957
2958   return TRUE;
2959
2960   /* ERRORS */
2961 no_create_rtpbin:
2962   {
2963     GST_ERROR ("no create_rtpbin function");
2964     g_critical ("no create_rtpbin vmethod function set");
2965     return FALSE;
2966   }
2967 no_rtpbin:
2968   {
2969     GST_WARNING ("no rtpbin element");
2970     g_warning ("failed to create element 'rtpbin', check your installation");
2971     return FALSE;
2972   }
2973 }
2974
2975 /**
2976  * gst_rtsp_media_prepare:
2977  * @media: a #GstRTSPMedia
2978  * @thread: (transfer full) (allow-none): a #GstRTSPThread to run the
2979  *   bus handler or %NULL
2980  *
2981  * Prepare @media for streaming. This function will create the objects
2982  * to manage the streaming. A pipeline must have been set on @media with
2983  * gst_rtsp_media_take_pipeline().
2984  *
2985  * It will preroll the pipeline and collect vital information about the streams
2986  * such as the duration.
2987  *
2988  * Returns: %TRUE on success.
2989  */
2990 gboolean
2991 gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
2992 {
2993   GstRTSPMediaPrivate *priv;
2994   GstRTSPMediaClass *klass;
2995
2996   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
2997
2998   priv = media->priv;
2999
3000   g_rec_mutex_lock (&priv->state_lock);
3001   priv->prepare_count++;
3002
3003   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED ||
3004       priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED)
3005     goto was_prepared;
3006
3007   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING)
3008     goto is_preparing;
3009
3010   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
3011     goto not_unprepared;
3012
3013   if (!priv->reusable && priv->reused)
3014     goto is_reused;
3015
3016   GST_INFO ("preparing media %p", media);
3017
3018   /* reset some variables */
3019   priv->is_live = FALSE;
3020   priv->seekable = -1;
3021   priv->buffering = FALSE;
3022
3023   /* we're preparing now */
3024   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
3025
3026   klass = GST_RTSP_MEDIA_GET_CLASS (media);
3027   if (klass->prepare) {
3028     if (!klass->prepare (media, thread))
3029       goto prepare_failed;
3030   }
3031
3032 wait_status:
3033   g_rec_mutex_unlock (&priv->state_lock);
3034
3035   /* now wait for all pads to be prerolled, FIXME, we should somehow be
3036    * able to do this async so that we don't block the server thread. */
3037   if (!wait_preroll (media))
3038     goto preroll_failed;
3039
3040   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
3041
3042   GST_INFO ("object %p is prerolled", media);
3043
3044   return TRUE;
3045
3046   /* OK */
3047 is_preparing:
3048   {
3049     /* we are not going to use the giving thread, so stop it. */
3050     if (thread)
3051       gst_rtsp_thread_stop (thread);
3052     goto wait_status;
3053   }
3054 was_prepared:
3055   {
3056     GST_LOG ("media %p was prepared", media);
3057     /* we are not going to use the giving thread, so stop it. */
3058     if (thread)
3059       gst_rtsp_thread_stop (thread);
3060     g_rec_mutex_unlock (&priv->state_lock);
3061     return TRUE;
3062   }
3063   /* ERRORS */
3064 not_unprepared:
3065   {
3066     /* we are not going to use the giving thread, so stop it. */
3067     if (thread)
3068       gst_rtsp_thread_stop (thread);
3069     GST_WARNING ("media %p was not unprepared", media);
3070     priv->prepare_count--;
3071     g_rec_mutex_unlock (&priv->state_lock);
3072     return FALSE;
3073   }
3074 is_reused:
3075   {
3076     /* we are not going to use the giving thread, so stop it. */
3077     if (thread)
3078       gst_rtsp_thread_stop (thread);
3079     priv->prepare_count--;
3080     g_rec_mutex_unlock (&priv->state_lock);
3081     GST_WARNING ("can not reuse media %p", media);
3082     return FALSE;
3083   }
3084 prepare_failed:
3085   {
3086     /* we are not going to use the giving thread, so stop it. */
3087     if (thread)
3088       gst_rtsp_thread_stop (thread);
3089     priv->prepare_count--;
3090     g_rec_mutex_unlock (&priv->state_lock);
3091     GST_ERROR ("failed to prepare media");
3092     return FALSE;
3093   }
3094 preroll_failed:
3095   {
3096     GST_WARNING ("failed to preroll pipeline");
3097     gst_rtsp_media_unprepare (media);
3098     return FALSE;
3099   }
3100 }
3101
3102 /* must be called with state-lock */
3103 static void
3104 finish_unprepare (GstRTSPMedia * media)
3105 {
3106   GstRTSPMediaPrivate *priv = media->priv;
3107   gint i;
3108   GList *walk;
3109
3110   GST_DEBUG ("shutting down");
3111
3112   /* release the lock on shutdown, otherwise pad_added_cb might try to
3113    * acquire the lock and then we deadlock */
3114   g_rec_mutex_unlock (&priv->state_lock);
3115   set_state (media, GST_STATE_NULL);
3116   g_rec_mutex_lock (&priv->state_lock);
3117
3118   media_streams_set_blocked (media, FALSE);
3119
3120   if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARING)
3121     return;
3122
3123   remove_fakesink (priv);
3124
3125   for (i = 0; i < priv->streams->len; i++) {
3126     GstRTSPStream *stream;
3127
3128     GST_INFO ("Removing elements of stream %d from pipeline", i);
3129
3130     stream = g_ptr_array_index (priv->streams, i);
3131
3132     gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
3133   }
3134
3135   /* remove the pad signal handlers */
3136   for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
3137     GstElement *elem = walk->data;
3138     DynPaySignalHandlers *handlers;
3139
3140     handlers =
3141         g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers");
3142     g_assert (handlers != NULL);
3143
3144     g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler);
3145     g_signal_handler_disconnect (G_OBJECT (elem),
3146         handlers->pad_removed_handler);
3147     g_signal_handler_disconnect (G_OBJECT (elem),
3148         handlers->no_more_pads_handler);
3149
3150     g_slice_free (DynPaySignalHandlers, handlers);
3151   }
3152
3153   gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
3154   priv->rtpbin = NULL;
3155
3156   if (priv->nettime)
3157     gst_object_unref (priv->nettime);
3158   priv->nettime = NULL;
3159
3160   priv->reused = TRUE;
3161   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARED);
3162
3163   /* when the media is not reusable, this will effectively unref the media and
3164    * recreate it */
3165   g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
3166
3167   /* the source has the last ref to the media */
3168   if (priv->source) {
3169     GST_DEBUG ("destroy source");
3170     g_source_destroy (priv->source);
3171     g_source_unref (priv->source);
3172   }
3173   if (priv->thread) {
3174     GST_DEBUG ("stop thread");
3175     gst_rtsp_thread_stop (priv->thread);
3176   }
3177 }
3178
3179 /* called with state-lock */
3180 static gboolean
3181 default_unprepare (GstRTSPMedia * media)
3182 {
3183   GstRTSPMediaPrivate *priv = media->priv;
3184
3185   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING);
3186
3187   if (priv->eos_shutdown) {
3188     GST_DEBUG ("sending EOS for shutdown");
3189     /* ref so that we don't disappear */
3190     gst_element_send_event (priv->pipeline, gst_event_new_eos ());
3191     /* we need to go to playing again for the EOS to propagate, normally in this
3192      * state, nothing is receiving data from us anymore so this is ok. */
3193     set_state (media, GST_STATE_PLAYING);
3194   } else {
3195     finish_unprepare (media);
3196   }
3197   return TRUE;
3198 }
3199
3200 /**
3201  * gst_rtsp_media_unprepare:
3202  * @media: a #GstRTSPMedia
3203  *
3204  * Unprepare @media. After this call, the media should be prepared again before
3205  * it can be used again. If the media is set to be non-reusable, a new instance
3206  * must be created.
3207  *
3208  * Returns: %TRUE on success.
3209  */
3210 gboolean
3211 gst_rtsp_media_unprepare (GstRTSPMedia * media)
3212 {
3213   GstRTSPMediaPrivate *priv;
3214   gboolean success;
3215
3216   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3217
3218   priv = media->priv;
3219
3220   g_rec_mutex_lock (&priv->state_lock);
3221   if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
3222     goto was_unprepared;
3223
3224   priv->prepare_count--;
3225   if (priv->prepare_count > 0)
3226     goto is_busy;
3227
3228   GST_INFO ("unprepare media %p", media);
3229   set_target_state (media, GST_STATE_NULL, FALSE);
3230   success = TRUE;
3231
3232   if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
3233     GstRTSPMediaClass *klass;
3234
3235     klass = GST_RTSP_MEDIA_GET_CLASS (media);
3236     if (klass->unprepare)
3237       success = klass->unprepare (media);
3238   } else {
3239     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING);
3240     finish_unprepare (media);
3241   }
3242   g_rec_mutex_unlock (&priv->state_lock);
3243
3244   return success;
3245
3246 was_unprepared:
3247   {
3248     g_rec_mutex_unlock (&priv->state_lock);
3249     GST_INFO ("media %p was already unprepared", media);
3250     return TRUE;
3251   }
3252 is_busy:
3253   {
3254     GST_INFO ("media %p still prepared %d times", media, priv->prepare_count);
3255     g_rec_mutex_unlock (&priv->state_lock);
3256     return TRUE;
3257   }
3258 }
3259
3260 /* should be called with state-lock */
3261 static GstClock *
3262 get_clock_unlocked (GstRTSPMedia * media)
3263 {
3264   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
3265     GST_DEBUG_OBJECT (media, "media was not prepared");
3266     return NULL;
3267   }
3268   return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
3269 }
3270
3271 /**
3272  * gst_rtsp_media_get_clock:
3273  * @media: a #GstRTSPMedia
3274  *
3275  * Get the clock that is used by the pipeline in @media.
3276  *
3277  * @media must be prepared before this method returns a valid clock object.
3278  *
3279  * Returns: (transfer full): the #GstClock used by @media. unref after usage.
3280  */
3281 GstClock *
3282 gst_rtsp_media_get_clock (GstRTSPMedia * media)
3283 {
3284   GstClock *clock;
3285   GstRTSPMediaPrivate *priv;
3286
3287   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
3288
3289   priv = media->priv;
3290
3291   g_rec_mutex_lock (&priv->state_lock);
3292   clock = get_clock_unlocked (media);
3293   g_rec_mutex_unlock (&priv->state_lock);
3294
3295   return clock;
3296 }
3297
3298 /**
3299  * gst_rtsp_media_get_base_time:
3300  * @media: a #GstRTSPMedia
3301  *
3302  * Get the base_time that is used by the pipeline in @media.
3303  *
3304  * @media must be prepared before this method returns a valid base_time.
3305  *
3306  * Returns: the base_time used by @media.
3307  */
3308 GstClockTime
3309 gst_rtsp_media_get_base_time (GstRTSPMedia * media)
3310 {
3311   GstClockTime result;
3312   GstRTSPMediaPrivate *priv;
3313
3314   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE);
3315
3316   priv = media->priv;
3317
3318   g_rec_mutex_lock (&priv->state_lock);
3319   if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
3320     goto not_prepared;
3321
3322   result = gst_element_get_base_time (media->priv->pipeline);
3323   g_rec_mutex_unlock (&priv->state_lock);
3324
3325   return result;
3326
3327   /* ERRORS */
3328 not_prepared:
3329   {
3330     g_rec_mutex_unlock (&priv->state_lock);
3331     GST_DEBUG_OBJECT (media, "media was not prepared");
3332     return GST_CLOCK_TIME_NONE;
3333   }
3334 }
3335
3336 /**
3337  * gst_rtsp_media_get_time_provider:
3338  * @media: a #GstRTSPMedia
3339  * @address: (allow-none): an address or %NULL
3340  * @port: a port or 0
3341  *
3342  * Get the #GstNetTimeProvider for the clock used by @media. The time provider
3343  * will listen on @address and @port for client time requests.
3344  *
3345  * Returns: (transfer full): the #GstNetTimeProvider of @media.
3346  */
3347 GstNetTimeProvider *
3348 gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
3349     guint16 port)
3350 {
3351   GstRTSPMediaPrivate *priv;
3352   GstNetTimeProvider *provider = NULL;
3353
3354   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
3355
3356   priv = media->priv;
3357
3358   g_rec_mutex_lock (&priv->state_lock);
3359   if (priv->time_provider) {
3360     if ((provider = priv->nettime) == NULL) {
3361       GstClock *clock;
3362
3363       if (priv->time_provider && (clock = get_clock_unlocked (media))) {
3364         provider = gst_net_time_provider_new (clock, address, port);
3365         gst_object_unref (clock);
3366
3367         priv->nettime = provider;
3368       }
3369     }
3370   }
3371   g_rec_mutex_unlock (&priv->state_lock);
3372
3373   if (provider)
3374     gst_object_ref (provider);
3375
3376   return provider;
3377 }
3378
3379 static gboolean
3380 default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info)
3381 {
3382   return gst_rtsp_sdp_from_media (sdp, info, media);
3383 }
3384
3385 /**
3386  * gst_rtsp_media_setup_sdp:
3387  * @media: a #GstRTSPMedia
3388  * @sdp: (transfer none): a #GstSDPMessage
3389  * @info: (transfer none): a #GstSDPInfo
3390  *
3391  * Add @media specific info to @sdp. @info is used to configure the connection
3392  * information in the SDP.
3393  *
3394  * Returns: TRUE on success.
3395  */
3396 gboolean
3397 gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
3398     GstSDPInfo * info)
3399 {
3400   GstRTSPMediaPrivate *priv;
3401   GstRTSPMediaClass *klass;
3402   gboolean res;
3403
3404   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3405   g_return_val_if_fail (sdp != NULL, FALSE);
3406   g_return_val_if_fail (info != NULL, FALSE);
3407
3408   priv = media->priv;
3409
3410   g_rec_mutex_lock (&priv->state_lock);
3411
3412   klass = GST_RTSP_MEDIA_GET_CLASS (media);
3413
3414   if (!klass->setup_sdp)
3415     goto no_setup_sdp;
3416
3417   res = klass->setup_sdp (media, sdp, info);
3418
3419   g_rec_mutex_unlock (&priv->state_lock);
3420
3421   return res;
3422
3423   /* ERRORS */
3424 no_setup_sdp:
3425   {
3426     g_rec_mutex_unlock (&priv->state_lock);
3427     GST_ERROR ("no setup_sdp function");
3428     g_critical ("no setup_sdp vmethod function set");
3429     return FALSE;
3430   }
3431 }
3432
3433 static gboolean
3434 default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp)
3435 {
3436   GstRTSPMediaPrivate *priv = media->priv;
3437   gint i, medias_len;
3438
3439   medias_len = gst_sdp_message_medias_len (sdp);
3440   if (medias_len != priv->streams->len) {
3441     GST_ERROR ("%p: Media has more or less streams than SDP (%d /= %d)", media,
3442         priv->streams->len, medias_len);
3443     return FALSE;
3444   }
3445
3446   for (i = 0; i < medias_len; i++) {
3447     const gchar *proto;
3448     const GstSDPMedia *sdp_media = gst_sdp_message_get_media (sdp, i);
3449     GstRTSPStream *stream;
3450     gint j, formats_len;
3451     const gchar *control;
3452     GstRTSPProfile profile, profiles;
3453
3454     stream = g_ptr_array_index (priv->streams, i);
3455
3456     /* TODO: Should we do something with the other SDP information? */
3457
3458     /* get proto */
3459     proto = gst_sdp_media_get_proto (sdp_media);
3460     if (proto == NULL) {
3461       GST_ERROR ("%p: SDP media %d has no proto", media, i);
3462       return FALSE;
3463     }
3464
3465     if (g_str_equal (proto, "RTP/AVP")) {
3466       profile = GST_RTSP_PROFILE_AVP;
3467     } else if (g_str_equal (proto, "RTP/SAVP")) {
3468       profile = GST_RTSP_PROFILE_SAVP;
3469     } else if (g_str_equal (proto, "RTP/AVPF")) {
3470       profile = GST_RTSP_PROFILE_AVPF;
3471     } else if (g_str_equal (proto, "RTP/SAVPF")) {
3472       profile = GST_RTSP_PROFILE_SAVPF;
3473     } else {
3474       GST_ERROR ("%p: unsupported profile '%s' for stream %d", media, proto, i);
3475       return FALSE;
3476     }
3477
3478     profiles = gst_rtsp_stream_get_profiles (stream);
3479     if ((profiles & profile) == 0) {
3480       GST_ERROR ("%p: unsupported profile '%s' for stream %d", media, proto, i);
3481       return FALSE;
3482     }
3483
3484     formats_len = gst_sdp_media_formats_len (sdp_media);
3485     for (j = 0; j < formats_len; j++) {
3486       gint pt;
3487       GstCaps *caps;
3488       GstStructure *s;
3489
3490       pt = atoi (gst_sdp_media_get_format (sdp_media, j));
3491
3492       GST_DEBUG (" looking at %d pt: %d", j, pt);
3493
3494       /* convert caps */
3495       caps = gst_sdp_media_get_caps_from_media (sdp_media, pt);
3496       if (caps == NULL) {
3497         GST_WARNING (" skipping pt %d without caps", pt);
3498         continue;
3499       }
3500
3501       /* do some tweaks */
3502       GST_DEBUG ("mapping sdp session level attributes to caps");
3503       gst_sdp_message_attributes_to_caps (sdp, caps);
3504       GST_DEBUG ("mapping sdp media level attributes to caps");
3505       gst_sdp_media_attributes_to_caps (sdp_media, caps);
3506
3507       s = gst_caps_get_structure (caps, 0);
3508       gst_structure_set_name (s, "application/x-rtp");
3509
3510       gst_rtsp_stream_set_pt_map (stream, pt, caps);
3511       gst_caps_unref (caps);
3512     }
3513
3514     control = gst_sdp_media_get_attribute_val (sdp_media, "control");
3515     if (control)
3516       gst_rtsp_stream_set_control (stream, control);
3517
3518   }
3519
3520   return TRUE;
3521 }
3522
3523 /**
3524  * gst_rtsp_media_handle_sdp:
3525  * @media: a #GstRTSPMedia
3526  * @sdp: (transfer none): a #GstSDPMessage
3527  *
3528  * Configure an SDP on @media for receiving streams
3529  *
3530  * Returns: TRUE on success.
3531  */
3532 gboolean
3533 gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp)
3534 {
3535   GstRTSPMediaPrivate *priv;
3536   GstRTSPMediaClass *klass;
3537   gboolean res;
3538
3539   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3540   g_return_val_if_fail (sdp != NULL, FALSE);
3541
3542   priv = media->priv;
3543
3544   g_rec_mutex_lock (&priv->state_lock);
3545
3546   klass = GST_RTSP_MEDIA_GET_CLASS (media);
3547
3548   if (!klass->handle_sdp)
3549     goto no_handle_sdp;
3550
3551   res = klass->handle_sdp (media, sdp);
3552
3553   g_rec_mutex_unlock (&priv->state_lock);
3554
3555   return res;
3556
3557   /* ERRORS */
3558 no_handle_sdp:
3559   {
3560     g_rec_mutex_unlock (&priv->state_lock);
3561     GST_ERROR ("no handle_sdp function");
3562     g_critical ("no handle_sdp vmethod function set");
3563     return FALSE;
3564   }
3565 }
3566
3567 static void
3568 do_set_seqnum (GstRTSPStream * stream)
3569 {
3570   guint16 seq_num;
3571   seq_num = gst_rtsp_stream_get_current_seqnum (stream);
3572   gst_rtsp_stream_set_seqnum_offset (stream, seq_num + 1);
3573 }
3574
3575 /* call with state_lock */
3576 static gboolean
3577 default_suspend (GstRTSPMedia * media)
3578 {
3579   GstRTSPMediaPrivate *priv = media->priv;
3580   GstStateChangeReturn ret;
3581
3582   switch (priv->suspend_mode) {
3583     case GST_RTSP_SUSPEND_MODE_NONE:
3584       GST_DEBUG ("media %p no suspend", media);
3585       break;
3586     case GST_RTSP_SUSPEND_MODE_PAUSE:
3587       GST_DEBUG ("media %p suspend to PAUSED", media);
3588       ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
3589       if (ret == GST_STATE_CHANGE_FAILURE)
3590         goto state_failed;
3591       break;
3592     case GST_RTSP_SUSPEND_MODE_RESET:
3593       GST_DEBUG ("media %p suspend to NULL", media);
3594       ret = set_target_state (media, GST_STATE_NULL, TRUE);
3595       if (ret == GST_STATE_CHANGE_FAILURE)
3596         goto state_failed;
3597       /* Because payloader needs to set the sequence number as
3598        * monotonic, we need to preserve the sequence number
3599        * after pause. (otherwise going from pause to play,  which
3600        * is actually from NULL to PLAY will create a new sequence
3601        * number. */
3602       g_ptr_array_foreach (priv->streams, (GFunc) do_set_seqnum, NULL);
3603       break;
3604     default:
3605       break;
3606   }
3607
3608   return TRUE;
3609
3610   /* ERRORS */
3611 state_failed:
3612   {
3613     GST_WARNING ("failed changing pipeline's state for media %p", media);
3614     return FALSE;
3615   }
3616 }
3617
3618 /**
3619  * gst_rtsp_media_suspend:
3620  * @media: a #GstRTSPMedia
3621  *
3622  * Suspend @media. The state of the pipeline managed by @media is set to
3623  * GST_STATE_NULL but all streams are kept. @media can be prepared again
3624  * with gst_rtsp_media_unsuspend()
3625  *
3626  * @media must be prepared with gst_rtsp_media_prepare();
3627  *
3628  * Returns: %TRUE on success.
3629  */
3630 gboolean
3631 gst_rtsp_media_suspend (GstRTSPMedia * media)
3632 {
3633   GstRTSPMediaPrivate *priv = media->priv;
3634   GstRTSPMediaClass *klass;
3635
3636   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3637
3638   GST_FIXME ("suspend for dynamic pipelines needs fixing");
3639
3640   g_rec_mutex_lock (&priv->state_lock);
3641   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
3642     goto not_prepared;
3643
3644   /* don't attempt to suspend when something is busy */
3645   if (priv->n_active > 0)
3646     goto done;
3647
3648   klass = GST_RTSP_MEDIA_GET_CLASS (media);
3649   if (klass->suspend) {
3650     if (!klass->suspend (media))
3651       goto suspend_failed;
3652   }
3653
3654   gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_SUSPENDED);
3655 done:
3656   g_rec_mutex_unlock (&priv->state_lock);
3657
3658   return TRUE;
3659
3660   /* ERRORS */
3661 not_prepared:
3662   {
3663     g_rec_mutex_unlock (&priv->state_lock);
3664     GST_WARNING ("media %p was not prepared", media);
3665     return FALSE;
3666   }
3667 suspend_failed:
3668   {
3669     g_rec_mutex_unlock (&priv->state_lock);
3670     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
3671     GST_WARNING ("failed to suspend media %p", media);
3672     return FALSE;
3673   }
3674 }
3675
3676 /* call with state_lock */
3677 static gboolean
3678 default_unsuspend (GstRTSPMedia * media)
3679 {
3680   GstRTSPMediaPrivate *priv = media->priv;
3681   gboolean preroll_ok;
3682
3683   switch (priv->suspend_mode) {
3684     case GST_RTSP_SUSPEND_MODE_NONE:
3685       if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD))
3686         break;
3687       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
3688       /* at this point the media pipeline has been updated and contain all
3689        * specific transport parts: all active streams contain at least one sink
3690        * element and it's safe to unblock any blocked streams that are active */
3691       media_unblock_linked (media);
3692       g_rec_mutex_unlock (&priv->state_lock);
3693       if (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_ERROR) {
3694         g_rec_mutex_lock (&priv->state_lock);
3695         goto preroll_failed;
3696       }
3697       g_rec_mutex_lock (&priv->state_lock);
3698       break;
3699     case GST_RTSP_SUSPEND_MODE_PAUSE:
3700       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
3701       break;
3702     case GST_RTSP_SUSPEND_MODE_RESET:
3703     {
3704       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
3705       /* at this point the media pipeline has been updated and contain all
3706        * specific transport parts: all active streams contain at least one sink
3707        * element and it's safe to unblock any blocked streams that are active */
3708       media_unblock_linked (media);
3709       if (!start_preroll (media))
3710         goto start_failed;
3711
3712       g_rec_mutex_unlock (&priv->state_lock);
3713       preroll_ok = wait_preroll (media);
3714       g_rec_mutex_lock (&priv->state_lock);
3715
3716       if (!preroll_ok)
3717         goto preroll_failed;
3718     }
3719     default:
3720       break;
3721   }
3722
3723   return TRUE;
3724
3725   /* ERRORS */
3726 start_failed:
3727   {
3728     GST_WARNING ("failed to preroll pipeline");
3729     return FALSE;
3730   }
3731 preroll_failed:
3732   {
3733     GST_WARNING ("failed to preroll pipeline");
3734     return FALSE;
3735   }
3736 }
3737
3738 /**
3739  * gst_rtsp_media_unsuspend:
3740  * @media: a #GstRTSPMedia
3741  *
3742  * Unsuspend @media if it was in a suspended state. This method does nothing
3743  * when the media was not in the suspended state.
3744  *
3745  * Returns: %TRUE on success.
3746  */
3747 gboolean
3748 gst_rtsp_media_unsuspend (GstRTSPMedia * media)
3749 {
3750   GstRTSPMediaPrivate *priv = media->priv;
3751   GstRTSPMediaClass *klass;
3752
3753   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3754
3755   g_rec_mutex_lock (&priv->state_lock);
3756   if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
3757     goto done;
3758
3759   klass = GST_RTSP_MEDIA_GET_CLASS (media);
3760   if (klass->unsuspend) {
3761     if (!klass->unsuspend (media))
3762       goto unsuspend_failed;
3763   }
3764
3765 done:
3766   g_rec_mutex_unlock (&priv->state_lock);
3767
3768   return TRUE;
3769
3770   /* ERRORS */
3771 unsuspend_failed:
3772   {
3773     g_rec_mutex_unlock (&priv->state_lock);
3774     GST_WARNING ("failed to unsuspend media %p", media);
3775     gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
3776     return FALSE;
3777   }
3778 }
3779
3780 /* must be called with state-lock */
3781 static void
3782 media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
3783 {
3784   GstRTSPMediaPrivate *priv = media->priv;
3785
3786   if (state == GST_STATE_NULL) {
3787     gst_rtsp_media_unprepare (media);
3788   } else {
3789     GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
3790     set_target_state (media, state, FALSE);
3791     /* when we are buffering, don't update the state yet, this will be done
3792      * when buffering finishes */
3793     if (priv->buffering) {
3794       GST_INFO ("Buffering busy, delay state change");
3795     } else {
3796       if (state == GST_STATE_PLAYING)
3797         /* make sure pads are not blocking anymore when going to PLAYING */
3798         media_unblock_linked (media);
3799
3800       set_state (media, state);
3801
3802       /* and suspend after pause */
3803       if (state == GST_STATE_PAUSED)
3804         gst_rtsp_media_suspend (media);
3805     }
3806   }
3807 }
3808
3809 /**
3810  * gst_rtsp_media_set_pipeline_state:
3811  * @media: a #GstRTSPMedia
3812  * @state: the target state of the pipeline
3813  *
3814  * Set the state of the pipeline managed by @media to @state
3815  */
3816 void
3817 gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state)
3818 {
3819   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
3820
3821   g_rec_mutex_lock (&media->priv->state_lock);
3822   media_set_pipeline_state_locked (media, state);
3823   g_rec_mutex_unlock (&media->priv->state_lock);
3824 }
3825
3826 /**
3827  * gst_rtsp_media_set_state:
3828  * @media: a #GstRTSPMedia
3829  * @state: the target state of the media
3830  * @transports: (transfer none) (element-type GstRtspServer.RTSPStreamTransport):
3831  * a #GPtrArray of #GstRTSPStreamTransport pointers
3832  *
3833  * Set the state of @media to @state and for the transports in @transports.
3834  *
3835  * @media must be prepared with gst_rtsp_media_prepare();
3836  *
3837  * Returns: %TRUE on success.
3838  */
3839 gboolean
3840 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
3841     GPtrArray * transports)
3842 {
3843   GstRTSPMediaPrivate *priv;
3844   gint i;
3845   gboolean activate, deactivate, do_state;
3846   gint old_active;
3847
3848   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
3849   g_return_val_if_fail (transports != NULL, FALSE);
3850
3851   priv = media->priv;
3852
3853   g_rec_mutex_lock (&priv->state_lock);
3854   if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR)
3855     goto error_status;
3856   if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED &&
3857       priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
3858     goto not_prepared;
3859
3860   /* NULL and READY are the same */
3861   if (state == GST_STATE_READY)
3862     state = GST_STATE_NULL;
3863
3864   activate = deactivate = FALSE;
3865
3866   GST_INFO ("going to state %s media %p, target state %s",
3867       gst_element_state_get_name (state), media,
3868       gst_element_state_get_name (priv->target_state));
3869
3870   switch (state) {
3871     case GST_STATE_NULL:
3872       /* we're going from PLAYING or PAUSED to READY or NULL, deactivate */
3873       if (priv->target_state >= GST_STATE_PAUSED)
3874         deactivate = TRUE;
3875       break;
3876     case GST_STATE_PAUSED:
3877       /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */
3878       if (priv->target_state == GST_STATE_PLAYING)
3879         deactivate = TRUE;
3880       break;
3881     case GST_STATE_PLAYING:
3882       /* we're going to PLAYING, activate */
3883       activate = TRUE;
3884       break;
3885     default:
3886       break;
3887   }
3888   old_active = priv->n_active;
3889
3890   GST_DEBUG ("%d transports, activate %d, deactivate %d", transports->len,
3891       activate, deactivate);
3892   for (i = 0; i < transports->len; i++) {
3893     GstRTSPStreamTransport *trans;
3894
3895     /* we need a non-NULL entry in the array */
3896     trans = g_ptr_array_index (transports, i);
3897     if (trans == NULL)
3898       continue;
3899
3900     if (activate) {
3901       if (gst_rtsp_stream_transport_set_active (trans, TRUE))
3902         priv->n_active++;
3903     } else if (deactivate) {
3904       if (gst_rtsp_stream_transport_set_active (trans, FALSE))
3905         priv->n_active--;
3906     }
3907   }
3908
3909   /* we just activated the first media, do the playing state change */
3910   if (old_active == 0 && activate)
3911     do_state = TRUE;
3912   /* if we have no more active media, do the downward state changes */
3913   else if (priv->n_active == 0)
3914     do_state = TRUE;
3915   else
3916     do_state = FALSE;
3917
3918   GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active,
3919       media, do_state);
3920
3921   if (priv->target_state != state) {
3922     if (do_state) {
3923       media_set_pipeline_state_locked (media, state);
3924       g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
3925           NULL);
3926     }
3927   }
3928
3929   /* remember where we are */
3930   if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
3931           old_active != priv->n_active))
3932     collect_media_stats (media);
3933
3934   g_rec_mutex_unlock (&priv->state_lock);
3935
3936   return TRUE;
3937
3938   /* ERRORS */
3939 not_prepared:
3940   {
3941     GST_WARNING ("media %p was not prepared", media);
3942     g_rec_mutex_unlock (&priv->state_lock);
3943     return FALSE;
3944   }
3945 error_status:
3946   {
3947     GST_WARNING ("media %p in error status while changing to state %d",
3948         media, state);
3949     if (state == GST_STATE_NULL) {
3950       for (i = 0; i < transports->len; i++) {
3951         GstRTSPStreamTransport *trans;
3952
3953         /* we need a non-NULL entry in the array */
3954         trans = g_ptr_array_index (transports, i);
3955         if (trans == NULL)
3956           continue;
3957
3958         gst_rtsp_stream_transport_set_active (trans, FALSE);
3959       }
3960       priv->n_active = 0;
3961     }
3962     g_rec_mutex_unlock (&priv->state_lock);
3963     return FALSE;
3964   }
3965 }
3966
3967 /**
3968  * gst_rtsp_media_set_transport_mode:
3969  * @media: a #GstRTSPMedia
3970  * @mode: the new value
3971  *
3972  * Sets if the media pipeline can work in PLAY or RECORD mode
3973  */
3974 void
3975 gst_rtsp_media_set_transport_mode (GstRTSPMedia * media,
3976     GstRTSPTransportMode mode)
3977 {
3978   GstRTSPMediaPrivate *priv;
3979
3980   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
3981
3982   priv = media->priv;
3983
3984   g_mutex_lock (&priv->lock);
3985   priv->transport_mode = mode;
3986   g_mutex_unlock (&priv->lock);
3987 }
3988
3989 /**
3990  * gst_rtsp_media_get_transport_mode:
3991  * @media: a #GstRTSPMedia
3992  *
3993  * Check if the pipeline for @media can be used for PLAY or RECORD methods.
3994  *
3995  * Returns: The transport mode.
3996  */
3997 GstRTSPTransportMode
3998 gst_rtsp_media_get_transport_mode (GstRTSPMedia * media)
3999 {
4000   GstRTSPMediaPrivate *priv;
4001   GstRTSPTransportMode res;
4002
4003   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
4004
4005   priv = media->priv;
4006
4007   g_mutex_lock (&priv->lock);
4008   res = priv->transport_mode;
4009   g_mutex_unlock (&priv->lock);
4010
4011   return res;
4012 }
4013
4014 /**
4015  * gst_rtsp_media_get_seekbale:
4016  * @media: a #GstRTSPMedia
4017  *
4018  * Check if the pipeline for @media seek and up to what point in time,
4019  * it can seek.
4020  *
4021  * Returns: -1 if the stream is not seekable, 0 if seekable only to the beginning
4022  * and > 0 to indicate the longest duration between any two random access points.
4023  * G_MAXINT64 means any value is possible.
4024  */
4025 GstClockTimeDiff
4026 gst_rtsp_media_seekable (GstRTSPMedia * media)
4027 {
4028   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
4029
4030   /* Currently we are not able to seek on live streams,
4031    * and no stream is seekable only to the beginning */
4032   return media->priv->seekable;
4033 }
4034
4035 /**
4036  * gst_rtsp_media_complete_pipeline:
4037  * @media: a #GstRTSPMedia
4038  * @transports: a list of #GstRTSPTransport
4039  *
4040  * Add a receiver and sender parts to the pipeline based on the transport from
4041  * SETUP.
4042  *
4043  * Returns: %TRUE if the media pipeline has been sucessfully updated.
4044  */
4045 gboolean
4046 gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports)
4047 {
4048   GstRTSPMediaPrivate *priv;
4049   guint i;
4050
4051   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
4052   g_return_val_if_fail (transports, FALSE);
4053
4054   GST_DEBUG_OBJECT (media, "complete pipeline");
4055
4056   priv = media->priv;
4057
4058   g_mutex_lock (&priv->lock);
4059   for (i = 0; i < priv->streams->len; i++) {
4060     GstRTSPStreamTransport *transport;
4061     GstRTSPStream *stream;
4062     const GstRTSPTransport *rtsp_transport;
4063
4064     transport = g_ptr_array_index (transports, i);
4065     if (!transport)
4066       continue;
4067
4068     stream = gst_rtsp_stream_transport_get_stream (transport);
4069     if (!stream)
4070       continue;
4071
4072     rtsp_transport = gst_rtsp_stream_transport_get_transport (transport);
4073
4074     if (!gst_rtsp_stream_complete_stream (stream, rtsp_transport)) {
4075       g_mutex_unlock (&priv->lock);
4076       return FALSE;
4077     }
4078   }
4079   g_mutex_unlock (&priv->lock);
4080
4081   return TRUE;
4082 }