2 * Copyright (C) 2013 Olivier Crete <olivier.crete@collabora.com>
4 * gstdevicemonitor.c: 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:gstdevicemonitor
24 * @short_description: A device monitor and prober
25 * @see_also: #GstDevice, #GstDeviceProvider
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
34 * The device monitor will monitor all devices matching the filters that
35 * the application has set.
38 * The basic use pattern of a device monitor is as follows:
41 * my_bus_func (GstBus * bus, GstMessage * message, gpointer user_data)
46 * switch (GST_MESSAGE_TYPE (message)) {
47 * case GST_MESSAGE_DEVICE_ADDED:
48 * gst_message_parse_device_added (message, &device);
49 * name = gst_device_get_display_name (device);
50 * g_print("Device added: %s\n", name);
53 * case GST_MESSAGE_DEVICE_REMOVED:
54 * gst_message_parse_device_removed (message, &device);
55 * name = gst_device_get_display_name (device);
56 * g_print("Device removed: %s\n", name);
63 * return G_SOURCE_CONTINUE;
67 * setup_raw_video_source_device_monitor (void) {
68 * GstDeviceMonitor *monitor;
72 * monitor = gst_device_monitor_new ();
74 * bus = gst_device_monitor_get_bus (monitor);
75 * gst_bus_add_watch (bus, my_bus_func, NULL);
76 * gst_object_unref (bus);
78 * caps = gst_caps_new_empty_simple ("video/x-raw");
79 * gst_device_monitor_add_filter (monitor, "Video/Source", caps);
80 * gst_caps_unref (caps);
82 * gst_device_monitor_start (monitor);
96 #include "gst_private.h"
97 #include "gstdevicemonitor.h"
99 struct _GstDeviceMonitorPrivate
105 GPtrArray *providers;
114 G_DEFINE_TYPE (GstDeviceMonitor, gst_device_monitor, GST_TYPE_OBJECT);
116 static void gst_device_monitor_dispose (GObject * object);
127 device_filter_free (struct DeviceFilter *filter)
129 g_strfreev (filter->classesv);
130 gst_caps_unref (filter->caps);
132 g_slice_free (struct DeviceFilter, filter);
136 gst_device_monitor_class_init (GstDeviceMonitorClass * klass)
138 GObjectClass *object_class = G_OBJECT_CLASS (klass);
140 g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate));
142 object_class->dispose = gst_device_monitor_dispose;
146 bus_sync_message (GstBus * bus, GstMessage * message,
147 GstDeviceMonitor * monitor)
149 GstMessageType type = GST_MESSAGE_TYPE (message);
151 if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
155 if (type == GST_MESSAGE_DEVICE_ADDED)
156 gst_message_parse_device_added (message, &device);
158 gst_message_parse_device_removed (message, &device);
160 GST_OBJECT_LOCK (monitor);
161 if (monitor->priv->filters->len) {
164 for (i = 0; i < monitor->priv->filters->len; i++) {
165 struct DeviceFilter *filter =
166 g_ptr_array_index (monitor->priv->filters, i);
169 caps = gst_device_get_caps (device);
170 matches = gst_caps_can_intersect (filter->caps, caps) &&
171 gst_device_has_classesv (device, filter->classesv);
172 gst_caps_unref (caps);
179 GST_OBJECT_UNLOCK (monitor);
181 gst_object_unref (device);
184 gst_bus_post (monitor->priv->bus, gst_message_ref (message));
190 gst_device_monitor_init (GstDeviceMonitor * self)
192 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
193 GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate);
195 self->priv->bus = gst_bus_new ();
196 gst_bus_set_flushing (self->priv->bus, TRUE);
198 self->priv->providers = g_ptr_array_new ();
199 self->priv->filters = g_ptr_array_new_with_free_func (
200 (GDestroyNotify) device_filter_free);
202 self->priv->last_id = 1;
207 gst_device_monitor_remove (GstDeviceMonitor * self, guint i)
209 GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
212 g_ptr_array_remove_index (self->priv->providers, i);
214 bus = gst_device_provider_get_bus (provider);
215 g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
216 gst_object_unref (bus);
218 gst_object_unref (provider);
222 gst_device_monitor_dispose (GObject * object)
224 GstDeviceMonitor *self = GST_DEVICE_MONITOR (object);
226 g_return_if_fail (!self->priv->started);
228 if (self->priv->providers) {
229 while (self->priv->providers->len)
230 gst_device_monitor_remove (self, self->priv->providers->len - 1);
231 g_ptr_array_unref (self->priv->providers);
232 self->priv->providers = NULL;
235 if (self->priv->filters) {
236 g_ptr_array_unref (self->priv->filters);
237 self->priv->filters = NULL;
240 gst_object_replace ((GstObject **) & self->priv->bus, NULL);
242 G_OBJECT_CLASS (gst_device_monitor_parent_class)->dispose (object);
246 * gst_device_monitor_get_devices:
247 * @monitor: A #GstDeviceProvider
249 * Gets a list of devices from all of the relevant monitors. This may actually
250 * probe the hardware if the monitor is not currently started.
252 * Returns: (transfer full) (element-type GstDevice): a #GList of
259 gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
261 GList *devices = NULL;
265 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
267 GST_OBJECT_LOCK (monitor);
269 if (monitor->priv->filters->len == 0) {
270 GST_OBJECT_UNLOCK (monitor);
271 GST_WARNING_OBJECT (monitor, "No filters have been set");
275 if (monitor->priv->providers->len == 0) {
276 GST_OBJECT_UNLOCK (monitor);
277 GST_WARNING_OBJECT (monitor, "No providers match the current filters");
283 g_list_free_full (devices, gst_object_unref);
286 cookie = monitor->priv->cookie;
288 for (i = 0; i < monitor->priv->providers->len; i++) {
290 GstDeviceProvider *provider =
291 gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
294 GST_OBJECT_UNLOCK (monitor);
296 tmpdev = gst_device_provider_get_devices (provider);
298 GST_OBJECT_LOCK (monitor);
300 for (item = tmpdev; item; item = item->next) {
301 GstDevice *dev = GST_DEVICE (item->data);
302 GstCaps *caps = gst_device_get_caps (dev);
305 for (j = 0; j < monitor->priv->filters->len; j++) {
306 struct DeviceFilter *filter =
307 g_ptr_array_index (monitor->priv->filters, j);
308 if (gst_caps_can_intersect (filter->caps, caps) &&
309 gst_device_has_classesv (dev, filter->classesv)) {
310 devices = g_list_prepend (devices, gst_object_ref (dev));
314 gst_caps_unref (caps);
317 g_list_free_full (tmpdev, gst_object_unref);
318 gst_object_unref (provider);
321 if (monitor->priv->cookie != cookie)
325 GST_OBJECT_UNLOCK (monitor);
327 return g_list_reverse (devices);
331 * gst_device_monitor_start:
332 * @monitor: A #GstDeviceMonitor
334 * Starts monitoring the devices, one this has succeeded, the
335 * %GST_MESSAGE_DEVICE_ADDED and %GST_MESSAGE_DEVICE_REMOVED messages
336 * will be emitted on the bus when the list of devices changes.
338 * Returns: %TRUE if the device monitoring could be started
344 gst_device_monitor_start (GstDeviceMonitor * monitor)
347 GList *pending = NULL, *started = NULL, *removed = NULL;
349 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
351 GST_OBJECT_LOCK (monitor);
353 if (monitor->priv->filters->len == 0) {
354 GST_OBJECT_UNLOCK (monitor);
355 GST_WARNING_OBJECT (monitor, "No filters have been set, will expose all "
357 gst_device_monitor_add_filter (monitor, NULL, NULL);
358 GST_OBJECT_LOCK (monitor);
361 if (monitor->priv->providers->len == 0) {
362 GST_OBJECT_UNLOCK (monitor);
363 GST_WARNING_OBJECT (monitor, "No providers match the current filters");
367 gst_bus_set_flushing (monitor->priv->bus, FALSE);
370 cookie = monitor->priv->cookie;
372 g_list_free_full (pending, gst_object_unref);
377 for (i = 0; i < monitor->priv->providers->len; i++) {
378 GstDeviceProvider *provider;
381 provider = g_ptr_array_index (monitor->priv->providers, i);
383 find = g_list_find (removed, provider);
385 /* this was already started, move to started list */
386 removed = g_list_remove_link (removed, find);
387 started = g_list_concat (started, find);
389 /* not started, add to pending list */
390 pending = g_list_append (pending, gst_object_ref (provider));
393 g_list_free_full (removed, gst_object_unref);
397 GstDeviceProvider *provider = pending->data;
399 if (gst_device_provider_can_monitor (provider)) {
400 GST_OBJECT_UNLOCK (monitor);
402 if (!gst_device_provider_start (provider))
405 GST_OBJECT_LOCK (monitor);
407 started = g_list_prepend (started, provider);
408 pending = g_list_delete_link (pending, pending);
410 if (monitor->priv->cookie != cookie)
413 monitor->priv->started = TRUE;
414 GST_OBJECT_UNLOCK (monitor);
416 g_list_free_full (started, gst_object_unref);
422 GST_OBJECT_LOCK (monitor);
423 gst_bus_set_flushing (monitor->priv->bus, TRUE);
424 GST_OBJECT_UNLOCK (monitor);
427 GstDeviceProvider *provider = started->data;
429 gst_device_provider_stop (provider);
430 gst_object_unref (provider);
432 started = g_list_delete_link (started, started);
439 * gst_device_monitor_stop:
440 * @monitor: A #GstDeviceProvider
442 * Stops monitoring the devices.
447 gst_device_monitor_stop (GstDeviceMonitor * monitor)
450 GList *started = NULL;
452 g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
454 gst_bus_set_flushing (monitor->priv->bus, TRUE);
456 GST_OBJECT_LOCK (monitor);
457 for (i = 0; i < monitor->priv->providers->len; i++) {
458 GstDeviceProvider *provider =
459 g_ptr_array_index (monitor->priv->providers, i);
461 started = g_list_prepend (started, gst_object_ref (provider));
463 GST_OBJECT_UNLOCK (monitor);
466 GstDeviceProvider *provider = started->data;
468 if (gst_device_provider_can_monitor (provider))
469 gst_device_provider_stop (provider);
471 started = g_list_delete_link (started, started);
472 gst_object_unref (provider);
475 GST_OBJECT_LOCK (monitor);
476 monitor->priv->started = FALSE;
477 GST_OBJECT_UNLOCK (monitor);
482 * gst_device_monitor_add_filter:
483 * @monitor: a device monitor
484 * @classes: (allow-none): device classes to use as filter or %NULL for any class
485 * @caps: (allow-none): the #GstCaps to filter or %NULL for ANY
487 * Adds a filter for which #GstDevice will be monitored, any device that matches
488 * all classes and the #GstCaps will be returned.
490 * Filters must be added before the #GstDeviceMonitor is started.
492 * Returns: The id of the new filter or 0 if no provider matched the filter's
498 gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
499 const gchar * classes, GstCaps * caps)
501 GList *factories = NULL;
502 struct DeviceFilter *filter;
504 gboolean matched = FALSE;
506 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
507 g_return_val_if_fail (!monitor->priv->started, 0);
509 GST_OBJECT_LOCK (monitor);
511 filter = g_slice_new0 (struct DeviceFilter);
512 filter->id = monitor->priv->last_id++;
514 filter->caps = gst_caps_ref (caps);
516 filter->caps = gst_caps_new_any ();
518 filter->classesv = g_strsplit (classes, "/", 0);
520 factories = gst_device_provider_factory_list_get_device_providers (1);
523 GstDeviceProviderFactory *factory = factories->data;
525 if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
526 GstDeviceProvider *provider;
528 provider = gst_device_provider_factory_get (factory);
533 for (i = 0; i < monitor->priv->providers->len; i++) {
534 if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
535 gst_object_unref (provider);
544 GstBus *bus = gst_device_provider_get_bus (provider);
547 gst_bus_enable_sync_message_emission (bus);
548 g_signal_connect (bus, "sync-message",
549 G_CALLBACK (bus_sync_message), monitor);
550 gst_object_unref (bus);
551 g_ptr_array_add (monitor->priv->providers, provider);
552 monitor->priv->cookie++;
556 factories = g_list_remove (factories, factory);
557 gst_object_unref (factory);
560 /* Ensure there is no leak here */
561 g_assert (factories == NULL);
565 g_ptr_array_add (monitor->priv->filters, filter);
567 device_filter_free (filter);
570 GST_OBJECT_UNLOCK (monitor);
576 * gst_device_monitor_remove_filter:
577 * @monitor: a device monitor
578 * @filter_id: the id of the filter
580 * Removes a filter from the #GstDeviceMonitor using the id that was returned
581 * by gst_device_monitor_add_filter().
583 * Returns: %TRUE of the filter id was valid, %FALSE otherwise
588 gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
591 gboolean removed = FALSE;
593 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
594 g_return_val_if_fail (!monitor->priv->started, FALSE);
595 g_return_val_if_fail (filter_id > 0, FALSE);
597 GST_OBJECT_LOCK (monitor);
598 for (i = 0; i < monitor->priv->filters->len; i++) {
599 struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);
601 if (filter->id == filter_id) {
602 g_ptr_array_remove_index (monitor->priv->filters, i);
609 for (i = 0; i < monitor->priv->providers->len; i++) {
610 GstDeviceProvider *provider =
611 g_ptr_array_index (monitor->priv->providers, i);
612 GstDeviceProviderFactory *factory =
613 gst_device_provider_get_factory (provider);
614 gboolean valid = FALSE;
616 for (j = 0; j < monitor->priv->filters->len; j++) {
617 struct DeviceFilter *filter =
618 g_ptr_array_index (monitor->priv->filters, j);
620 if (gst_device_provider_factory_has_classesv (factory,
628 monitor->priv->cookie++;
629 gst_device_monitor_remove (monitor, i);
635 GST_OBJECT_UNLOCK (monitor);
643 * gst_device_monitor_new:
645 * Create a new #GstDeviceMonitor
647 * Returns: (transfer full): a new device monitor.
652 gst_device_monitor_new (void)
654 return g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
658 * gst_device_monitor_get_bus:
659 * @monitor: a #GstDeviceProvider
661 * Gets the #GstBus of this #GstDeviceMonitor
663 * Returns: (transfer full): a #GstBus
668 gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
670 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
672 return gst_object_ref (monitor->priv->bus);