Sleep-paced threads stall for hundreds of milliseconds when iOS coalesces a backgrounded app's wakeups, and the deadline resets that discarded the deficit left the capture backlog queued until its ring overflowed: regular dropouts that worsen the longer the app stays backgrounded. Pace both 20 ms hands-offs from the AVAudioSourceNode render callback instead (mix via Audio.RunCycle with deviceClockedAudio, capture handoff from the ring), wake the UDP sender on a queue signal instead of a 1 ms poll, and let stalled consumers drop their backlog to the buffer target instead of ratcheting it.
58 lines
3.2 KiB
Markdown
58 lines
3.2 KiB
Markdown
# VoiceCat status
|
|
|
|
Updated: 2026-09-22
|
|
|
|
## Current state
|
|
|
|
VoiceCat's supported implementation is .NET 10. The managed protocol, crypto, TLS, server,
|
|
CLI, client state, audio engine, Windows client, macOS client, and iOS client are implemented.
|
|
Retired implementations and compatibility projects have been removed; this tree contains only
|
|
the supported product and its required native media boundaries.
|
|
|
|
The source-of-truth layout is:
|
|
|
|
- `proto/voicecat.proto` — wire schema.
|
|
- `src/` — protocol, crypto, codec/DSP bindings, server, client core, audio, and CLI.
|
|
- `tests/VoiceCat.Tests/` — managed behavior and integration tests.
|
|
- `clients/windows/` — WinForms application over the managed core.
|
|
- `clients/apple/` — AppKit and UIKit applications over the managed core.
|
|
- `native/media/` and `native/rnnoise/` — required Opus/RNNoise shim and vendored RNNoise.
|
|
- `native/apple/broadcast/` — required ReplayKit upload extension and shared ring producer.
|
|
|
|
The physical-device iOS voice path now supports ReplayKit fallback, stable Apple VPIO voice-chat
|
|
capture using a paced 20 ms handoff, and true built-in stereo microphone capture. Stereo was
|
|
verified on an iPhone 16 Pro Max with a two-channel AVAudioEngine input and distinct left/right
|
|
samples; the managed Apple binding requires native use of its otherwise-unmapped stereo polar
|
|
pattern constant.
|
|
|
|
The iOS user list now opens a remote-user detail view with independent tuning for each active
|
|
audio stream. Private messages are grouped into per-user conversations with direct access to the
|
|
same user and audio controls.
|
|
|
|
SQLite schema v4 persists DRED and the channel packet-loss mode. Manual loss remains the default;
|
|
automatic Fast/Balanced/Stable modes measure each sender's authenticated UDP uplink at the server,
|
|
cap the applied Opus hint at 30%, and feed it back over TLS.
|
|
|
|
## Release gates
|
|
|
|
- Run real multi-person calls on Windows, macOS, and physical iOS hardware, including adaptive
|
|
20/40/60 ms buffering, duration-aware DRED/FEC, automatic packet-loss feedback, and mismatched
|
|
input/output endpoints.
|
|
- Complete NVDA and VoiceOver navigation/announcement passes.
|
|
- Verify iOS remote-user tuning and private-conversation navigation with VoiceOver, including
|
|
multiple streams, users without active streams, and users who disconnect while a view is open.
|
|
- Exercise iOS background/lock, interruption, Bluetooth, route-change, ReplayKit, and iOS 27
|
|
ScreenCaptureKit paths on devices. The background/lock gate keeps a call active for 15+ minutes
|
|
backgrounded and screen-locked with no periodic glitches and flat `VC_AUDIO` `feedDrops`/`starved`
|
|
counters (the render callback now paces the mix and the 20 ms capture handoff). Complete a
|
|
30-minute iOS call and Wi-Fi/cellular switching with voice restoration, plus extended
|
|
mono/stereo/voice-chat switching while joined. Verify Windows desktop/per-app stereo sharing.
|
|
- Complete Developer ID signing/notarization. The iOS host and ReplayKit extension have been
|
|
distribution-signed and packaged locally; upload the IPA for Apple's server-side validation.
|
|
- Run the published Linux container and a 30-minute-or-longer server soak.
|
|
|
|
## Working rule
|
|
|
|
Keep this file short. It records only current state and open release gates. Git history is the
|
|
implementation diary.
|