9cea6ca962c152de6e468628245db9400e292985
[platform/upstream/gst-rtsp-server.git] / gst / rtsp-server / rtsp-media-factory.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  * Copyright (C) 2015 Centricular Ltd
4  *     Author: Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:rtsp-media-factory
23  * @short_description: A factory for media pipelines
24  * @see_also: #GstRTSPMountPoints, #GstRTSPMedia
25  *
26  * The #GstRTSPMediaFactory is responsible for creating or recycling
27  * #GstRTSPMedia objects based on the passed URL.
28  *
29  * The default implementation of the object can create #GstRTSPMedia objects
30  * containing a pipeline created from a launch description set with
31  * gst_rtsp_media_factory_set_launch().
32  *
33  * Media from a factory can be shared by setting the shared flag with
34  * gst_rtsp_media_factory_set_shared(). When a factory is shared,
35  * gst_rtsp_media_factory_construct() will return the same #GstRTSPMedia when
36  * the url matches.
37  *
38  * Last reviewed on 2013-07-11 (1.0.0)
39  */
40
41 #include "rtsp-media-factory.h"
42
43 #define GST_RTSP_MEDIA_FACTORY_GET_PRIVATE(obj)  \
44        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryPrivate))
45
46 #define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)       (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock))
47 #define GST_RTSP_MEDIA_FACTORY_LOCK(f)           (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
48 #define GST_RTSP_MEDIA_FACTORY_UNLOCK(f)         (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f)))
49
50 struct _GstRTSPMediaFactoryPrivate
51 {
52   GMutex lock;                  /* protects everything but medias */
53   GstRTSPPermissions *permissions;
54   gchar *launch;
55   gboolean shared;
56   GstRTSPSuspendMode suspend_mode;
57   gboolean eos_shutdown;
58   GstRTSPProfile profiles;
59   GstRTSPLowerTrans protocols;
60   guint buffer_size;
61   GstRTSPAddressPool *pool;
62   GstRTSPTransportMode transport_mode;
63   gboolean stop_on_disconnect;
64   gchar *multicast_iface;
65
66   GstClockTime rtx_time;
67   guint latency;
68
69   GMutex medias_lock;
70   GHashTable *medias;           /* protected by medias_lock */
71
72   GType media_gtype;
73
74   GstClock *clock;
75
76   GstRTSPPublishClockMode publish_clock_mode;
77 };
78
79 #define DEFAULT_LAUNCH          NULL
80 #define DEFAULT_SHARED          FALSE
81 #define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
82 #define DEFAULT_EOS_SHUTDOWN    FALSE
83 #define DEFAULT_PROFILES        GST_RTSP_PROFILE_AVP
84 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
85                                         GST_RTSP_LOWER_TRANS_TCP
86 #define DEFAULT_BUFFER_SIZE     0x80000
87 #define DEFAULT_LATENCY         200
88 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
89 #define DEFAULT_STOP_ON_DISCONNECT TRUE
90
91 enum
92 {
93   PROP_0,
94   PROP_LAUNCH,
95   PROP_SHARED,
96   PROP_SUSPEND_MODE,
97   PROP_EOS_SHUTDOWN,
98   PROP_PROFILES,
99   PROP_PROTOCOLS,
100   PROP_BUFFER_SIZE,
101   PROP_LATENCY,
102   PROP_TRANSPORT_MODE,
103   PROP_STOP_ON_DISCONNECT,
104   PROP_CLOCK,
105   PROP_LAST
106 };
107
108 enum
109 {
110   SIGNAL_MEDIA_CONSTRUCTED,
111   SIGNAL_MEDIA_CONFIGURE,
112   SIGNAL_LAST
113 };
114
115 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
116 #define GST_CAT_DEFAULT rtsp_media_debug
117
118 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
119
120 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
121     GValue * value, GParamSpec * pspec);
122 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
123     const GValue * value, GParamSpec * pspec);
124 static void gst_rtsp_media_factory_finalize (GObject * obj);
125
126 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
127     const GstRTSPUrl * url);
128 static GstElement *default_create_element (GstRTSPMediaFactory * factory,
129     const GstRTSPUrl * url);
130 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
131     const GstRTSPUrl * url);
132 static void default_configure (GstRTSPMediaFactory * factory,
133     GstRTSPMedia * media);
134 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
135     GstRTSPMedia * media);
136
137 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
138
139 static void
140 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
141 {
142   GObjectClass *gobject_class;
143
144   g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryPrivate));
145
146   gobject_class = G_OBJECT_CLASS (klass);
147
148   gobject_class->get_property = gst_rtsp_media_factory_get_property;
149   gobject_class->set_property = gst_rtsp_media_factory_set_property;
150   gobject_class->finalize = gst_rtsp_media_factory_finalize;
151
152   /**
153    * GstRTSPMediaFactory::launch:
154    *
155    * The gst_parse_launch() line to use for constructing the pipeline in the
156    * default prepare vmethod.
157    *
158    * The pipeline description should return a GstBin as the toplevel element
159    * which can be accomplished by enclosing the dscription with brackets '('
160    * ')'.
161    *
162    * The description should return a pipeline with payloaders named pay0, pay1,
163    * etc.. Each of the payloaders will result in a stream.
164    *
165    * Support for dynamic payloaders can be accomplished by adding payloaders
166    * named dynpay0, dynpay1, etc..
167    */
168   g_object_class_install_property (gobject_class, PROP_LAUNCH,
169       g_param_spec_string ("launch", "Launch",
170           "A launch description of the pipeline", DEFAULT_LAUNCH,
171           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
172
173   g_object_class_install_property (gobject_class, PROP_SHARED,
174       g_param_spec_boolean ("shared", "Shared",
175           "If media from this factory is shared", DEFAULT_SHARED,
176           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
177
178   g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
179       g_param_spec_enum ("suspend-mode", "Suspend Mode",
180           "Control how media will be suspended", GST_TYPE_RTSP_SUSPEND_MODE,
181           DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182
183   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
184       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
185           "Send EOS down the pipeline before shutting down",
186           DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187
188   g_object_class_install_property (gobject_class, PROP_PROFILES,
189       g_param_spec_flags ("profiles", "Profiles",
190           "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE,
191           DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192
193   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
194       g_param_spec_flags ("protocols", "Protocols",
195           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
196           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197
198   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
199       g_param_spec_uint ("buffer-size", "Buffer Size",
200           "The kernel UDP buffer size to use", 0, G_MAXUINT,
201           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202
203   g_object_class_install_property (gobject_class, PROP_LATENCY,
204       g_param_spec_uint ("latency", "Latency",
205           "Latency used for receiving media in milliseconds", 0, G_MAXUINT,
206           DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207
208   g_object_class_install_property (gobject_class, PROP_TRANSPORT_MODE,
209       g_param_spec_flags ("transport-mode", "Transport Mode",
210           "If media from this factory is for PLAY or RECORD",
211           GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213
214   g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT,
215       g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect",
216           "If media from this factory should be stopped "
217           "when a client disconnects without TEARDOWN",
218           DEFAULT_STOP_ON_DISCONNECT,
219           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
220
221   g_object_class_install_property (gobject_class, PROP_CLOCK,
222       g_param_spec_object ("clock", "Clock",
223           "Clock to be used by the pipelines created for all "
224           "medias of this factory", GST_TYPE_CLOCK,
225           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
226
227   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
228       g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
229       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
230           media_constructed), NULL, NULL, g_cclosure_marshal_generic,
231       G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
232
233   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] =
234       g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass),
235       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
236           media_configure), NULL, NULL, g_cclosure_marshal_generic,
237       G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
238
239   klass->gen_key = default_gen_key;
240   klass->create_element = default_create_element;
241   klass->construct = default_construct;
242   klass->configure = default_configure;
243   klass->create_pipeline = default_create_pipeline;
244
245   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
246       "GstRTSPMediaFactory");
247 }
248
249 static void
250 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
251 {
252   GstRTSPMediaFactoryPrivate *priv =
253       GST_RTSP_MEDIA_FACTORY_GET_PRIVATE (factory);
254   factory->priv = priv;
255
256   priv->launch = g_strdup (DEFAULT_LAUNCH);
257   priv->shared = DEFAULT_SHARED;
258   priv->suspend_mode = DEFAULT_SUSPEND_MODE;
259   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
260   priv->profiles = DEFAULT_PROFILES;
261   priv->protocols = DEFAULT_PROTOCOLS;
262   priv->buffer_size = DEFAULT_BUFFER_SIZE;
263   priv->latency = DEFAULT_LATENCY;
264   priv->transport_mode = DEFAULT_TRANSPORT_MODE;
265   priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
266   priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
267
268   g_mutex_init (&priv->lock);
269   g_mutex_init (&priv->medias_lock);
270   priv->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
271       g_free, g_object_unref);
272   priv->media_gtype = GST_TYPE_RTSP_MEDIA;
273 }
274
275 static void
276 gst_rtsp_media_factory_finalize (GObject * obj)
277 {
278   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
279   GstRTSPMediaFactoryPrivate *priv = factory->priv;
280
281   if (priv->permissions)
282     gst_rtsp_permissions_unref (priv->permissions);
283   g_hash_table_unref (priv->medias);
284   g_mutex_clear (&priv->medias_lock);
285   g_free (priv->launch);
286   g_mutex_clear (&priv->lock);
287   if (priv->pool)
288     g_object_unref (priv->pool);
289   g_free (priv->multicast_iface);
290
291   G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
292 }
293
294 static void
295 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
296     GValue * value, GParamSpec * pspec)
297 {
298   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
299
300   switch (propid) {
301     case PROP_LAUNCH:
302       g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
303       break;
304     case PROP_SHARED:
305       g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
306       break;
307     case PROP_SUSPEND_MODE:
308       g_value_set_enum (value,
309           gst_rtsp_media_factory_get_suspend_mode (factory));
310       break;
311     case PROP_EOS_SHUTDOWN:
312       g_value_set_boolean (value,
313           gst_rtsp_media_factory_is_eos_shutdown (factory));
314       break;
315     case PROP_PROFILES:
316       g_value_set_flags (value, gst_rtsp_media_factory_get_profiles (factory));
317       break;
318     case PROP_PROTOCOLS:
319       g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory));
320       break;
321     case PROP_BUFFER_SIZE:
322       g_value_set_uint (value,
323           gst_rtsp_media_factory_get_buffer_size (factory));
324       break;
325     case PROP_LATENCY:
326       g_value_set_uint (value, gst_rtsp_media_factory_get_latency (factory));
327       break;
328     case PROP_TRANSPORT_MODE:
329       g_value_set_flags (value,
330           gst_rtsp_media_factory_get_transport_mode (factory));
331       break;
332     case PROP_STOP_ON_DISCONNECT:
333       g_value_set_boolean (value,
334           gst_rtsp_media_factory_is_stop_on_disonnect (factory));
335       break;
336     case PROP_CLOCK:
337       g_value_take_object (value, gst_rtsp_media_factory_get_clock (factory));
338       break;
339     default:
340       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
341   }
342 }
343
344 static void
345 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
346     const GValue * value, GParamSpec * pspec)
347 {
348   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
349
350   switch (propid) {
351     case PROP_LAUNCH:
352       gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
353       break;
354     case PROP_SHARED:
355       gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
356       break;
357     case PROP_SUSPEND_MODE:
358       gst_rtsp_media_factory_set_suspend_mode (factory,
359           g_value_get_enum (value));
360       break;
361     case PROP_EOS_SHUTDOWN:
362       gst_rtsp_media_factory_set_eos_shutdown (factory,
363           g_value_get_boolean (value));
364       break;
365     case PROP_PROFILES:
366       gst_rtsp_media_factory_set_profiles (factory, g_value_get_flags (value));
367       break;
368     case PROP_PROTOCOLS:
369       gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value));
370       break;
371     case PROP_BUFFER_SIZE:
372       gst_rtsp_media_factory_set_buffer_size (factory,
373           g_value_get_uint (value));
374       break;
375     case PROP_LATENCY:
376       gst_rtsp_media_factory_set_latency (factory, g_value_get_uint (value));
377       break;
378     case PROP_TRANSPORT_MODE:
379       gst_rtsp_media_factory_set_transport_mode (factory,
380           g_value_get_flags (value));
381       break;
382     case PROP_STOP_ON_DISCONNECT:
383       gst_rtsp_media_factory_set_stop_on_disconnect (factory,
384           g_value_get_boolean (value));
385       break;
386     case PROP_CLOCK:
387       gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value));
388       break;
389     default:
390       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
391   }
392 }
393
394 /**
395  * gst_rtsp_media_factory_new:
396  *
397  * Create a new #GstRTSPMediaFactory instance.
398  *
399  * Returns: (transfer full): a new #GstRTSPMediaFactory object.
400  */
401 GstRTSPMediaFactory *
402 gst_rtsp_media_factory_new (void)
403 {
404   GstRTSPMediaFactory *result;
405
406   result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
407
408   return result;
409 }
410
411 /**
412  * gst_rtsp_media_factory_set_permissions:
413  * @factory: a #GstRTSPMediaFactory
414  * @permissions: (transfer none): a #GstRTSPPermissions
415  *
416  * Set @permissions on @factory.
417  */
418 void
419 gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory * factory,
420     GstRTSPPermissions * permissions)
421 {
422   GstRTSPMediaFactoryPrivate *priv;
423
424   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
425
426   priv = factory->priv;
427
428   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
429   if (priv->permissions)
430     gst_rtsp_permissions_unref (priv->permissions);
431   if ((priv->permissions = permissions))
432     gst_rtsp_permissions_ref (permissions);
433   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
434 }
435
436 /**
437  * gst_rtsp_media_factory_get_permissions:
438  * @factory: a #GstRTSPMediaFactory
439  *
440  * Get the permissions object from @factory.
441  *
442  * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage.
443  */
444 GstRTSPPermissions *
445 gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory * factory)
446 {
447   GstRTSPMediaFactoryPrivate *priv;
448   GstRTSPPermissions *result;
449
450   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
451
452   priv = factory->priv;
453
454   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
455   if ((result = priv->permissions))
456     gst_rtsp_permissions_ref (result);
457   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
458
459   return result;
460 }
461
462 /**
463  * gst_rtsp_media_factory_add_role:
464  * @factory: a #GstRTSPMediaFactory
465  * @role: a role
466  * @fieldname: the first field name
467  * @...: additional arguments
468  *
469  * A convenience method to add @role with @fieldname and additional arguments to
470  * the permissions of @factory. If @factory had no permissions, new permissions
471  * will be created and the role will be added to it.
472  */
473 void
474 gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory,
475     const gchar * role, const gchar * fieldname, ...)
476 {
477   GstRTSPMediaFactoryPrivate *priv;
478   va_list var_args;
479
480   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
481   g_return_if_fail (role != NULL);
482   g_return_if_fail (fieldname != NULL);
483
484   priv = factory->priv;
485
486   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
487   if (priv->permissions == NULL)
488     priv->permissions = gst_rtsp_permissions_new ();
489
490   va_start (var_args, fieldname);
491   gst_rtsp_permissions_add_role_valist (priv->permissions, role, fieldname,
492       var_args);
493   va_end (var_args);
494   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
495 }
496
497 /**
498  * gst_rtsp_media_factory_set_launch:
499  * @factory: a #GstRTSPMediaFactory
500  * @launch: the launch description
501  *
502  *
503  * The gst_parse_launch() line to use for constructing the pipeline in the
504  * default prepare vmethod.
505  *
506  * The pipeline description should return a GstBin as the toplevel element
507  * which can be accomplished by enclosing the dscription with brackets '('
508  * ')'.
509  *
510  * The description should return a pipeline with payloaders named pay0, pay1,
511  * etc.. Each of the payloaders will result in a stream.
512  */
513 void
514 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
515     const gchar * launch)
516 {
517   GstRTSPMediaFactoryPrivate *priv;
518
519   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
520   g_return_if_fail (launch != NULL);
521
522   priv = factory->priv;
523
524   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
525   g_free (priv->launch);
526   priv->launch = g_strdup (launch);
527   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
528 }
529
530 /**
531  * gst_rtsp_media_factory_get_launch:
532  * @factory: a #GstRTSPMediaFactory
533  *
534  * Get the gst_parse_launch() pipeline description that will be used in the
535  * default prepare vmethod.
536  *
537  * Returns: (transfer full): the configured launch description. g_free() after
538  * usage.
539  */
540 gchar *
541 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
542 {
543   GstRTSPMediaFactoryPrivate *priv;
544   gchar *result;
545
546   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
547
548   priv = factory->priv;
549
550   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
551   result = g_strdup (priv->launch);
552   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
553
554   return result;
555 }
556
557 /**
558  * gst_rtsp_media_factory_set_suspend_mode:
559  * @factory: a #GstRTSPMediaFactory
560  * @mode: the new #GstRTSPSuspendMode
561  *
562  * Configure how media created from this factory will be suspended.
563  */
564 void
565 gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory * factory,
566     GstRTSPSuspendMode mode)
567 {
568   GstRTSPMediaFactoryPrivate *priv;
569
570   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
571
572   priv = factory->priv;
573
574   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
575   priv->suspend_mode = mode;
576   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
577 }
578
579 /**
580  * gst_rtsp_media_factory_get_suspend_mode:
581  * @factory: a #GstRTSPMediaFactory
582  *
583  * Get how media created from this factory will be suspended.
584  *
585  * Returns: a #GstRTSPSuspendMode.
586  */
587 GstRTSPSuspendMode
588 gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory * factory)
589 {
590   GstRTSPMediaFactoryPrivate *priv;
591   GstRTSPSuspendMode result;
592
593   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
594       GST_RTSP_SUSPEND_MODE_NONE);
595
596   priv = factory->priv;
597
598   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
599   result = priv->suspend_mode;
600   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
601
602   return result;
603 }
604
605 /**
606  * gst_rtsp_media_factory_set_shared:
607  * @factory: a #GstRTSPMediaFactory
608  * @shared: the new value
609  *
610  * Configure if media created from this factory can be shared between clients.
611  */
612 void
613 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
614     gboolean shared)
615 {
616   GstRTSPMediaFactoryPrivate *priv;
617
618   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
619
620   priv = factory->priv;
621
622   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
623   priv->shared = shared;
624   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
625 }
626
627 /**
628  * gst_rtsp_media_factory_is_shared:
629  * @factory: a #GstRTSPMediaFactory
630  *
631  * Get if media created from this factory can be shared between clients.
632  *
633  * Returns: %TRUE if the media will be shared between clients.
634  */
635 gboolean
636 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
637 {
638   GstRTSPMediaFactoryPrivate *priv;
639   gboolean result;
640
641   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
642
643   priv = factory->priv;
644
645   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
646   result = priv->shared;
647   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
648
649   return result;
650 }
651
652 /**
653  * gst_rtsp_media_factory_set_eos_shutdown:
654  * @factory: a #GstRTSPMediaFactory
655  * @eos_shutdown: the new value
656  *
657  * Configure if media created from this factory will have an EOS sent to the
658  * pipeline before shutdown.
659  */
660 void
661 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
662     gboolean eos_shutdown)
663 {
664   GstRTSPMediaFactoryPrivate *priv;
665
666   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
667
668   priv = factory->priv;
669
670   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
671   priv->eos_shutdown = eos_shutdown;
672   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
673 }
674
675 /**
676  * gst_rtsp_media_factory_is_eos_shutdown:
677  * @factory: a #GstRTSPMediaFactory
678  *
679  * Get if media created from this factory will have an EOS event sent to the
680  * pipeline before shutdown.
681  *
682  * Returns: %TRUE if the media will receive EOS before shutdown.
683  */
684 gboolean
685 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
686 {
687   GstRTSPMediaFactoryPrivate *priv;
688   gboolean result;
689
690   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
691
692   priv = factory->priv;
693
694   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
695   result = priv->eos_shutdown;
696   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
697
698   return result;
699 }
700
701 /**
702  * gst_rtsp_media_factory_set_buffer_size:
703  * @factory: a #GstRTSPMedia
704  * @size: the new value
705  *
706  * Set the kernel UDP buffer size.
707  */
708 void
709 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
710     guint size)
711 {
712   GstRTSPMediaFactoryPrivate *priv;
713
714   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
715
716   priv = factory->priv;
717
718   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
719   priv->buffer_size = size;
720   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
721 }
722
723 /**
724  * gst_rtsp_media_factory_get_buffer_size:
725  * @factory: a #GstRTSPMedia
726  *
727  * Get the kernel UDP buffer size.
728  *
729  * Returns: the kernel UDP buffer size.
730  */
731 guint
732 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
733 {
734   GstRTSPMediaFactoryPrivate *priv;
735   guint result;
736
737   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
738
739   priv = factory->priv;
740
741   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
742   result = priv->buffer_size;
743   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
744
745   return result;
746 }
747
748 /**
749  * gst_rtsp_media_factory_set_address_pool:
750  * @factory: a #GstRTSPMediaFactory
751  * @pool: (transfer none): a #GstRTSPAddressPool
752  *
753  * configure @pool to be used as the address pool of @factory.
754  */
755 void
756 gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory,
757     GstRTSPAddressPool * pool)
758 {
759   GstRTSPMediaFactoryPrivate *priv;
760   GstRTSPAddressPool *old;
761
762   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
763
764   priv = factory->priv;
765
766   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
767   if ((old = priv->pool) != pool)
768     priv->pool = pool ? g_object_ref (pool) : NULL;
769   else
770     old = NULL;
771   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
772
773   if (old)
774     g_object_unref (old);
775 }
776
777 /**
778  * gst_rtsp_media_factory_get_address_pool:
779  * @factory: a #GstRTSPMediaFactory
780  *
781  * Get the #GstRTSPAddressPool used as the address pool of @factory.
782  *
783  * Returns: (transfer full): the #GstRTSPAddressPool of @factory. g_object_unref() after
784  * usage.
785  */
786 GstRTSPAddressPool *
787 gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory)
788 {
789   GstRTSPMediaFactoryPrivate *priv;
790   GstRTSPAddressPool *result;
791
792   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
793
794   priv = factory->priv;
795
796   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
797   if ((result = priv->pool))
798     g_object_ref (result);
799   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
800
801   return result;
802 }
803
804 /**
805  * gst_rtsp_media_factory_set_multicast_iface:
806  * @media_factory: a #GstRTSPMediaFactory
807  * @multicast_iface: (transfer none): a multicast interface name
808  *
809  * configure @multicast_iface to be used for @media_factory.
810  */
811 void
812 gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory,
813     const gchar * multicast_iface)
814 {
815   GstRTSPMediaFactoryPrivate *priv;
816   gchar *old;
817
818   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory));
819
820   priv = media_factory->priv;
821
822   GST_LOG_OBJECT (media_factory, "set multicast interface %s", multicast_iface);
823
824   g_mutex_lock (&priv->lock);
825   if ((old = priv->multicast_iface) != multicast_iface)
826     priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL;
827   else
828     old = NULL;
829   g_mutex_unlock (&priv->lock);
830
831   if (old)
832     g_free (old);
833 }
834
835 /**
836  * gst_rtsp_media_factory_get_multicast_iface:
837  * @media_factory: a #GstRTSPMediaFactory
838  *
839  * Get the multicast interface used for @media_factory.
840  *
841  * Returns: (transfer full): the multicast interface for @media_factory. g_free() after
842  * usage.
843  */
844 gchar *
845 gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory * media_factory)
846 {
847   GstRTSPMediaFactoryPrivate *priv;
848   gchar *result;
849
850   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory), NULL);
851
852   priv = media_factory->priv;
853
854   g_mutex_lock (&priv->lock);
855   if ((result = priv->multicast_iface))
856     result = g_strdup (result);
857   g_mutex_unlock (&priv->lock);
858
859   return result;
860 }
861
862 /**
863  * gst_rtsp_media_factory_set_profiles:
864  * @factory: a #GstRTSPMediaFactory
865  * @profiles: the new flags
866  *
867  * Configure the allowed profiles for @factory.
868  */
869 void
870 gst_rtsp_media_factory_set_profiles (GstRTSPMediaFactory * factory,
871     GstRTSPProfile profiles)
872 {
873   GstRTSPMediaFactoryPrivate *priv;
874
875   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
876
877   priv = factory->priv;
878
879   GST_DEBUG_OBJECT (factory, "profiles %d", profiles);
880
881   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
882   priv->profiles = profiles;
883   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
884 }
885
886 /**
887  * gst_rtsp_media_factory_get_profiles:
888  * @factory: a #GstRTSPMediaFactory
889  *
890  * Get the allowed profiles of @factory.
891  *
892  * Returns: a #GstRTSPProfile
893  */
894 GstRTSPProfile
895 gst_rtsp_media_factory_get_profiles (GstRTSPMediaFactory * factory)
896 {
897   GstRTSPMediaFactoryPrivate *priv;
898   GstRTSPProfile res;
899
900   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
901       GST_RTSP_PROFILE_UNKNOWN);
902
903   priv = factory->priv;
904
905   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
906   res = priv->profiles;
907   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
908
909   return res;
910 }
911
912 /**
913  * gst_rtsp_media_factory_set_protocols:
914  * @factory: a #GstRTSPMediaFactory
915  * @protocols: the new flags
916  *
917  * Configure the allowed lower transport for @factory.
918  */
919 void
920 gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory,
921     GstRTSPLowerTrans protocols)
922 {
923   GstRTSPMediaFactoryPrivate *priv;
924
925   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
926
927   priv = factory->priv;
928
929   GST_DEBUG_OBJECT (factory, "protocols %d", protocols);
930
931   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
932   priv->protocols = protocols;
933   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
934 }
935
936 /**
937  * gst_rtsp_media_factory_get_protocols:
938  * @factory: a #GstRTSPMediaFactory
939  *
940  * Get the allowed protocols of @factory.
941  *
942  * Returns: a #GstRTSPLowerTrans
943  */
944 GstRTSPLowerTrans
945 gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
946 {
947   GstRTSPMediaFactoryPrivate *priv;
948   GstRTSPLowerTrans res;
949
950   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
951       GST_RTSP_LOWER_TRANS_UNKNOWN);
952
953   priv = factory->priv;
954
955   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
956   res = priv->protocols;
957   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
958
959   return res;
960 }
961
962 /**
963  * gst_rtsp_media_factory_set_stop_on_disconnect:
964  * @factory: a #GstRTSPMediaFactory
965  * @stop_on_disconnect: the new value
966  *
967  * Configure if media created from this factory should be stopped
968  * when a client disconnects without sending TEARDOWN.
969  */
970 void
971 gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory * factory,
972     gboolean stop_on_disconnect)
973 {
974   GstRTSPMediaFactoryPrivate *priv;
975
976   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
977
978   priv = factory->priv;
979
980   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
981   priv->stop_on_disconnect = stop_on_disconnect;
982   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
983 }
984
985 /**
986  * gst_rtsp_media_factory_is_stop_on_disconnect:
987  * @factory: a #GstRTSPMediaFactory
988  *
989  * Get if media created from this factory should be stopped when a client
990  * disconnects without sending TEARDOWN.
991  *
992  * Returns: %TRUE if the media will be stopped when a client disconnects
993  *     without sending TEARDOWN.
994  */
995 gboolean
996 gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory * factory)
997 {
998   GstRTSPMediaFactoryPrivate *priv;
999   gboolean result;
1000
1001   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), TRUE);
1002
1003   priv = factory->priv;
1004
1005   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1006   result = priv->stop_on_disconnect;
1007   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1008
1009   return result;
1010 }
1011
1012 /**
1013  * gst_rtsp_media_factory_set_retransmission_time:
1014  * @factory: a #GstRTSPMediaFactory
1015  * @time: a #GstClockTime
1016  *
1017  * Configure the time to store for possible retransmission
1018  */
1019 void
1020 gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory,
1021     GstClockTime time)
1022 {
1023   GstRTSPMediaFactoryPrivate *priv;
1024
1025   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
1026
1027   priv = factory->priv;
1028
1029   GST_DEBUG_OBJECT (factory, "retransmission time %" G_GUINT64_FORMAT, time);
1030
1031   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1032   priv->rtx_time = time;
1033   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1034 }
1035
1036 /**
1037  * gst_rtsp_media_factory_get_retransmission_time:
1038  * @factory: a #GstRTSPMediaFactory
1039  *
1040  * Get the time that is stored for retransmission purposes
1041  *
1042  * Returns: a #GstClockTime
1043  */
1044 GstClockTime
1045 gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory)
1046 {
1047   GstRTSPMediaFactoryPrivate *priv;
1048   GstClockTime res;
1049
1050   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
1051
1052   priv = factory->priv;
1053
1054   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1055   res = priv->rtx_time;
1056   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1057
1058   return res;
1059 }
1060
1061 /**
1062  * gst_rtsp_media_factory_set_latency:
1063  * @factory: a #GstRTSPMediaFactory
1064  * @latency: latency in milliseconds
1065  *
1066  * Configure the latency used for receiving media
1067  */
1068 void
1069 gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory,
1070     guint latency)
1071 {
1072   GstRTSPMediaFactoryPrivate *priv;
1073
1074   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
1075
1076   priv = factory->priv;
1077
1078   GST_DEBUG_OBJECT (factory, "latency %ums", latency);
1079
1080   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1081   priv->latency = latency;
1082   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1083 }
1084
1085 /**
1086  * gst_rtsp_media_factory_get_latency:
1087  * @factory: a #GstRTSPMediaFactory
1088  *
1089  * Get the latency that is used for receiving media
1090  *
1091  * Returns: latency in milliseconds
1092  */
1093 guint
1094 gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory)
1095 {
1096   GstRTSPMediaFactoryPrivate *priv;
1097   guint res;
1098
1099   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
1100
1101   priv = factory->priv;
1102
1103   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1104   res = priv->latency;
1105   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1106
1107   return res;
1108 }
1109
1110 static gboolean
1111 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
1112 {
1113   return (media1 == media2);
1114 }
1115
1116 static void
1117 media_unprepared (GstRTSPMedia * media, GWeakRef * ref)
1118 {
1119   GstRTSPMediaFactory *factory = g_weak_ref_get (ref);
1120   GstRTSPMediaFactoryPrivate *priv;
1121
1122   if (!factory)
1123     return;
1124
1125   priv = factory->priv;
1126
1127   g_mutex_lock (&priv->medias_lock);
1128   g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media);
1129   g_mutex_unlock (&priv->medias_lock);
1130
1131   g_object_unref (factory);
1132 }
1133
1134 static GWeakRef *
1135 weak_ref_new (gpointer obj)
1136 {
1137   GWeakRef *ref = g_slice_new (GWeakRef);
1138
1139   g_weak_ref_init (ref, obj);
1140   return ref;
1141 }
1142
1143 static void
1144 weak_ref_free (GWeakRef * ref)
1145 {
1146   g_weak_ref_clear (ref);
1147   g_slice_free (GWeakRef, ref);
1148 }
1149
1150 /**
1151  * gst_rtsp_media_factory_construct:
1152  * @factory: a #GstRTSPMediaFactory
1153  * @url: the url used
1154  *
1155  * Construct the media object and create its streams. Implementations
1156  * should create the needed gstreamer elements and add them to the result
1157  * object. No state changes should be performed on them yet.
1158  *
1159  * One or more GstRTSPStream objects should be created from the result
1160  * with gst_rtsp_media_create_stream ().
1161  *
1162  * After the media is constructed, it can be configured and then prepared
1163  * with gst_rtsp_media_prepare ().
1164  *
1165  * Returns: (transfer full): a new #GstRTSPMedia if the media could be prepared.
1166  */
1167 GstRTSPMedia *
1168 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
1169     const GstRTSPUrl * url)
1170 {
1171   GstRTSPMediaFactoryPrivate *priv;
1172   gchar *key;
1173   GstRTSPMedia *media;
1174   GstRTSPMediaFactoryClass *klass;
1175
1176   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
1177   g_return_val_if_fail (url != NULL, NULL);
1178
1179   priv = factory->priv;
1180   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
1181
1182   /* convert the url to a key for the hashtable. NULL return or a NULL function
1183    * will not cache anything for this factory. */
1184   if (klass->gen_key)
1185     key = klass->gen_key (factory, url);
1186   else
1187     key = NULL;
1188
1189   g_mutex_lock (&priv->medias_lock);
1190   if (key) {
1191     /* we have a key, see if we find a cached media */
1192     media = g_hash_table_lookup (priv->medias, key);
1193     if (media)
1194       g_object_ref (media);
1195   } else
1196     media = NULL;
1197
1198   if (media == NULL) {
1199     /* nothing cached found, try to create one */
1200     if (klass->construct) {
1201       media = klass->construct (factory, url);
1202       if (media)
1203         g_signal_emit (factory,
1204             gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
1205             NULL);
1206     } else
1207       media = NULL;
1208
1209     if (media) {
1210       /* configure the media */
1211       if (klass->configure)
1212         klass->configure (factory, media);
1213
1214       g_signal_emit (factory,
1215           gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
1216           NULL);
1217
1218       /* check if we can cache this media */
1219       if (gst_rtsp_media_is_shared (media)) {
1220         /* insert in the hashtable, takes ownership of the key */
1221         g_object_ref (media);
1222         g_hash_table_insert (priv->medias, key, media);
1223         key = NULL;
1224       }
1225       if (!gst_rtsp_media_is_reusable (media)) {
1226         /* when not reusable, connect to the unprepare signal to remove the item
1227          * from our cache when it gets unprepared */
1228         g_signal_connect_data (media, "unprepared",
1229             (GCallback) media_unprepared, weak_ref_new (factory),
1230             (GClosureNotify) weak_ref_free, 0);
1231       }
1232     }
1233   }
1234   g_mutex_unlock (&priv->medias_lock);
1235
1236   if (key)
1237     g_free (key);
1238
1239   GST_INFO ("constructed media %p for url %s", media, url->abspath);
1240
1241   return media;
1242 }
1243
1244 /**
1245  * gst_rtsp_media_factory_set_media_gtype:
1246  * @factory: a #GstRTSPMediaFactory
1247  * @media_gtype: the GType of the class to create
1248  *
1249  * Configure the GType of the GstRTSPMedia subclass to
1250  * create (by default, overridden construct vmethods
1251  * may of course do something different)
1252  *
1253  * Since: 1.6
1254  */
1255 void
1256 gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFactory * factory,
1257     GType media_gtype)
1258 {
1259   GstRTSPMediaFactoryPrivate *priv;
1260
1261   g_return_if_fail (g_type_is_a (media_gtype, GST_TYPE_RTSP_MEDIA));
1262
1263   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1264   priv = factory->priv;
1265   priv->media_gtype = media_gtype;
1266   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1267 }
1268
1269 /**
1270  * gst_rtsp_media_factory_get_media_gtype:
1271  * @factory: a #GstRTSPMediaFactory
1272  *
1273  * Return the GType of the GstRTSPMedia subclass this
1274  * factory will create.
1275  *
1276  * Since: 1.6
1277  */
1278 GType
1279 gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory)
1280 {
1281   GstRTSPMediaFactoryPrivate *priv;
1282   GType ret;
1283
1284   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1285   priv = factory->priv;
1286   ret = priv->media_gtype;
1287   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1288
1289   return ret;
1290 }
1291
1292 /**
1293  * gst_rtsp_media_factory_set_clock:
1294  * @factory: a #GstRTSPMediaFactory
1295  * @clockd: the clock to be used by the media factory
1296  *
1297  * Configures a specific clock to be used by the pipelines
1298  * of all medias created from this factory.
1299  *
1300  * Since: 1.8
1301  */
1302 void
1303 gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory * factory,
1304     GstClock * clock)
1305 {
1306   GstRTSPMediaFactoryPrivate *priv;
1307
1308   g_return_if_fail (GST_IS_CLOCK (clock) || clock == NULL);
1309
1310   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1311   priv = factory->priv;
1312   priv->clock = clock ? gst_object_ref (clock) : NULL;
1313   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1314 }
1315
1316 /**
1317  * gst_rtsp_media_factory_get_clock:
1318  * @factory: a #GstRTSPMediaFactory
1319  *
1320  * Returns the clock that is going to be used by the pipelines
1321  * of all medias created from this factory.
1322  *
1323  * Returns: (transfer full): The GstClock
1324  *
1325  * Since: 1.8
1326  */
1327 GstClock *
1328 gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory * factory)
1329 {
1330   GstRTSPMediaFactoryPrivate *priv;
1331   GstClock *ret;
1332
1333   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1334   priv = factory->priv;
1335   ret = priv->clock ? gst_object_ref (priv->clock) : NULL;
1336   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1337
1338   return ret;
1339 }
1340
1341 /**
1342  * gst_rtsp_media_factory_set_publish_clock_mode:
1343  * @factory: a #GstRTSPMediaFactory
1344  * @mode: the clock publish mode
1345  *
1346  * Sets if and how the media clock should be published according to RFC7273.
1347  *
1348  * Since: 1.8
1349  */
1350 void
1351 gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory,
1352     GstRTSPPublishClockMode mode)
1353 {
1354   GstRTSPMediaFactoryPrivate *priv;
1355
1356   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1357   priv = factory->priv;
1358   priv->publish_clock_mode = mode;
1359   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1360 }
1361
1362 /**
1363  * gst_rtsp_media_factory_get_publish_clock_mode:
1364  * @factory: a #GstRTSPMediaFactory
1365  *
1366  * Gets if and how the media clock should be published according to RFC7273.
1367  *
1368  * Returns: The GstRTSPPublishClockMode
1369  *
1370  * Since: 1.8
1371  */
1372 GstRTSPPublishClockMode
1373 gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory)
1374 {
1375   GstRTSPMediaFactoryPrivate *priv;
1376   GstRTSPPublishClockMode ret;
1377
1378   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1379   priv = factory->priv;
1380   ret = priv->publish_clock_mode;
1381   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1382
1383   return ret;
1384 }
1385
1386 static gchar *
1387 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
1388 {
1389   gchar *result;
1390   const gchar *pre_query;
1391   const gchar *query;
1392   guint16 port;
1393
1394   pre_query = url->query ? "?" : "";
1395   query = url->query ? url->query : "";
1396
1397   gst_rtsp_url_get_port (url, &port);
1398
1399   result = g_strdup_printf ("%u%s%s%s", port, url->abspath, pre_query, query);
1400
1401   return result;
1402 }
1403
1404 static GstElement *
1405 default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
1406 {
1407   GstRTSPMediaFactoryPrivate *priv = factory->priv;
1408   GstElement *element;
1409   GError *error = NULL;
1410
1411   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1412   /* we need a parse syntax */
1413   if (priv->launch == NULL)
1414     goto no_launch;
1415
1416   /* parse the user provided launch line */
1417   element =
1418       gst_parse_launch_full (priv->launch, NULL, GST_PARSE_FLAG_PLACE_IN_BIN,
1419       &error);
1420   if (element == NULL)
1421     goto parse_error;
1422
1423   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1424
1425   if (error != NULL) {
1426     /* a recoverable error was encountered */
1427     GST_WARNING ("recoverable parsing error: %s", error->message);
1428     g_error_free (error);
1429   }
1430   return element;
1431
1432   /* ERRORS */
1433 no_launch:
1434   {
1435     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1436     g_critical ("no launch line specified");
1437     return NULL;
1438   }
1439 parse_error:
1440   {
1441     g_critical ("could not parse launch syntax (%s): %s", priv->launch,
1442         (error ? error->message : "unknown reason"));
1443     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1444     if (error)
1445       g_error_free (error);
1446     return NULL;
1447   }
1448 }
1449
1450 static GstRTSPMedia *
1451 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
1452 {
1453   GstRTSPMedia *media;
1454   GstElement *element, *pipeline;
1455   GstRTSPMediaFactoryClass *klass;
1456   GType media_gtype;
1457
1458   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
1459
1460   if (!klass->create_pipeline)
1461     goto no_create;
1462
1463   element = gst_rtsp_media_factory_create_element (factory, url);
1464   if (element == NULL)
1465     goto no_element;
1466
1467   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1468   media_gtype = factory->priv->media_gtype;
1469   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1470
1471   /* create a new empty media */
1472   media = g_object_new (media_gtype, "element", element, NULL);
1473
1474   gst_rtsp_media_collect_streams (media);
1475
1476   pipeline = klass->create_pipeline (factory, media);
1477   if (pipeline == NULL)
1478     goto no_pipeline;
1479
1480   return media;
1481
1482   /* ERRORS */
1483 no_create:
1484   {
1485     g_critical ("no create_pipeline function");
1486     return NULL;
1487   }
1488 no_element:
1489   {
1490     g_critical ("could not create element");
1491     return NULL;
1492   }
1493 no_pipeline:
1494   {
1495     g_critical ("can't create pipeline");
1496     g_object_unref (media);
1497     return NULL;
1498   }
1499 }
1500
1501 static GstElement *
1502 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
1503 {
1504   GstElement *pipeline;
1505
1506   pipeline = gst_pipeline_new ("media-pipeline");
1507
1508   /* FIXME 2.0: This should be done by the caller, not the vfunc. Every
1509    * implementation of the vfunc has to call it otherwise at the end.
1510    * Also it does not allow use to add further behaviour here that could
1511    * be reused by subclasses that chain up */
1512   gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline));
1513
1514   return pipeline;
1515 }
1516
1517 static void
1518 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
1519 {
1520   GstRTSPMediaFactoryPrivate *priv = factory->priv;
1521   gboolean shared, eos_shutdown, stop_on_disconnect;
1522   guint size;
1523   GstRTSPSuspendMode suspend_mode;
1524   GstRTSPProfile profiles;
1525   GstRTSPLowerTrans protocols;
1526   GstRTSPAddressPool *pool;
1527   GstRTSPPermissions *perms;
1528   GstClockTime rtx_time;
1529   guint latency;
1530   GstRTSPTransportMode transport_mode;
1531   GstClock *clock;
1532   gchar *multicast_iface;
1533   GstRTSPPublishClockMode publish_clock_mode;
1534
1535   /* configure the sharedness */
1536   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1537   suspend_mode = priv->suspend_mode;
1538   shared = priv->shared;
1539   eos_shutdown = priv->eos_shutdown;
1540   size = priv->buffer_size;
1541   profiles = priv->profiles;
1542   protocols = priv->protocols;
1543   rtx_time = priv->rtx_time;
1544   latency = priv->latency;
1545   transport_mode = priv->transport_mode;
1546   stop_on_disconnect = priv->stop_on_disconnect;
1547   clock = priv->clock ? gst_object_ref (priv->clock) : NULL;
1548   publish_clock_mode = priv->publish_clock_mode;
1549   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1550
1551   gst_rtsp_media_set_suspend_mode (media, suspend_mode);
1552   gst_rtsp_media_set_shared (media, shared);
1553   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
1554   gst_rtsp_media_set_buffer_size (media, size);
1555   gst_rtsp_media_set_profiles (media, profiles);
1556   gst_rtsp_media_set_protocols (media, protocols);
1557   gst_rtsp_media_set_retransmission_time (media, rtx_time);
1558   gst_rtsp_media_set_latency (media, latency);
1559   gst_rtsp_media_set_transport_mode (media, transport_mode);
1560   gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect);
1561   gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode);
1562
1563   if (clock) {
1564     gst_rtsp_media_set_clock (media, clock);
1565     gst_object_unref (clock);
1566   }
1567
1568   if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) {
1569     gst_rtsp_media_set_address_pool (media, pool);
1570     g_object_unref (pool);
1571   }
1572   if ((multicast_iface = gst_rtsp_media_factory_get_multicast_iface (factory))) {
1573     gst_rtsp_media_set_multicast_iface (media, multicast_iface);
1574     g_free (multicast_iface);
1575   }
1576   if ((perms = gst_rtsp_media_factory_get_permissions (factory))) {
1577     gst_rtsp_media_set_permissions (media, perms);
1578     gst_rtsp_permissions_unref (perms);
1579   }
1580 }
1581
1582 /**
1583  * gst_rtsp_media_factory_create_element:
1584  * @factory: a #GstRTSPMediaFactory
1585  * @url: the url used
1586  *
1587  * Construct and return a #GstElement that is a #GstBin containing
1588  * the elements to use for streaming the media.
1589  *
1590  * The bin should contain payloaders pay\%d for each stream. The default
1591  * implementation of this function returns the bin created from the
1592  * launch parameter.
1593  *
1594  * Returns: (transfer floating): a new #GstElement.
1595  */
1596 GstElement *
1597 gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory,
1598     const GstRTSPUrl * url)
1599 {
1600   GstRTSPMediaFactoryClass *klass;
1601   GstElement *result;
1602
1603   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
1604   g_return_val_if_fail (url != NULL, NULL);
1605
1606   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
1607
1608   if (klass->create_element)
1609     result = klass->create_element (factory, url);
1610   else
1611     result = NULL;
1612
1613   return result;
1614 }
1615
1616 /**
1617  * gst_rtsp_media_factory_set_transport_mode:
1618  * @factory: a #GstRTSPMediaFactory
1619  * @mode: the new value
1620  *
1621  * Configure if this factory creates media for PLAY or RECORD modes.
1622  */
1623 void
1624 gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory * factory,
1625     GstRTSPTransportMode mode)
1626 {
1627   GstRTSPMediaFactoryPrivate *priv;
1628
1629   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
1630
1631   priv = factory->priv;
1632
1633   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1634   priv->transport_mode = mode;
1635   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1636 }
1637
1638 /**
1639  * gst_rtsp_media_factory_get_transport_mode:
1640  * @factory: a #GstRTSPMediaFactory
1641  *
1642  * Get if media created from this factory can be used for PLAY or RECORD
1643  * methods.
1644  *
1645  * Returns: The supported transport modes.
1646  */
1647 GstRTSPTransportMode
1648 gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory * factory)
1649 {
1650   GstRTSPMediaFactoryPrivate *priv;
1651   GstRTSPTransportMode result;
1652
1653   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
1654
1655   priv = factory->priv;
1656
1657   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
1658   result = priv->transport_mode;
1659   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
1660
1661   return result;
1662 }