0c9dda96175374cfdb8a490d6fab7cc874be8490
[platform/upstream/gstreamer.git] / gst / gstglobaldevicemonitor.c
1 /* GStreamer
2  * Copyright (C) 2013 Olivier Crete <olivier.crete@collabora.com>
3  *
4  * gstglobaldevicemonitor.c: Global device monitor
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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstglobaldevicemonitor
24  * @short_description: A global device monitor and prober
25  * @see_also: #GstDevice, #GstDeviceProvider
26  *
27  * Applications should create a #GstGlobalDeviceMonitor when they want
28  * to probe, list and monitor devices of a specific type. The
29  * #GstGlobalDeviceMonitor will create the appropriate
30  * #GstDeviceProvider objects and manage them. It will then post
31  * messages on its #GstBus for devices that have been added and
32  * removed.
33  *
34  * Since: 1.4
35  */
36
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include "gst_private.h"
43 #include "gstglobaldevicemonitor.h"
44
45 struct _GstGlobalDeviceMonitorPrivate
46 {
47   gboolean started;
48
49   GstBus *bus;
50
51   GPtrArray *providers;
52   guint cookie;
53
54   GstCaps *caps;
55   gchar *classes;
56 };
57
58
59 G_DEFINE_TYPE (GstGlobalDeviceMonitor, gst_global_device_monitor,
60     GST_TYPE_OBJECT);
61
62 static void gst_global_device_monitor_dispose (GObject * object);
63
64 static void
65 gst_global_device_monitor_class_init (GstGlobalDeviceMonitorClass * klass)
66 {
67   GObjectClass *object_class = G_OBJECT_CLASS (klass);
68
69   g_type_class_add_private (klass, sizeof (GstGlobalDeviceMonitorPrivate));
70
71   object_class->dispose = gst_global_device_monitor_dispose;
72 }
73
74 static void
75 bus_sync_message (GstBus * bus, GstMessage * message,
76     GstGlobalDeviceMonitor * monitor)
77 {
78   GstMessageType type = GST_MESSAGE_TYPE (message);
79
80   if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
81     gboolean matches;
82     GstCaps *caps;
83     GstDevice *device;
84
85     if (type == GST_MESSAGE_DEVICE_ADDED)
86       gst_message_parse_device_added (message, &device);
87     else
88       gst_message_parse_device_removed (message, &device);
89
90     GST_OBJECT_LOCK (monitor);
91     caps = gst_device_get_caps (device);
92     matches = gst_caps_can_intersect (monitor->priv->caps, caps) &&
93         gst_device_has_classes (device, monitor->priv->classes);
94     gst_caps_unref (caps);
95     GST_OBJECT_UNLOCK (monitor);
96
97     if (matches)
98       gst_bus_post (monitor->priv->bus, gst_message_ref (message));
99   }
100 }
101
102
103 static void
104 gst_global_device_monitor_init (GstGlobalDeviceMonitor * self)
105 {
106   GList *factories;
107
108   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
109       GST_TYPE_GLOBAL_DEVICE_MONITOR, GstGlobalDeviceMonitorPrivate);
110
111   self->priv->bus = gst_bus_new ();
112   gst_bus_set_flushing (self->priv->bus, TRUE);
113
114   self->priv->providers = g_ptr_array_new ();
115   self->priv->caps = gst_caps_new_any ();
116   self->priv->classes = g_strdup ("");
117
118   factories =
119       gst_device_provider_factory_list_get_device_providers (self->priv->
120       classes, 1);
121
122   while (factories) {
123     GstDeviceProviderFactory *factory = factories->data;
124     GstDeviceProvider *provider;
125
126     factories = g_list_remove (factories, factory);
127
128     provider = gst_device_provider_factory_get (factory);
129     if (provider) {
130       GstBus *bus = gst_device_provider_get_bus (provider);
131
132       gst_bus_enable_sync_message_emission (bus);
133       g_signal_connect (bus, "sync-message",
134           G_CALLBACK (bus_sync_message), self);
135       g_ptr_array_add (self->priv->providers, provider);
136     }
137
138     gst_object_unref (factory);
139   }
140 }
141
142
143 static void
144 gst_global_device_monitor_remove (GstGlobalDeviceMonitor * self, guint i)
145 {
146   GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
147   GstBus *bus;
148
149   g_ptr_array_remove_index_fast (self->priv->providers, i);
150
151   bus = gst_device_provider_get_bus (provider);
152   g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
153   gst_object_unref (bus);
154
155   gst_object_unref (provider);
156 }
157
158 static void
159 gst_global_device_monitor_dispose (GObject * object)
160 {
161   GstGlobalDeviceMonitor *self = GST_GLOBAL_DEVICE_MONITOR (object);
162
163   g_return_if_fail (self->priv->started == FALSE);
164
165   if (self->priv->providers) {
166     while (self->priv->providers->len)
167       gst_global_device_monitor_remove (self, self->priv->providers->len - 1);
168     g_ptr_array_unref (self->priv->providers);
169     self->priv->providers = NULL;
170   }
171
172   gst_caps_replace (&self->priv->caps, NULL);
173   g_free (self->priv->classes);
174   gst_object_replace ((GstObject **) & self->priv->bus, NULL);
175
176   G_OBJECT_CLASS (gst_global_device_monitor_parent_class)->dispose (object);
177 }
178
179 /**
180  * gst_global_device_monitor_get_devices:
181  * @monitor: A #GstDeviceProvider
182  *
183  * Gets a list of devices from all of the relevant monitors. This may actually
184  * probe the hardware if the global monitor is not currently started.
185  *
186  * Returns: (transfer full) (element-type GstDevice): a #GList of
187  *   #GstDevice
188  *
189  * Since: 1.4
190  */
191
192 GList *
193 gst_global_device_monitor_get_devices (GstGlobalDeviceMonitor * monitor)
194 {
195   GList *devices = NULL;
196   guint i;
197   guint cookie;
198
199   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
200
201   GST_OBJECT_LOCK (monitor);
202
203 again:
204
205   g_list_free_full (devices, gst_object_unref);
206   devices = NULL;
207
208   cookie = monitor->priv->cookie;
209
210   for (i = 0; i < monitor->priv->providers->len; i++) {
211     GList *tmpdev;
212     GstDeviceProvider *provider =
213         gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
214     GList *item;
215
216     GST_OBJECT_UNLOCK (monitor);
217
218     tmpdev = gst_device_provider_get_devices (provider);
219
220     for (item = tmpdev; item; item = item->next) {
221       GstDevice *dev = GST_DEVICE (item->data);
222       GstCaps *caps = gst_device_get_caps (dev);
223
224       if (gst_caps_can_intersect (monitor->priv->caps, caps) &&
225           gst_device_has_classes (dev, monitor->priv->classes))
226         devices = g_list_prepend (devices, gst_object_ref (dev));
227       gst_caps_unref (caps);
228     }
229
230     g_list_free_full (tmpdev, gst_object_unref);
231     gst_object_unref (provider);
232
233     GST_OBJECT_LOCK (monitor);
234
235     if (monitor->priv->cookie != cookie)
236       goto again;
237   }
238
239   GST_OBJECT_UNLOCK (monitor);
240
241   return devices;
242 }
243
244 /**
245  * gst_global_device_monitor_start:
246  * @monitor: A #GstGlobalDeviceMonitor
247  *
248  * Starts monitoring the devices, one this has succeeded, the
249  * %GST_MESSAGE_DEVICE_ADDED and %GST_MESSAGE_DEVICE_REMOVED messages
250  * will be emitted on the bus when the list of devices changes.
251  *
252  * Returns: %TRUE if the device monitoring could be started
253  *
254  * Since: 1.4
255  */
256
257 gboolean
258 gst_global_device_monitor_start (GstGlobalDeviceMonitor * monitor)
259 {
260   guint i;
261
262   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), FALSE);
263
264   GST_OBJECT_LOCK (monitor);
265
266   if (monitor->priv->providers->len == 0) {
267     GST_OBJECT_UNLOCK (monitor);
268     return FALSE;
269   }
270
271   gst_bus_set_flushing (monitor->priv->bus, FALSE);
272
273   for (i = 0; i < monitor->priv->providers->len; i++) {
274     if (!gst_device_provider_start (g_ptr_array_index (monitor->priv->providers,
275                 i))) {
276       gst_bus_set_flushing (monitor->priv->bus, TRUE);
277
278       for (; i != 0; i--)
279         gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers,
280                 i - 1));
281
282       GST_OBJECT_UNLOCK (monitor);
283       return FALSE;
284     }
285   }
286
287   monitor->priv->started = TRUE;
288   GST_OBJECT_UNLOCK (monitor);
289
290   return TRUE;
291 }
292
293 /**
294  * gst_global_device_monitor_stop:
295  * @monitor: A #GstDeviceProvider
296  *
297  * Stops monitoring the devices.
298  *
299  * Since: 1.4
300  */
301 void
302 gst_global_device_monitor_stop (GstGlobalDeviceMonitor * monitor)
303 {
304   guint i;
305
306   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
307
308   gst_bus_set_flushing (monitor->priv->bus, TRUE);
309
310   GST_OBJECT_LOCK (monitor);
311   for (i = 0; i < monitor->priv->providers->len; i++)
312     gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers, i));
313   monitor->priv->started = FALSE;
314   GST_OBJECT_UNLOCK (monitor);
315
316 }
317
318 /**
319  * gst_global_device_monitor_set_classes_filter:
320  * @monitor: the global device monitor
321  * @classes: device classes to use as filter
322  *
323  * Filter devices monitored by device class, e.g. in case you are only
324  * interested in a certain type of device like audio devices or
325  * video sources.
326  *
327  * Since: 1.4
328  */
329 void
330 gst_global_device_monitor_set_classes_filter (GstGlobalDeviceMonitor * monitor,
331     const gchar * classes)
332 {
333   GList *factories = NULL;
334   guint i;
335
336   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
337   g_return_if_fail (!monitor->priv->started);
338
339   GST_OBJECT_LOCK (monitor);
340   if (!strcmp (monitor->priv->classes, classes)) {
341     GST_OBJECT_UNLOCK (monitor);
342     return;
343   }
344
345   g_free (monitor->priv->classes);
346   monitor->priv->classes = g_strdup (classes);
347
348   factories = gst_device_provider_factory_list_get_device_providers (classes,
349       1);
350
351   for (i = 0; i < monitor->priv->providers->len; i++) {
352     GstDeviceProvider *provider;
353     GstDeviceProviderFactory *f;
354     GList *item;
355
356     provider = g_ptr_array_index (monitor->priv->providers, i);
357     f = gst_device_provider_get_factory (provider);
358
359     item = g_list_find (factories, f);
360
361     if (item) {
362       /* If the item is in our list, then remove it from the list of factories,
363        * we don't have it to re-create it later
364        */
365       factories = g_list_remove_link (factories, item);
366       gst_object_unref (f);
367     } else {
368       /* If it's not in our list, them remove it from the list of providers.
369        */
370
371       monitor->priv->cookie++;
372       gst_global_device_monitor_remove (monitor, i);
373       i--;
374     }
375   }
376
377   while (factories) {
378     GstDeviceProviderFactory *factory = factories->data;
379     GstDeviceProvider *provider;
380
381     factories = g_list_remove (factories, factory);
382
383     provider = gst_device_provider_factory_get (factory);
384     if (provider) {
385       GstBus *bus = gst_device_provider_get_bus (provider);
386
387       gst_bus_enable_sync_message_emission (bus);
388       g_signal_connect (bus, "sync-message",
389           G_CALLBACK (bus_sync_message), monitor);
390       gst_object_unref (bus);
391       g_ptr_array_add (monitor->priv->providers, provider);
392       monitor->priv->cookie++;
393     }
394
395     gst_object_unref (factory);
396   }
397
398   GST_OBJECT_UNLOCK (monitor);
399 }
400
401 /**
402  * gst_global_device_monitor_get_classes_filter:
403  * @monitor: the global device monitor
404  *
405  * Return the type (device classes) filter active for device filtering.
406  *
407  * Returns: string of device classes that are being filtered.
408  *
409  * Since: 1.4
410  */
411 gchar *
412 gst_global_device_monitor_get_classes_filter (GstGlobalDeviceMonitor * monitor)
413 {
414   gchar *res;
415
416   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), 0);
417
418   GST_OBJECT_LOCK (monitor);
419   res = g_strdup (monitor->priv->classes);
420   GST_OBJECT_UNLOCK (monitor);
421
422   return res;
423 }
424
425 /**
426  * gst_global_device_monitor_set_caps_filter:
427  * @monitor: the global device monitor
428  * @caps: caps to filter
429  *
430  * Set caps to use as filter for devices. By default ANY caps are used,
431  * meaning no caps filter is active.
432  *
433  * Since: 1.4
434  */
435 void
436 gst_global_device_monitor_set_caps_filter (GstGlobalDeviceMonitor * monitor,
437     GstCaps * caps)
438 {
439   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
440   g_return_if_fail (GST_IS_CAPS (caps));
441
442   GST_OBJECT_LOCK (monitor);
443   gst_caps_replace (&monitor->priv->caps, caps);
444   GST_OBJECT_UNLOCK (monitor);
445 }
446
447 /**
448  * gst_global_device_monitor_get_caps_filter:
449  * @monitor: a global device monitor
450  *
451  * Get the #GstCaps filter set by gst_global_device_monitor_set_caps_filter().
452  *
453  * Returns: (transfer full): the filter caps that are active (or ANY caps)
454  *
455  * Since: 1.4
456  */
457 GstCaps *
458 gst_global_device_monitor_get_caps_filter (GstGlobalDeviceMonitor * monitor)
459 {
460   GstCaps *res;
461
462   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
463
464   GST_OBJECT_LOCK (monitor);
465   res = gst_caps_ref (monitor->priv->caps);
466   GST_OBJECT_UNLOCK (monitor);
467
468   return res;
469 }
470
471 /**
472  * gst_global_device_monitor_new:
473  *
474  * Create a new #GstGlobalDeviceMonitor
475  *
476  * Returns: (transfer full): a new global device monitor.
477  *
478  * Since: 1.4
479  */
480 GstGlobalDeviceMonitor *
481 gst_global_device_monitor_new (void)
482 {
483   return g_object_new (GST_TYPE_GLOBAL_DEVICE_MONITOR, NULL);
484 }
485
486 /**
487  * gst_global_device_monitor_get_bus:
488  * @monitor: a #GstDeviceProvider
489  *
490  * Gets the #GstBus of this #GstGlobalDeviceMonitor
491  *
492  * Returns: (transfer full): a #GstBus
493  *
494  * Since: 1.4
495  */
496 GstBus *
497 gst_global_device_monitor_get_bus (GstGlobalDeviceMonitor * monitor)
498 {
499   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
500
501   return gst_object_ref (monitor->priv->bus);
502 }