Call-audiobron: per-track gedecodeerde PCM via eigen flutter_webrtc-fork (#2527) #2595

Merged
brenno merged 1 commit from feat/call-audio-tap-2527 into main 2026-10-26 19:58:55 +00:00
Owner

Summary

  • Fork-binding: audioTrackFrames(track) in de LibreKAT-fork van flutter_webrtc (pin b82f0db, gemerged in fork-main via LibreKAT/flutter_webrtc#1). Darwin: remote via het publieke RTCAudioRenderer-protocol, lokaal via LocalAudioTrack's APM-renderer (capture-pad). Web: ScriptProcessorNode op elk jsTrack achter een dempknooppunt — de tap speelt niets af. Upstream-patch: flutter-webrtc/flutter-webrtc#2250.
  • OciDeck-naad: openCallAudioCapture(fact, taps) met een concurrente merge — asyncExpand pauzeert de taps-bron zolang een framestroom loopt, dus een remote tap zou daarmee nooit openen; eigen merge met één subscription per tap. Resample naar 16k mono, post-mute onderdrukking in de tap zelf (gemute track → géén frames, on-wire-contract).
  • Sessie stempelt participantId via de roster; provider krijgt CallAudioGate + onDone→fout (een dode tap mag niet als stille leugen doorstaan); UI toont live Ontvangen brokken: n — telt, schrijft niets weg.
  • Eerlijk: wholeCall wordt alleen geclaimd op macOS en web. Windows, Linux, iOS en Android melden noPerSourceTap tot een echte proef het tegendeel zegt — geen dode opnameknop.

Bewaakte waarden

  • Botsing benoemd: een eigen fork onderhouden (waarde 6) tegen de functie zelf — de fork is de enige eerlijke route (de binding kon het niet), is inspecteerbaar op eigen forge en de uitgang staat open via de ingediende upstream-patch; landt die, dan gaat de override weg.
  • Geen .md-formaat-, opslag- of egress-wijziging: PCM blijft in-proces, ASR-forwarding blijft achter de aparte toestemming.

Bewijs (echte tweepersoonscalls, Jitsi-testbed stable-11248)

  • macOS (integration_test/jitsi_audio_tap_test.dart, echte libwebrtc + solo.js-tegenpartij): TAP-PROEF remote=6 local=6 remoteMaxAmp=9 mutedLocal=0 unmuteLocal=400 — remote gedecodeerde PCM met amplitude, lokale frames stoppen bij dempen en hervatten, tijdstempels monotoon per bron.
  • web (echte Chrome + Playwright, gebouwde bundle): ~13 brok/s remote-only gedempt → ~23/s na unmute (lokaal erbij) → ~12/s na re-mute; rode opname-indicator en live teller zichtbaar in probe-out screenshots.

Test plan

  • make check groen op commit 35dce9d17 (format, analyze --fatal-infos, ~14,7k tests, coverage 86,5%, per-file floor, goldens)
  • make check-secrets + make sast groen
  • echte macOS-proef + echte web-proef
  • Windows/Linux/iOS/Android: geen claim — volgt pas na echte proef per platform

Generated with Devin

## Summary - **Fork-binding**: `audioTrackFrames(track)` in de LibreKAT-fork van `flutter_webrtc` (pin `b82f0db`, gemerged in fork-main via LibreKAT/flutter_webrtc#1). Darwin: remote via het publieke `RTCAudioRenderer`-protocol, lokaal via `LocalAudioTrack`'s APM-renderer (capture-pad). Web: `ScriptProcessorNode` op elk jsTrack achter een dempknooppunt — de tap speelt niets af. Upstream-patch: flutter-webrtc/flutter-webrtc#2250. - **OciDeck-naad**: `openCallAudioCapture(fact, taps)` met een *concurrente* merge — `asyncExpand` pauzeert de taps-bron zolang een framestroom loopt, dus een remote tap zou daarmee nooit openen; eigen merge met één subscription per tap. Resample naar 16k mono, post-mute onderdrukking in de tap zelf (gemute track → géén frames, on-wire-contract). - **Sessie** stempelt participantId via de roster; **provider** krijgt `CallAudioGate` + `onDone`→fout (een dode tap mag niet als stille leugen doorstaan); **UI** toont live `Ontvangen brokken: n` — telt, schrijft niets weg. - **Eerlijk**: `wholeCall` wordt alleen geclaimd op macOS en web. Windows, Linux, iOS en Android melden `noPerSourceTap` tot een echte proef het tegendeel zegt — geen dode opnameknop. ## Bewaakte waarden - Botsing benoemd: een eigen fork onderhouden (waarde 6) tegen de functie zelf — de fork is de enige eerlijke route (de binding kon het niet), is inspecteerbaar op eigen forge en de uitgang staat open via de ingediende upstream-patch; landt die, dan gaat de override weg. - Geen `.md`-formaat-, opslag- of egress-wijziging: PCM blijft in-proces, ASR-forwarding blijft achter de aparte toestemming. ## Bewijs (echte tweepersoonscalls, Jitsi-testbed stable-11248) - **macOS** (`integration_test/jitsi_audio_tap_test.dart`, echte libwebrtc + solo.js-tegenpartij): `TAP-PROEF remote=6 local=6 remoteMaxAmp=9 mutedLocal=0 unmuteLocal=400` — remote gedecodeerde PCM met amplitude, lokale frames stoppen bij dempen en hervatten, tijdstempels monotoon per bron. - **web** (echte Chrome + Playwright, gebouwde bundle): ~13 brok/s remote-only gedempt → ~23/s na unmute (lokaal erbij) → ~12/s na re-mute; rode opname-indicator en live teller zichtbaar in probe-out screenshots. #### Test plan - [x] `make check` groen op commit 35dce9d17 (format, analyze --fatal-infos, ~14,7k tests, coverage 86,5%, per-file floor, goldens) - [x] `make check-secrets` + `make sast` groen - [x] echte macOS-proef + echte web-proef - [ ] Windows/Linux/iOS/Android: geen claim — volgt pas na echte proef per platform Generated with [Devin](https://devin.ai)
De huidige binding kan geen aparte, gedecodeerde samples per bron leveren —
MediaRecorder schrijft een INPUT/OUTPUT-mix. De LibreKAT-fork voegt daarom
`audioTrackFrames(track)` toe: op Darwin remote via het publieke
RTCAudioRenderer-protocol en lokaal via de APM-renderer van LocalAudioTrack,
op web via een ScriptProcessorNode op elk jsTrack achter een dempknooppunt.

De sessie stempelt participantId via de roster, de adapter resampled naar
16k mono en de merge is concurrent (asyncExpand pauzeert de taps-bron — een
remote tap zou dan nooit openen). Post-mute onderdrukking zit in de tap
zelf: een gemute track levert geen frames.

Bewezen in echte tweepersoonscalls: macOS-integratietest (remote PCM met
amplitude, lokale frames stoppen bij dempen en hervatten; TAP-PROEF
remote=6 local=6 mutedLocal=0 unmuteLocal=400) en web in echte Chrome
(brokken-teller ~13/s remote-only gedempt, ~23/s na unmute, ~12/s na
re-mute). Windows, Linux, iOS en Android claimen niets — de binding meldt
daar eerlijk noPerSourceTap.

Upstream-patch ingediend als flutter-webrtc/flutter-webrtc#2250.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
brenno force-pushed feat/call-audio-tap-2527 from a7e3016a32 to 35dce9d179 2026-10-26 19:58:40 +00:00 Compare
brenno merged commit cb597ae8ce into main 2026-10-26 19:58:55 +00:00
Sign in to join this conversation.
No description provided.