wasapi2: Fix for device open failure on old OS
authorSeungha Yang <seungha@centricular.com>
Wed, 19 Jan 2022 20:59:36 +0000 (05:59 +0900)
committerSeungha Yang <seungha@centricular.com>
Thu, 20 Jan 2022 14:04:46 +0000 (23:04 +0900)
To open automatic stream routing aware device,
at least Windows10 Anniversary Update is required.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1545>

subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2client.cpp
subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2util.c
subprojects/gst-plugins-bad/sys/wasapi2/gstwasapi2util.h
subprojects/gst-plugins-bad/sys/wasapi2/meson.build

index 9489399..f8a4220 100644 (file)
@@ -164,7 +164,7 @@ public:
       HRESULT async_hr = S_OK;
 
       async_hr = ActivateAudioInterfaceAsync (device_id.c_str (),
-            __uuidof(IAudioClient3), nullptr, this, &async_op);
+            __uuidof(IAudioClient), nullptr, this, &async_op);
 
       /* for debugging */
       gst_wasapi2_result (async_hr);
@@ -590,17 +590,22 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
    * Note that default device is much preferred
    * See https://docs.microsoft.com/en-us/windows/win32/coreaudio/automatic-stream-routing
    */
-  if (self->device_id &&
-      g_ascii_strcasecmp (self->device_id, default_device_id.c_str ()) == 0) {
-    GST_DEBUG_OBJECT (self, "Default device was requested");
-    use_default_device = TRUE;
-  } else if (self->device_index < 0 && !self->device_id) {
-    GST_DEBUG_OBJECT (self,
-        "No device was explicitly requested, use default device");
-    use_default_device = TRUE;
-  } else if (!self->device_id && self->device_index == 0) {
-    GST_DEBUG_OBJECT (self, "device-index == zero means default device");
-    use_default_device = TRUE;
+
+  /* DEVINTERFACE_AUDIO_CAPTURE and DEVINTERFACE_AUDIO_RENDER are available
+   * as of Windows 10 */
+  if (gst_wasapi2_can_automatic_stream_routing ()) {
+    if (self->device_id &&
+        g_ascii_strcasecmp (self->device_id, default_device_id.c_str ()) == 0) {
+      GST_DEBUG_OBJECT (self, "Default device was requested");
+      use_default_device = TRUE;
+    } else if (self->device_index < 0 && !self->device_id) {
+      GST_DEBUG_OBJECT (self,
+          "No device was explicitly requested, use default device");
+      use_default_device = TRUE;
+    } else if (!self->device_id && self->device_index == 0) {
+      GST_DEBUG_OBJECT (self, "device-index == zero means default device");
+      use_default_device = TRUE;
+    }
   }
 
   if (use_default_device) {
@@ -652,8 +657,13 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
 
   GST_DEBUG_OBJECT (self, "Available device count: %d", count);
 
-  /* zero is for default device */
-  device_index = 1;
+  if (gst_wasapi2_can_automatic_stream_routing ()) {
+    /* zero is for default device */
+    device_index = 1;
+  } else {
+    device_index = 0;
+  }
+
   for (unsigned int i = 0; i < count; i++) {
     /* *INDENT-OFF* */
     ComPtr<IDeviceInformation> device_info;
@@ -713,6 +723,15 @@ gst_wasapi2_client_activate_async (GstWasapi2Client * self,
     GST_DEBUG_OBJECT (self, "device [%d] id: %s, name: %s",
         device_index, cur_device_id.c_str (), cur_device_name.c_str ());
 
+    if (self->device_index < 0 && !self->device_id) {
+      GST_INFO_OBJECT (self, "Select the first device, device id %s",
+          cur_device_id.c_str ());
+      target_device_id_wstring = id.GetRawBuffer (nullptr);
+      target_device_id = cur_device_id;
+      target_device_name = cur_device_name;
+      break;
+    }
+
     if (self->device_id &&
         g_ascii_strcasecmp (self->device_id, cur_device_id.c_str ()) == 0) {
       GST_INFO_OBJECT (self,
index f108687..fe666f4 100644 (file)
@@ -26,6 +26,7 @@
 #include "gstwasapi2util.h"
 #include <audioclient.h>
 #include <mmdeviceapi.h>
+#include <winternl.h>
 
 GST_DEBUG_CATEGORY_EXTERN (gst_wasapi2_debug);
 #define GST_CAT_DEFAULT gst_wasapi2_debug
@@ -443,3 +444,49 @@ gst_wasapi2_util_parse_waveformatex (WAVEFORMATEX * format,
 
   return TRUE;
 }
+
+gboolean
+gst_wasapi2_can_automatic_stream_routing (void)
+{
+#ifdef GST_WASAPI2_WINAPI_ONLY_APP
+  /* Assume we are on very recent OS */
+  return TRUE;
+#else
+  static gboolean ret = FALSE;
+  static gsize version_once = 0;
+
+  if (g_once_init_enter (&version_once)) {
+    OSVERSIONINFOEXW osverinfo;
+    typedef NTSTATUS (WINAPI fRtlGetVersion) (PRTL_OSVERSIONINFOEXW);
+    fRtlGetVersion *RtlGetVersion = NULL;
+    HMODULE hmodule = NULL;
+
+    memset (&osverinfo, 0, sizeof (OSVERSIONINFOEXW));
+    osverinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
+
+    hmodule = LoadLibraryW (L"ntdll.dll");
+    if (hmodule)
+      RtlGetVersion =
+          (fRtlGetVersion *) GetProcAddress (hmodule, "RtlGetVersion");
+
+    if (RtlGetVersion) {
+      RtlGetVersion (&osverinfo);
+
+      /* automatic stream routing requires Windows 10
+       * Anniversary Update (version 1607, build number 14393.0) */
+      if (osverinfo.dwMajorVersion > 10 ||
+          (osverinfo.dwMajorVersion == 10 && osverinfo.dwBuildNumber >= 14393))
+        ret = TRUE;
+    }
+
+    if (hmodule)
+      FreeLibrary (hmodule);
+
+    g_once_init_leave (&version_once, 1);
+  }
+
+  GST_INFO ("Automatic stream routing support: %d", ret);
+
+  return ret;
+#endif
+}
index fd5a963..f824f2b 100644 (file)
@@ -63,6 +63,8 @@ gboolean      gst_wasapi2_util_parse_waveformatex (WAVEFORMATEX * format,
 
 gchar *       gst_wasapi2_util_get_error_message  (HRESULT hr);
 
+gboolean      gst_wasapi2_can_automatic_stream_routing (void);
+
 G_END_DECLS
 
 #endif /* __GST_WASAPI_UTIL_H__ */
index 0fd22c4..59a134b 100644 (file)
@@ -83,6 +83,16 @@ if not winapi_app
   endif
 endif
 
+winapi_desktop = cxx.compiles('''#include <winapifamily.h>
+    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    #error "not win32"
+    #endif''',
+    name: 'building for WINAPI_PARTITION_DESKTOP')
+
+if winapi_app and not winapi_desktop
+  extra_args += ['-DGST_WASAPI2_WINAPI_ONLY_APP']
+endif
+
 win10_sdk = cxx.compiles('''#include <windows.h>
     #ifndef WDK_NTDDI_VERSION
     #error "unknown Windows SDK version"