nx_codec.nx source
↩ module page · 185 lines · 7404 B
1// nx_codec.nx -- abstract codec base class.
2//
3// The reusable composition primitive that audio (NishiVoice v1/v2)
4// and video (NishiVideo v1/v2) codecs implement. Consumers (audio
5// session, video session, future passthrough/test fakes) hold a
6// `*nx_codec` and never touch concrete codec types directly -- the
7// vtable handles dispatch.
8//
9// Per cardinal feedback-bits-up-exceed-never-match: codecs grade
10// themselves via nx_codec_grade. The vtable's grade_card_fn lets
11// any consumer ask any codec for its honest WIN/LOSE/TIE/UNMEASURED
12// per-axis verdict at runtime.
13//
14// Per cardinal feedback-end-to-end-bit-traceability-architecture:
15// every codec frame carries a CAS hash via frame_cas_hash_fn so
16// streams become Merkle chains; any consumer can prove tamper-
17// freedom of replayed bytes.
18//
19// genealogy_id: nx_voice_codec_v1 + nx_video_codec_v1 + nx_codec_grade +
20// nx_attest_merkle_chain + nx_media_session
21// lineage_id: nx_codec_q10
22
23// nx_safety_envelope:
24// intended_use: OOP base for sovereign media codecs
25// sil_target: SIL2
26// evidence: composes nx_voice_codec v1 (voice_call_test.sh proves
27// two-process UDP round-trip) + nx_video_codec v1
28// (codec_grade_card.nx asserts 11 WINs vs incumbents)
29// verdict: NOT_YET_EVALUATED -- pending end-to-end smoke
30
31import "nx_syscalls.nx"
32
33// ---- Sealed codec-id enum ----
34// Append-only. Re-numbering breaks the wire frame header.
35
36const NX_CODEC_ID_UNKNOWN: i64 = 0
37const NX_CODEC_ID_NISHIVOICE_V1: i64 = 1
38const NX_CODEC_ID_NISHIVOICE_V2: i64 = 2
39const NX_CODEC_ID_NISHIVIDEO_V1: i64 = 11
40const NX_CODEC_ID_NISHIVIDEO_V2: i64 = 12
41const NX_CODEC_ID_PASSTHROUGH: i64 = 99 // test fixture
42const NX_CODEC_ID_N: i64 = 100
43
44// ---- Sealed codec-kind enum (audio vs video vs other) ----
45
46const NX_CODEC_KIND_UNKNOWN: i64 = 0
47const NX_CODEC_KIND_AUDIO: i64 = 1
48const NX_CODEC_KIND_VIDEO: i64 = 2
49const NX_CODEC_KIND_DATA: i64 = 3
50const NX_CODEC_KIND_N: i64 = 4
51
52// ---- Sealed verdict enum (returned by encode/decode/frame_cas_hash) ----
53//
54// Negative = error; 0 = success; positive = number of bytes written
55// to the output buffer. Caller distinguishes via sign.
56
57const NX_CODEC_ERR_OUT_TOO_SMALL: i64 = -1
58const NX_CODEC_ERR_BAD_INPUT: i64 = -2
59const NX_CODEC_ERR_BAD_MAGIC: i64 = -3
60const NX_CODEC_ERR_BAD_TIER: i64 = -4
61const NX_CODEC_ERR_NOT_SUPPORTED: i64 = -5
62
63// ---- The base struct ----
64//
65// Embedded as the FIRST field of concrete codec subtypes (e.g.
66// nx_voice_codec_v1_impl wraps the existing nx_voice_codec.nx state).
67//
68// 8 i64 config fields + 4 vtable slots = 12 * 8 = 96 bytes.
69
70struct nx_codec {
71 // -- identity --
72 codec_id: i64, // NX_CODEC_ID_*
73 kind: i64, // NX_CODEC_KIND_*
74
75 // -- config --
76 frame_size_in: i64, // input frame in samples (audio) or block-pixels (video)
77 frame_size_out: i64, // max wire-frame bytes per encode (for cap-pre-alloc)
78 sample_rate: i64, // audio only; 0 for video
79 bitrate_target: i64, // bits per second
80 tier: i64, // NX_HW_TIER_* (set by codec constructor from nx_hwprobe)
81
82 // -- private state pointer --
83 state: i64, // codec-specific state struct (cast in impl)
84
85 // -- vtable --
86 encode_fn: func(*nx_codec, *u8, i64, *u8, i64) -> i64, // (src, src_n, dst, dst_cap) -> dst_n or NX_CODEC_ERR_*
87 decode_fn: func(*nx_codec, *u8, i64, *u8, i64) -> i64,
88 frame_cas_hash_fn: func(*nx_codec, *u8, i64, *u8) -> i64, // (frame, frame_n, out_hash_32B) -> 0 or err
89 grade_card_fn: func(*nx_codec, *u8, i64) -> i64, // (out_buf, out_cap) -> bytes written
90}
91
92const NX_CODEC_BYTES: i64 = 96
93
94// ---- Generic methods (read state, no vtable dispatch) ----
95
96func nx_codec_id(c: *nx_codec) -> i64 { return c.codec_id }
97func nx_codec_kind(c: *nx_codec) -> i64 { return c.kind }
98func nx_codec_frame_size_in(c: *nx_codec) -> i64 { return c.frame_size_in }
99func nx_codec_frame_size_out(c: *nx_codec) -> i64 { return c.frame_size_out }
100func nx_codec_sample_rate(c: *nx_codec) -> i64 { return c.sample_rate }
101func nx_codec_bitrate_target(c: *nx_codec) -> i64 { return c.bitrate_target }
102func nx_codec_tier(c: *nx_codec) -> i64 { return c.tier }
103
104// ---- Virtual call sites ----
105
106// Virtual call sites dispatch through the vtable directly. The
107// parser supports `c.fn_ptr_field(args)` for any arity since the
108// 2026-05-19 four-pillar fix (see [[feedback-four-pillar-parser-
109// fnptr-struct-multiarg]] + bench/nx_fn_ptr_struct_call_smoke.nx).
110
111func nx_codec_encode(c: *nx_codec, src: *u8, src_n: i64,
112 dst: *u8, dst_cap: i64) -> i64 {
113 if src_n <= 0 { return NX_CODEC_ERR_BAD_INPUT }
114 if dst_cap <= 0 { return NX_CODEC_ERR_OUT_TOO_SMALL }
115 return c.encode_fn(c, src, src_n, dst, dst_cap)
116}
117
118func nx_codec_decode(c: *nx_codec, src: *u8, src_n: i64,
119 dst: *u8, dst_cap: i64) -> i64 {
120 if src_n <= 0 { return NX_CODEC_ERR_BAD_INPUT }
121 if dst_cap <= 0 { return NX_CODEC_ERR_OUT_TOO_SMALL }
122 return c.decode_fn(c, src, src_n, dst, dst_cap)
123}
124
125func nx_codec_frame_cas_hash(c: *nx_codec, frame: *u8, frame_n: i64,
126 out_hash_32B: *u8) -> i64 {
127 if frame_n <= 0 { return NX_CODEC_ERR_BAD_INPUT }
128 return c.frame_cas_hash_fn(c, frame, frame_n, out_hash_32B)
129}
130
131func nx_codec_grade_card(c: *nx_codec, out_buf: *u8, out_cap: i64) -> i64 {
132 if out_cap <= 0 { return NX_CODEC_ERR_OUT_TOO_SMALL }
133 return c.grade_card_fn(c, out_buf, out_cap)
134}
135
136// ---- Default vtable implementations ----
137//
138// All four return NX_CODEC_ERR_NOT_SUPPORTED so a partially-wired
139// subtype is honest about its gaps rather than silently no-op.
140
141func nx_codec_default_encode(c: *nx_codec, src: *u8, src_n: i64,
142 dst: *u8, dst_cap: i64) -> i64 {
143 return NX_CODEC_ERR_NOT_SUPPORTED
144}
145
146func nx_codec_default_decode(c: *nx_codec, src: *u8, src_n: i64,
147 dst: *u8, dst_cap: i64) -> i64 {
148 return NX_CODEC_ERR_NOT_SUPPORTED
149}
150
151func nx_codec_default_frame_cas_hash(c: *nx_codec, frame: *u8, frame_n: i64,
152 out_hash_32B: *u8) -> i64 {
153 return NX_CODEC_ERR_NOT_SUPPORTED
154}
155
156func nx_codec_default_grade_card(c: *nx_codec, out_buf: *u8, out_cap: i64) -> i64 {
157 return NX_CODEC_ERR_NOT_SUPPORTED
158}
159
160// ---- Base-struct initializer ----
161//
162// Subtypes call this from their constructors before wiring their own
163// vtable + private state. Sets identity + safe defaults so an
164// unmodified codec still returns NOT_SUPPORTED honestly instead of
165// crashing.
166
167func nx_codec_init(c: *nx_codec,
168 codec_id: i64, kind: i64,
169 frame_size_in: i64, frame_size_out: i64,
170 sample_rate: i64, bitrate_target: i64,
171 tier: i64) -> i64 {
172 c.codec_id = codec_id
173 c.kind = kind
174 c.frame_size_in = frame_size_in
175 c.frame_size_out = frame_size_out
176 c.sample_rate = sample_rate
177 c.bitrate_target = bitrate_target
178 c.tier = tier
179 c.state = 0
180 c.encode_fn = nx_codec_default_encode
181 c.decode_fn = nx_codec_default_decode
182 c.frame_cas_hash_fn = nx_codec_default_frame_cas_hash
183 c.grade_card_fn = nx_codec_default_grade_card
184 return 0
185}