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