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