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