From 36a40dc51a583412fdb3c5dde0fd7269d3236d26 Mon Sep 17 00:00:00 2001 From: Ali Chraghi Date: Thu, 19 Jan 2023 17:39:07 +0330 Subject: [PATCH] sysaudio: add workaround for wine wine crashes when using AudioClient3. it's weird since it returns success when quering --- libs/sysaudio/src/wasapi.zig | 55 ++++++++++++++---------------- libs/sysaudio/src/wasapi/win32.zig | 16 ++++++--- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/libs/sysaudio/src/wasapi.zig b/libs/sysaudio/src/wasapi.zig index f171e2ac..0e0ac449 100644 --- a/libs/sysaudio/src/wasapi.zig +++ b/libs/sysaudio/src/wasapi.zig @@ -9,6 +9,7 @@ pub const Context = struct { devices_info: util.DevicesInfo, enumerator: ?*win32.IMMDeviceEnumerator, watcher: ?Watcher, + is_wine: bool, const Watcher = struct { deviceChangeFn: main.DeviceChangeFn, @@ -72,6 +73,15 @@ pub const Context = struct { }, }, } else null, + .is_wine = blk: { + const hntdll = win32.GetModuleHandleA("ntdll.dll"); + if (hntdll) |_| { + if (win32.GetProcAddress(hntdll, "wine_get_version")) |_| { + break :blk true; + } + } + break :blk false; + }, }; if (options.deviceChangeFn) |_| { @@ -303,27 +313,15 @@ pub const Context = struct { }, .formats = blk: { var audio_client: ?*win32.IAudioClient = null; - var audio_client3: ?*win32.IAudioClient3 = null; - hr = imm_device.?.Activate(win32.IID_IAudioClient3, win32.CLSCTX_ALL, null, @ptrCast(?*?*anyopaque, &audio_client3)); - if (hr == win32.S_OK) { - hr = audio_client3.?.QueryInterface(win32.IID_IAudioClient, @ptrCast(?*?*anyopaque, &audio_client)); - switch (hr) { - win32.S_OK => {}, - win32.E_NOINTERFACE => unreachable, - win32.E_POINTER => unreachable, - else => return error.OpeningDevice, - } - } else { - hr = imm_device.?.Activate(win32.IID_IAudioClient, win32.CLSCTX_ALL, null, @ptrCast(?*?*anyopaque, &audio_client)); - switch (hr) { - win32.S_OK => {}, - win32.E_POINTER => unreachable, - win32.E_INVALIDARG => unreachable, - win32.E_NOINTERFACE => unreachable, - win32.E_OUTOFMEMORY => return error.OutOfMemory, - win32.AUDCLNT_E_DEVICE_INVALIDATED => unreachable, - else => return error.OpeningDevice, - } + hr = imm_device.?.Activate(win32.IID_IAudioClient, win32.CLSCTX_ALL, null, @ptrCast(?*?*anyopaque, &audio_client)); + switch (hr) { + win32.S_OK => {}, + win32.E_POINTER => unreachable, + win32.E_INVALIDARG => unreachable, + win32.E_NOINTERFACE => unreachable, + win32.E_OUTOFMEMORY => return error.OutOfMemory, + win32.AUDCLNT_E_DEVICE_INVALIDATED => unreachable, + else => return error.OpeningDevice, } var fmt_arr = std.ArrayList(main.Format).init(self.allocator); @@ -493,10 +491,10 @@ pub const Context = struct { .SubFormat = toSubFormat(format) catch return error.OpeningDevice, }; - if (audio_client3) |_| { + if (!self.is_wine and audio_client3 != null) { hr = audio_client3.?.InitializeSharedAudioStream( win32.AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - 0, + 0, // TODO: use the advantage of AudioClient3 @ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), &wave_format)), null, ); @@ -600,11 +598,11 @@ pub const Context = struct { .ready_event = ready_event, .aborted = .{ .value = false }, .is_paused = false, - .sample_rate = sample_rate, .writeFn = writeFn, .user_data = options.user_data, .channels = device.channels, .format = format, + .sample_rate = sample_rate, .write_step = format.frameSize(device.channels.len), }; return .{ .wasapi = player }; @@ -658,16 +656,16 @@ pub const Player = struct { audio_client: ?*win32.IAudioClient, audio_client3: ?*win32.IAudioClient3, render_client: ?*win32.IAudioRenderClient, - ready_event: win32.HANDLE, + ready_event: *anyopaque, aborted: std.atomic.Atomic(bool), is_paused: bool, - sample_rate: u24, writeFn: main.WriteFn, user_data: ?*anyopaque, - write_step: u8, channels: []main.Channel, format: main.Format, + sample_rate: u24, + write_step: u8, pub fn deinit(self: *Player) void { self.aborted.store(true, .Unordered); @@ -821,9 +819,6 @@ pub const Player = struct { } return vol; } - pub fn sampleRate(self: Player) u24 { - return self.sample_rate; - } }; pub fn freeDevice(allocator: std.mem.Allocator, self: main.Device) void { diff --git a/libs/sysaudio/src/wasapi/win32.zig b/libs/sysaudio/src/wasapi/win32.zig index 59d52ca6..e9a821bc 100644 --- a/libs/sysaudio/src/wasapi/win32.zig +++ b/libs/sysaudio/src/wasapi/win32.zig @@ -222,11 +222,18 @@ pub extern "kernel32" fn CreateEventA( bManualReset: BOOL, bInitialState: BOOL, lpName: ?[*:0]const u8, -) callconv(WINAPI) ?HANDLE; +) callconv(WINAPI) ?*anyopaque; pub extern "kernel32" fn WaitForSingleObject( - hHandle: ?HANDLE, + hHandle: ?*anyopaque, dwMilliseconds: u32, ) callconv(WINAPI) u32; +pub extern "kernel32" fn GetModuleHandleA( + lpModuleName: ?[*:0]const u8, +) callconv(WINAPI) ?*anyopaque; +pub extern "kernel32" fn GetProcAddress( + hModule: ?*anyopaque, + lpProcName: ?[*:0]const u8, +) callconv(WINAPI) ?*const fn () callconv(WINAPI) isize; pub const INFINITE = 4294967295; pub const SECURITY_ATTRIBUTES = extern struct { nLength: u32, @@ -1168,7 +1175,6 @@ pub const AUDCLNT_SHAREMODE = enum(i32) { SHARED = 0, EXCLUSIVE = 1, }; -pub const HANDLE = @import("std").os.windows.HANDLE; pub const IID_IAudioClient = &Guid.initString("1cb9ad4c-dbfa-4c32-b178-c2f568a703b2"); pub const IAudioClient = extern struct { pub const VTable = extern struct { @@ -1220,7 +1226,7 @@ pub const IAudioClient = extern struct { ) callconv(WINAPI) HRESULT, SetEventHandle: *const fn ( self: *const IAudioClient, - eventHandle: ?HANDLE, + eventHandle: ?*anyopaque, ) callconv(WINAPI) HRESULT, GetService: *const fn ( self: *const IAudioClient, @@ -1262,7 +1268,7 @@ pub const IAudioClient = extern struct { pub inline fn Reset(self: *const T) HRESULT { return @ptrCast(*const IAudioClient.VTable, self.vtable).Reset(@ptrCast(*const IAudioClient, self)); } - pub inline fn SetEventHandle(self: *const T, eventHandle: ?HANDLE) HRESULT { + pub inline fn SetEventHandle(self: *const T, eventHandle: ?*anyopaque) HRESULT { return @ptrCast(*const IAudioClient.VTable, self.vtable).SetEventHandle(@ptrCast(*const IAudioClient, self), eventHandle); } pub inline fn GetService(self: *const T, riid: ?*const Guid, ppv: ?*?*anyopaque) HRESULT {