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_fast (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);
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)
348 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
350 GST_OBJECT_LOCK (monitor);
352 if (monitor->priv->filters->len == 0) {
353 GST_OBJECT_UNLOCK (monitor);
354 GST_WARNING_OBJECT (monitor, "No filters have been set, will expose all "
356 gst_device_monitor_add_filter (monitor, NULL, NULL);
357 GST_OBJECT_LOCK (monitor);
360 if (monitor->priv->providers->len == 0) {
361 GST_OBJECT_UNLOCK (monitor);
362 GST_WARNING_OBJECT (monitor, "No providers match the current filters");
366 gst_bus_set_flushing (monitor->priv->bus, FALSE);
368 for (i = 0; i < monitor->priv->providers->len; i++) {
369 GstDeviceProvider *provider =
370 g_ptr_array_index (monitor->priv->providers, i);
372 if (gst_device_provider_can_monitor (provider)) {
373 if (!gst_device_provider_start (provider)) {
374 gst_bus_set_flushing (monitor->priv->bus, TRUE);
377 gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers,
380 GST_OBJECT_UNLOCK (monitor);
386 monitor->priv->started = TRUE;
387 GST_OBJECT_UNLOCK (monitor);
393 * gst_device_monitor_stop:
394 * @monitor: A #GstDeviceProvider
396 * Stops monitoring the devices.
401 gst_device_monitor_stop (GstDeviceMonitor * monitor)
405 g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
407 gst_bus_set_flushing (monitor->priv->bus, TRUE);
409 GST_OBJECT_LOCK (monitor);
410 for (i = 0; i < monitor->priv->providers->len; i++) {
411 GstDeviceProvider *provider =
412 g_ptr_array_index (monitor->priv->providers, i);
414 if (gst_device_provider_can_monitor (provider))
415 gst_device_provider_stop (provider);
417 monitor->priv->started = FALSE;
418 GST_OBJECT_UNLOCK (monitor);
423 * gst_device_monitor_add_filter:
424 * @monitor: a device monitor
425 * @classes: (allow-none): device classes to use as filter or %NULL for any class
426 * @caps: (allow-none): the #GstCaps to filter or %NULL for ANY
428 * Adds a filter for which #GstDevice will be monitored, any device that matches
429 * all classes and the #GstCaps will be returned.
431 * Filters must be added before the #GstDeviceMonitor is started.
433 * Returns: The id of the new filter or %0 if no provider matched the filter's
439 gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
440 const gchar * classes, GstCaps * caps)
442 GList *factories = NULL;
443 struct DeviceFilter *filter;
445 gboolean matched = FALSE;
447 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
448 g_return_val_if_fail (!monitor->priv->started, 0);
450 GST_OBJECT_LOCK (monitor);
452 filter = g_slice_new0 (struct DeviceFilter);
453 filter->id = monitor->priv->last_id++;
455 filter->caps = gst_caps_ref (caps);
457 filter->caps = gst_caps_new_any ();
459 filter->classesv = g_strsplit (classes, "/", 0);
461 factories = gst_device_provider_factory_list_get_device_providers (1);
464 GstDeviceProviderFactory *factory = factories->data;
467 if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
468 GstDeviceProvider *provider;
470 provider = gst_device_provider_factory_get (factory);
475 for (i = 0; i < monitor->priv->providers->len; i++) {
476 if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
477 gst_object_unref (provider);
486 GstBus *bus = gst_device_provider_get_bus (provider);
489 gst_bus_enable_sync_message_emission (bus);
490 g_signal_connect (bus, "sync-message",
491 G_CALLBACK (bus_sync_message), monitor);
492 gst_object_unref (bus);
493 g_ptr_array_add (monitor->priv->providers, provider);
494 monitor->priv->cookie++;
498 factories = g_list_remove (factories, factory);
499 gst_object_unref (factory);
502 /* Ensure there is no leak here */
503 g_assert (factories == NULL);
507 g_ptr_array_add (monitor->priv->filters, filter);
509 device_filter_free (filter);
512 GST_OBJECT_UNLOCK (monitor);
518 * gst_device_monitor_remove_filter:
519 * @monitor: a device monitor
520 * @filter_id: the id of the filter
522 * Removes a filter from the #GstDeviceMonitor using the id that was returned
523 * by gst_device_monitor_add_filter().
525 * Returns: %TRUE of the filter id was valid, %FALSE otherwise
530 gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
533 gboolean removed = FALSE;
535 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
536 g_return_val_if_fail (!monitor->priv->started, FALSE);
537 g_return_val_if_fail (filter_id > 0, FALSE);
539 GST_OBJECT_LOCK (monitor);
540 for (i = 0; i < monitor->priv->filters->len; i++) {
541 struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);
543 if (filter->id == filter_id) {
544 g_ptr_array_remove_index (monitor->priv->filters, i);
551 for (i = 0; i < monitor->priv->providers->len; i++) {
552 GstDeviceProvider *provider =
553 g_ptr_array_index (monitor->priv->providers, i);
554 GstDeviceProviderFactory *factory =
555 gst_device_provider_get_factory (provider);
556 gboolean valid = FALSE;
558 for (j = 0; j < monitor->priv->filters->len; j++) {
559 struct DeviceFilter *filter =
560 g_ptr_array_index (monitor->priv->filters, j);
562 if (gst_device_provider_factory_has_classesv (factory,
570 monitor->priv->cookie++;
571 gst_device_monitor_remove (monitor, i);
577 GST_OBJECT_UNLOCK (monitor);
585 * gst_device_monitor_new:
587 * Create a new #GstDeviceMonitor
589 * Returns: (transfer full): a new device monitor.
594 gst_device_monitor_new (void)
596 return g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
600 * gst_device_monitor_get_bus:
601 * @monitor: a #GstDeviceProvider
603 * Gets the #GstBus of this #GstDeviceMonitor
605 * Returns: (transfer full): a #GstBus
610 gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
612 g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
614 return gst_object_ref (monitor->priv->bus);