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