code wiki / (root) / nx_nack.nx

nx_nack.nx source

↩ module page · 27 lines · 1834 B

1// nx_nack.nx -- SOVEREIGN NACK (negative-acknowledgement selective retransmit), the loss-recovery rung 2// that partners FEC + the jitter buffer. BENCHMARK: WebRTC's rtx/NACK -- when a frame is lost and FEC 3// can't cover it, the receiver ASKS for it again, but ONLY if a retransmit can still arrive before its 4// playout deadline (otherwise the request is wasted bandwidth). Built from scratch, pure integer, no third 5// party, transport-agnostic. The DECISION is the whole game: request iff (time-to-deadline >= one RTT + 6// a frame), rate-limited to one request per RTT (a retransmit can't have arrived sooner), capped at 7// NACK_MAX_RETRIES (give up, let concealment handle it -- no NACK storm). Sender keeps a small history 8// ring so it can honor requests. license_tier: ORIGINAL 9 10const NACK_MAX_RETRIES: i64 = 3 11 12// receiver: should we request retransmit of `seq` at time `now`? deadline = when it must be played out. 13func nack_should_request(seq: i64, now: i64, anchor_play: i64, anchor_seq: i64, frame_us: i64, 14 rtt_us: i64, retries: i64, last_nack: i64) -> i64 { 15 let deadline: i64 = anchor_play + (seq - anchor_seq) * frame_us 16 let ttl: i64 = deadline - now 17 if ttl < rtt_us + frame_us { return 0 } // a retransmit can't arrive in time -> don't waste it 18 if retries >= NACK_MAX_RETRIES { return 0 } // give up after N tries (conceal instead) 19 if retries > 0 { if now - last_nack < rtt_us { return 0 } } // one request per RTT max (no storm) 20 return 1 21} 22 23// sender history ring (seq -> present): put on send, query on NACK. 24func nack_hist_put(hist_seq: *i64, H: i64, seq: i64) -> i64 { hist_seq[seq % H] = seq; return 0 } 25func nack_hist_has(hist_seq: *i64, H: i64, seq: i64) -> i64 { if hist_seq[seq % H] == seq { return 1 } return 0 } 26 27func main() -> i64 { return 0 }