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