structure: add a todo comment
[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;
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 if (monitor->priv->filters->len) {
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     } else {
269       matches = TRUE;
270     }
271     GST_OBJECT_UNLOCK (monitor);
272
273     gst_object_unref (provider);
274     gst_object_unref (device);
275
276     if (matches)
277       gst_bus_post (monitor->priv->bus, gst_message_ref (message));
278   }
279 }
280
281
282 static void
283 gst_device_monitor_init (GstDeviceMonitor * self)
284 {
285   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
286       GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate);
287
288   self->priv->show_all = DEFAULT_SHOW_ALL;
289
290   self->priv->bus = gst_bus_new ();
291   gst_bus_set_flushing (self->priv->bus, TRUE);
292
293   self->priv->providers = g_ptr_array_new ();
294   self->priv->filters = g_ptr_array_new_with_free_func (
295       (GDestroyNotify) device_filter_free);
296
297   self->priv->last_id = 1;
298 }
299
300
301 static void
302 gst_device_monitor_remove (GstDeviceMonitor * self, guint i)
303 {
304   GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
305   GstBus *bus;
306
307   g_ptr_array_remove_index (self->priv->providers, i);
308
309   bus = gst_device_provider_get_bus (provider);
310   g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
311   gst_object_unref (bus);
312
313   gst_object_unref (provider);
314 }
315
316 static void
317 gst_device_monitor_dispose (GObject * object)
318 {
319   GstDeviceMonitor *self = GST_DEVICE_MONITOR (object);
320
321   g_return_if_fail (!self->priv->started);
322
323   if (self->priv->providers) {
324     while (self->priv->providers->len)
325       gst_device_monitor_remove (self, self->priv->providers->len - 1);
326     g_ptr_array_unref (self->priv->providers);
327     self->priv->providers = NULL;
328   }
329
330   if (self->priv->filters) {
331     g_ptr_array_unref (self->priv->filters);
332     self->priv->filters = NULL;
333   }
334
335   gst_object_replace ((GstObject **) & self->priv->bus, NULL);
336
337   G_OBJECT_CLASS (gst_device_monitor_parent_class)->dispose (object);
338 }
339
340 /**
341  * gst_device_monitor_get_devices:
342  * @monitor: A #GstDeviceProvider
343  *
344  * Gets a list of devices from all of the relevant monitors. This may actually
345  * probe the hardware if the monitor is not currently started.
346  *
347  * Returns: (transfer full) (element-type GstDevice): a #GList of
348  *   #GstDevice
349  *
350  * Since: 1.4
351  */
352
353 GList *
354 gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
355 {
356   GList *devices = NULL, *hidden = NULL;
357   guint i;
358   guint cookie;
359
360   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
361
362   GST_OBJECT_LOCK (monitor);
363
364   if (monitor->priv->filters->len == 0) {
365     GST_OBJECT_UNLOCK (monitor);
366     GST_WARNING_OBJECT (monitor, "No filters have been set");
367     return FALSE;
368   }
369
370   if (monitor->priv->providers->len == 0) {
371     GST_OBJECT_UNLOCK (monitor);
372     GST_WARNING_OBJECT (monitor, "No providers match the current filters");
373     return FALSE;
374   }
375
376 again:
377
378   g_list_free_full (devices, gst_object_unref);
379   g_list_free_full (hidden, g_free);
380   devices = NULL;
381   hidden = NULL;
382
383   cookie = monitor->priv->cookie;
384
385   for (i = 0; i < monitor->priv->providers->len; i++) {
386     GList *tmpdev;
387     GstDeviceProvider *provider =
388         gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
389     GList *item;
390
391     if (!is_provider_hidden (monitor, hidden, provider)) {
392       GST_OBJECT_UNLOCK (monitor);
393
394       tmpdev = gst_device_provider_get_devices (provider);
395
396       GST_OBJECT_LOCK (monitor);
397       update_hidden_providers_list (&hidden, provider);
398     } else {
399       tmpdev = NULL;
400     }
401
402
403     for (item = tmpdev; item; item = item->next) {
404       GstDevice *dev = GST_DEVICE (item->data);
405       GstCaps *caps = gst_device_get_caps (dev);
406       guint j;
407
408       for (j = 0; j < monitor->priv->filters->len; j++) {
409         struct DeviceFilter *filter =
410             g_ptr_array_index (monitor->priv->filters, j);
411
412         if (gst_caps_can_intersect (filter->caps, caps) &&
413             gst_device_has_classesv (dev, filter->classesv)) {
414           devices = g_list_prepend (devices, gst_object_ref (dev));
415           break;
416         }
417       }
418       gst_caps_unref (caps);
419     }
420
421     g_list_free_full (tmpdev, gst_object_unref);
422     gst_object_unref (provider);
423
424     if (monitor->priv->cookie != cookie)
425       goto again;
426   }
427   g_list_free_full (hidden, g_free);
428
429   GST_OBJECT_UNLOCK (monitor);
430
431   return g_list_reverse (devices);
432 }
433
434 /**
435  * gst_device_monitor_start:
436  * @monitor: A #GstDeviceMonitor
437  *
438  * Starts monitoring the devices, one this has succeeded, the
439  * %GST_MESSAGE_DEVICE_ADDED and %GST_MESSAGE_DEVICE_REMOVED messages
440  * will be emitted on the bus when the list of devices changes.
441  *
442  * Returns: %TRUE if the device monitoring could be started
443  *
444  * Since: 1.4
445  */
446
447 gboolean
448 gst_device_monitor_start (GstDeviceMonitor * monitor)
449 {
450   guint cookie, i;
451   GList *pending = NULL, *started = NULL, *removed = NULL;
452
453   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
454
455   GST_OBJECT_LOCK (monitor);
456
457   if (monitor->priv->filters->len == 0) {
458     GST_OBJECT_UNLOCK (monitor);
459     GST_WARNING_OBJECT (monitor, "No filters have been set, will expose all "
460         "devices found");
461     gst_device_monitor_add_filter (monitor, NULL, NULL);
462     GST_OBJECT_LOCK (monitor);
463   }
464
465   if (monitor->priv->providers->len == 0) {
466     GST_OBJECT_UNLOCK (monitor);
467     GST_WARNING_OBJECT (monitor, "No providers match the current filters");
468     return FALSE;
469   }
470
471   gst_bus_set_flushing (monitor->priv->bus, FALSE);
472
473 again:
474   cookie = monitor->priv->cookie;
475
476   g_list_free_full (pending, gst_object_unref);
477   pending = NULL;
478   removed = started;
479   started = NULL;
480
481   for (i = 0; i < monitor->priv->providers->len; i++) {
482     GstDeviceProvider *provider;
483     GList *find;
484
485     provider = g_ptr_array_index (monitor->priv->providers, i);
486
487     find = g_list_find (removed, provider);
488     if (find) {
489       /* this was already started, move to started list */
490       removed = g_list_remove_link (removed, find);
491       started = g_list_concat (started, find);
492     } else {
493       /* not started, add to pending list */
494       pending = g_list_append (pending, gst_object_ref (provider));
495     }
496   }
497   g_list_free_full (removed, gst_object_unref);
498   removed = NULL;
499
500   while (pending) {
501     GstDeviceProvider *provider = pending->data;
502
503     if (gst_device_provider_can_monitor (provider)) {
504       GST_OBJECT_UNLOCK (monitor);
505
506       if (!gst_device_provider_start (provider))
507         goto start_failed;
508
509       GST_OBJECT_LOCK (monitor);
510     }
511     started = g_list_prepend (started, provider);
512     pending = g_list_delete_link (pending, pending);
513
514     if (monitor->priv->cookie != cookie)
515       goto again;
516   }
517   monitor->priv->started = TRUE;
518   GST_OBJECT_UNLOCK (monitor);
519
520   g_list_free_full (started, gst_object_unref);
521
522   return TRUE;
523
524 start_failed:
525   {
526     GST_OBJECT_LOCK (monitor);
527     gst_bus_set_flushing (monitor->priv->bus, TRUE);
528     GST_OBJECT_UNLOCK (monitor);
529
530     while (started) {
531       GstDeviceProvider *provider = started->data;
532
533       gst_device_provider_stop (provider);
534       gst_object_unref (provider);
535
536       started = g_list_delete_link (started, started);
537     }
538     return FALSE;
539   }
540 }
541
542 /**
543  * gst_device_monitor_stop:
544  * @monitor: A #GstDeviceProvider
545  *
546  * Stops monitoring the devices.
547  *
548  * Since: 1.4
549  */
550 void
551 gst_device_monitor_stop (GstDeviceMonitor * monitor)
552 {
553   guint i;
554   GList *started = NULL;
555
556   g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
557
558   gst_bus_set_flushing (monitor->priv->bus, TRUE);
559
560   GST_OBJECT_LOCK (monitor);
561   for (i = 0; i < monitor->priv->providers->len; i++) {
562     GstDeviceProvider *provider =
563         g_ptr_array_index (monitor->priv->providers, i);
564
565     started = g_list_prepend (started, gst_object_ref (provider));
566   }
567   GST_OBJECT_UNLOCK (monitor);
568
569   while (started) {
570     GstDeviceProvider *provider = started->data;
571
572     if (gst_device_provider_can_monitor (provider))
573       gst_device_provider_stop (provider);
574
575     started = g_list_delete_link (started, started);
576     gst_object_unref (provider);
577   }
578
579   GST_OBJECT_LOCK (monitor);
580   monitor->priv->started = FALSE;
581   GST_OBJECT_UNLOCK (monitor);
582
583 }
584
585 static void
586 provider_hidden (GstDeviceProvider * provider, const gchar * hidden,
587     GstDeviceMonitor * monitor)
588 {
589   GST_OBJECT_LOCK (monitor);
590   monitor->priv->hidden =
591       g_list_prepend (monitor->priv->hidden, g_strdup (hidden));
592   GST_OBJECT_UNLOCK (monitor);
593 }
594
595 static void
596 provider_unhidden (GstDeviceProvider * provider, const gchar * hidden,
597     GstDeviceMonitor * monitor)
598 {
599   GList *find;
600
601   GST_OBJECT_LOCK (monitor);
602   find =
603       g_list_find_custom (monitor->priv->hidden, hidden,
604       (GCompareFunc) g_strcmp0);
605   if (find) {
606     g_free (find->data);
607     monitor->priv->hidden = g_list_delete_link (monitor->priv->hidden, find);
608   }
609   GST_OBJECT_UNLOCK (monitor);
610 }
611
612 /**
613  * gst_device_monitor_add_filter:
614  * @monitor: a device monitor
615  * @classes: (allow-none): device classes to use as filter or %NULL for any class
616  * @caps: (allow-none): the #GstCaps to filter or %NULL for ANY
617  *
618  * Adds a filter for which #GstDevice will be monitored, any device that matches
619  * all these classes and the #GstCaps will be returned.
620  *
621  * If this function is called multiple times to add more filters, each will be
622  * matched independently. That is, adding more filters will not further restrict
623  * what devices are matched.
624  *
625  * The #GstCaps supported by the device as returned by gst_device_get_caps() are
626  * not intersected with caps filters added using this function.
627  *
628  * Filters must be added before the #GstDeviceMonitor is started.
629  *
630  * Returns: The id of the new filter or 0 if no provider matched the filter's
631  *  classes.
632  *
633  * Since: 1.4
634  */
635 guint
636 gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
637     const gchar * classes, GstCaps * caps)
638 {
639   GList *factories = NULL;
640   struct DeviceFilter *filter;
641   guint id = 0;
642   gboolean matched = FALSE;
643
644   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
645   g_return_val_if_fail (!monitor->priv->started, 0);
646
647   GST_OBJECT_LOCK (monitor);
648
649   filter = g_slice_new0 (struct DeviceFilter);
650   filter->id = monitor->priv->last_id++;
651   if (caps)
652     filter->caps = gst_caps_ref (caps);
653   else
654     filter->caps = gst_caps_new_any ();
655   if (classes)
656     filter->classesv = g_strsplit (classes, "/", 0);
657
658   factories = gst_device_provider_factory_list_get_device_providers (1);
659
660   while (factories) {
661     GstDeviceProviderFactory *factory = factories->data;
662
663     if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
664       GstDeviceProvider *provider;
665
666       provider = gst_device_provider_factory_get (factory);
667
668       if (provider) {
669         guint i;
670
671         for (i = 0; i < monitor->priv->providers->len; i++) {
672           if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
673             gst_object_unref (provider);
674             provider = NULL;
675             matched = TRUE;
676             break;
677           }
678         }
679       }
680
681       if (provider) {
682         GstBus *bus = gst_device_provider_get_bus (provider);
683
684         update_hidden_providers_list (&monitor->priv->hidden, provider);
685         g_signal_connect (provider, "provider-hidden",
686             (GCallback) provider_hidden, monitor);
687         g_signal_connect (provider, "provider-unhidden",
688             (GCallback) provider_unhidden, monitor);
689
690         matched = TRUE;
691         gst_bus_enable_sync_message_emission (bus);
692         g_signal_connect (bus, "sync-message",
693             G_CALLBACK (bus_sync_message), monitor);
694         gst_object_unref (bus);
695         g_ptr_array_add (monitor->priv->providers, provider);
696         monitor->priv->cookie++;
697       }
698     }
699
700     factories = g_list_remove (factories, factory);
701     gst_object_unref (factory);
702   }
703
704   /* Ensure there is no leak here */
705   g_assert (factories == NULL);
706
707   if (matched)
708     id = filter->id;
709   g_ptr_array_add (monitor->priv->filters, filter);
710
711   GST_OBJECT_UNLOCK (monitor);
712
713   return id;
714 }
715
716 /**
717  * gst_device_monitor_remove_filter:
718  * @monitor: a device monitor
719  * @filter_id: the id of the filter
720  *
721  * Removes a filter from the #GstDeviceMonitor using the id that was returned
722  * by gst_device_monitor_add_filter().
723  *
724  * Returns: %TRUE of the filter id was valid, %FALSE otherwise
725  *
726  * Since: 1.4
727  */
728 gboolean
729 gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
730 {
731   guint i, j;
732   gboolean removed = FALSE;
733
734   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
735   g_return_val_if_fail (!monitor->priv->started, FALSE);
736   g_return_val_if_fail (filter_id > 0, FALSE);
737
738   GST_OBJECT_LOCK (monitor);
739   for (i = 0; i < monitor->priv->filters->len; i++) {
740     struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);
741
742     if (filter->id == filter_id) {
743       g_ptr_array_remove_index (monitor->priv->filters, i);
744       removed = TRUE;
745       break;
746     }
747   }
748
749   if (removed) {
750     for (i = 0; i < monitor->priv->providers->len; i++) {
751       GstDeviceProvider *provider =
752           g_ptr_array_index (monitor->priv->providers, i);
753       GstDeviceProviderFactory *factory =
754           gst_device_provider_get_factory (provider);
755       gboolean valid = FALSE;
756
757       for (j = 0; j < monitor->priv->filters->len; j++) {
758         struct DeviceFilter *filter =
759             g_ptr_array_index (monitor->priv->filters, j);
760
761         if (gst_device_provider_factory_has_classesv (factory,
762                 filter->classesv)) {
763           valid = TRUE;
764           break;
765         }
766       }
767
768       if (!valid) {
769         monitor->priv->cookie++;
770         gst_device_monitor_remove (monitor, i);
771         i--;
772       }
773     }
774   }
775
776   GST_OBJECT_UNLOCK (monitor);
777
778   return removed;
779 }
780
781
782
783 /**
784  * gst_device_monitor_new:
785  *
786  * Create a new #GstDeviceMonitor
787  *
788  * Returns: (transfer full): a new device monitor.
789  *
790  * Since: 1.4
791  */
792 GstDeviceMonitor *
793 gst_device_monitor_new (void)
794 {
795   GstDeviceMonitor *monitor;
796
797   monitor = g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
798
799   /* Clear floating flag */
800   gst_object_ref_sink (monitor);
801
802   return monitor;
803 }
804
805 /**
806  * gst_device_monitor_get_bus:
807  * @monitor: a #GstDeviceProvider
808  *
809  * Gets the #GstBus of this #GstDeviceMonitor
810  *
811  * Returns: (transfer full): a #GstBus
812  *
813  * Since: 1.4
814  */
815 GstBus *
816 gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
817 {
818   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
819
820   return gst_object_ref (monitor->priv->bus);
821 }
822
823 /**
824  * gst_device_monitor_get_providers:
825  * @monitor: a #GstDeviceMonitor
826  *
827  * Get a list of the currently selected device provider factories.
828  *
829  * This
830  *
831  * Returns: (transfer full) (array zero-terminated=1) (element-type gchar*):
832  *     A list of device provider factory names that are currently being
833  *     monitored by @monitor or %NULL when nothing is being monitored.
834  *
835  * Since: 1.6
836  */
837 gchar **
838 gst_device_monitor_get_providers (GstDeviceMonitor * monitor)
839 {
840   guint i, len;
841   gchar **res = NULL;
842
843   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
844
845   GST_OBJECT_LOCK (monitor);
846   len = monitor->priv->providers->len;
847   if (len == 0)
848     goto done;
849
850   res = g_new (gchar *, len + 1);
851
852   for (i = 0; i < len; i++) {
853     GstDeviceProvider *provider =
854         g_ptr_array_index (monitor->priv->providers, i);
855     GstDeviceProviderFactory *factory =
856         gst_device_provider_get_factory (provider);
857
858     res[i] = g_strdup (GST_OBJECT_NAME (factory));
859   }
860   res[i] = NULL;
861
862 done:
863   GST_OBJECT_UNLOCK (monitor);
864
865   return res;
866 }
867
868 /**
869  * gst_device_monitor_set_show_all_devices:
870  * @monitor: a #GstDeviceMonitor
871  * @show_all: show all devices
872  *
873  * Set if all devices should be visible, even those devices from hidden
874  * providers. Setting @show_all to true might show some devices multiple times.
875  *
876  * Since: 1.6
877  */
878 void
879 gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor,
880     gboolean show_all)
881 {
882   g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
883
884   GST_OBJECT_LOCK (monitor);
885   monitor->priv->show_all = show_all;
886   GST_OBJECT_UNLOCK (monitor);
887 }
888
889 /**
890  * gst_device_monitor_get_show_all_devices:
891  * @monitor: a #GstDeviceMonitor
892  *
893  * Get if @monitor is curretly showing all devices, even those from hidden
894  * providers.
895  *
896  * Returns: %TRUE when all devices will be shown.
897  *
898  * Since: 1.6
899  */
900 gboolean
901 gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor)
902 {
903   gboolean res;
904
905   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
906
907   GST_OBJECT_LOCK (monitor);
908   res = monitor->priv->show_all;
909   GST_OBJECT_UNLOCK (monitor);
910
911   return res;
912 }