poll: minor docs clarification
[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  * @title: GstDeviceMonitor
25  * @short_description: A device monitor and prober
26  * @see_also: #GstDevice, #GstDeviceProvider
27  *
28  * Applications should create a #GstDeviceMonitor when they want
29  * to probe, list and monitor devices of a specific type. The
30  * #GstDeviceMonitor will create the appropriate
31  * #GstDeviceProvider objects and manage them. It will then post
32  * messages on its #GstBus for devices that have been added and
33  * removed.
34  *
35  * The device monitor will monitor all devices matching the filters that
36  * the application has set.
37  *
38  * The basic use pattern of a device monitor is as follows:
39  * |[
40  *   static gboolean
41  *   my_bus_func (GstBus * bus, GstMessage * message, gpointer user_data)
42  *   {
43  *      GstDevice *device;
44  *      gchar *name;
45  *
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);
51  *          g_free (name);
52  *          gst_object_unref (device);
53  *          break;
54  *        case GST_MESSAGE_DEVICE_REMOVED:
55  *          gst_message_parse_device_removed (message, &device);
56  *          name = gst_device_get_display_name (device);
57  *          g_print("Device removed: %s\n", name);
58  *          g_free (name);
59  *          gst_object_unref (device);
60  *          break;
61  *        default:
62  *          break;
63  *      }
64  *
65  *      return G_SOURCE_CONTINUE;
66  *   }
67  *
68  *   GstDeviceMonitor *
69  *   setup_raw_video_source_device_monitor (void) {
70  *      GstDeviceMonitor *monitor;
71  *      GstBus *bus;
72  *      GstCaps *caps;
73  *
74  *      monitor = gst_device_monitor_new ();
75  *
76  *      bus = gst_device_monitor_get_bus (monitor);
77  *      gst_bus_add_watch (bus, my_bus_func, NULL);
78  *      gst_object_unref (bus);
79  *
80  *      caps = gst_caps_new_empty_simple ("video/x-raw");
81  *      gst_device_monitor_add_filter (monitor, "Video/Source", caps);
82  *      gst_caps_unref (caps);
83  *
84  *      gst_device_monitor_start (monitor);
85  *
86  *      return monitor;
87  *   }
88  * ]|
89  *
90  * Since: 1.4
91  */
92
93
94 #ifdef HAVE_CONFIG_H
95 #include "config.h"
96 #endif
97
98 #include "gst_private.h"
99 #include "gstdevicemonitor.h"
100
101 struct _GstDeviceMonitorPrivate
102 {
103   gboolean started;
104
105   GstBus *bus;
106
107   GPtrArray *providers;
108   guint cookie;
109
110   GPtrArray *filters;
111
112   guint last_id;
113   GList *hidden;
114   gboolean show_all;
115 };
116
117 #define DEFAULT_SHOW_ALL        FALSE
118
119 enum
120 {
121   PROP_SHOW_ALL = 1,
122 };
123
124 G_DEFINE_TYPE (GstDeviceMonitor, gst_device_monitor, GST_TYPE_OBJECT);
125
126 static void gst_device_monitor_dispose (GObject * object);
127
128 struct DeviceFilter
129 {
130   guint id;
131
132   gchar **classesv;
133   GstCaps *caps;
134 };
135
136 static void
137 device_filter_free (struct DeviceFilter *filter)
138 {
139   g_strfreev (filter->classesv);
140   gst_caps_unref (filter->caps);
141
142   g_slice_free (struct DeviceFilter, filter);
143 }
144
145 static void
146 gst_device_monitor_get_property (GObject * object, guint prop_id,
147     GValue * value, GParamSpec * pspec)
148 {
149   GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
150
151   switch (prop_id) {
152     case PROP_SHOW_ALL:
153       g_value_set_boolean (value,
154           gst_device_monitor_get_show_all_devices (monitor));
155       break;
156     default:
157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158       break;
159   }
160 }
161
162 static void
163 gst_device_monitor_set_property (GObject * object, guint prop_id,
164     const GValue * value, GParamSpec * pspec)
165 {
166   GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
167
168   switch (prop_id) {
169     case PROP_SHOW_ALL:
170       gst_device_monitor_set_show_all_devices (monitor,
171           g_value_get_boolean (value));
172       break;
173     default:
174       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175       break;
176   }
177 }
178
179
180 static void
181 gst_device_monitor_class_init (GstDeviceMonitorClass * klass)
182 {
183   GObjectClass *object_class = G_OBJECT_CLASS (klass);
184
185   g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate));
186
187   object_class->get_property = gst_device_monitor_get_property;
188   object_class->set_property = gst_device_monitor_set_property;
189   object_class->dispose = gst_device_monitor_dispose;
190
191   g_object_class_install_property (object_class, PROP_SHOW_ALL,
192       g_param_spec_boolean ("show-all", "Show All",
193           "Show all devices, even those from hidden providers",
194           DEFAULT_SHOW_ALL, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
195 }
196
197 /* must be called with monitor lock */
198 static gboolean
199 is_provider_hidden (GstDeviceMonitor * monitor, GList * hidden,
200     GstDeviceProvider * provider)
201 {
202   GstDeviceProviderFactory *factory;
203
204   if (monitor->priv->show_all)
205     return FALSE;
206
207   factory = gst_device_provider_get_factory (provider);
208   if (g_list_find_custom (hidden, GST_OBJECT_NAME (factory),
209           (GCompareFunc) g_strcmp0))
210     return TRUE;
211
212   return FALSE;
213 }
214
215 /* must be called with monitor lock */
216 static void
217 update_hidden_providers_list (GList ** hidden, GstDeviceProvider * provider)
218 {
219   gchar **obs;
220
221   obs = gst_device_provider_get_hidden_providers (provider);
222   if (obs) {
223     gint i;
224
225     for (i = 0; obs[i]; i++)
226       *hidden = g_list_prepend (*hidden, obs[i]);
227
228     g_free (obs);
229   }
230 }
231
232 static void
233 bus_sync_message (GstBus * bus, GstMessage * message,
234     GstDeviceMonitor * monitor)
235 {
236   GstMessageType type = GST_MESSAGE_TYPE (message);
237
238   if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
239     gboolean matches = TRUE;
240     GstDevice *device;
241     GstDeviceProvider *provider;
242
243     if (type == GST_MESSAGE_DEVICE_ADDED)
244       gst_message_parse_device_added (message, &device);
245     else
246       gst_message_parse_device_removed (message, &device);
247
248     GST_OBJECT_LOCK (monitor);
249     provider =
250         GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device)));
251     if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) {
252       matches = FALSE;
253     } else {
254       guint i;
255
256       for (i = 0; i < monitor->priv->filters->len; i++) {
257         struct DeviceFilter *filter =
258             g_ptr_array_index (monitor->priv->filters, i);
259         GstCaps *caps;
260
261         caps = gst_device_get_caps (device);
262         matches = gst_caps_can_intersect (filter->caps, caps) &&
263             gst_device_has_classesv (device, filter->classesv);
264         gst_caps_unref (caps);
265         if (matches)
266           break;
267       }
268     }
269     GST_OBJECT_UNLOCK (monitor);
270
271     gst_object_unref (provider);
272     gst_object_unref (device);
273
274     if (matches)
275       gst_bus_post (monitor->priv->bus, gst_message_ref (message));
276   }
277 }
278
279
280 static void
281 gst_device_monitor_init (GstDeviceMonitor * self)
282 {
283   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
284       GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate);
285
286   self->priv->show_all = DEFAULT_SHOW_ALL;
287
288   self->priv->bus = gst_bus_new ();
289   gst_bus_set_flushing (self->priv->bus, TRUE);
290
291   self->priv->providers = g_ptr_array_new ();
292   self->priv->filters = g_ptr_array_new_with_free_func (
293       (GDestroyNotify) device_filter_free);
294
295   self->priv->last_id = 1;
296 }
297
298
299 static void
300 gst_device_monitor_remove (GstDeviceMonitor * self, guint i)
301 {
302   GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
303   GstBus *bus;
304
305   g_ptr_array_remove_index (self->priv->providers, i);
306
307   bus = gst_device_provider_get_bus (provider);
308   g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
309   gst_object_unref (bus);
310
311   gst_object_unref (provider);
312 }
313
314 static void
315 gst_device_monitor_dispose (GObject * object)
316 {
317   GstDeviceMonitor *self = GST_DEVICE_MONITOR (object);
318
319   g_return_if_fail (!self->priv->started);
320
321   if (self->priv->providers) {
322     while (self->priv->providers->len)
323       gst_device_monitor_remove (self, self->priv->providers->len - 1);
324     g_ptr_array_unref (self->priv->providers);
325     self->priv->providers = NULL;
326   }
327
328   if (self->priv->filters) {
329     g_ptr_array_unref (self->priv->filters);
330     self->priv->filters = NULL;
331   }
332
333   gst_object_replace ((GstObject **) & self->priv->bus, NULL);
334
335   G_OBJECT_CLASS (gst_device_monitor_parent_class)->dispose (object);
336 }
337
338 /**
339  * gst_device_monitor_get_devices:
340  * @monitor: A #GstDeviceProvider
341  *
342  * Gets a list of devices from all of the relevant monitors. This may actually
343  * probe the hardware if the monitor is not currently started.
344  *
345  * Returns: (transfer full) (element-type GstDevice) (nullable): a #GList of
346  *   #GstDevice
347  *
348  * Since: 1.4
349  */
350
351 GList *
352 gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
353 {
354   GList *devices = NULL, *hidden = NULL;
355   guint i;
356   guint cookie;
357
358   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
359
360   GST_OBJECT_LOCK (monitor);
361
362   if (monitor->priv->filters->len == 0) {
363     GST_OBJECT_UNLOCK (monitor);
364     GST_WARNING_OBJECT (monitor, "No filters have been set");
365     return NULL;
366   }
367
368   if (monitor->priv->providers->len == 0) {
369     GST_OBJECT_UNLOCK (monitor);
370     GST_WARNING_OBJECT (monitor, "No providers match the current filters");
371     return NULL;
372   }
373
374 again:
375
376   g_list_free_full (devices, gst_object_unref);
377   g_list_free_full (hidden, g_free);
378   devices = NULL;
379   hidden = NULL;
380
381   cookie = monitor->priv->cookie;
382
383   for (i = 0; i < monitor->priv->providers->len; i++) {
384     GList *tmpdev;
385     GstDeviceProvider *provider =
386         gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
387     GList *item;
388
389     if (!is_provider_hidden (monitor, hidden, provider)) {
390       GST_OBJECT_UNLOCK (monitor);
391
392       tmpdev = gst_device_provider_get_devices (provider);
393
394       GST_OBJECT_LOCK (monitor);
395       update_hidden_providers_list (&hidden, provider);
396     } else {
397       tmpdev = NULL;
398     }
399
400
401     for (item = tmpdev; item; item = item->next) {
402       GstDevice *dev = GST_DEVICE (item->data);
403       GstCaps *caps = gst_device_get_caps (dev);
404       guint j;
405
406       for (j = 0; j < monitor->priv->filters->len; j++) {
407         struct DeviceFilter *filter =
408             g_ptr_array_index (monitor->priv->filters, j);
409
410         if (gst_caps_can_intersect (filter->caps, caps) &&
411             gst_device_has_classesv (dev, filter->classesv)) {
412           devices = g_list_prepend (devices, gst_object_ref (dev));
413           break;
414         }
415       }
416       gst_caps_unref (caps);
417     }
418
419     g_list_free_full (tmpdev, gst_object_unref);
420     gst_object_unref (provider);
421
422     if (monitor->priv->cookie != cookie)
423       goto again;
424   }
425   g_list_free_full (hidden, g_free);
426
427   GST_OBJECT_UNLOCK (monitor);
428
429   return g_list_reverse (devices);
430 }
431
432 /**
433  * gst_device_monitor_start:
434  * @monitor: A #GstDeviceMonitor
435  *
436  * Starts monitoring the devices, one this has succeeded, the
437  * %GST_MESSAGE_DEVICE_ADDED and %GST_MESSAGE_DEVICE_REMOVED messages
438  * will be emitted on the bus when the list of devices changes.
439  *
440  * Returns: %TRUE if the device monitoring could be started
441  *
442  * Since: 1.4
443  */
444
445 gboolean
446 gst_device_monitor_start (GstDeviceMonitor * monitor)
447 {
448   guint cookie, i;
449   GList *pending = NULL, *started = NULL, *removed = NULL;
450
451   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
452
453   GST_OBJECT_LOCK (monitor);
454
455   if (monitor->priv->filters->len == 0) {
456     GST_OBJECT_UNLOCK (monitor);
457     GST_WARNING_OBJECT (monitor, "No filters have been set, will expose all "
458         "devices found");
459     gst_device_monitor_add_filter (monitor, NULL, NULL);
460     GST_OBJECT_LOCK (monitor);
461   }
462
463   if (monitor->priv->providers->len == 0) {
464     GST_OBJECT_UNLOCK (monitor);
465     GST_WARNING_OBJECT (monitor, "No providers match the current filters");
466     return FALSE;
467   }
468
469   gst_bus_set_flushing (monitor->priv->bus, FALSE);
470
471 again:
472   cookie = monitor->priv->cookie;
473
474   g_list_free_full (pending, gst_object_unref);
475   pending = NULL;
476   removed = started;
477   started = NULL;
478
479   for (i = 0; i < monitor->priv->providers->len; i++) {
480     GstDeviceProvider *provider;
481     GList *find;
482
483     provider = g_ptr_array_index (monitor->priv->providers, i);
484
485     find = g_list_find (removed, provider);
486     if (find) {
487       /* this was already started, move to started list */
488       removed = g_list_remove_link (removed, find);
489       started = g_list_concat (started, find);
490     } else {
491       /* not started, add to pending list */
492       pending = g_list_append (pending, gst_object_ref (provider));
493     }
494   }
495   g_list_free_full (removed, gst_object_unref);
496   removed = NULL;
497
498   while (pending) {
499     GstDeviceProvider *provider = pending->data;
500
501     if (gst_device_provider_can_monitor (provider)) {
502       GST_OBJECT_UNLOCK (monitor);
503
504       if (!gst_device_provider_start (provider))
505         goto start_failed;
506
507       GST_OBJECT_LOCK (monitor);
508     }
509     started = g_list_prepend (started, provider);
510     pending = g_list_delete_link (pending, pending);
511
512     if (monitor->priv->cookie != cookie)
513       goto again;
514   }
515   monitor->priv->started = TRUE;
516   GST_OBJECT_UNLOCK (monitor);
517
518   g_list_free_full (started, gst_object_unref);
519
520   return TRUE;
521
522 start_failed:
523   {
524     GST_OBJECT_LOCK (monitor);
525     gst_bus_set_flushing (monitor->priv->bus, TRUE);
526     GST_OBJECT_UNLOCK (monitor);
527
528     while (started) {
529       GstDeviceProvider *provider = started->data;
530
531       gst_device_provider_stop (provider);
532       gst_object_unref (provider);
533
534       started = g_list_delete_link (started, started);
535     }
536     return FALSE;
537   }
538 }
539
540 /**
541  * gst_device_monitor_stop:
542  * @monitor: A #GstDeviceProvider
543  *
544  * Stops monitoring the devices.
545  *
546  * Since: 1.4
547  */
548 void
549 gst_device_monitor_stop (GstDeviceMonitor * monitor)
550 {
551   guint i;
552   GList *started = NULL;
553
554   g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
555
556   gst_bus_set_flushing (monitor->priv->bus, TRUE);
557
558   GST_OBJECT_LOCK (monitor);
559   for (i = 0; i < monitor->priv->providers->len; i++) {
560     GstDeviceProvider *provider =
561         g_ptr_array_index (monitor->priv->providers, i);
562
563     started = g_list_prepend (started, gst_object_ref (provider));
564   }
565   GST_OBJECT_UNLOCK (monitor);
566
567   while (started) {
568     GstDeviceProvider *provider = started->data;
569
570     if (gst_device_provider_can_monitor (provider))
571       gst_device_provider_stop (provider);
572
573     started = g_list_delete_link (started, started);
574     gst_object_unref (provider);
575   }
576
577   GST_OBJECT_LOCK (monitor);
578   monitor->priv->started = FALSE;
579   GST_OBJECT_UNLOCK (monitor);
580
581 }
582
583 static void
584 provider_hidden (GstDeviceProvider * provider, const gchar * hidden,
585     GstDeviceMonitor * monitor)
586 {
587   GST_OBJECT_LOCK (monitor);
588   monitor->priv->hidden =
589       g_list_prepend (monitor->priv->hidden, g_strdup (hidden));
590   GST_OBJECT_UNLOCK (monitor);
591 }
592
593 static void
594 provider_unhidden (GstDeviceProvider * provider, const gchar * hidden,
595     GstDeviceMonitor * monitor)
596 {
597   GList *find;
598
599   GST_OBJECT_LOCK (monitor);
600   find =
601       g_list_find_custom (monitor->priv->hidden, hidden,
602       (GCompareFunc) g_strcmp0);
603   if (find) {
604     g_free (find->data);
605     monitor->priv->hidden = g_list_delete_link (monitor->priv->hidden, find);
606   }
607   GST_OBJECT_UNLOCK (monitor);
608 }
609
610 /**
611  * gst_device_monitor_add_filter:
612  * @monitor: a device monitor
613  * @classes: (allow-none): device classes to use as filter or %NULL for any class
614  * @caps: (allow-none): the #GstCaps to filter or %NULL for ANY
615  *
616  * Adds a filter for which #GstDevice will be monitored, any device that matches
617  * all these classes and the #GstCaps will be returned.
618  *
619  * If this function is called multiple times to add more filters, each will be
620  * matched independently. That is, adding more filters will not further restrict
621  * what devices are matched.
622  *
623  * The #GstCaps supported by the device as returned by gst_device_get_caps() are
624  * not intersected with caps filters added using this function.
625  *
626  * Filters must be added before the #GstDeviceMonitor is started.
627  *
628  * Returns: The id of the new filter or 0 if no provider matched the filter's
629  *  classes.
630  *
631  * Since: 1.4
632  */
633 guint
634 gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
635     const gchar * classes, GstCaps * caps)
636 {
637   GList *factories = NULL;
638   struct DeviceFilter *filter;
639   guint id = 0;
640   gboolean matched = FALSE;
641
642   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
643   g_return_val_if_fail (!monitor->priv->started, 0);
644
645   GST_OBJECT_LOCK (monitor);
646
647   filter = g_slice_new0 (struct DeviceFilter);
648   filter->id = monitor->priv->last_id++;
649   if (caps)
650     filter->caps = gst_caps_ref (caps);
651   else
652     filter->caps = gst_caps_new_any ();
653   if (classes)
654     filter->classesv = g_strsplit (classes, "/", 0);
655
656   factories = gst_device_provider_factory_list_get_device_providers (1);
657
658   while (factories) {
659     GstDeviceProviderFactory *factory = factories->data;
660
661     if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
662       GstDeviceProvider *provider;
663
664       provider = gst_device_provider_factory_get (factory);
665
666       if (provider) {
667         guint i;
668
669         for (i = 0; i < monitor->priv->providers->len; i++) {
670           if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
671             gst_object_unref (provider);
672             provider = NULL;
673             matched = TRUE;
674             break;
675           }
676         }
677       }
678
679       if (provider) {
680         GstBus *bus = gst_device_provider_get_bus (provider);
681
682         update_hidden_providers_list (&monitor->priv->hidden, provider);
683         g_signal_connect (provider, "provider-hidden",
684             (GCallback) provider_hidden, monitor);
685         g_signal_connect (provider, "provider-unhidden",
686             (GCallback) provider_unhidden, monitor);
687
688         matched = TRUE;
689         gst_bus_enable_sync_message_emission (bus);
690         g_signal_connect (bus, "sync-message",
691             G_CALLBACK (bus_sync_message), monitor);
692         gst_object_unref (bus);
693         g_ptr_array_add (monitor->priv->providers, provider);
694         monitor->priv->cookie++;
695       }
696     }
697
698     factories = g_list_remove (factories, factory);
699     gst_object_unref (factory);
700   }
701
702   /* Ensure there is no leak here */
703   g_assert (factories == NULL);
704
705   if (matched)
706     id = filter->id;
707   g_ptr_array_add (monitor->priv->filters, filter);
708
709   GST_OBJECT_UNLOCK (monitor);
710
711   return id;
712 }
713
714 /**
715  * gst_device_monitor_remove_filter:
716  * @monitor: a device monitor
717  * @filter_id: the id of the filter
718  *
719  * Removes a filter from the #GstDeviceMonitor using the id that was returned
720  * by gst_device_monitor_add_filter().
721  *
722  * Returns: %TRUE of the filter id was valid, %FALSE otherwise
723  *
724  * Since: 1.4
725  */
726 gboolean
727 gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
728 {
729   guint i, j;
730   gboolean removed = FALSE;
731
732   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
733   g_return_val_if_fail (!monitor->priv->started, FALSE);
734   g_return_val_if_fail (filter_id > 0, FALSE);
735
736   GST_OBJECT_LOCK (monitor);
737   for (i = 0; i < monitor->priv->filters->len; i++) {
738     struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);
739
740     if (filter->id == filter_id) {
741       g_ptr_array_remove_index (monitor->priv->filters, i);
742       removed = TRUE;
743       break;
744     }
745   }
746
747   if (removed) {
748     for (i = 0; i < monitor->priv->providers->len; i++) {
749       GstDeviceProvider *provider =
750           g_ptr_array_index (monitor->priv->providers, i);
751       GstDeviceProviderFactory *factory =
752           gst_device_provider_get_factory (provider);
753       gboolean valid = FALSE;
754
755       for (j = 0; j < monitor->priv->filters->len; j++) {
756         struct DeviceFilter *filter =
757             g_ptr_array_index (monitor->priv->filters, j);
758
759         if (gst_device_provider_factory_has_classesv (factory,
760                 filter->classesv)) {
761           valid = TRUE;
762           break;
763         }
764       }
765
766       if (!valid) {
767         monitor->priv->cookie++;
768         gst_device_monitor_remove (monitor, i);
769         i--;
770       }
771     }
772   }
773
774   GST_OBJECT_UNLOCK (monitor);
775
776   return removed;
777 }
778
779
780
781 /**
782  * gst_device_monitor_new:
783  *
784  * Create a new #GstDeviceMonitor
785  *
786  * Returns: (transfer full): a new device monitor.
787  *
788  * Since: 1.4
789  */
790 GstDeviceMonitor *
791 gst_device_monitor_new (void)
792 {
793   GstDeviceMonitor *monitor;
794
795   monitor = g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
796
797   /* Clear floating flag */
798   gst_object_ref_sink (monitor);
799
800   return monitor;
801 }
802
803 /**
804  * gst_device_monitor_get_bus:
805  * @monitor: a #GstDeviceProvider
806  *
807  * Gets the #GstBus of this #GstDeviceMonitor
808  *
809  * Returns: (transfer full): a #GstBus
810  *
811  * Since: 1.4
812  */
813 GstBus *
814 gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
815 {
816   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
817
818   return gst_object_ref (monitor->priv->bus);
819 }
820
821 /**
822  * gst_device_monitor_get_providers:
823  * @monitor: a #GstDeviceMonitor
824  *
825  * Get a list of the currently selected device provider factories.
826  *
827  * This
828  *
829  * Returns: (transfer full) (array zero-terminated=1) (element-type gchar*):
830  *     A list of device provider factory names that are currently being
831  *     monitored by @monitor or %NULL when nothing is being monitored.
832  *
833  * Since: 1.6
834  */
835 gchar **
836 gst_device_monitor_get_providers (GstDeviceMonitor * monitor)
837 {
838   guint i, len;
839   gchar **res = NULL;
840
841   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
842
843   GST_OBJECT_LOCK (monitor);
844   len = monitor->priv->providers->len;
845   if (len == 0)
846     goto done;
847
848   res = g_new (gchar *, len + 1);
849
850   for (i = 0; i < len; i++) {
851     GstDeviceProvider *provider =
852         g_ptr_array_index (monitor->priv->providers, i);
853     GstDeviceProviderFactory *factory =
854         gst_device_provider_get_factory (provider);
855
856     res[i] = g_strdup (GST_OBJECT_NAME (factory));
857   }
858   res[i] = NULL;
859
860 done:
861   GST_OBJECT_UNLOCK (monitor);
862
863   return res;
864 }
865
866 /**
867  * gst_device_monitor_set_show_all_devices:
868  * @monitor: a #GstDeviceMonitor
869  * @show_all: show all devices
870  *
871  * Set if all devices should be visible, even those devices from hidden
872  * providers. Setting @show_all to true might show some devices multiple times.
873  *
874  * Since: 1.6
875  */
876 void
877 gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor,
878     gboolean show_all)
879 {
880   g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
881
882   GST_OBJECT_LOCK (monitor);
883   monitor->priv->show_all = show_all;
884   GST_OBJECT_UNLOCK (monitor);
885 }
886
887 /**
888  * gst_device_monitor_get_show_all_devices:
889  * @monitor: a #GstDeviceMonitor
890  *
891  * Get if @monitor is curretly showing all devices, even those from hidden
892  * providers.
893  *
894  * Returns: %TRUE when all devices will be shown.
895  *
896  * Since: 1.6
897  */
898 gboolean
899 gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor)
900 {
901   gboolean res;
902
903   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
904
905   GST_OBJECT_LOCK (monitor);
906   res = monitor->priv->show_all;
907   GST_OBJECT_UNLOCK (monitor);
908
909   return res;
910 }