2 * Copyright (C) 2013 Olivier Crete <olivier.crete@collabora.com>
4 * gstglobaldevicemonitor.c: Global device monitor
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.
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.
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.
23 * SECTION:gstglobaldevicemonitor
24 * @short_description: A global device monitor and prober
25 * @see_also: #GstDevice, #GstDeviceProvider
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
42 #include "gst_private.h"
43 #include "gstglobaldevicemonitor.h"
45 struct _GstGlobalDeviceMonitorPrivate
59 G_DEFINE_TYPE (GstGlobalDeviceMonitor, gst_global_device_monitor,
62 static void gst_global_device_monitor_dispose (GObject * object);
65 gst_global_device_monitor_class_init (GstGlobalDeviceMonitorClass * klass)
67 GObjectClass *object_class = G_OBJECT_CLASS (klass);
69 g_type_class_add_private (klass, sizeof (GstGlobalDeviceMonitorPrivate));
71 object_class->dispose = gst_global_device_monitor_dispose;
75 bus_sync_message (GstBus * bus, GstMessage * message,
76 GstGlobalDeviceMonitor * monitor)
78 GstMessageType type = GST_MESSAGE_TYPE (message);
80 if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
85 if (type == GST_MESSAGE_DEVICE_ADDED)
86 gst_message_parse_device_added (message, &device);
88 gst_message_parse_device_removed (message, &device);
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);
98 gst_bus_post (monitor->priv->bus, gst_message_ref (message));
104 gst_global_device_monitor_init (GstGlobalDeviceMonitor * self)
108 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
109 GST_TYPE_GLOBAL_DEVICE_MONITOR, GstGlobalDeviceMonitorPrivate);
111 self->priv->bus = gst_bus_new ();
112 gst_bus_set_flushing (self->priv->bus, TRUE);
114 self->priv->providers = g_ptr_array_new ();
115 self->priv->caps = gst_caps_new_any ();
116 self->priv->classes = g_strdup ("");
119 gst_device_provider_factory_list_get_device_providers (self->priv->
123 GstDeviceProviderFactory *factory = factories->data;
124 GstDeviceProvider *provider;
126 factories = g_list_remove (factories, factory);
128 provider = gst_device_provider_factory_get (factory);
130 GstBus *bus = gst_device_provider_get_bus (provider);
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);
138 gst_object_unref (factory);
144 gst_global_device_monitor_remove (GstGlobalDeviceMonitor * self, guint i)
146 GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
149 g_ptr_array_remove_index_fast (self->priv->providers, i);
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);
155 gst_object_unref (provider);
159 gst_global_device_monitor_dispose (GObject * object)
161 GstGlobalDeviceMonitor *self = GST_GLOBAL_DEVICE_MONITOR (object);
163 g_return_if_fail (self->priv->started == FALSE);
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;
172 gst_caps_replace (&self->priv->caps, NULL);
173 g_free (self->priv->classes);
174 gst_object_replace ((GstObject **) & self->priv->bus, NULL);
176 G_OBJECT_CLASS (gst_global_device_monitor_parent_class)->dispose (object);
180 * gst_global_device_monitor_get_devices:
181 * @monitor: A #GstDeviceProvider
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.
186 * Returns: (transfer full) (element-type GstDevice): a #GList of
193 gst_global_device_monitor_get_devices (GstGlobalDeviceMonitor * monitor)
195 GList *devices = NULL;
199 g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
201 GST_OBJECT_LOCK (monitor);
205 g_list_free_full (devices, gst_object_unref);
208 cookie = monitor->priv->cookie;
210 for (i = 0; i < monitor->priv->providers->len; i++) {
212 GstDeviceProvider *provider =
213 gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
216 GST_OBJECT_UNLOCK (monitor);
218 tmpdev = gst_device_provider_get_devices (provider);
220 for (item = tmpdev; item; item = item->next) {
221 GstDevice *dev = GST_DEVICE (item->data);
222 GstCaps *caps = gst_device_get_caps (dev);
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);
230 g_list_free_full (tmpdev, gst_object_unref);
231 gst_object_unref (provider);
233 GST_OBJECT_LOCK (monitor);
235 if (monitor->priv->cookie != cookie)
239 GST_OBJECT_UNLOCK (monitor);
245 * gst_global_device_monitor_start:
246 * @monitor: A #GstGlobalDeviceMonitor
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.
252 * Returns: %TRUE if the device monitoring could be started
258 gst_global_device_monitor_start (GstGlobalDeviceMonitor * monitor)
262 g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), FALSE);
264 GST_OBJECT_LOCK (monitor);
266 if (monitor->priv->providers->len == 0) {
267 GST_OBJECT_UNLOCK (monitor);
271 gst_bus_set_flushing (monitor->priv->bus, FALSE);
273 for (i = 0; i < monitor->priv->providers->len; i++) {
274 if (!gst_device_provider_start (g_ptr_array_index (monitor->priv->providers,
276 gst_bus_set_flushing (monitor->priv->bus, TRUE);
279 gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers,
282 GST_OBJECT_UNLOCK (monitor);
287 monitor->priv->started = TRUE;
288 GST_OBJECT_UNLOCK (monitor);
294 * gst_global_device_monitor_stop:
295 * @monitor: A #GstDeviceProvider
297 * Stops monitoring the devices.
302 gst_global_device_monitor_stop (GstGlobalDeviceMonitor * monitor)
306 g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
308 gst_bus_set_flushing (monitor->priv->bus, TRUE);
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);
319 * gst_global_device_monitor_set_classes_filter:
320 * @monitor: the global device monitor
321 * @classes: device classes to use as filter
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
330 gst_global_device_monitor_set_classes_filter (GstGlobalDeviceMonitor * monitor,
331 const gchar * classes)
333 GList *factories = NULL;
336 g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
337 g_return_if_fail (!monitor->priv->started);
339 GST_OBJECT_LOCK (monitor);
340 if (!strcmp (monitor->priv->classes, classes)) {
341 GST_OBJECT_UNLOCK (monitor);
345 g_free (monitor->priv->classes);
346 monitor->priv->classes = g_strdup (classes);
348 factories = gst_device_provider_factory_list_get_device_providers (classes,
351 for (i = 0; i < monitor->priv->providers->len; i++) {
352 GstDeviceProvider *provider;
353 GstDeviceProviderFactory *f;
356 provider = g_ptr_array_index (monitor->priv->providers, i);
357 f = gst_device_provider_get_factory (provider);
359 item = g_list_find (factories, f);
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
365 factories = g_list_remove_link (factories, item);
366 gst_object_unref (f);
368 /* If it's not in our list, them remove it from the list of providers.
371 monitor->priv->cookie++;
372 gst_global_device_monitor_remove (monitor, i);
378 GstDeviceProviderFactory *factory = factories->data;
379 GstDeviceProvider *provider;
381 factories = g_list_remove (factories, factory);
383 provider = gst_device_provider_factory_get (factory);
385 GstBus *bus = gst_device_provider_get_bus (provider);
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++;
395 gst_object_unref (factory);
398 GST_OBJECT_UNLOCK (monitor);
402 * gst_global_device_monitor_get_classes_filter:
403 * @monitor: the global device monitor
405 * Return the type (device classes) filter active for device filtering.
407 * Returns: string of device classes that are being filtered.
412 gst_global_device_monitor_get_classes_filter (GstGlobalDeviceMonitor * monitor)
416 g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), 0);
418 GST_OBJECT_LOCK (monitor);
419 res = g_strdup (monitor->priv->classes);
420 GST_OBJECT_UNLOCK (monitor);
426 * gst_global_device_monitor_set_caps_filter:
427 * @monitor: the global device monitor
428 * @caps: caps to filter
430 * Set caps to use as filter for devices. By default ANY caps are used,
431 * meaning no caps filter is active.
436 gst_global_device_monitor_set_caps_filter (GstGlobalDeviceMonitor * monitor,
439 g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor));
440 g_return_if_fail (GST_IS_CAPS (caps));
442 GST_OBJECT_LOCK (monitor);
443 gst_caps_replace (&monitor->priv->caps, caps);
444 GST_OBJECT_UNLOCK (monitor);
448 * gst_global_device_monitor_get_caps_filter:
449 * @monitor: a global device monitor
451 * Get the #GstCaps filter set by gst_global_device_monitor_set_caps_filter().
453 * Returns: (transfer full): the filter caps that are active (or ANY caps)
458 gst_global_device_monitor_get_caps_filter (GstGlobalDeviceMonitor * monitor)
462 g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
464 GST_OBJECT_LOCK (monitor);
465 res = gst_caps_ref (monitor->priv->caps);
466 GST_OBJECT_UNLOCK (monitor);
472 * gst_global_device_monitor_new:
474 * Create a new #GstGlobalDeviceMonitor
476 * Returns: (transfer full): a new global device monitor.
480 GstGlobalDeviceMonitor *
481 gst_global_device_monitor_new (void)
483 return g_object_new (GST_TYPE_GLOBAL_DEVICE_MONITOR, NULL);
487 * gst_global_device_monitor_get_bus:
488 * @monitor: a #GstDeviceProvider
490 * Gets the #GstBus of this #GstGlobalDeviceMonitor
492 * Returns: (transfer full): a #GstBus
497 gst_global_device_monitor_get_bus (GstGlobalDeviceMonitor * monitor)
499 g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
501 return gst_object_ref (monitor->priv->bus);