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