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