gstdevicemonitor.c 22.4 KB
Newer Older
1 2 3
/* GStreamer
 * Copyright (C) 2013 Olivier Crete <olivier.crete@collabora.com>
 *
4
 * gstdevicemonitor.c: device monitor
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
21 22

/**
23 24
 * SECTION:gstdevicemonitor
 * @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 32 33
 * messages on its #GstBus for devices that have been added and
 * removed.
 *
34 35 36
 * The device monitor will monitor all devices matching the filters that
 * the application has set.
 *
37
 *
38
 * The basic use pattern of a device monitor is as follows:
39 40 41 42 43
 * |[
 *   static gboolean
 *   my_bus_func (GstBus * bus, GstMessage * message, gpointer user_data)
 *   {
 *      GstDevice *device;
44
 *      gchar *name;
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
 *
 *      switch (GST_MESSAGE_TYPE (message)) {
 *        case GST_MESSAGE_DEVICE_ADDED:
 *          gst_message_parse_device_added (message, &device);
 *          name = gst_device_get_display_name (device);
 *          g_print("Device added: %s\n", name);
 *          g_free (name);
 *          break;
 *        case GST_MESSAGE_DEVICE_REMOVED:
 *          gst_message_parse_device_removed (message, &device);
 *          name = gst_device_get_display_name (device);
 *          g_print("Device removed: %s\n", name);
 *          g_free (name);
 *          break;
 *        default:
 *          break;
 *      }
 *
 *      return G_SOURCE_CONTINUE;
 *   }
 *
 *   GstDeviceMonitor *
 *   setup_raw_video_source_device_monitor (void) {
 *      GstDeviceMonitor *monitor;
 *      GstBus *bus;
 *      GstCaps *caps;
 *
 *      monitor = gst_device_monitor_new ();
 *
 *      bus = gst_device_monitor_get_bus (monitor);
 *      gst_bus_add_watch (bus, my_bus_func, NULL);
 *      gst_object_unref (bus);
 *
78
 *      caps = gst_caps_new_empty_simple ("video/x-raw");
79 80 81 82 83 84 85 86 87
 *      gst_device_monitor_add_filter (monitor, "Video/Source", caps);
 *      gst_caps_unref (caps);
 *
 *      gst_device_monitor_start (monitor);
 *
 *      return monitor;
 *   }
 * ]|
 *
88 89 90 91
 * Since: 1.4
 */


92 93 94 95
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

96
#include "gst_private.h"
97
#include "gstdevicemonitor.h"
98

99
struct _GstDeviceMonitorPrivate
100 101 102 103 104
{
  gboolean started;

  GstBus *bus;

105
  GPtrArray *providers;
106 107
  guint cookie;

108 109 110
  GPtrArray *filters;

  guint last_id;
111 112
  GList *hidden;
  gboolean show_all;
113 114
};

115 116 117 118 119 120
#define DEFAULT_SHOW_ALL        FALSE

enum
{
  PROP_SHOW_ALL = 1,
};
121

122
G_DEFINE_TYPE (GstDeviceMonitor, gst_device_monitor, GST_TYPE_OBJECT);
123

124
static void gst_device_monitor_dispose (GObject * object);
125

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
struct DeviceFilter
{
  guint id;

  gchar **classesv;
  GstCaps *caps;
};

static void
device_filter_free (struct DeviceFilter *filter)
{
  g_strfreev (filter->classesv);
  gst_caps_unref (filter->caps);

  g_slice_free (struct DeviceFilter, filter);
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static void
gst_device_monitor_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);

  switch (prop_id) {
    case PROP_SHOW_ALL:
      g_value_set_boolean (value,
          gst_device_monitor_get_show_all_devices (monitor));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_device_monitor_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);

  switch (prop_id) {
    case PROP_SHOW_ALL:
      gst_device_monitor_set_show_all_devices (monitor,
          g_value_get_boolean (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}


178
static void
179
gst_device_monitor_class_init (GstDeviceMonitorClass * klass)
180 181 182
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

183
  g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate));
184

185 186
  object_class->get_property = gst_device_monitor_get_property;
  object_class->set_property = gst_device_monitor_set_property;
187
  object_class->dispose = gst_device_monitor_dispose;
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

  g_object_class_install_property (object_class, PROP_SHOW_ALL,
      g_param_spec_boolean ("show-all", "Show All",
          "Show all devices, even those from hidden providers",
          DEFAULT_SHOW_ALL, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
}

/* must be called with monitor lock */
static gboolean
is_provider_hidden (GstDeviceMonitor * monitor, GList * hidden,
    GstDeviceProvider * provider)
{
  GstDeviceProviderFactory *factory;

  if (monitor->priv->show_all)
    return FALSE;

  factory = gst_device_provider_get_factory (provider);
  if (g_list_find_custom (hidden, GST_OBJECT_NAME (factory),
          (GCompareFunc) g_strcmp0))
    return TRUE;

  return FALSE;
}

/* must be called with monitor lock */
static void
update_hidden_providers_list (GList ** hidden, GstDeviceProvider * provider)
{
  gchar **obs;

  obs = gst_device_provider_get_hidden_providers (provider);
  if (obs) {
    gint i;

    for (i = 0; obs[i]; i++)
      *hidden = g_list_prepend (*hidden, obs[i]);

    g_free (obs);
  }
228 229 230 231
}

static void
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 243 244 245 246
      gst_message_parse_device_added (message, &device);
    else
      gst_message_parse_device_removed (message, &device);

    GST_OBJECT_LOCK (monitor);
247 248 249 250 251
    provider =
        GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device)));
    if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) {
      matches = FALSE;
    } else if (monitor->priv->filters->len) {
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
      guint i;

      for (i = 0; i < monitor->priv->filters->len; i++) {
        struct DeviceFilter *filter =
            g_ptr_array_index (monitor->priv->filters, i);
        GstCaps *caps;

        caps = gst_device_get_caps (device);
        matches = gst_caps_can_intersect (filter->caps, caps) &&
            gst_device_has_classesv (device, filter->classesv);
        gst_caps_unref (caps);
        if (matches)
          break;
      }
    } else {
      matches = TRUE;
    }
269 270
    GST_OBJECT_UNLOCK (monitor);

271 272
    gst_object_unref (device);

273
    if (matches)
274 275 276 277 278 279
      gst_bus_post (monitor->priv->bus, gst_message_ref (message));
  }
}


static void
280
gst_device_monitor_init (GstDeviceMonitor * self)
281 282
{
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
283
      GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate);
284

285 286
  self->priv->show_all = DEFAULT_SHOW_ALL;

287 288 289
  self->priv->bus = gst_bus_new ();
  gst_bus_set_flushing (self->priv->bus, TRUE);

290
  self->priv->providers = g_ptr_array_new ();
291 292
  self->priv->filters = g_ptr_array_new_with_free_func (
      (GDestroyNotify) device_filter_free);
293

294
  self->priv->last_id = 1;
295 296 297 298
}


static void
299
gst_device_monitor_remove (GstDeviceMonitor * self, guint i)
300
{
301
  GstDeviceProvider *provider = g_ptr_array_index (self->priv->providers, i);
302 303
  GstBus *bus;

304
  g_ptr_array_remove_index (self->priv->providers, i);
305

306
  bus = gst_device_provider_get_bus (provider);
307 308 309
  g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
  gst_object_unref (bus);

310
  gst_object_unref (provider);
311 312 313
}

static void
314
gst_device_monitor_dispose (GObject * object)
315
{
316
  GstDeviceMonitor *self = GST_DEVICE_MONITOR (object);
317

318
  g_return_if_fail (!self->priv->started);
319

320 321
  if (self->priv->providers) {
    while (self->priv->providers->len)
322
      gst_device_monitor_remove (self, self->priv->providers->len - 1);
323 324
    g_ptr_array_unref (self->priv->providers);
    self->priv->providers = NULL;
325 326
  }

327 328 329 330
  if (self->priv->filters) {
    g_ptr_array_unref (self->priv->filters);
    self->priv->filters = NULL;
  }
331

332 333
  gst_object_replace ((GstObject **) & self->priv->bus, NULL);

334
  G_OBJECT_CLASS (gst_device_monitor_parent_class)->dispose (object);
335 336 337
}

/**
338
 * gst_device_monitor_get_devices:
339
 * @monitor: A #GstDeviceProvider
340 341
 *
 * Gets a list of devices from all of the relevant monitors. This may actually
342
 * probe the hardware if the monitor is not currently started.
343 344 345
 *
 * Returns: (transfer full) (element-type GstDevice): a #GList of
 *   #GstDevice
346 347
 *
 * Since: 1.4
348 349 350
 */

GList *
351
gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
352
{
353
  GList *devices = NULL, *hidden = NULL;
354 355 356
  guint i;
  guint cookie;

357
  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
358

359
  GST_OBJECT_LOCK (monitor);
360

361 362 363 364 365 366 367 368 369 370 371 372
  if (monitor->priv->filters->len == 0) {
    GST_OBJECT_UNLOCK (monitor);
    GST_WARNING_OBJECT (monitor, "No filters have been set");
    return FALSE;
  }

  if (monitor->priv->providers->len == 0) {
    GST_OBJECT_UNLOCK (monitor);
    GST_WARNING_OBJECT (monitor, "No providers match the current filters");
    return FALSE;
  }

373 374 375
again:

  g_list_free_full (devices, gst_object_unref);
376
  g_list_free_full (hidden, g_free);
377
  devices = NULL;
378
  hidden = NULL;
379

380
  cookie = monitor->priv->cookie;
381

382
  for (i = 0; i < monitor->priv->providers->len; i++) {
383
    GList *tmpdev;
384 385
    GstDeviceProvider *provider =
        gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
386 387
    GList *item;

388 389
    if (!is_provider_hidden (monitor, hidden, provider)) {
      GST_OBJECT_UNLOCK (monitor);
390

391 392 393 394 395 396 397
      tmpdev = gst_device_provider_get_devices (provider);

      GST_OBJECT_LOCK (monitor);
      update_hidden_providers_list (&hidden, provider);
    } else {
      tmpdev = NULL;
    }
398

399

400 401 402
    for (item = tmpdev; item; item = item->next) {
      GstDevice *dev = GST_DEVICE (item->data);
      GstCaps *caps = gst_device_get_caps (dev);
403 404 405 406 407
      guint j;

      for (j = 0; j < monitor->priv->filters->len; j++) {
        struct DeviceFilter *filter =
            g_ptr_array_index (monitor->priv->filters, j);
408

409 410 411 412 413 414
        if (gst_caps_can_intersect (filter->caps, caps) &&
            gst_device_has_classesv (dev, filter->classesv)) {
          devices = g_list_prepend (devices, gst_object_ref (dev));
          break;
        }
      }
415 416 417 418
      gst_caps_unref (caps);
    }

    g_list_free_full (tmpdev, gst_object_unref);
419
    gst_object_unref (provider);
420

421
    if (monitor->priv->cookie != cookie)
422 423
      goto again;
  }
424
  g_list_free_full (hidden, g_free);
425

426
  GST_OBJECT_UNLOCK (monitor);
427

428
  return g_list_reverse (devices);
429 430 431
}

/**
432 433
 * gst_device_monitor_start:
 * @monitor: A #GstDeviceMonitor
434 435
 *
 * Starts monitoring the devices, one this has succeeded, the
436 437
 * %GST_MESSAGE_DEVICE_ADDED and %GST_MESSAGE_DEVICE_REMOVED messages
 * will be emitted on the bus when the list of devices changes.
438 439
 *
 * Returns: %TRUE if the device monitoring could be started
440 441
 *
 * Since: 1.4
442 443 444
 */

gboolean
445
gst_device_monitor_start (GstDeviceMonitor * monitor)
446
{
447 448
  guint cookie, i;
  GList *pending = NULL, *started = NULL, *removed = NULL;
449

450
  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
451

452
  GST_OBJECT_LOCK (monitor);
453

454 455
  if (monitor->priv->filters->len == 0) {
    GST_OBJECT_UNLOCK (monitor);
456 457 458 459
    GST_WARNING_OBJECT (monitor, "No filters have been set, will expose all "
        "devices found");
    gst_device_monitor_add_filter (monitor, NULL, NULL);
    GST_OBJECT_LOCK (monitor);
460 461
  }

462
  if (monitor->priv->providers->len == 0) {
463
    GST_OBJECT_UNLOCK (monitor);
464
    GST_WARNING_OBJECT (monitor, "No providers match the current filters");
465 466 467
    return FALSE;
  }

468
  gst_bus_set_flushing (monitor->priv->bus, FALSE);
469

470 471 472 473 474 475 476 477
again:
  cookie = monitor->priv->cookie;

  g_list_free_full (pending, gst_object_unref);
  pending = NULL;
  removed = started;
  started = NULL;

478
  for (i = 0; i < monitor->priv->providers->len; i++) {
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
    GstDeviceProvider *provider;
    GList *find;

    provider = g_ptr_array_index (monitor->priv->providers, i);

    find = g_list_find (removed, provider);
    if (find) {
      /* this was already started, move to started list */
      removed = g_list_remove_link (removed, find);
      started = g_list_concat (started, find);
    } else {
      /* not started, add to pending list */
      pending = g_list_append (pending, gst_object_ref (provider));
    }
  }
  g_list_free_full (removed, gst_object_unref);
  removed = NULL;

  while (pending) {
    GstDeviceProvider *provider = pending->data;
499 500

    if (gst_device_provider_can_monitor (provider)) {
501
      GST_OBJECT_UNLOCK (monitor);
502

503 504
      if (!gst_device_provider_start (provider))
        goto start_failed;
505

506
      GST_OBJECT_LOCK (monitor);
507
    }
508 509
    started = g_list_prepend (started, provider);
    pending = g_list_delete_link (pending, pending);
510

511 512 513
    if (monitor->priv->cookie != cookie)
      goto again;
  }
514 515
  monitor->priv->started = TRUE;
  GST_OBJECT_UNLOCK (monitor);
516

517 518
  g_list_free_full (started, gst_object_unref);

519
  return TRUE;
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536

start_failed:
  {
    GST_OBJECT_LOCK (monitor);
    gst_bus_set_flushing (monitor->priv->bus, TRUE);
    GST_OBJECT_UNLOCK (monitor);

    while (started) {
      GstDeviceProvider *provider = started->data;

      gst_device_provider_stop (provider);
      gst_object_unref (provider);

      started = g_list_delete_link (started, started);
    }
    return FALSE;
  }
537 538 539
}

/**
540
 * gst_device_monitor_stop:
541
 * @monitor: A #GstDeviceProvider
542 543
 *
 * Stops monitoring the devices.
544 545
 *
 * Since: 1.4
546 547
 */
void
548
gst_device_monitor_stop (GstDeviceMonitor * monitor)
549 550
{
  guint i;
551
  GList *started = NULL;
552

553
  g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
554

555
  gst_bus_set_flushing (monitor->priv->bus, TRUE);
556

557
  GST_OBJECT_LOCK (monitor);
558 559 560 561
  for (i = 0; i < monitor->priv->providers->len; i++) {
    GstDeviceProvider *provider =
        g_ptr_array_index (monitor->priv->providers, i);

562 563 564 565 566 567 568
    started = g_list_prepend (started, gst_object_ref (provider));
  }
  GST_OBJECT_UNLOCK (monitor);

  while (started) {
    GstDeviceProvider *provider = started->data;

569 570
    if (gst_device_provider_can_monitor (provider))
      gst_device_provider_stop (provider);
571 572 573

    started = g_list_delete_link (started, started);
    gst_object_unref (provider);
574
  }
575 576

  GST_OBJECT_LOCK (monitor);
577 578
  monitor->priv->started = FALSE;
  GST_OBJECT_UNLOCK (monitor);
579 580 581

}

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
static void
provider_hidden (GstDeviceProvider * provider, const gchar * hidden,
    GstDeviceMonitor * monitor)
{
  GST_OBJECT_LOCK (monitor);
  monitor->priv->hidden =
      g_list_prepend (monitor->priv->hidden, g_strdup (hidden));
  GST_OBJECT_UNLOCK (monitor);
}

static void
provider_unhidden (GstDeviceProvider * provider, const gchar * hidden,
    GstDeviceMonitor * monitor)
{
  GList *find;

  GST_OBJECT_LOCK (monitor);
  find =
      g_list_find_custom (monitor->priv->hidden, hidden,
      (GCompareFunc) g_strcmp0);
  if (find) {
    g_free (find->data);
    monitor->priv->hidden = g_list_delete_link (monitor->priv->hidden, find);
  }
  GST_OBJECT_UNLOCK (monitor);
}

609
/**
610 611
 * gst_device_monitor_add_filter:
 * @monitor: a device monitor
612
 * @classes: (allow-none): device classes to use as filter or %NULL for any class
613
 * @caps: (allow-none): the #GstCaps to filter or %NULL for ANY
614
 *
615 616 617 618 619
 * Adds a filter for which #GstDevice will be monitored, any device that matches
 * all classes and the #GstCaps will be returned.
 *
 * Filters must be added before the #GstDeviceMonitor is started.
 *
Nicolas Dufresne's avatar
Nicolas Dufresne committed
620
 * Returns: The id of the new filter or 0 if no provider matched the filter's
621
 *  classes.
622 623 624
 *
 * Since: 1.4
 */
625 626 627
guint
gst_device_monitor_add_filter (GstDeviceMonitor * monitor,
    const gchar * classes, GstCaps * caps)
628 629
{
  GList *factories = NULL;
630 631 632
  struct DeviceFilter *filter;
  guint id = 0;
  gboolean matched = FALSE;
633

634 635
  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), 0);
  g_return_val_if_fail (!monitor->priv->started, 0);
636

637
  GST_OBJECT_LOCK (monitor);
638

639 640 641 642 643 644 645 646
  filter = g_slice_new0 (struct DeviceFilter);
  filter->id = monitor->priv->last_id++;
  if (caps)
    filter->caps = gst_caps_ref (caps);
  else
    filter->caps = gst_caps_new_any ();
  if (classes)
    filter->classesv = g_strsplit (classes, "/", 0);
647

648
  factories = gst_device_provider_factory_list_get_device_providers (1);
649

650 651
  while (factories) {
    GstDeviceProviderFactory *factory = factories->data;
652

653 654
    if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) {
      GstDeviceProvider *provider;
655

656
      provider = gst_device_provider_factory_get (factory);
657

658 659
      if (provider) {
        guint i;
660

661 662 663 664 665 666 667 668 669
        for (i = 0; i < monitor->priv->providers->len; i++) {
          if (g_ptr_array_index (monitor->priv->providers, i) == provider) {
            gst_object_unref (provider);
            provider = NULL;
            matched = TRUE;
            break;
          }
        }
      }
670

671 672
      if (provider) {
        GstBus *bus = gst_device_provider_get_bus (provider);
673

674 675 676 677 678 679
        update_hidden_providers_list (&monitor->priv->hidden, provider);
        g_signal_connect (provider, "provider-hidden",
            (GCallback) provider_hidden, monitor);
        g_signal_connect (provider, "provider-unhidden",
            (GCallback) provider_unhidden, monitor);

680 681 682 683 684 685 686 687
        matched = TRUE;
        gst_bus_enable_sync_message_emission (bus);
        g_signal_connect (bus, "sync-message",
            G_CALLBACK (bus_sync_message), monitor);
        gst_object_unref (bus);
        g_ptr_array_add (monitor->priv->providers, provider);
        monitor->priv->cookie++;
      }
688 689
    }

690
    factories = g_list_remove (factories, factory);
691 692 693
    gst_object_unref (factory);
  }

694 695
  /* Ensure there is no leak here */
  g_assert (factories == NULL);
696

697 698 699 700 701 702
  if (matched) {
    id = filter->id;
    g_ptr_array_add (monitor->priv->filters, filter);
  } else {
    device_filter_free (filter);
  }
703

704
  GST_OBJECT_UNLOCK (monitor);
705

706
  return id;
707 708
}

709
/**
710
 * gst_device_monitor_remove_filter:
711
 * @monitor: a device monitor
712
 * @filter_id: the id of the filter
713
 *
714 715
 * Removes a filter from the #GstDeviceMonitor using the id that was returned
 * by gst_device_monitor_add_filter().
716
 *
717
 * Returns: %TRUE of the filter id was valid, %FALSE otherwise
718 719 720
 *
 * Since: 1.4
 */
721 722
gboolean
gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, guint filter_id)
723
{
724 725
  guint i, j;
  gboolean removed = FALSE;
726

727 728 729
  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
  g_return_val_if_fail (!monitor->priv->started, FALSE);
  g_return_val_if_fail (filter_id > 0, FALSE);
730

731
  GST_OBJECT_LOCK (monitor);
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
  for (i = 0; i < monitor->priv->filters->len; i++) {
    struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i);

    if (filter->id == filter_id) {
      g_ptr_array_remove_index (monitor->priv->filters, i);
      removed = TRUE;
      break;
    }
  }

  if (removed) {
    for (i = 0; i < monitor->priv->providers->len; i++) {
      GstDeviceProvider *provider =
          g_ptr_array_index (monitor->priv->providers, i);
      GstDeviceProviderFactory *factory =
          gst_device_provider_get_factory (provider);
      gboolean valid = FALSE;

      for (j = 0; j < monitor->priv->filters->len; j++) {
        struct DeviceFilter *filter =
            g_ptr_array_index (monitor->priv->filters, j);

        if (gst_device_provider_factory_has_classesv (factory,
                filter->classesv)) {
          valid = TRUE;
          break;
        }
      }

      if (!valid) {
        monitor->priv->cookie++;
        gst_device_monitor_remove (monitor, i);
        i--;
      }
    }
  }

769
  GST_OBJECT_UNLOCK (monitor);
770

771
  return removed;
772 773
}

774 775


776
/**
777
 * gst_device_monitor_new:
778
 *
779
 * Create a new #GstDeviceMonitor
780
 *
781
 * Returns: (transfer full): a new device monitor.
782 783 784
 *
 * Since: 1.4
 */
785 786
GstDeviceMonitor *
gst_device_monitor_new (void)
787
{
788
  return g_object_new (GST_TYPE_DEVICE_MONITOR, NULL);
789 790 791
}

/**
792
 * gst_device_monitor_get_bus:
793
 * @monitor: a #GstDeviceProvider
794
 *
795
 * Gets the #GstBus of this #GstDeviceMonitor
796 797
 *
 * Returns: (transfer full): a #GstBus
798 799
 *
 * Since: 1.4
800 801
 */
GstBus *
802
gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
803
{
804
  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
805 806 807

  return gst_object_ref (monitor->priv->bus);
}
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

/**
 * gst_device_monitor_get_providers:
 * @monitor: a #GstDeviceMonitor
 *
 * Get a list of the currently selected device provider factories.
 *
 * This
 *
 * Returns: (transfer full) (array zero-terminated=1) (element-type gchar*):
 *     A list of device provider factory names that are currently being
 *     monitored by @monitor or %NULL when nothing is being monitored.
 *
 * Since: 1.6
 */
gchar **
gst_device_monitor_get_providers (GstDeviceMonitor * monitor)
{
  guint i, len;
  gchar **res = NULL;

  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);

  GST_OBJECT_LOCK (monitor);
  len = monitor->priv->providers->len;
  if (len == 0)
    goto done;

  res = g_new (gchar *, len + 1);

  for (i = 0; i < len; i++) {
    GstDeviceProvider *provider =
        g_ptr_array_index (monitor->priv->providers, i);
    GstDeviceProviderFactory *factory =
        gst_device_provider_get_factory (provider);

    res[i] = g_strdup (GST_OBJECT_NAME (factory));
  }
  res[i] = NULL;

done:
  GST_OBJECT_UNLOCK (monitor);

  return res;
}
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898

/**
 * gst_device_monitor_set_show_all_devices:
 * @monitor: a #GstDeviceMonitor
 * @show_all: show all devices
 *
 * Set if all devices should be visible, even those devices from hidden
 * providers. Setting @show_all to true might show some devices multiple times.
 *
 * Since: 1.6
 */
void
gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor,
    gboolean show_all)
{
  g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));

  GST_OBJECT_LOCK (monitor);
  monitor->priv->show_all = show_all;
  GST_OBJECT_UNLOCK (monitor);
}

/**
 * gst_device_monitor_get_show_all_devices:
 * @monitor: a #GstDeviceMonitor
 *
 * Get if @monitor is curretly showing all devices, even those from hidden
 * providers.
 *
 * Returns: %TRUE when all devices will be shown.
 *
 * Since: 1.6
 */
gboolean
gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);

  GST_OBJECT_LOCK (monitor);
  res = monitor->priv->show_all;
  GST_OBJECT_UNLOCK (monitor);

  return res;
}