diff --git a/libs/sysaudio/src/wasapi.zig b/libs/sysaudio/src/wasapi.zig index 0b514e99..5c52b724 100644 --- a/libs/sysaudio/src/wasapi.zig +++ b/libs/sysaudio/src/wasapi.zig @@ -472,7 +472,8 @@ pub const Context = struct { hr = audio_client.?.Initialize( .SHARED, - win32.AUDCLNT_STREAMFLAGS_NOPERSIST, + win32.AUDCLNT_STREAMFLAGS_EVENTCALLBACK | + win32.AUDCLNT_STREAMFLAGS_NOPERSIST, 0, 0, @ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), &wave_format)), @@ -526,6 +527,18 @@ pub const Context = struct { else => return error.OpeningDevice, } + var ready_event = win32.CreateEventA(null, 0, 0, null) orelse return error.SystemResources; + hr = audio_client.?.SetEventHandle(ready_event); + switch (hr) { + win32.S_OK => {}, + win32.E_INVALIDARG => unreachable, + win32.AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED => unreachable, + win32.AUDCLNT_E_NOT_INITIALIZED => unreachable, + win32.AUDCLNT_E_DEVICE_INVALIDATED => return error.OpeningDevice, + win32.AUDCLNT_E_SERVICE_NOT_RUNNING => return error.OpeningDevice, + else => return error.OpeningDevice, + } + return .{ .wasapi = .{ .thread = undefined, @@ -538,6 +551,7 @@ pub const Context = struct { .simple_volume = simple_volume, .imm_device = imm_device, .render_client = render_client, + .ready_event = ready_event, .is_paused = false, .vol = 1.0, .aborted = .{ .value = false }, @@ -595,6 +609,7 @@ pub const Player = struct { imm_device: ?*win32.IMMDevice, audio_client: ?*win32.IAudioClient, render_client: ?*win32.IAudioRenderClient, + ready_event: win32.HANDLE, aborted: std.atomic.Atomic(bool), is_paused: bool, vol: f32, @@ -634,8 +649,10 @@ pub const Player = struct { } while (!self.aborted.load(.Unordered)) { - var frames_buf: u32 = 0; - hr = self.audio_client.?.GetBufferSize(&frames_buf); + _ = win32.WaitForSingleObject(self.ready_event, win32.INFINITE); + + var buf_frames: u32 = 0; + hr = self.audio_client.?.GetBufferSize(&buf_frames); switch (hr) { win32.S_OK => {}, win32.E_POINTER => unreachable, @@ -645,8 +662,8 @@ pub const Player = struct { else => unreachable, } - var frames_used: u32 = 0; - hr = self.audio_client.?.GetCurrentPadding(&frames_used); + var padding_frames: u32 = 0; + hr = self.audio_client.?.GetCurrentPadding(&padding_frames); switch (hr) { win32.S_OK => {}, win32.E_POINTER => unreachable, @@ -655,10 +672,10 @@ pub const Player = struct { win32.AUDCLNT_E_SERVICE_NOT_RUNNING => return, else => unreachable, } - const writable_frame_count = frames_buf - frames_used; - if (writable_frame_count > 0) { + const frames = buf_frames - padding_frames; + if (frames > 0) { var data: [*]u8 = undefined; - hr = self.render_client.?.GetBuffer(writable_frame_count, @ptrCast(?*?*u8, &data)); + hr = self.render_client.?.GetBuffer(frames, @ptrCast(?*?*u8, &data)); switch (hr) { win32.S_OK => {}, win32.E_POINTER => unreachable, @@ -676,8 +693,9 @@ pub const Player = struct { ch.*.ptr = data + self.format().frameSize(i); } - self.writeFn(parent, writable_frame_count); - hr = self.render_client.?.ReleaseBuffer(writable_frame_count, 0); + self.writeFn(parent, frames); + + hr = self.render_client.?.ReleaseBuffer(frames, 0); switch (hr) { win32.S_OK => {}, win32.E_INVALIDARG => unreachable, @@ -776,4 +794,4 @@ pub fn freeDevice(allocator: std.mem.Allocator, self: main.Device) void { test { std.testing.refAllDeclsRecursive(@This()); -} \ No newline at end of file +} diff --git a/libs/sysaudio/src/wasapi/win32.zig b/libs/sysaudio/src/wasapi/win32.zig index 1a5dd63f..24720bea 100644 --- a/libs/sysaudio/src/wasapi/win32.zig +++ b/libs/sysaudio/src/wasapi/win32.zig @@ -217,6 +217,22 @@ pub extern "ole32" fn CoCreateInstance( riid: *const Guid, ppv: ?*?*anyopaque, ) callconv(WINAPI) HRESULT; +pub extern "kernel32" fn CreateEventA( + lpEventAttributes: ?*SECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: ?[*:0]const u8, +) callconv(WINAPI) ?HANDLE; +pub extern "kernel32" fn WaitForSingleObject( + hHandle: ?HANDLE, + dwMilliseconds: u32, +) callconv(WINAPI) u32; +pub const INFINITE = 4294967295; +pub const SECURITY_ATTRIBUTES = extern struct { + nLength: u32, + lpSecurityDescriptor: ?*anyopaque, + bInheritHandle: BOOL, +}; pub const IID_IUnknown = &Guid.initString("00000000-0000-0000-c000-000000000046"); pub const IUnknown = extern struct { pub const VTable = extern struct { @@ -1576,7 +1592,14 @@ pub const IMMEndpoint = extern struct { } pub usingnamespace MethodMixin(@This()); }; +pub const AUDCLNT_STREAMFLAGS_CROSSPROCESS = 65536; +pub const AUDCLNT_STREAMFLAGS_LOOPBACK = 131072; +pub const AUDCLNT_STREAMFLAGS_EVENTCALLBACK = 262144; pub const AUDCLNT_STREAMFLAGS_NOPERSIST = 524288; +pub const AUDCLNT_STREAMFLAGS_RATEADJUST = 1048576; +pub const AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY = 134217728; +pub const AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM = 2147483648; +pub const AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED = 268435456; pub const PKEY_Device_FriendlyName = PROPERTYKEY{ .fmtid = Guid.initString("a45c254e-df1c-4efd-8020-67d146a850e0"), .pid = 14 }; pub const CLSID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = &Guid.initString("00000003-0000-0010-8000-00aa00389b71"); pub const SPEAKER_FRONT_LEFT = 1;