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