From 4f62047b7d9b0950b1f3d3e8a9bba2030af297df Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 4 Nov 2023 19:36:06 +0900 Subject: [PATCH] wasapi2device: Ignore activation failed device Enumerates all devices even if activation error is detected Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3090 Part-of: --- .../sys/wasapi2/gstwasapi2client.cpp | 83 ++++++++++++++++------ .../gst-plugins-bad/sys/wasapi2/gstwasapi2client.h | 11 +++ .../gst-plugins-bad/sys/wasapi2/gstwasapi2device.c | 10 ++- 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp index 72bcc83..35520be 100644 --- a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp +++ b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp @@ -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(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 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) { diff --git a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.h b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.h index 4c2ee21..d3a0014 100644 --- a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.h +++ b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.h @@ -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__ */ diff --git a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2device.c b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2device.c index 0d70801..3eb0e32 100644 --- a/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2device.c +++ b/subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2device.c @@ -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) { -- 2.7.4