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