wasapi2device: Ignore activation failed device
authorSeungha Yang <seungha@centricular.com>
Sat, 4 Nov 2023 10:36:06 +0000 (19:36 +0900)
committerTim-Philipp Müller <tim@centricular.com>
Mon, 6 Nov 2023 13:19:13 +0000 (13:19 +0000)
Enumerates all devices even if activation error is detected

Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3090
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5609>

subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp
subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.h
subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2device.c

index 72bcc83..35520be 100644 (file)
@@ -239,6 +239,7 @@ private:
 
 typedef enum
 {
+  GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND = -2,
   GST_WASAPI2_CLIENT_ACTIVATE_FAILED = -1,
   GST_WASAPI2_CLIENT_ACTIVATE_INIT = 0,
   GST_WASAPI2_CLIENT_ACTIVATE_WAIT,
@@ -579,7 +580,7 @@ gst_wasapi2_client_get_default_device_id (GstWasapi2Client * self)
 }
 /* *INDENT-ON* */
 
-static gboolean
+static void
 gst_wasapi2_client_activate_async (GstWasapi2Client * self,
     GstWasapiDeviceActivator * activator)
 {
@@ -606,18 +607,20 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
   memset (&activation_params, 0, sizeof (GST_AUDIOCLIENT_ACTIVATION_PARAMS));
   activation_params.ActivationType = GST_AUDIOCLIENT_ACTIVATION_TYPE_DEFAULT;
 
+  self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND;
+
   if (self->device_class ==
       GST_WASAPI2_CLIENT_DEVICE_CLASS_INCLUDE_PROCESS_LOOPBACK_CAPTURE ||
       self->device_class ==
       GST_WASAPI2_CLIENT_DEVICE_CLASS_EXCLUDE_PROCESS_LOOPBACK_CAPTURE) {
     if (self->target_pid == 0) {
       GST_ERROR_OBJECT (self, "Process loopback mode without PID");
-      goto failed;
+      return;
     }
 
     if (!gst_wasapi2_can_process_loopback ()) {
       GST_ERROR_OBJECT (self, "Process loopback is not supported");
-      goto failed;
+      return;
     }
 
     process_loopback = TRUE;
@@ -656,7 +659,7 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
   default_device_id_wstring = gst_wasapi2_client_get_default_device_id (self);
   if (default_device_id_wstring.empty ()) {
     GST_WARNING_OBJECT (self, "Couldn't get default device id");
-    goto failed;
+    return;
   }
 
   default_device_id = convert_wstring_to_string (default_device_id_wstring);
@@ -701,31 +704,31 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
 
   hr = GetActivationFactory (hstr_device_info.Get (), &device_info_static);
   if (!gst_wasapi2_result (hr))
-    goto failed;
+    return;
 
   hr = device_info_static->FindAllAsyncDeviceClass (device_class, &async_op);
   device_info_static.Reset ();
   if (!gst_wasapi2_result (hr))
-    goto failed;
+    return;
 
   /* *INDENT-OFF* */
   hr = SyncWait<DeviceInformationCollection*>(async_op.Get ());
   /* *INDENT-ON* */
   if (!gst_wasapi2_result (hr))
-    goto failed;
+    return;
 
   hr = async_op->GetResults (&device_list);
   async_op.Reset ();
   if (!gst_wasapi2_result (hr))
-    goto failed;
+    return;
 
   hr = device_list->get_Size (&count);
   if (!gst_wasapi2_result (hr))
-    goto failed;
+    return;
 
   if (count == 0) {
     GST_WARNING_OBJECT (self, "No available device");
-    goto failed;
+    return;
   }
 
   /* device_index 0 will be assigned for default device
@@ -733,7 +736,7 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
   if (self->device_index >= 0 && self->device_index > (gint) count) {
     GST_WARNING_OBJECT (self, "Device index %d is unavailable",
         self->device_index);
-    goto failed;
+    return;
   }
 
   GST_DEBUG_OBJECT (self, "Available device count: %d", count);
@@ -839,7 +842,7 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
 
   if (target_device_id_wstring.empty ()) {
     GST_WARNING_OBJECT (self, "Couldn't find target device");
-    goto failed;
+    return;
   }
 
 activate:
@@ -854,6 +857,8 @@ activate:
   /* default device supports automatic stream routing */
   self->can_auto_routing = use_default_device;
 
+  self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_INIT;
+
   if (process_loopback) {
     hr = activator->ActivateDeviceAsync (target_device_id_wstring,
         &activation_params);
@@ -863,26 +868,22 @@ activate:
 
   if (!gst_wasapi2_result (hr)) {
     GST_WARNING_OBJECT (self, "Failed to activate device");
-    goto failed;
+    self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_FAILED;
+    return;
   }
 
   g_mutex_lock (&self->lock);
   if (self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_INIT)
     self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_WAIT;
   g_mutex_unlock (&self->lock);
-
-  return TRUE;
-
-failed:
-  self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_FAILED;
-
-  return FALSE;
 }
 
 static const gchar *
 activate_state_to_string (GstWasapi2ClientActivateState state)
 {
   switch (state) {
+    case GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND:
+      return "NOT-FOUND";
     case GST_WASAPI2_CLIENT_ACTIVATE_FAILED:
       return "FAILED";
     case GST_WASAPI2_CLIENT_ACTIVATE_INIT:
@@ -913,7 +914,7 @@ gst_wasapi2_client_thread_func (GstWasapi2Client * self)
 
   if (!gst_wasapi2_result (hr)) {
     GST_ERROR_OBJECT (self, "Could not create activator object");
-    self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_FAILED;
+    self->activate_state = GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND;
     goto run_loop;
   }
 
@@ -1080,7 +1081,8 @@ gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class,
    * RoInitializeWrapper dtor is called */
   core_dispatcher.Reset ();
 
-  if (self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_FAILED) {
+  if (self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_FAILED ||
+      self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND) {
     gst_object_unref (self);
     return nullptr;
   }
@@ -1090,6 +1092,43 @@ gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class,
   return self;
 }
 
+GstWasapi2Result
+gst_wasapi2_client_enumerate (GstWasapi2ClientDeviceClass device_class,
+    gint device_index, GstWasapi2Client ** client)
+{
+  GstWasapi2Client *self;
+  /* *INDENT-OFF* */
+  ComPtr<ICoreDispatcher> core_dispatcher;
+  /* *INDENT-ON* */
+  /* Multiple COM init is allowed */
+  RoInitializeWrapper init_wrapper (RO_INIT_MULTITHREADED);
+
+  *client = nullptr;
+
+  find_dispatcher (&core_dispatcher);
+
+  self = (GstWasapi2Client *) g_object_new (GST_TYPE_WASAPI2_CLIENT,
+      "device-class", device_class, "device-index", device_index,
+      "dispatcher", core_dispatcher.Get (), nullptr);
+
+  /* Reset explicitly to ensure that it happens before
+   * RoInitializeWrapper dtor is called */
+  core_dispatcher.Reset ();
+
+  if (self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_NOT_FOUND) {
+    gst_object_unref (self);
+    return GST_WASAPI2_DEVICE_NOT_FOUND;
+  } else if (self->activate_state == GST_WASAPI2_CLIENT_ACTIVATE_FAILED) {
+    gst_object_unref (self);
+    return GST_WASAPI2_ACTIVATION_FAILED;
+  }
+
+  gst_object_ref_sink (self);
+
+  *client = self;
+  return GST_WASAPI2_OK;
+}
+
 IAudioClient *
 gst_wasapi2_client_get_handle (GstWasapi2Client * client)
 {
index 4c2ee21..d3a0014 100644 (file)
@@ -35,6 +35,13 @@ typedef enum
   GST_WASAPI2_CLIENT_DEVICE_CLASS_EXCLUDE_PROCESS_LOOPBACK_CAPTURE,
 } GstWasapi2ClientDeviceClass;
 
+typedef enum
+{
+  GST_WASAPI2_OK,
+  GST_WASAPI2_DEVICE_NOT_FOUND,
+  GST_WASAPI2_ACTIVATION_FAILED,
+} GstWasapi2Result;
+
 static inline gboolean
 gst_wasapi2_device_class_is_loopback (GstWasapi2ClientDeviceClass device_class)
 {
@@ -81,6 +88,10 @@ IAudioClient *     gst_wasapi2_client_get_handle (GstWasapi2Client * client);
 
 GstCaps *          gst_wasapi2_client_get_caps (GstWasapi2Client * client);
 
+GstWasapi2Result   gst_wasapi2_client_enumerate (GstWasapi2ClientDeviceClass device_class,
+                                                 gint device_index,
+                                                 GstWasapi2Client ** client);
+
 G_END_DECLS
 
 #endif /* __GST_WASAPI2_CLIENT_H__ */
index 0d70801..3eb0e32 100644 (file)
@@ -282,11 +282,15 @@ gst_wasapi2_device_provider_probe_internal (GstWasapi2DeviceProvider * self,
     GstCaps *caps = NULL;
     gchar *device_id = NULL;
     gchar *device_name = NULL;
+    GstWasapi2Result result;
 
-    client = gst_wasapi2_client_new (client_class, i, NULL, 0, NULL);
-
-    if (!client)
+    result = gst_wasapi2_client_enumerate (client_class, i, &client);
+    if (result == GST_WASAPI2_DEVICE_NOT_FOUND)
       return;
+    else if (result == GST_WASAPI2_ACTIVATION_FAILED)
+      continue;
+
+    g_assert (client);
 
     caps = gst_wasapi2_client_get_caps (client);
     if (!caps) {