nx_audio_capture.nx source
↩ module page · 132 lines · 4555 B
1// nx_audio_capture.nx -- abstract audio-capture backend + null impl.
2//
3// Capture backends provide PCM samples to nx_audio_session. Same
4// OOP pattern as nx_codec: typed-fn-ptr vtable in struct, concrete
5// backends embed this struct and wire their own impls.
6//
7// Shipping backends (today):
8// nx_audio_capture_null -- always returns 0 bytes (CI / headless)
9// nx_audio_capture_synth -- sine wave (test fixture, FUTURE file)
10//
11// Queued backends:
12// nx_audio_capture_alsa -- Linux ALSA (Synology / RPi deployment)
13// nx_audio_capture_webaudio -- wasm bridge to browser AudioContext
14// nx_audio_capture_coreaudio -- macOS
15
16// nx_safety_envelope:
17// intended_use: reusable audio capture abstraction
18// sil_target: SIL2
19// evidence: composes nx_fn_ptr_typed (compiler-enforced arity)
20// verdict: NOT_YET_EVALUATED
21
22import "nx_syscalls_x86_64.nx"
23
24// ---- Sealed enum: backend kind ----
25
26const NX_AUDIO_CAPTURE_KIND_UNKNOWN: i64 = 0
27const NX_AUDIO_CAPTURE_KIND_NULL: i64 = 1
28const NX_AUDIO_CAPTURE_KIND_SYNTH: i64 = 2
29const NX_AUDIO_CAPTURE_KIND_ALSA: i64 = 3
30const NX_AUDIO_CAPTURE_KIND_WEBAUDIO: i64 = 4
31const NX_AUDIO_CAPTURE_KIND_COREAUDIO: i64 = 5
32const NX_AUDIO_CAPTURE_KIND_N: i64 = 6
33
34// ---- Sealed error codes ----
35
36const NX_AUDIO_CAPTURE_ERR_NOT_OPEN: i64 = -1
37const NX_AUDIO_CAPTURE_ERR_BAD_SIZE: i64 = -2
38const NX_AUDIO_CAPTURE_ERR_BACKEND: i64 = -3
39const NX_AUDIO_CAPTURE_ERR_CLOSED: i64 = -4
40
41// ---- The struct ----
42
43struct nx_audio_capture {
44 kind: i64, // NX_AUDIO_CAPTURE_KIND_*
45 sample_rate: i64,
46 channels: i64,
47 state: i64, // 0 = closed, 1 = open
48 private: i64, // backend-specific pointer (cast in impl)
49
50 // -- vtable --
51 open_fn: func(*nx_audio_capture) -> i64,
52 close_fn: func(*nx_audio_capture) -> i64,
53 pull_frame_fn: func(*nx_audio_capture, *u8, i64) -> i64, // (dst, dst_cap) -> bytes or err
54}
55
56const NX_AUDIO_CAPTURE_BYTES: i64 = 64
57
58// ---- Generic accessors ----
59
60func nx_audio_capture_kind(c: *nx_audio_capture) -> i64 { return c.kind }
61func nx_audio_capture_sample_rate(c: *nx_audio_capture) -> i64 { return c.sample_rate }
62func nx_audio_capture_channels(c: *nx_audio_capture) -> i64 { return c.channels }
63func nx_audio_capture_is_open(c: *nx_audio_capture) -> i64 { return c.state }
64
65// ---- Virtual call sites ----
66
67func nx_audio_capture_open(c: *nx_audio_capture) -> i64 {
68 return c.open_fn(c)
69}
70
71func nx_audio_capture_close(c: *nx_audio_capture) -> i64 {
72 return c.close_fn(c)
73}
74
75func nx_audio_capture_pull_frame(c: *nx_audio_capture,
76 dst: *u8, dst_cap: i64) -> i64 {
77 if c.state == 0 { return NX_AUDIO_CAPTURE_ERR_NOT_OPEN }
78 if dst_cap <= 0 { return NX_AUDIO_CAPTURE_ERR_BAD_SIZE }
79 return c.pull_frame_fn(c, dst, dst_cap)
80}
81
82// ---- Default vtable impls ----
83
84func nx_audio_capture_default_open(c: *nx_audio_capture) -> i64 {
85 c.state = 1
86 return 0
87}
88
89func nx_audio_capture_default_close(c: *nx_audio_capture) -> i64 {
90 c.state = 0
91 return 0
92}
93
94func nx_audio_capture_default_pull_frame(c: *nx_audio_capture,
95 dst: *u8, dst_cap: i64) -> i64 {
96 return 0
97}
98
99// ---- Base initializer ----
100
101func nx_audio_capture_init(c: *nx_audio_capture,
102 kind: i64, sample_rate: i64, channels: i64) -> i64 {
103 c.kind = kind
104 c.sample_rate = sample_rate
105 c.channels = channels
106 c.state = 0
107 c.private = 0
108 c.open_fn = nx_audio_capture_default_open
109 c.close_fn = nx_audio_capture_default_close
110 c.pull_frame_fn = nx_audio_capture_default_pull_frame
111 return 0
112}
113
114// ===================================================================
115// nx_audio_capture_null -- always-zero-bytes backend
116// ===================================================================
117//
118// Useful for CI runs (no real audio device), default-attached
119// playback in nx_cli_meet-from-sshd, and as a smoke fixture.
120
121func nx_audio_capture_null_pull_frame(c: *nx_audio_capture,
122 dst: *u8, dst_cap: i64) -> i64 {
123 return 0
124}
125
126func nx_audio_capture_null_new(c: *nx_audio_capture,
127 sample_rate: i64, channels: i64) -> i64 {
128 nx_audio_capture_init(c, NX_AUDIO_CAPTURE_KIND_NULL, sample_rate, channels)
129 // Defaults already null-shaped; explicit re-wire for clarity.
130 c.pull_frame_fn = nx_audio_capture_null_pull_frame
131 return 0
132}