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