media: add suspend modes
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-media-factory.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 /**
20  * SECTION:rtsp-media-factory
21  * @short_description: A factory for media pipelines
22  * @see_also: #GstRTSPMountPoints, #GstRTSPMedia
23  *
24  * The #GstRTSPMediaFactory is responsible for creating or recycling
25  * #GstRTSPMedia objects based on the passed URL.
26  *
27  * The default implementation of the object can create #GstRTSPMedia objects
28  * containing a pipeline created from a launch description set with
29  * gst_rtsp_media_factory_set_launch().
30  *
31  * Media from a factory can be shared by setting the shared flag with
32  * gst_rtsp_media_factory_set_shared(). When a factory is shared,
33  * gst_rtsp_media_factory_construct() will return the same #GstRTSPMedia when
34  * the url matches.
35  *
36  * Last reviewed on 2013-07-11 (1.0.0)
37  */
38
39 #include "rtsp-media-factory.h"
40
41 #define GST_RTSP_MEDIA_FACTORY_GET_PRIVATE(obj)  \
42        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryPrivate))
43
44 #define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)       (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock))
45 #define GST_RTSP_MEDIA_FACTORY_LOCK(f)           (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
46 #define GST_RTSP_MEDIA_FACTORY_UNLOCK(f)         (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
47
48 struct _GstRTSPMediaFactoryPrivate
49 {
50   GMutex lock;                  /* protects everything but medias */
51   GstRTSPPermissions *permissions;
52   gchar *launch;
53   gboolean shared;
54   GstRTSPSuspendMode suspend_mode;
55   gboolean eos_shutdown;
56   GstRTSPLowerTrans protocols;
57   guint buffer_size;
58   GstRTSPAddressPool *pool;
59
60   GMutex medias_lock;
61   GHashTable *medias;           /* protected by medias_lock */
62 };
63
64 #define DEFAULT_LAUNCH          NULL
65 #define DEFAULT_SHARED          FALSE
66 #define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
67 #define DEFAULT_EOS_SHUTDOWN    FALSE
68 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
69                                         GST_RTSP_LOWER_TRANS_TCP
70 #define DEFAULT_BUFFER_SIZE     0x80000
71
72 enum
73 {
74   PROP_0,
75   PROP_LAUNCH,
76   PROP_SHARED,
77   PROP_SUSPEND_MODE,
78   PROP_EOS_SHUTDOWN,
79   PROP_PROTOCOLS,
80   PROP_BUFFER_SIZE,
81   PROP_LAST
82 };
83
84 enum
85 {
86   SIGNAL_MEDIA_CONSTRUCTED,
87   SIGNAL_MEDIA_CONFIGURE,
88   SIGNAL_LAST
89 };
90
91 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
92 #define GST_CAT_DEFAULT rtsp_media_debug
93
94 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
95
96 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
97     GValue * value, GParamSpec * pspec);
98 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
99     const GValue * value, GParamSpec * pspec);
100 static void gst_rtsp_media_factory_finalize (GObject * obj);
101
102 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
103     const GstRTSPUrl * url);
104 static GstElement *default_create_element (GstRTSPMediaFactory * factory,
105     const GstRTSPUrl * url);
106 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
107     const GstRTSPUrl * url);
108 static void default_configure (GstRTSPMediaFactory * factory,
109     GstRTSPMedia * media);
110 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
111     GstRTSPMedia * media);
112
113 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
114
115 static void
116 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
117 {
118   GObjectClass *gobject_class;
119
120   g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryPrivate));
121
122   gobject_class = G_OBJECT_CLASS (klass);
123
124   gobject_class->get_property = gst_rtsp_media_factory_get_property;
125   gobject_class->set_property = gst_rtsp_media_factory_set_property;
126   gobject_class->finalize = gst_rtsp_media_factory_finalize;
127
128   /**
129    * GstRTSPMediaFactory::launch:
130    *
131    * The gst_parse_launch() line to use for constructing the pipeline in the
132    * default prepare vmethod.
133    *
134    * The pipeline description should return a GstBin as the toplevel element
135    * which can be accomplished by enclosing the dscription with brackets '('
136    * ')'.
137    *
138    * The description should return a pipeline with payloaders named pay0, pay1,
139    * etc.. Each of the payloaders will result in a stream.
140    *
141    * Support for dynamic payloaders can be accomplished by adding payloaders
142    * named dynpay0, dynpay1, etc..
143    */
144   g_object_class_install_property (gobject_class, PROP_LAUNCH,
145       g_param_spec_string ("launch", "Launch",
146           "A launch description of the pipeline", DEFAULT_LAUNCH,
147           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
148
149   g_object_class_install_property (gobject_class, PROP_SHARED,
150       g_param_spec_boolean ("shared", "Shared",
151           "If media from this factory is shared", DEFAULT_SHARED,
152           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
153
154   g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
155       g_param_spec_enum ("suspend-mode", "Suspend Mode",
156           "Control how media will be suspended", GST_TYPE_RTSP_SUSPEND_MODE,
157           DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
158
159   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
160       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
161           "Send EOS down the pipeline before shutting down",
162           DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
163
164   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
165       g_param_spec_flags ("protocols", "Protocols",
166           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
167           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168
169   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
170       g_param_spec_uint ("buffer-size", "Buffer Size",
171           "The kernel UDP buffer size to use", 0, G_MAXUINT,
172           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
173
174   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
175       g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
176       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
177           media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
178       G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
179
180   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] =
181       g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass),
182       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
183           media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
184       G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
185
186   klass->gen_key = default_gen_key;
187   klass->create_element = default_create_element;
188   klass->construct = default_construct;
189   klass->configure = default_configure;
190   klass->create_pipeline = default_create_pipeline;
191
192   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
193       "GstRTSPMediaFactory");
194 }
195
196 static void
197 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
198 {
199   GstRTSPMediaFactoryPrivate *priv =
200       GST_RTSP_MEDIA_FACTORY_GET_PRIVATE (factory);
201   factory->priv = priv;
202
203   priv->launch = g_strdup (DEFAULT_LAUNCH);
204   priv->shared = DEFAULT_SHARED;
205   priv->suspend_mode = DEFAULT_SUSPEND_MODE;
206   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
207   priv->protocols = DEFAULT_PROTOCOLS;
208   priv->buffer_size = DEFAULT_BUFFER_SIZE;
209
210   g_mutex_init (&priv->lock);
211   g_mutex_init (&priv->medias_lock);
212   priv->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
213       g_free, g_object_unref);
214 }
215
216 static void
217 gst_rtsp_media_factory_finalize (GObject * obj)
218 {
219   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
220   GstRTSPMediaFactoryPrivate *priv = factory->priv;
221
222   if (priv->permissions)
223     gst_rtsp_permissions_unref (priv->permissions);
224   g_hash_table_unref (priv->medias);
225   g_mutex_clear (&priv->medias_lock);
226   g_free (priv->launch);
227   g_mutex_clear (&priv->lock);
228   if (priv->pool)
229     g_object_unref (priv->pool);
230
231   G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
232 }
233
234 static void
235 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
236     GValue * value, GParamSpec * pspec)
237 {
238   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
239
240   switch (propid) {
241     case PROP_LAUNCH:
242       g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
243       break;
244     case PROP_SHARED:
245       g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
246       break;
247     case PROP_SUSPEND_MODE:
248       g_value_set_enum (value,
249           gst_rtsp_media_factory_get_suspend_mode (factory));
250       break;
251     case PROP_EOS_SHUTDOWN:
252       g_value_set_boolean (value,
253           gst_rtsp_media_factory_is_eos_shutdown (factory));
254       break;
255     case PROP_PROTOCOLS:
256       g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory));
257       break;
258     case PROP_BUFFER_SIZE:
259       g_value_set_uint (value,
260           gst_rtsp_media_factory_get_buffer_size (factory));
261       break;
262     default:
263       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
264   }
265 }
266
267 static void
268 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
269     const GValue * value, GParamSpec * pspec)
270 {
271   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
272
273   switch (propid) {
274     case PROP_LAUNCH:
275       gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
276       break;
277     case PROP_SHARED:
278       gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
279       break;
280     case PROP_SUSPEND_MODE:
281       gst_rtsp_media_factory_set_suspend_mode (factory,
282           g_value_get_enum (value));
283       break;
284     case PROP_EOS_SHUTDOWN:
285       gst_rtsp_media_factory_set_eos_shutdown (factory,
286           g_value_get_boolean (value));
287       break;
288     case PROP_PROTOCOLS:
289       gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value));
290       break;
291     case PROP_BUFFER_SIZE:
292       gst_rtsp_media_factory_set_buffer_size (factory,
293           g_value_get_uint (value));
294       break;
295     default:
296       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
297   }
298 }
299
300 /**
301  * gst_rtsp_media_factory_new:
302  *
303  * Create a new #GstRTSPMediaFactory instance.
304  *
305  * Returns: a new #GstRTSPMediaFactory object.
306  */
307 GstRTSPMediaFactory *
308 gst_rtsp_media_factory_new (void)
309 {
310   GstRTSPMediaFactory *result;
311
312   result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
313
314   return result;
315 }
316
317 /**
318  * gst_rtsp_media_factory_set_permissions:
319  * @factory: a #GstRTSPMediaFactory
320  * @permissions: a #GstRTSPPermissions
321  *
322  * Set @permissions on @factory.
323  */
324 void
325 gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory * factory,
326     GstRTSPPermissions * permissions)
327 {
328   GstRTSPMediaFactoryPrivate *priv;
329
330   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
331
332   priv = factory->priv;
333
334   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
335   if (priv->permissions)
336     gst_rtsp_permissions_unref (priv->permissions);
337   if ((priv->permissions = permissions))
338     gst_rtsp_permissions_ref (permissions);
339   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
340 }
341
342 /**
343  * gst_rtsp_media_factory_get_permissions:
344  * @factory: a #GstRTSPMediaFactory
345  *
346  * Get the permissions object from @factory.
347  *
348  * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage.
349  */
350 GstRTSPPermissions *
351 gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory * factory)
352 {
353   GstRTSPMediaFactoryPrivate *priv;
354   GstRTSPPermissions *result;
355
356   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
357
358   priv = factory->priv;
359
360   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
361   if ((result = priv->permissions))
362     gst_rtsp_permissions_ref (result);
363   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
364
365   return result;
366 }
367
368 /**
369  * gst_rtsp_media_factory_add_role:
370  * @factory: a #GstRTSPMediaFactory
371  * @role: a role
372  * @fieldname: the first field name
373  * @...: additional arguments
374  *
375  * A convenience method to add @role with @fieldname and additional arguments to
376  * the permissions of @factory. If @factory had no permissions, new permissions
377  * will be created and the role will be added to it.
378  */
379 void
380 gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory,
381     const gchar * role, const gchar * fieldname, ...)
382 {
383   GstRTSPMediaFactoryPrivate *priv;
384   va_list var_args;
385
386   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
387   g_return_if_fail (role != NULL);
388   g_return_if_fail (fieldname != NULL);
389
390   priv = factory->priv;
391
392   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
393   if (priv->permissions == NULL)
394     priv->permissions = gst_rtsp_permissions_new ();
395
396   va_start (var_args, fieldname);
397   gst_rtsp_permissions_add_role_valist (priv->permissions, role, fieldname,
398       var_args);
399   va_end (var_args);
400   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
401 }
402
403 /**
404  * gst_rtsp_media_factory_set_launch:
405  * @factory: a #GstRTSPMediaFactory
406  * @launch: the launch description
407  *
408  *
409  * The gst_parse_launch() line to use for constructing the pipeline in the
410  * default prepare vmethod.
411  *
412  * The pipeline description should return a GstBin as the toplevel element
413  * which can be accomplished by enclosing the dscription with brackets '('
414  * ')'.
415  *
416  * The description should return a pipeline with payloaders named pay0, pay1,
417  * etc.. Each of the payloaders will result in a stream.
418  */
419 void
420 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
421     const gchar * launch)
422 {
423   GstRTSPMediaFactoryPrivate *priv;
424
425   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
426   g_return_if_fail (launch != NULL);
427
428   priv = factory->priv;
429
430   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
431   g_free (priv->launch);
432   priv->launch = g_strdup (launch);
433   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
434 }
435
436 /**
437  * gst_rtsp_media_factory_get_launch:
438  * @factory: a #GstRTSPMediaFactory
439  *
440  * Get the gst_parse_launch() pipeline description that will be used in the
441  * default prepare vmethod.
442  *
443  * Returns: the configured launch description. g_free() after usage.
444  */
445 gchar *
446 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
447 {
448   GstRTSPMediaFactoryPrivate *priv;
449   gchar *result;
450
451   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
452
453   priv = factory->priv;
454
455   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
456   result = g_strdup (priv->launch);
457   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
458
459   return result;
460 }
461
462 /**
463  * gst_rtsp_media_factory_set_suspend_mode:
464  * @factory: a #GstRTSPMediaFactory
465  * @mode: the new #GstRTSPSuspendMode
466  *
467  * Configure how media created from this factory will be suspended.
468  */
469 void
470 gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory * factory,
471     GstRTSPSuspendMode mode)
472 {
473   GstRTSPMediaFactoryPrivate *priv;
474
475   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
476
477   priv = factory->priv;
478
479   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
480   priv->suspend_mode = mode;
481   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
482 }
483
484 /**
485  * gst_rtsp_media_factory_get_suspend_mode:
486  * @factory: a #GstRTSPMediaFactory
487  *
488  * Get how media created from this factory will be suspended.
489  *
490  * Returns: a #GstRTSPSuspendMode.
491  */
492 GstRTSPSuspendMode
493 gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory * factory)
494 {
495   GstRTSPMediaFactoryPrivate *priv;
496   GstRTSPSuspendMode result;
497
498   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
499       GST_RTSP_SUSPEND_MODE_NONE);
500
501   priv = factory->priv;
502
503   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
504   result = priv->suspend_mode;
505   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
506
507   return result;
508 }
509
510 /**
511  * gst_rtsp_media_factory_set_shared:
512  * @factory: a #GstRTSPMediaFactory
513  * @shared: the new value
514  *
515  * Configure if media created from this factory can be shared between clients.
516  */
517 void
518 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
519     gboolean shared)
520 {
521   GstRTSPMediaFactoryPrivate *priv;
522
523   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
524
525   priv = factory->priv;
526
527   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
528   priv->shared = shared;
529   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
530 }
531
532 /**
533  * gst_rtsp_media_factory_is_shared:
534  * @factory: a #GstRTSPMediaFactory
535  *
536  * Get if media created from this factory can be shared between clients.
537  *
538  * Returns: %TRUE if the media will be shared between clients.
539  */
540 gboolean
541 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
542 {
543   GstRTSPMediaFactoryPrivate *priv;
544   gboolean result;
545
546   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
547
548   priv = factory->priv;
549
550   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
551   result = priv->shared;
552   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
553
554   return result;
555 }
556
557 /**
558  * gst_rtsp_media_factory_set_eos_shutdown:
559  * @factory: a #GstRTSPMediaFactory
560  * @eos_shutdown: the new value
561  *
562  * Configure if media created from this factory will have an EOS sent to the
563  * pipeline before shutdown.
564  */
565 void
566 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
567     gboolean eos_shutdown)
568 {
569   GstRTSPMediaFactoryPrivate *priv;
570
571   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
572
573   priv = factory->priv;
574
575   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
576   priv->eos_shutdown = eos_shutdown;
577   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
578 }
579
580 /**
581  * gst_rtsp_media_factory_is_eos_shutdown:
582  * @factory: a #GstRTSPMediaFactory
583  *
584  * Get if media created from this factory will have an EOS event sent to the
585  * pipeline before shutdown.
586  *
587  * Returns: %TRUE if the media will receive EOS before shutdown.
588  */
589 gboolean
590 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
591 {
592   GstRTSPMediaFactoryPrivate *priv;
593   gboolean result;
594
595   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
596
597   priv = factory->priv;
598
599   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
600   result = priv->eos_shutdown;
601   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
602
603   return result;
604 }
605
606 /**
607  * gst_rtsp_media_factory_set_buffer_size:
608  * @factory: a #GstRTSPMedia
609  * @size: the new value
610  *
611  * Set the kernel UDP buffer size.
612  */
613 void
614 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
615     guint size)
616 {
617   GstRTSPMediaFactoryPrivate *priv;
618
619   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
620
621   priv = factory->priv;
622
623   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
624   priv->buffer_size = size;
625   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
626 }
627
628 /**
629  * gst_rtsp_media_factory_get_buffer_size:
630  * @factory: a #GstRTSPMedia
631  *
632  * Get the kernel UDP buffer size.
633  *
634  * Returns: the kernel UDP buffer size.
635  */
636 guint
637 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
638 {
639   GstRTSPMediaFactoryPrivate *priv;
640   guint result;
641
642   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
643
644   priv = factory->priv;
645
646   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
647   result = priv->buffer_size;
648   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
649
650   return result;
651 }
652
653 /**
654  * gst_rtsp_media_factory_set_address_pool:
655  * @factory: a #GstRTSPMediaFactory
656  * @pool: a #GstRTSPAddressPool
657  *
658  * configure @pool to be used as the address pool of @factory.
659  */
660 void
661 gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory,
662     GstRTSPAddressPool * pool)
663 {
664   GstRTSPMediaFactoryPrivate *priv;
665   GstRTSPAddressPool *old;
666
667   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
668
669   priv = factory->priv;
670
671   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
672   if ((old = priv->pool) != pool)
673     priv->pool = pool ? g_object_ref (pool) : NULL;
674   else
675     old = NULL;
676   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
677
678   if (old)
679     g_object_unref (old);
680 }
681
682 /**
683  * gst_rtsp_media_factory_get_address_pool:
684  * @factory: a #GstRTSPMediaFactory
685  *
686  * Get the #GstRTSPAddressPool used as the address pool of @factory.
687  *
688  * Returns: (transfer full): the #GstRTSPAddressPool of @factory. g_object_unref() after
689  * usage.
690  */
691 GstRTSPAddressPool *
692 gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory)
693 {
694   GstRTSPMediaFactoryPrivate *priv;
695   GstRTSPAddressPool *result;
696
697   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
698
699   priv = factory->priv;
700
701   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
702   if ((result = priv->pool))
703     g_object_ref (result);
704   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
705
706   return result;
707 }
708
709 /**
710  * gst_rtsp_media_factory_set_protocols:
711  * @factory: a #GstRTSPMediaFactory
712  * @protocols: the new flags
713  *
714  * Configure the allowed lower transport for @factory.
715  */
716 void
717 gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory,
718     GstRTSPLowerTrans protocols)
719 {
720   GstRTSPMediaFactoryPrivate *priv;
721
722   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
723
724   priv = factory->priv;
725
726   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
727   priv->protocols = protocols;
728   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
729 }
730
731 /**
732  * gst_rtsp_media_factory_get_protocols:
733  * @factory: a #GstRTSPMediaFactory
734  *
735  * Get the allowed protocols of @factory.
736  *
737  * Returns: a #GstRTSPLowerTrans
738  */
739 GstRTSPLowerTrans
740 gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
741 {
742   GstRTSPMediaFactoryPrivate *priv;
743   GstRTSPLowerTrans res;
744
745   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
746       GST_RTSP_LOWER_TRANS_UNKNOWN);
747
748   priv = factory->priv;
749
750   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
751   res = priv->protocols;
752   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
753
754   return res;
755 }
756
757 static gboolean
758 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
759 {
760   return (media1 == media2);
761 }
762
763 static void
764 media_unprepared (GstRTSPMedia * media, GWeakRef * ref)
765 {
766   GstRTSPMediaFactory *factory = g_weak_ref_get (ref);
767   GstRTSPMediaFactoryPrivate *priv;
768
769   if (!factory)
770     return;
771
772   priv = factory->priv;;
773
774   g_mutex_lock (&priv->medias_lock);
775   g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media);
776   g_mutex_unlock (&priv->medias_lock);
777
778   g_object_unref (factory);
779 }
780
781 static GWeakRef *
782 weak_ref_new (gpointer obj)
783 {
784   GWeakRef *ref = g_slice_new (GWeakRef);
785
786   g_weak_ref_init (ref, obj);
787   return ref;
788 }
789
790 static void
791 weak_ref_free (GWeakRef * ref)
792 {
793   g_weak_ref_clear (ref);
794   g_slice_free (GWeakRef, ref);
795 }
796
797 /**
798  * gst_rtsp_media_factory_construct:
799  * @factory: a #GstRTSPMediaFactory
800  * @url: the url used
801  *
802  * Construct the media object and create its streams. Implementations
803  * should create the needed gstreamer elements and add them to the result
804  * object. No state changes should be performed on them yet.
805  *
806  * One or more GstRTSPStream objects should be created from the result
807  * with gst_rtsp_media_create_stream ().
808  *
809  * After the media is constructed, it can be configured and then prepared
810  * with gst_rtsp_media_prepare ().
811  *
812  * Returns: (transfer full): a new #GstRTSPMedia if the media could be prepared.
813  */
814 GstRTSPMedia *
815 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
816     const GstRTSPUrl * url)
817 {
818   GstRTSPMediaFactoryPrivate *priv;
819   gchar *key;
820   GstRTSPMedia *media;
821   GstRTSPMediaFactoryClass *klass;
822
823   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
824   g_return_val_if_fail (url != NULL, NULL);
825
826   priv = factory->priv;;
827   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
828
829   /* convert the url to a key for the hashtable. NULL return or a NULL function
830    * will not cache anything for this factory. */
831   if (klass->gen_key)
832     key = klass->gen_key (factory, url);
833   else
834     key = NULL;
835
836   g_mutex_lock (&priv->medias_lock);
837   if (key) {
838     /* we have a key, see if we find a cached media */
839     media = g_hash_table_lookup (priv->medias, key);
840     if (media)
841       g_object_ref (media);
842   } else
843     media = NULL;
844
845   if (media == NULL) {
846     /* nothing cached found, try to create one */
847     if (klass->construct) {
848       media = klass->construct (factory, url);
849       if (media)
850         g_signal_emit (factory,
851             gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
852             NULL);
853     } else
854       media = NULL;
855
856     if (media) {
857       /* configure the media */
858       if (klass->configure)
859         klass->configure (factory, media);
860
861       g_signal_emit (factory,
862           gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
863           NULL);
864
865       /* check if we can cache this media */
866       if (gst_rtsp_media_is_shared (media)) {
867         /* insert in the hashtable, takes ownership of the key */
868         g_object_ref (media);
869         g_hash_table_insert (priv->medias, key, media);
870         key = NULL;
871       }
872       if (!gst_rtsp_media_is_reusable (media)) {
873         /* when not reusable, connect to the unprepare signal to remove the item
874          * from our cache when it gets unprepared */
875         g_signal_connect_data (media, "unprepared",
876             (GCallback) media_unprepared, weak_ref_new (factory),
877             (GClosureNotify) weak_ref_free, 0);
878       }
879     }
880   }
881   g_mutex_unlock (&priv->medias_lock);
882
883   if (key)
884     g_free (key);
885
886   GST_INFO ("constructed media %p for url %s", media, url->abspath);
887
888   return media;
889 }
890
891 static gchar *
892 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
893 {
894   gchar *result;
895   const gchar *pre_query;
896   const gchar *query;
897
898   pre_query = url->query ? "?" : "";
899   query = url->query ? url->query : "";
900
901   result =
902       g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
903
904   return result;
905 }
906
907 static GstElement *
908 default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
909 {
910   GstRTSPMediaFactoryPrivate *priv = factory->priv;
911   GstElement *element;
912   GError *error = NULL;
913
914   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
915   /* we need a parse syntax */
916   if (priv->launch == NULL)
917     goto no_launch;
918
919   /* parse the user provided launch line */
920   element = gst_parse_launch (priv->launch, &error);
921   if (element == NULL)
922     goto parse_error;
923
924   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
925
926   if (error != NULL) {
927     /* a recoverable error was encountered */
928     GST_WARNING ("recoverable parsing error: %s", error->message);
929     g_error_free (error);
930   }
931   return element;
932
933   /* ERRORS */
934 no_launch:
935   {
936     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
937     g_critical ("no launch line specified");
938     return NULL;
939   }
940 parse_error:
941   {
942     g_critical ("could not parse launch syntax (%s): %s", priv->launch,
943         (error ? error->message : "unknown reason"));
944     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
945     if (error)
946       g_error_free (error);
947     return NULL;
948   }
949 }
950
951 static GstRTSPMedia *
952 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
953 {
954   GstRTSPMedia *media;
955   GstElement *element, *pipeline;
956   GstRTSPMediaFactoryClass *klass;
957
958   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
959
960   if (!klass->create_pipeline)
961     goto no_create;
962
963   element = gst_rtsp_media_factory_create_element (factory, url);
964   if (element == NULL)
965     goto no_element;
966
967   /* create a new empty media */
968   media = gst_rtsp_media_new (element);
969
970   gst_rtsp_media_collect_streams (media);
971
972   pipeline = klass->create_pipeline (factory, media);
973   if (pipeline == NULL)
974     goto no_pipeline;
975
976   return media;
977
978   /* ERRORS */
979 no_create:
980   {
981     g_critical ("no create_pipeline function");
982     return NULL;
983   }
984 no_element:
985   {
986     g_critical ("could not create element");
987     return NULL;
988   }
989 no_pipeline:
990   {
991     g_critical ("can't create pipeline");
992     g_object_unref (media);
993     return NULL;
994   }
995 }
996
997 static GstElement *
998 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
999 {
1000   GstElement *pipeline;
1001
1002   pipeline = gst_pipeline_new ("media-pipeline");
1003   gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline));
1004
1005   return pipeline;
1006 }
1007
1008 static void
1009 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
1010 {
1011   GstRTSPMediaFactoryPrivate *priv = factory->priv;
1012   gboolean shared, eos_shutdown;
1013   guint size;
1014   GstRTSPSuspendMode suspend_mode;
1015   GstRTSPLowerTrans protocols;
1016   GstRTSPAddressPool *pool;
1017   GstRTSPPermissions *perms;
1018
1019   /* configure the sharedness */
1020   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1021   suspend_mode = priv->suspend_mode;
1022   shared = priv->shared;
1023   eos_shutdown = priv->eos_shutdown;
1024   size = priv->buffer_size;
1025   protocols = priv->protocols;
1026   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1027
1028   gst_rtsp_media_set_suspend_mode (media, suspend_mode);
1029   gst_rtsp_media_set_shared (media, shared);
1030   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
1031   gst_rtsp_media_set_buffer_size (media, size);
1032   gst_rtsp_media_set_protocols (media, protocols);
1033
1034   if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) {
1035     gst_rtsp_media_set_address_pool (media, pool);
1036     g_object_unref (pool);
1037   }
1038   if ((perms = gst_rtsp_media_factory_get_permissions (factory))) {
1039     gst_rtsp_media_set_permissions (media, perms);
1040     gst_rtsp_permissions_unref (perms);
1041   }
1042 }
1043
1044 /**
1045  * gst_rtsp_media_factory_create_element:
1046  * @factory: a #GstRTSPMediaFactory
1047  * @url: the url used
1048  *
1049  * Construct and return a #GstElement that is a #GstBin containing
1050  * the elements to use for streaming the media.
1051  *
1052  * The bin should contain payloaders pay\%d for each stream. The default
1053  * implementation of this function returns the bin created from the
1054  * launch parameter.
1055  *
1056  * Returns: (transfer floating) a new #GstElement.
1057  */
1058 GstElement *
1059 gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory,
1060     const GstRTSPUrl * url)
1061 {
1062   GstRTSPMediaFactoryClass *klass;
1063   GstElement *result;
1064
1065   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
1066   g_return_val_if_fail (url != NULL, NULL);
1067
1068   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
1069
1070   if (klass->create_element)
1071     result = klass->create_element (factory, url);
1072   else
1073     result = NULL;
1074
1075   return result;
1076 }