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