code wiki / _hdl_build / nx_jitter_buffer_gate.nx
nx_jitter_buffer_gate.nx source
↩ module page · 145 lines · 7162 B
1import "nx_gate_base.nx"
2// nx_jitter_buffer_gate.nx -- proves the sovereign jitter buffer does what WebRTC's does, MEASURED on a
3// deterministic reordered/lossy/jittered arrival trace (no real time -- a virtual playout clock):
4// ORDERED OUT: frames pushed out-of-order (incl injected reorders) leave in strict seq order.
5// LOSS CONCEALED: genuinely-lost frames are SKIPPED, playout never stalls on the gap.
6// COMPLETE: every real (non-lost) frame is played exactly once (clean run).
7// ADAPTIVE: a high-jitter trace grows the playout delay vs a low-jitter trace (deeper buffer).
8// NEG-CONTROL: playing raw arrival order (no buffer) would be OUT of order -> proves the buffer earns it.
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_jitter_buffer.nx"
12
13const K: i64 = 180
14const FRAME_US: i64 = 33333 // 30 fps
15const NET_US: i64 = 50000
16const BASE_US: i64 = 66666 // 2-frame base playout delay
17const NSLOT: i64 = 64
18
19func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
20" as *u8); return ok }
21func gn(v: i64) -> i64 {
22 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
23 let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
24 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
25
26func is_lost(i: i64) -> i64 { if i==50 { return 1 } if i==100 { return 1 } if i==130 { return 1 } return 0 }
27
28// run one trace at jitter magnitude J; fill res[0]=released res[1]=skipped res[2]=mono_ok
29// res[3]=target_delay res[4]=all_real_played res[5]=lost_never_played res[6]=raw_order_inversions
30func run_trace(J: i64, seed: i64, res: *i64) -> i64 {
31 let ts: *i64 = sys_mmap(8 * K) as *i64
32 let arr: *i64 = sys_mmap(8 * K) as *i64
33 let ord: *i64 = sys_mmap(8 * K) as *i64
34 let played: *i64 = sys_mmap(8 * K) as *i64
35 let slots: *i64 = sys_mmap(8 * NSLOT * 4) as *i64
36 let st: *i64 = sys_mmap(8 * 16) as *i64
37 let out: *i64 = sys_mmap(8 * 4) as *i64
38 var i: i64 = 0
39 while i < K { played[i] = 0; i = i + 1 }
40 var s: i64 = seed
41 i = 0
42 while i < K {
43 ts[i] = i * FRAME_US
44 s = (s * 1103515245 + 12345) & 0x7fffffff
45 let jit: i64 = (s % (2 * J + 1)) - J
46 arr[i] = ts[i] + NET_US + jit
47 i = i + 1
48 }
49 // INJECT guaranteed reorders WITHIN the buffer depth (adjacent swap: a later seq arrives just before
50 // an earlier one -> the buffer must reorder them, and both are recoverable). A reorder DEEPER than the
51 // playout delay is correctly DROPPED (tested implicitly by the high-jitter trace), not a bug.
52 let sw0: i64 = arr[20]; arr[20] = arr[21]; arr[21] = sw0
53 let sw1: i64 = arr[70]; arr[70] = arr[71]; arr[71] = sw1
54
55 // build ord = non-lost frame indices sorted by arrival (insertion sort)
56 var m: i64 = 0
57 i = 0
58 while i < K { if is_lost(i) == 0 { ord[m] = i; m = m + 1 } i = i + 1 }
59 var a: i64 = 1
60 while a < m {
61 let key: i64 = ord[a]
62 let ka: i64 = arr[key]
63 var b: i64 = a - 1
64 var go: i64 = 1
65 while go == 1 { if b >= 0 { if arr[ord[b]] > ka { ord[b+1] = ord[b]; b = b - 1 } else { go = 0 } } else { go = 0 } }
66 ord[b+1] = key
67 a = a + 1
68 }
69 // count raw-order inversions (how out-of-order the arrival trace is -- the neg-control baseline)
70 var inversions: i64 = 0
71 i = 1
72 while i < m { if ord[i] < ord[i-1] { inversions = inversions + 1 } i = i + 1 }
73
74 // ---- simulate: paced playout clock, push arrivals as they pass ----
75 jb_init(st, BASE_US)
76 var released: i64 = 0
77 var skipped: i64 = 0
78 var last: i64 = 0 - 1
79 var mono: i64 = 1
80 var pp: i64 = 0
81 var now: i64 = arr[ord[0]]
82 var tick: i64 = 0
83 let budget: i64 = K + 60
84 while tick < budget {
85 var go2: i64 = 1
86 while go2 == 1 { if pp < m { if arr[ord[pp]] <= now { jb_push(st, slots, NSLOT, ord[pp], ts[ord[pp]], arr[ord[pp]]); pp = pp + 1 } else { go2 = 0 } } else { go2 = 0 } }
87 jb_pop(st, slots, NSLOT, now, out)
88 if out[1] == 1 {
89 let sq: i64 = out[0]
90 if sq <= last { mono = 0 }
91 last = sq
92 if sq >= 0 { if sq < K { played[sq] = 1 } }
93 released = released + 1
94 }
95 if out[1] == (0 - 1) { skipped = skipped + 1 }
96 now = now + FRAME_US
97 tick = tick + 1
98 }
99 // audit played[]
100 var all_real: i64 = 1
101 var lost_played: i64 = 0
102 i = 0
103 while i < K {
104 if is_lost(i) == 1 { if played[i] == 1 { lost_played = 1 } }
105 else { if played[i] == 0 { all_real = 0 } }
106 i = i + 1
107 }
108 res[0] = released
109 res[1] = skipped
110 res[2] = mono
111 res[3] = jb_target_delay(st)
112 res[4] = all_real
113 res[5] = lost_played
114 res[6] = inversions
115 return 0
116}
117
118func main() -> i64 {
119 gw("=== nx_jitter_buffer_gate: sovereign reorder + jitter-absorb + loss-conceal (WebRTC-class, from scratch) ===\n" as *u8)
120 let lo: *i64 = sys_mmap(8 * 8) as *i64
121 let hi: *i64 = sys_mmap(8 * 8) as *i64
122 run_trace(8000, 12345, lo) // mild jitter + injected reorders + 3 losses
123 run_trace(45000, 99991, hi) // heavy jitter
124
125 gw(" LOW-jitter : released=" as *u8); gn(lo[0]); gw(" skipped=" as *u8); gn(lo[1]); gw(" ordered=" as *u8); gn(lo[2])
126 gw(" all_real_played=" as *u8); gn(lo[4]); gw(" lost_played=" as *u8); gn(lo[5]); gw(" arrival_inversions=" as *u8); gn(lo[6]); gw(" target_delay=" as *u8); gn(lo[3]); gw("us\n" as *u8)
127 gw(" HIGH-jitter: released=" as *u8); gn(hi[0]); gw(" skipped=" as *u8); gn(hi[1]); gw(" ordered=" as *u8); gn(hi[2]); gw(" target_delay=" as *u8); gn(hi[3]); gw("us\n" as *u8)
128
129 var bad: i64 = 0
130 // clean run: ordered out, all real frames played, no lost frame played, exactly the 3 losses skipped
131 if lo[2] != 1 { bad = bad + 1; gw(" FAIL: output not in seq order\n" as *u8) }
132 if lo[4] != 1 { bad = bad + 1; gw(" FAIL: a real frame was never played\n" as *u8) }
133 if lo[5] != 0 { bad = bad + 1; gw(" FAIL: a lost frame was 'played' (phantom)\n" as *u8) }
134 if lo[0] != K - 3 { bad = bad + 1; gw(" FAIL: released != K-3 (not every real frame out once)\n" as *u8) }
135 if lo[1] != 3 { bad = bad + 1; gw(" FAIL: skip count != the 3 real losses\n" as *u8) }
136 // NEG-CONTROL: the arrival trace WAS out of order (else the buffer did nothing) -- injected reorders guarantee it
137 if lo[6] <= 0 { bad = bad + 1; gw(" FAIL: neg-control -- arrival trace was already ordered, buffer unproven\n" as *u8) }
138 // ADAPTIVE: heavy jitter deepens the buffer
139 if hi[3] <= lo[3] { bad = bad + 1; gw(" FAIL: playout delay did not adapt up under heavier jitter\n" as *u8) }
140 if hi[2] != 1 { bad = bad + 1; gw(" FAIL: high-jitter output not in seq order\n" as *u8) }
141
142 if bad == 0 { gw("JITTER-BUFFER-GATE verdict=GREEN -- reorders fixed, losses concealed, delay adaptive (arrival had " as *u8); gn(lo[6]); gw(" inversions, output had 0)\n" as *u8); return 0 }
143 gw("JITTER-BUFFER-GATE verdict=RED fails=" as *u8); gn(bad); gw("\n" as *u8)
144 return 1
145}