ReviewOS

also looking at this

home-lang/home

feat(media): add bounded PCM capture, owned snapshots and A/V streaming

#917
Merged chris wants to merge feat/pcm-av-streaming into main
11 files +683 -0
packages/audio/src/io/native_capture.zigadded+41-0
Changes to packages/audio/src/io/native_capture.zig
@@ -0,0 +1,41 @@
1//! Home opaque, header-checked ALSA capture. Build C boundary and link libasound.
2//! Calls serialize; close only after read returns. S16LE mono/stereo, BOOTTIME ns.
3const Handle = opaque {};
4pub const Config = extern struct { sample_rate: u32, channels: u32, block_frames: u32 };
5extern fn home_audio_open(*const Config, [*:0]const u8, *?*Handle) c_int;
6extern fn home_audio_read(*Handle, [*]u8, u32, u32, *u32, *u64, *i64) c_int;
7extern fn home_audio_close(*Handle) void;
8pub const Block = struct { frames: u32, timestamp_ns: u64, clock_error_ns: i64 };
9pub const Capture = struct {
10 handle: *Handle,
11 config: Config,
12 failed: bool = false,
13 pub fn init(cfg: Config, device: [:0]const u8) !Capture {
14 var out: ?*Handle = null;
15 try check(home_audio_open(&cfg, device.ptr, &out));
16 return .{ .handle = out.?, .config = cfg };
17 }
18 pub fn deinit(s: *Capture) void {
19 home_audio_close(s.handle);
20 }
21 pub fn read(s: *Capture, data: []u8, timeout_ms: u32) !?Block {
22 if (s.failed) return error.CaptureFailed;
23 if (data.len < @as(u64, s.config.block_frames) * s.config.channels * 2 or timeout_ms > 1000) return error.InvalidConfiguration;
24 var block: Block = undefined;
25 const rc = home_audio_read(s.handle, data.ptr, @intCast(s.config.block_frames), timeout_ms, &block.frames, &block.timestamp_ns, &block.clock_error_ns);
26 if (rc == 1) return null;
27 check(rc) catch |err| {
28 s.failed = true;
29 return err;
30 };
31 return block;
32 }
33};
34fn check(rc: c_int) !void {
35 return switch (rc) {
36 0 => {},
37 -1 => error.InvalidConfiguration,
38 -2 => error.OutOfMemory,
39 else => error.CaptureFailed,
40 };
41}