gboolean
gst_device_monitor_start (GstDeviceMonitor * monitor)
{
  guint i;

  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);

  GST_OBJECT_LOCK (monitor);

  if (monitor->priv->filters->len == 0) {
    GST_OBJECT_UNLOCK (monitor);
    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);
  }

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

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

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

    if (gst_device_provider_can_monitor (provider)) {
      if (!gst_device_provider_start (provider)) {
        gst_bus_set_flushing (monitor->priv->bus, TRUE);

        for (; i != 0; i--)
          gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers,
                  i - 1));

        GST_OBJECT_UNLOCK (monitor);
        return FALSE;
      }
    }
  }

  monitor->priv->started = TRUE;
  GST_OBJECT_UNLOCK (monitor);

  return TRUE;
}
gboolean
gst_device_monitor_start (GstDeviceMonitor * monitor)
{
    guint cookie, i;
    GList *pending = NULL, *started = NULL, *removed = NULL;

    g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);

    GST_OBJECT_LOCK (monitor);

    if (monitor->priv->filters->len == 0) {
        GST_OBJECT_UNLOCK (monitor);
        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);
    }

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

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

again:
    cookie = monitor->priv->cookie;

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

    for (i = 0; i < monitor->priv->providers->len; i++) {
        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;

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

            if (!gst_device_provider_start (provider))
                goto start_failed;

            GST_OBJECT_LOCK (monitor);
        }
        started = g_list_prepend (started, provider);
        pending = g_list_delete_link (pending, pending);

        if (monitor->priv->cookie != cookie)
            goto again;
    }
    monitor->priv->started = TRUE;
    GST_OBJECT_UNLOCK (monitor);

    g_list_free_full (started, gst_object_unref);

    return TRUE;

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;
    }
}