sysaudio: add workaround for wine

wine crashes when using AudioClient3. it's weird since it returns success when quering
This commit is contained in:
Ali Chraghi 2023-01-19 17:39:07 +03:30 committed by Stephen Gutekanst
parent 7315d1ab62
commit 36a40dc51a
2 changed files with 36 additions and 35 deletions

View file

@ -9,6 +9,7 @@ pub const Context = struct {
devices_info: util.DevicesInfo, devices_info: util.DevicesInfo,
enumerator: ?*win32.IMMDeviceEnumerator, enumerator: ?*win32.IMMDeviceEnumerator,
watcher: ?Watcher, watcher: ?Watcher,
is_wine: bool,
const Watcher = struct { const Watcher = struct {
deviceChangeFn: main.DeviceChangeFn, deviceChangeFn: main.DeviceChangeFn,
@ -72,6 +73,15 @@ pub const Context = struct {
}, },
}, },
} else null, } 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) |_| { if (options.deviceChangeFn) |_| {
@ -303,17 +313,6 @@ pub const Context = struct {
}, },
.formats = blk: { .formats = blk: {
var audio_client: ?*win32.IAudioClient = null; 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)); hr = imm_device.?.Activate(win32.IID_IAudioClient, win32.CLSCTX_ALL, null, @ptrCast(?*?*anyopaque, &audio_client));
switch (hr) { switch (hr) {
win32.S_OK => {}, win32.S_OK => {},
@ -324,7 +323,6 @@ pub const Context = struct {
win32.AUDCLNT_E_DEVICE_INVALIDATED => unreachable, win32.AUDCLNT_E_DEVICE_INVALIDATED => unreachable,
else => return error.OpeningDevice, else => return error.OpeningDevice,
} }
}
var fmt_arr = std.ArrayList(main.Format).init(self.allocator); var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
var closest_match: ?*win32.WAVEFORMATEX = null; var closest_match: ?*win32.WAVEFORMATEX = null;
@ -493,10 +491,10 @@ pub const Context = struct {
.SubFormat = toSubFormat(format) catch return error.OpeningDevice, .SubFormat = toSubFormat(format) catch return error.OpeningDevice,
}; };
if (audio_client3) |_| { if (!self.is_wine and audio_client3 != null) {
hr = audio_client3.?.InitializeSharedAudioStream( hr = audio_client3.?.InitializeSharedAudioStream(
win32.AUDCLNT_STREAMFLAGS_EVENTCALLBACK, win32.AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, // TODO: use the advantage of AudioClient3
@ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), &wave_format)), @ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), &wave_format)),
null, null,
); );
@ -600,11 +598,11 @@ pub const Context = struct {
.ready_event = ready_event, .ready_event = ready_event,
.aborted = .{ .value = false }, .aborted = .{ .value = false },
.is_paused = false, .is_paused = false,
.sample_rate = sample_rate,
.writeFn = writeFn, .writeFn = writeFn,
.user_data = options.user_data, .user_data = options.user_data,
.channels = device.channels, .channels = device.channels,
.format = format, .format = format,
.sample_rate = sample_rate,
.write_step = format.frameSize(device.channels.len), .write_step = format.frameSize(device.channels.len),
}; };
return .{ .wasapi = player }; return .{ .wasapi = player };
@ -658,16 +656,16 @@ pub const Player = struct {
audio_client: ?*win32.IAudioClient, audio_client: ?*win32.IAudioClient,
audio_client3: ?*win32.IAudioClient3, audio_client3: ?*win32.IAudioClient3,
render_client: ?*win32.IAudioRenderClient, render_client: ?*win32.IAudioRenderClient,
ready_event: win32.HANDLE, ready_event: *anyopaque,
aborted: std.atomic.Atomic(bool), aborted: std.atomic.Atomic(bool),
is_paused: bool, is_paused: bool,
sample_rate: u24,
writeFn: main.WriteFn, writeFn: main.WriteFn,
user_data: ?*anyopaque, user_data: ?*anyopaque,
write_step: u8,
channels: []main.Channel, channels: []main.Channel,
format: main.Format, format: main.Format,
sample_rate: u24,
write_step: u8,
pub fn deinit(self: *Player) void { pub fn deinit(self: *Player) void {
self.aborted.store(true, .Unordered); self.aborted.store(true, .Unordered);
@ -821,9 +819,6 @@ pub const Player = struct {
} }
return vol; return vol;
} }
pub fn sampleRate(self: Player) u24 {
return self.sample_rate;
}
}; };
pub fn freeDevice(allocator: std.mem.Allocator, self: main.Device) void { pub fn freeDevice(allocator: std.mem.Allocator, self: main.Device) void {

View file

@ -222,11 +222,18 @@ pub extern "kernel32" fn CreateEventA(
bManualReset: BOOL, bManualReset: BOOL,
bInitialState: BOOL, bInitialState: BOOL,
lpName: ?[*:0]const u8, lpName: ?[*:0]const u8,
) callconv(WINAPI) ?HANDLE; ) callconv(WINAPI) ?*anyopaque;
pub extern "kernel32" fn WaitForSingleObject( pub extern "kernel32" fn WaitForSingleObject(
hHandle: ?HANDLE, hHandle: ?*anyopaque,
dwMilliseconds: u32, dwMilliseconds: u32,
) callconv(WINAPI) 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 INFINITE = 4294967295;
pub const SECURITY_ATTRIBUTES = extern struct { pub const SECURITY_ATTRIBUTES = extern struct {
nLength: u32, nLength: u32,
@ -1168,7 +1175,6 @@ pub const AUDCLNT_SHAREMODE = enum(i32) {
SHARED = 0, SHARED = 0,
EXCLUSIVE = 1, EXCLUSIVE = 1,
}; };
pub const HANDLE = @import("std").os.windows.HANDLE;
pub const IID_IAudioClient = &Guid.initString("1cb9ad4c-dbfa-4c32-b178-c2f568a703b2"); pub const IID_IAudioClient = &Guid.initString("1cb9ad4c-dbfa-4c32-b178-c2f568a703b2");
pub const IAudioClient = extern struct { pub const IAudioClient = extern struct {
pub const VTable = extern struct { pub const VTable = extern struct {
@ -1220,7 +1226,7 @@ pub const IAudioClient = extern struct {
) callconv(WINAPI) HRESULT, ) callconv(WINAPI) HRESULT,
SetEventHandle: *const fn ( SetEventHandle: *const fn (
self: *const IAudioClient, self: *const IAudioClient,
eventHandle: ?HANDLE, eventHandle: ?*anyopaque,
) callconv(WINAPI) HRESULT, ) callconv(WINAPI) HRESULT,
GetService: *const fn ( GetService: *const fn (
self: *const IAudioClient, self: *const IAudioClient,
@ -1262,7 +1268,7 @@ pub const IAudioClient = extern struct {
pub inline fn Reset(self: *const T) HRESULT { pub inline fn Reset(self: *const T) HRESULT {
return @ptrCast(*const IAudioClient.VTable, self.vtable).Reset(@ptrCast(*const IAudioClient, self)); 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); 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 { pub inline fn GetService(self: *const T, riid: ?*const Guid, ppv: ?*?*anyopaque) HRESULT {