Add separate def for extra size time
[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  * @short_description: A device monitor and prober
25  * @see_also: #GstDevice, #GstDeviceProvider
26  *
27  * Applications should create a #GstDeviceMonitor when they want
28  * to probe, list and monitor devices of a specific type. The
29  * #GstDeviceMonitor will create the appropriate
30  * #GstDeviceProvider objects and manage them. It will then post
31  * messages on its #GstBus for devices that have been added and
32  * removed.
33  *
34  * The device monitor will monitor all devices matching the filters that
35  * the application has set.
36  *
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  *          break;
53  *        case GST_MESSAGE_DEVICE_REMOVED:
54  *          gst_message_parse_device_removed (message, &device);
55  *          name = gst_device_get_display_name (device);
56  *          g_print("Device removed: %s\n", name);
57  *          g_free (name);
58  *          break;
59  *        default:
60  *          break;
61  *      }
62  *
63  *      return G_SOURCE_CONTINUE;
64  *   }
65  *
66  *   GstDeviceMonitor *
67  *   setup_raw_video_source_device_monitor (void) {
68  *      GstDeviceMonitor *monitor;
69  *      GstBus *bus;
70  *      GstCaps *caps;
71  *
72  *      monitor = gst_device_monitor_new ();
73  *
74  *      bus = gst_device_monitor_get_bus (monitor);
75  *      gst_bus_add_watch (bus, my_bus_func, NULL);
76  *      gst_object_unref (bus);
77  *
78  *      caps = gst_caps_new_empty_simple ("video/x-raw");
79  *      gst_device_monitor_add_filter (monitor, "Video/Source", caps);
80  *      gst_caps_unref (caps);
81  *
82  *      gst_device_monitor_start (monitor);
83  *
84  *      return monitor;
85  *   }
86  * ]|
87  *
88  * Since: 1.4
89  */
90
91
92 #ifdef HAVE_CONFIG_H
93 #include "config.h"
94 #endif
95
96 #include "gst_private.h"
97 #include "gstdevicemonitor.h"
98
99 struct _GstDeviceMonitorPrivate
100 {
101   gboolean started;
102
103   GstBus *bus;
104
105   GPtrArray *providers;
106   guint cookie;
107
108   GPtrArray *filters;
109
110   guint last_id;
111   GList *hidden;
112   gboolean show_all;
113 };
114
115 #define DEFAULT_SHOW_ALL        FALSE
116
117 enum
118 {
119   PROP_SHOW_ALL = 1,
120 };
121
122 G_DEFINE_TYPE (GstDeviceMonitor, gst_device_monitor, GST_TYPE_OBJECT);
123
124 static void gst_device_monitor_dispose (GObject * object);
125
126 struct DeviceFilter
127 {
128   guint id;
129
130   gchar **classesv;
131   GstCaps *caps;
132 };
133
134 static void
135 device_filter_free (struct DeviceFilter *filter)
136 {
137   g_strfreev (filter->classesv);
138   gst_caps_unref (filter->caps);
139
140   g_slice_free (struct DeviceFilter, filter);
141 }
142
143 static void
144 gst_device_monitor_get_property (GObject * object, guint prop_id,
145     GValue * value, GParamSpec * pspec)
146 {
147   GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
148
149   switch (prop_id) {
150     case PROP_SHOW_ALL:
151       g_value_set_boolean (value,
152           gst_device_monitor_get_show_all_devices (monitor));
153       break;
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156       break;
157   }
158 }
159
160 static void
161 gst_device_monitor_set_property (GObject * object, guint prop_id,
162     const GValue * value, GParamSpec * pspec)
163 {
164   GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
165
166   switch (prop_id) {
167     case PROP_SHOW_ALL:
168       gst_device_monitor_set_show_all_devices (monitor,
169           g_value_get_boolean (value));
170       break;
171     default:
172       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173       break;
174   }
175 }
176
177
178 static void
179 gst_device_monitor_class_init (GstDeviceMonitorClass * klass)
180 {
181   GObjectClass *object_class = G_OBJECT_CLASS (klass);
182
183   g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate));
184
185   object_class->get_property = gst_device_monitor_get_property;
186   object_class->set_property = gst_device_monitor_set_property;
187   object_class->dispose = gst_device_monitor_dispose;
188
189   g_object_class_install_property (object_class, PROP_SHOW_ALL,
190       g_param_spec_boolean ("show-all", "Show All",
191           "Show all devices, even those from hidden providers",
192           DEFAULT_SHOW_ALL, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
193 }
194
195 /* must be called with monitor lock */
196 static gboolean
197 is_provider_hidden (GstDeviceMonitor * monitor, GList * hidden,
198     GstDeviceProvider * provider)
199 {
200   GstDeviceProviderFactory *factory;
201
202   if (monitor->priv->show_all)
203     return FALSE;
204
205   factory = gst_device_provider_get_factory (provider);
206   if (g_list_find_custom (hidden, GST_OBJECT_NAME (factory),
207           (GCompareFunc) g_strcmp0))
208     return TRUE;
209
210   return FALSE;
211 }
212
213 /* must be called with monitor lock */
214 static void
215 update_hidden_providers_list (GList ** hidden, GstDeviceProvider * provider)
216 {
217   gchar **obs;
218
219   obs = gst_device_provider_get_hidden_providers (provider);
220   if (obs) {
221     gint i;
222
223     for (i = 0; obs[i]; i++)
224       *hidden = g_list_prepend (*hidden, obs[i]);
225
226     g_free (obs);
227   }
228 }
229
230 static void
231 bus_sync_message (GstBus * bus, GstMessage * message,
232     GstDeviceMonitor * monitor)
233 {
234   GstMessageType type = GST_MESSAGE_TYPE (message);
235
236   if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
237     gboolean matches;
238     GstDevice *device;
239     GstDeviceProvider *provider;
240
241     if (type == GST_MESSAGE_DEVICE_ADDED)
242       gst_message_parse_device_added (message, &device);
243     else
244       gst_message_parse_device_removed (message, &device);
245
246     GST_OBJECT_LOCK (monitor);
247     provider =
248         GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device)));
249     if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) {
250       matches = FALSE;
251     } else if (monitor->priv->filters->len) {
252       guint i;
253
254       for (i = 0; i < monitor->priv->filters->len; i++) {
255         struct DeviceFilter *filter =
256             g_ptr_array_index (monitor->priv->filters, i);
257         GstCaps *caps;
258
259         caps = gst_device_get_caps (device);
260         matches = gst_caps_can_intersect (filter->caps, caps) &&
261             gst_device_has_classesv (device, filter->classesv);
262         gst_caps_unref (caps);
263         if (matches)
264           break;
265       }
266     } else {
267       matches = TRUE;
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): 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 FALSE;
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 FALSE;
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 classes and the #GstCaps will be returned.
618  *
619  * Filters must be added before the #GstDeviceMonitor is started.
620  *
621  * Returns: The id of the new filter or 0 if no provider matched the filter's
622  *  classes.
623  *
624  * Since: 1.4
625  */
626 guint
627 gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
628     const gchar * classes, GstCaps * caps)
629 {
630   GList *factories = NULL;
631   struct DeviceFilter *filter;
632   guint id = 0;
633   gboolean matched = FALSE;
634
635   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
636   g_return_val_if_fail (!monitor->priv->started, 0);
637
638   GST_OBJECT_LOCK (monitor);
639
640   filter = g_slice_new0 (struct DeviceFilter);
641   filter->id = monitor->priv->last_id++;
642   if (caps)
643     filter->caps = gst_caps_ref (caps);
644   else
645     filter->caps = gst_caps_new_any ();
646   if (classes)
647     filter->classesv = g_strsplit (classes, "/", 0);
648
649   factories = gst_device_provider_factory_list_get_device_providers (1);
650
651   while (factories) {
652     GstDeviceProviderFactory *factory = factories->data;
653
654     if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
655       GstDeviceProvider *provider;
656
657       provider = gst_device_provider_factory_get (factory);
658
659       if (provider) {
660         guint i;
661
662         for (i = 0; i < monitor->priv->providers->len; i++) {
663           if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
664             gst_object_unref (provider);
665             provider = NULL;
666             matched = TRUE;
667             break;
668           }
669         }
670       }
671
672       if (provider) {
673         GstBus *bus = gst_device_provider_get_bus (provider);
674
675         update_hidden_providers_list (&monitor->priv->hidden, provider);
676         g_signal_connect (provider, "provider-hidden",
677             (GCallback) provider_hidden, monitor);
678         g_signal_connect (provider, "provider-unhidden",
679             (GCallback) provider_unhidden, monitor);
680
681         matched = TRUE;
682         gst_bus_enable_sync_message_emission (bus);
683         g_signal_connect (bus, "sync-message",
684             G_CALLBACK (bus_sync_message), monitor);
685         gst_object_unref (bus);
686         g_ptr_array_add (monitor->priv->providers, provider);
687         monitor->priv->cookie++;
688       }
689     }
690
691     factories = g_list_remove (factories, factory);
692     gst_object_unref (factory);
693   }
694
695   /* Ensure there is no leak here */
696   g_assert (factories == NULL);
697
698   if (matched) {
699     id = filter->id;
700     g_ptr_array_add (monitor->priv->filters, filter);
701   } else {
702     device_filter_free (filter);
703   }
704
705   GST_OBJECT_UNLOCK (monitor);
706
707   return id;
708 }
709
710 /**
711  * gst_device_monitor_remove_filter:
712  * @monitor: a device monitor
713  * @filter_id: the id of the filter
714  *
715  * Removes a filter from the #GstDeviceMonitor using the id that was returned
716  * by gst_device_monitor_add_filter().
717  *
718  * Returns: %TRUE of the filter id was valid, %FALSE otherwise
719  *
720  * Since: 1.4
721  */
722 gboolean
723 gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
724 {
725   guint i, j;
726   gboolean removed = FALSE;
727
728   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
729   g_return_val_if_fail (!monitor->priv->started, FALSE);
730   g_return_val_if_fail (filter_id > 0, FALSE);
731
732   GST_OBJECT_LOCK (monitor);
733   for (i = 0; i < monitor->priv->filters->len; i++) {
734     struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);
735
736     if (filter->id == filter_id) {
737       g_ptr_array_remove_index (monitor->priv->filters, i);
738       removed = TRUE;
739       break;
740     }
741   }
742
743   if (removed) {
744     for (i = 0; i < monitor->priv->providers->len; i++) {
745       GstDeviceProvider *provider =
746           g_ptr_array_index (monitor->priv->providers, i);
747       GstDeviceProviderFactory *factory =
748           gst_device_provider_get_factory (provider);
749       gboolean valid = FALSE;
750
751       for (j = 0; j < monitor->priv->filters->len; j++) {
752         struct DeviceFilter *filter =
753             g_ptr_array_index (monitor->priv->filters, j);
754
755         if (gst_device_provider_factory_has_classesv (factory,
756                 filter->classesv)) {
757           valid = TRUE;
758           break;
759         }
760       }
761
762       if (!valid) {
763         monitor->priv->cookie++;
764         gst_device_monitor_remove (monitor, i);
765         i--;
766       }
767     }
768   }
769
770   GST_OBJECT_UNLOCK (monitor);
771
772   return removed;
773 }
774
775
776
777 /**
778  * gst_device_monitor_new:
779  *
780  * Create a new #GstDeviceMonitor
781  *
782  * Returns: (transfer full): a new device monitor.
783  *
784  * Since: 1.4
785  */
786 GstDeviceMonitor *
787 gst_device_monitor_new (void)
788 {
789   return g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
790 }
791
792 /**
793  * gst_device_monitor_get_bus:
794  * @monitor: a #GstDeviceProvider
795  *
796  * Gets the #GstBus of this #GstDeviceMonitor
797  *
798  * Returns: (transfer full): a #GstBus
799  *
800  * Since: 1.4
801  */
802 GstBus *
803 gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
804 {
805   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
806
807   return gst_object_ref (monitor->priv->bus);
808 }
809
810 /**
811  * gst_device_monitor_get_providers:
812  * @monitor: a #GstDeviceMonitor
813  *
814  * Get a list of the currently selected device provider factories.
815  *
816  * This
817  *
818  * Returns: (transfer full) (array zero-terminated=1) (element-type gchar*):
819  *     A list of device provider factory names that are currently being
820  *     monitored by @monitor or %NULL when nothing is being monitored.
821  *
822  * Since: 1.6
823  */
824 gchar **
825 gst_device_monitor_get_providers (GstDeviceMonitor * monitor)
826 {
827   guint i, len;
828   gchar **res = NULL;
829
830   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
831
832   GST_OBJECT_LOCK (monitor);
833   len = monitor->priv->providers->len;
834   if (len == 0)
835     goto done;
836
837   res = g_new (gchar *, len + 1);
838
839   for (i = 0; i < len; i++) {
840     GstDeviceProvider *provider =
841         g_ptr_array_index (monitor->priv->providers, i);
842     GstDeviceProviderFactory *factory =
843         gst_device_provider_get_factory (provider);
844
845     res[i] = g_strdup (GST_OBJECT_NAME (factory));
846   }
847   res[i] = NULL;
848
849 done:
850   GST_OBJECT_UNLOCK (monitor);
851
852   return res;
853 }
854
855 /**
856  * gst_device_monitor_set_show_all_devices:
857  * @monitor: a #GstDeviceMonitor
858  * @show_all: show all devices
859  *
860  * Set if all devices should be visible, even those devices from hidden
861  * providers. Setting @show_all to true might show some devices multiple times.
862  *
863  * Since: 1.6
864  */
865 void
866 gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor,
867     gboolean show_all)
868 {
869   g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
870
871   GST_OBJECT_LOCK (monitor);
872   monitor->priv->show_all = show_all;
873   GST_OBJECT_UNLOCK (monitor);
874 }
875
876 /**
877  * gst_device_monitor_get_show_all_devices:
878  * @monitor: a #GstDeviceMonitor
879  *
880  * Get if @monitor is curretly showing all devices, even those from hidden
881  * providers.
882  *
883  * Returns: %TRUE when all devices will be shown.
884  *
885  * Since: 1.6
886  */
887 gboolean
888 gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor)
889 {
890   gboolean res;
891
892   g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
893
894   GST_OBJECT_LOCK (monitor);
895   res = monitor->priv->show_all;
896   GST_OBJECT_UNLOCK (monitor);
897
898   return res;
899 }