From 21f3efe78ecfdbeef81e4ba525e94233efaa9e29 Mon Sep 17 00:00:00 2001 From: iddev5 Date: Thu, 14 Jul 2022 13:20:23 +0530 Subject: [PATCH] sysaudio: webaudio: Add intitial implementation and boilerplate --- sysaudio/src/main.zig | 2 +- sysaudio/src/webaudio.zig | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 sysaudio/src/webaudio.zig diff --git a/sysaudio/src/main.zig b/sysaudio/src/main.zig index cdd03821..77d1e91a 100644 --- a/sysaudio/src/main.zig +++ b/sysaudio/src/main.zig @@ -2,7 +2,7 @@ const std = @import("std"); const mem = std.mem; const testing = std.testing; const builtin = @import("builtin"); -const Backend = switch (builtin.os.tag) { +const Backend = if (builtin.cpu.arch == .wasm32) @import("webaudio.zig") else switch (builtin.os.tag) { .linux, .windows, .macos, diff --git a/sysaudio/src/webaudio.zig b/sysaudio/src/webaudio.zig new file mode 100644 index 00000000..024f1668 --- /dev/null +++ b/sysaudio/src/webaudio.zig @@ -0,0 +1,88 @@ +const std = @import("std"); +const Mode = @import("main.zig").Mode; +const DeviceDescriptor = @import("main.zig").DeviceDescriptor; +const js = @import("sysjs"); + +const Audio = @This(); + +pub const Device = struct { + context: js.Object, + + pub fn deinit(device: Device) void { + device.context.deinit(); + } +}; + +pub const DeviceIterator = struct { + ctx: *Audio, + mode: Mode, + + pub fn next(_: DeviceIterator) IteratorError!?DeviceDescriptor { + return null; + } +}; + +pub const IteratorError = error{}; + +pub const Error = error{ + AudioUnsupported, +}; + +context_constructor: js.Function, + +pub fn init() Error!Audio { + const context = js.global().get("AudioContext"); + if (context.is(.undef)) + return error.AudioUnsupported; + + return Audio{ .context_constructor = context.view(.func) }; +} + +pub fn deinit(audio: Audio) void { + audio.context_constructor.deinit(); +} + +pub fn waitEvents(_: Audio) void {} + +pub fn requestDevice(audio: Audio, config: DeviceDescriptor) Error!Device { + const context = audio.context_constructor.construct(&.{}); + _ = context.call("suspend", &.{}); + + const input_channels = if (config.mode.? == .input) js.createNumber(@intToFloat(f64, config.channels.?)) else js.createUndefined(); + const output_channels = if (config.mode.? == .output) js.createNumber(@intToFloat(f64, config.channels.?)) else js.createUndefined(); + + const node = context.call("createScriptProcessor", &.{ js.createNumber(4096), input_channels, output_channels }).view(.object); + defer node.deinit(); + + context.set("node", node.toValue()); + + { + const audio_process_event = js.createFunction(audioProcessEvent); + defer audio_process_event.deinit(); + node.set("onaudioprocess", audio_process_event.toValue()); + } + + { + const destination = context.get("destination").view(.object); + defer destination.deinit(); + _ = node.call("connect", &.{destination.toValue()}); + } + + return Device{ + .context = context, + }; +} + +fn audioProcessEvent(args: js.Object, _: usize) js.Value { + const audio_event = args.getIndex(0).view(.object); + _ = audio_event; + return js.createUndefined(); +} + +pub fn outputDeviceIterator(audio: Audio) DeviceIterator { + return .{ .audio = audio, .mode = .output }; +} + +pub fn inputDeviceIterator(audio: Audio) DeviceIterator { + return .{ .audio = audio, .mode = .input }; +}