38 lines
2.4 KiB
Markdown
38 lines
2.4 KiB
Markdown
# Group call: WASM Opus FEC / PLC decode path
|
|
|
|
Receive-side decoding can use **libopus** in a dedicated Worker (`gcall-opus-fec.worker.ts`) so **PLC** (zero-length decode) and **in-band FEC** (`decode_fec = 1`) match the encoder when the browser sends FEC (`useinbandfec` in `useGroupVoiceCall`).
|
|
|
|
## Build (only if you change the native wrapper)
|
|
|
|
The app **always tries** the WASM FEC decode path in group calls. The prebuilt bundle is committed at `src/wasm-libopus-fec/libopus-fec.js`. Rebuild only after editing `native/libopus-fec-wasm/` (requires [emsdk](https://emscripten.org/docs/getting_started/downloads.html) at repo root `.emsdk/`):
|
|
|
|
```bash
|
|
./native/libopus-fec-wasm/build.sh
|
|
```
|
|
|
|
If the worker or WASM fails to initialize, the hook **falls back** to **WebCodecs `AudioDecoder`** (no libopus FEC control).
|
|
|
|
**Emergency disable** (debugging only): `VITE_GCALL_WASM_FEC=0` in `.env`, or `localStorage.setItem('gcallWasmFec','0')` then reload.
|
|
|
|
## Behaviour
|
|
|
|
- **+1 frame jitter hold** when the flag is desired (see `JitterBuffer` extra hold), so the next packet is more often present before decode (FEC window).
|
|
- **PLC/FEC sequence** per pop matches the plan: PLC for early burst losses, then FEC + normal on the same packet with **separate PCM buffers**.
|
|
- **`MAX_PCM_FRAMES_PER_TICK`**: excess PCM is deferred to the next scheduler tick (see `GCALL_WASM_FEC_MAX_PCM_PER_TICK`).
|
|
- **Large seq gap** (`> 32`): worker decoder is reset before processing.
|
|
- **Metrics**: `GroupCallPerformanceTracker` records `wasmFecPlcFrames`, `wasmFecAttempts`, `wasmFecSuccessCoarse` (coarse heuristic), `wasmFecDeferredPcmTicks` on the snapshot and per-source window metrics.
|
|
|
|
## Manual verification
|
|
|
|
1. Two clients on a group call with WASM path enabled.
|
|
2. Confirm sender path: `groupCallWindowMetrics` / logs should show encoder FEC when `AudioEncoder.isConfigSupported` accepts `useinbandfec`.
|
|
3. Induce loss (throttle network or drop packets in a test build) and compare concealment / missing-frame stats with flag on vs off.
|
|
4. Inspect snapshot: `wasmFecAttempts` and `wasmFecSuccessCoarse` should move under loss; `fecSuccessCoarse` is approximate (non-zero energy after FEC decode).
|
|
|
|
## Files
|
|
|
|
- `native/libopus-fec-wasm/` — C wrapper + `build.sh`
|
|
- `src/wasm-libopus-fec/libopus-fec.js` — generated bundle
|
|
- `src/workers/gcall-opus-fec.worker.ts` — decode worker
|
|
- `src/hooks/useGroupVoiceCall.ts` — jitter drain, worker wiring, metrics
|