nx_video_client_wasm.nx
buildroot/runtime/nx_video_client_wasm.nx
about
nx_video_client_wasm.nx -- the Nishi Video BROWSER CLIENT CORE, for the
WAT/WASM target. Operator 2026-06-10: "we dont want to use javascript or
anything except as a last mile translation for 3rd party browsers."
ALL format/protocol/sample logic the video client needs lives HERE, in
NishiLang, shipped to the browser as nx_video_client.wasm. The JS that
remains in app.js is a named LAST-MILE SHIM: mount this module + bridge
the platform primitives the browser gates behind JS APIs (getUserMedia,
canvas pixels, AudioContext buffers, WebSocket send/recv). No format
byte and no sample arithmetic is computed in JavaScript.
Like nx_sha256_wasm.nx: imports NOTHING, works in caller-supplied linear
memory regions, no syscalls. Team-side authority for the NV1 container
is nx_nv1.nx -- nx_vc_gate cross-checks this module against it natively.
Exports (pointers are i64 offsets into the module's linear memory):
NV1 container (NLC1 -- see knowledge/specs/2026-06-10-nishilossless-...)
vc_nv1_header(out, rate) -> 24
vc_nv1_chunk(out, w, kind, t_ms, payload, n) -> new w
vc_nv1_end(out, w, dur_ms) -> new w
vc_nv1_validate(buf, n, info) -> 0 | negative defect code
vc_nv1_next(buf, n, off, info) -> next off | 0 at end | negative
info[0]=kind info[1]=len info[2]=t_ms info[3]=payload_off
Room wire frames (13-byte kind/id/seq header, relay broadcast)
vc_wire_pack(out, kind, id, seq, payload, n) -> total len
vc_wire_parse(buf, n, info) -> 0 | -1
info[0]=kind info[1]=seq info[2]=payload_off info[3]=payload_len
Sample plane (IEEE 754 decoded with INTEGER math -- bit-exact, no
float unit on the trust path; matches the JS path it replaces:
clamp [-1,1] then TRUNCATE toward zero; NaN->0, +/-Inf->clamp)
vc_f32_to_i16(inb, n_samples, outb) -> n_samples (LE f32 bits -> LE i16)
vc_i16_to_f32(inb, n_samples, outb) -> n_samples (LE i16 -> LE f32 bits, EXACT)
Send-rate governor (the fps/quality ladder decision)
vc_ladder_step(idx, n_rungs, rtt_ms, degrade_ms, recover_ms, good) -> idx
license_tier: ORIGINAL
dependencies 4 imports · 9 importers
imports: nx_media_budget.nxnx_video_ui_core.nxnx_video_codec_wasm.nxnx_vcodec_nf_table.nx
imported by: nx_audio_lossless_gate.nxnx_lpc_speed_bench.nxnx_vc_fecwire_gate.nxnx_vc_gate.nxnx_vcore_a64_kat.nxnx_video_client_live_verify.nxnx_video_client_wasm_vm_gate.nxnx_video_qoe_live.nxnx_video_swarm_probe.nx
structs
| none |
consts
| 56 | const VC_MAGIC_65536: i64 = 65536 |
| 57 | const VC_MAGIC_16777216: i64 = 16777216 |
| 58 | const VC_MAGIC_2147483648: i64 = 2147483648 |
| 59 | const VC_MAGIC_8388608: i64 = 8388608 |
| 60 | const VC_MAGIC_8388607: i64 = 8388607 |
| 61 | const VC_MAGIC_32768: i64 = 32768 |
| 62 | const VC_MAGIC_32767: i64 = 32767 |
| 63 | const VC_MAGIC_2048: i64 = 2048 |
| 64 | const VC_MAGIC_2764: i64 = 2764 |
| 66 | const VC_NV1_HDR: i64 = 24 |
| 67 | const VC_NV1_CHDR: i64 = 9 |
| 503 | const VC_RES_UPLIFT_CLS_CAP: i64 = 7 |
| 515 | const VC_LADDER_RUNGS: i64 = 10 |
| 560 | const VC_RECOVER_DELTA: i64 = 100 |
| 569 | const VC_DEGRADE_DELTA: i64 = 250 |
| 629 | const VC_BWE_MAX_STEP: i64 = 3 // per-tick decrease cap: 3 rungs ~= a 3x fps cut, enough for one tick |
| 630 | const VC_BWE_DRAIN_SHIFT: i64 = 2 // recover only below bp_max>>2 (a quarter of the back-pressure line) |
| 631 | const VC_BWE_RECOVER_TICKS: i64 = 5 // clean ticks before one +1 recovery (at a 300ms tick ~= 1.5s cadence) |
| 666 | const VV_CTX_EST: i64 = 0x80 |
| 667 | const VV_CTX_PROBS: i64 = 0x180 |
| 668 | const VV_CTX_T8C: i64 = 0x280 |
| 669 | const VV_CTX_RCSCR: i64 = 0x1800 |
| 682 | const VV_MAX_W: i64 = 1152 |
| 683 | const VV_MAX_H: i64 = 640 |
| 684 | const VV_WASM_PAGE: i64 = 65536 |
| 685 | const VV_PEER_SLOTS: i64 = 8 // RX slots = NX_SIG2_MAX_PEERS (the relay's room cap) |
| 686 | const VV_MB: i64 = 16 |
| 687 | const VV_NF_TABLE_BYTES: i64 = 4096 // trained restoration table (vc_nf_load) -- its own declared size |
| 688 | const VV_DRIFT_SLOT_BYTES: i64 = 1024 // one i64[128] drift ledger per peer slot |
| 832 | const VC_FEC_K: i64 = 8 |
| 833 | const VC_FEC_M: i64 = 2 |
| 834 | const VC_GF_POLY: i64 = 0x11d |
| 1070 | const VC_NREACTS: i64 = 6 |
functions
| 69 | func vc_rd_u32(b: *u8, off: i64) -> i64 |
| 77 | func vc_wr_u32(b: *u8, off: i64, v: i64) -> i64 |
| 87 | func vc_nv1_header(out: *u8, rate: i64) -> i64 |
| 97 | func vc_nv1_chunk(out: *u8, w: i64, kind: i64, t_ms: i64, payload: *u8, n: i64) -> i64 |
| 106 | func vc_nv1_end(out: *u8, w: i64, dur_ms: i64) -> i64 |
| 114 | func vc_nv1_validate(buf: *u8, n: i64, info: *i64) -> i64 |
| 158 | func vc_nv1_next(buf: *u8, n: i64, off: i64, info: *i64) -> i64 |
| 173 | func vc_wire_pack(out: *u8, kind: i64, id: *u8, seq: i64, payload: *u8, n: i64) -> i64 |
| 183 | func vc_wire_parse(buf: *u8, n: i64, info: *i64) -> i64 |
| 199 | func vc_f32_bits_to_i16(bits: i64) -> i64 |
| 228 | func vc_i16_to_f32_bits(v: i64) -> i64 |
| 248 | func vc_f32_to_i16(inb: *u8, n_samples: i64, outb: *u8) -> i64 |
| 261 | func vc_i16_to_f32(inb: *u8, n_samples: i64, outb: *u8) -> i64 |
| 281 | func vc_lpc_rd_i16(b: *u8, off: i64) -> i64 |
| 288 | func vc_lpc_wr_i16(b: *u8, idx: i64, v: i64) -> i64 called by 1: vc_lpc_decode |
| 296 | func vc_lpc_bit_put(b: *u8, pos: i64, bit: i64) -> i64 called by 1: vc_lpc_rice_put |
| 304 | func vc_lpc_bit_get(b: *u8, cur: *i64, lim: i64) -> i64 called by 1: vc_lpc_rice_get |
| 311 | func vc_lpc_rice_put(b: *u8, pos: i64, u: i64, k: i64) -> i64 |
| 324 | func vc_lpc_rice_get(b: *u8, cur: *i64, lim: i64, k: i64) -> i64 |
| 343 | func vc_lpc_residuals(x: *i64, n: i64, o: i64, u: *i64) -> i64 called by 1: vc_lpc_encode |
| 365 | func vc_lpc_cost_bits(u: *i64, m: i64, k: i64) -> i64 called by 1: vc_lpc_encode |
| 377 | func vc_lpc_encode(pcm: *u8, nsamples: i64, out: *u8, outcap: i64, scratch: *i64) -> i64 called by 3: roundtripmainmain calls 5: vc_wr_u32vc_lpc_rd_i16vc_lpc_residualsvc_lpc_cost_bitsvc_lpc_rice_put |
| 434 | func vc_lpc_decode(pl: *u8, plen: i64, out: *u8, outcap: i64, scratch: *i64) -> i64 |
| 504 | func vc_res_uplift_cap() -> i64 { return VC_RES_UPLIFT_CLS_CAP } |
| 505 | func vc_pick_ready(slot: i64, mask: i64, n: i64) -> i64 |
| 516 | func vc_ladder_rungs() -> i64 { return VC_LADDER_RUNGS } |
| 517 | func vc_ladder_fps(idx: i64) -> i64 |
| 529 | func vc_ladder_q_permille(idx: i64) -> i64 |
| 549 | func vc_ladder_floor(n_peers: i64) -> i64 |
| 580 | func vc_ladder_step(idx: i64, n_rungs: i64, rtt_ms: i64, called by 1: main |
| 632 | func vc_ilog2(v: i64) -> i64 { var n: i64 = 0; var x: i64 = v; while x > 1 { x = x >> 1; n = n + 1 } return n } called by 1: vc_bwe_step |
| 633 | func vc_bwe_step(eff_idx: i64, raw_idx: i64, n_rungs: i64, buf: i64, bp_max: i64, st: *i64) -> i64 calls 1: vc_ilog2 |
| 689 | func vv_page_tidy(n: i64) -> i64 { return ((n + VV_WASM_PAGE - 1) / VV_WASM_PAGE) * VV_WASM_PAGE } |
| 690 | func vc_max_w() -> i64 { return VV_MAX_W } |
| 691 | func vc_max_h() -> i64 { return VV_MAX_H } |
| 692 | func vc_peer_slots() -> i64 { return VV_PEER_SLOTS } |
| 694 | func vc_slot_yuv() -> i64 { return vv_page_tidy(VV_MAX_W * VV_MAX_H * 3 / 2) } |
| 696 | func vc_slot_rgba() -> i64 { return vv_page_tidy(VV_MAX_W * VV_MAX_H * 4) } calls 1: vv_page_tidy |
| 699 | func vc_wirebuf() -> i64 { return vc_slot_yuv() } calls 1: vc_slot_yuv |
| 701 | func vc_heat_bytes() -> i64 { return vv_page_tidy(((VV_MAX_W + VV_MB - 1) / VV_MB) * ((VV_MAX_H + VV_MB - 1) / VV_MB) * 8) } calls 1: vv_page_tidy |
| 703 | func vc_nfscr_bytes() -> i64 { return vv_page_tidy(VV_MAX_W * VV_MAX_H) } calls 1: vv_page_tidy |
| 704 | func vc_nftbl_bytes() -> i64 { return VV_NF_TABLE_BYTES } |
| 705 | func vc_drift_bytes() -> i64 { return vv_page_tidy(VV_PEER_SLOTS * VV_DRIFT_SLOT_BYTES) } calls 1: vv_page_tidy |
| 710 | func vv_ctx_mvplane_off() -> i64 { return VV_CTX_RCSCR + VV_MAX_W * VV_MAX_H * 3 / 2 } |
| 711 | func vc_ctx_bytes() -> i64 { return vv_page_tidy(vv_ctx_mvplane_off() + ((VV_MAX_W + VV_MB - 1) / VV_MB) * 16) } |
| 713 | func vv_init_ctx(base: i64) -> i64 { vc_t8_init((base + VV_CTX_T8C) as *i64); return 0 } calls 1: vc_t8_init |
| 728 | func vv_seed_rctx(base: i64, rc: i64, nf: i64, sig: i64, part: i64, deblock: i64, heatp: i64, nftbl: i64, nfscr: i64) -> i64 calls 1: vv_ctx_mvplane_off |
| 781 | func vc_res_tier(cls: i64, flex_all: i64, all818: i64) -> i64 called by 1: vc_res_tier_hd |
| 816 | func vc_res_tier_hd(cls: i64, flex_all: i64, all818: i64, all_hd: i64) -> i64 calls 1: vc_res_tier |
| 836 | func vc_gf_mul(tbl: *i64, a: i64, b: i64) -> i64 |
| 841 | func vc_gf_inv(tbl: *i64, a: i64) -> i64 { return tbl[255 - tbl[512 + a]] } |
| 844 | func vc_fec_init(tbl: *i64) -> i64 |
| 878 | func vc_fec_encode(tbl: *i64, data: *u8, shards: *u8, S: i64) -> i64 |
| 898 | func vc_fec_decode(tbl: *i64, shards: *u8, erased: *i64, out: *u8, S: i64, scratchA: *i64) -> i64 |
| 960 | func vc_fecs_shard_size(flen: i64) -> i64 { return (flen + 7) / 8 } called by 1: main |
| 964 | func vc_fecs_pack(tbl: *i64, frame: *u8, flen: i64, block_id: i64, scratch_data: *u8, scratch_shards: *u8, out: *u8) -> i64 |
| 994 | func vc_fecrx_reset(st: *i64) -> i64 called by 1: main |
| 1006 | func vc_fecrx_add(st: *i64, tbl: *i64, payload: *u8, plen: i64, scratchA: *i64, scratchSh: *u8, out: *u8, outcap: i64) -> i64 |
| 1071 | func vc_react_pack(out: *u8, idx: i64) -> i64 |
| 1078 | func vc_react_parse(pay: *u8, plen: i64) -> i64 |
| 1084 | func vc_react_emoji(idx: i64, out: *u8) -> i64 |
| 1095 | func vc_chat_pack(out: *u8, name: *u8, nlen: i64, text: *u8, tlen: i64) -> i64 called by 1: main |
| 1110 | func vc_chat_parse(pay: *u8, plen: i64, info: *i64) -> i64 called by 1: main |