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