2026-09-19 22:40:48 +02:00
|
|
|
# VoiceCat status
|
2026-06-15 21:09:09 +02:00
|
|
|
|
2026-09-25 12:27:27 +02:00
|
|
|
Updated: 2026-09-25
|
2026-06-15 21:09:09 +02:00
|
|
|
|
2026-09-19 22:40:48 +02:00
|
|
|
## Current state
|
2026-06-15 21:09:09 +02:00
|
|
|
|
2026-09-21 00:11:01 +02:00
|
|
|
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.
|
2026-06-15 21:09:09 +02:00
|
|
|
|
2026-09-21 00:11:01 +02:00
|
|
|
The source-of-truth layout is:
|
2026-06-15 21:09:09 +02:00
|
|
|
|
2026-09-19 22:40:48 +02:00
|
|
|
- `proto/voicecat.proto` — wire schema.
|
2026-09-21 00:11:01 +02:00
|
|
|
- `src/` — protocol, crypto, codec/DSP bindings, server, client core, audio, and CLI.
|
|
|
|
|
- `tests/VoiceCat.Tests/` — managed behavior and integration tests.
|
2026-09-19 22:40:48 +02:00
|
|
|
- `clients/windows/` — WinForms application over the managed core.
|
2026-09-21 00:11:01 +02:00
|
|
|
- `clients/apple/` — AppKit and UIKit applications over the managed core.
|
|
|
|
|
- `native/media/` and `native/rnnoise/` — required Opus/RNNoise shim and vendored RNNoise.
|
2026-09-19 22:40:48 +02:00
|
|
|
- `native/apple/broadcast/` — required ReplayKit upload extension and shared ring producer.
|
2026-09-19 15:43:37 +02:00
|
|
|
|
2026-09-21 18:04:00 +02:00
|
|
|
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
|
2026-09-25 12:27:27 +02:00
|
|
|
pattern constant. The voice-chat preset now leaves speaker routing off so a connected Bluetooth
|
|
|
|
|
headset can supply both input and output; speaker routing remains an explicit Advanced setting.
|
|
|
|
|
Device-selected inputs are not saved as preferences during route refresh. Bluetooth switching
|
|
|
|
|
still needs device validation.
|
2026-09-21 14:14:15 +02:00
|
|
|
|
2026-09-22 22:07:00 +02:00
|
|
|
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
|
2026-09-25 17:00:25 +02:00
|
|
|
same user and audio controls. Lists reload only when their rendered content actually changed and
|
|
|
|
|
only while on screen, and the 20 Hz microphone level is a separate signal from the general model
|
|
|
|
|
change, so VoiceOver explore mode no longer re-announces the row under a dragging finger or loses
|
|
|
|
|
the element a double tap was aimed at.
|
|
|
|
|
|
|
|
|
|
The iOS audio graph is rebuilt only when the audio configuration changed. A lost connection
|
|
|
|
|
unbinds the client but keeps the session, graph, and route alive, so a reconnect rebinds to a
|
2026-09-25 20:56:31 +02:00
|
|
|
live Bluetooth HFP link instead of renegotiating one, and foregrounding ensures the graph is
|
|
|
|
|
running rather than rebuilding it. The input side — input node, voice processing, and capture tap
|
|
|
|
|
— is built once per session rather than added when voice is joined, so joining and leaving voice
|
|
|
|
|
name a stream instead of replacing the graph. The input is rendered through a silent mixer,
|
|
|
|
|
because the voice-processing IO unit only stays up while the input is in the render chain. Route
|
|
|
|
|
changes no longer force a rebuild; media-services resets still do, and the stall watchdog now
|
|
|
|
|
backs off and stops after four failed attempts instead of rebuilding without end.
|
|
|
|
|
|
2026-09-26 20:30:24 +02:00
|
|
|
An explicit disconnect now pauses the prepared iOS graph and releases the audio session; the
|
|
|
|
|
next connection resumes that graph before attempting a rebuild. A signed iOS 26 simulator gate
|
|
|
|
|
verified guest-to-account editing, saved-password login after a process restart, two voice joins,
|
|
|
|
|
and a screen-audio stream started before the microphone. Screen sharing no longer forces a graph
|
|
|
|
|
rebuild, and its pump subscribes before announcing the stream. An idle shared broadcast ring is
|
|
|
|
|
no longer held mapped through suspension. A TestFlight report from build 2026092504 was an iOS
|
|
|
|
|
`0xdead10cc` shared-file-lock termination; physical-device validation of that mitigation remains
|
|
|
|
|
open.
|
|
|
|
|
|
2026-09-25 20:56:31 +02:00
|
|
|
Voice-chat capture is not yet reliable on the first attempt: a graph with voice processing still
|
|
|
|
|
sometimes fails to start and is only recovered by a watchdog rebuild, which costs seconds before
|
|
|
|
|
audio appears. Speaker output is an explicit choice that no longer changes the preset. Every
|
|
|
|
|
rebuild logs `VC_REBUILD cause=`, and `VC_START`/`VC_START_CHECK` record whether the graph
|
|
|
|
|
survived its start; that instrumentation is what the remaining investigation needs.
|
2026-09-22 22:07:00 +02:00
|
|
|
|
2026-09-24 19:15:16 +02:00
|
|
|
The media path now survives changing networks. A client whose source address changes proves
|
|
|
|
|
possession of its media key from the new address with an authenticated `Rebind` frame and the
|
|
|
|
|
relay moves its endpoint, instead of the session dying silently in both directions; the client
|
|
|
|
|
rebuilds its UDP socket rather than retrying on one pinned to a vanished interface. The control
|
|
|
|
|
connection is judged live by server traffic rather than assumed live, so a blackholed TCP path
|
2026-09-25 17:20:52 +02:00
|
|
|
is detected in 30 s instead of waiting minutes for the OS, and 12 s on iOS. iOS also watches the
|
|
|
|
|
system path and fails the control connection the moment the carrying interface changes, so a
|
|
|
|
|
handover reconnects in about a second instead of waiting out the silence timeout; access-point
|
|
|
|
|
roaming and an unusable-but-unchanged link are deliberately not handovers and are ridden out.
|
|
|
|
|
The first reconnect attempt is immediate, and a loss is only announced once an attempt has
|
|
|
|
|
actually failed, so a handover reads as a hiccup rather than a dropped call. A control reconnect
|
|
|
|
|
still re-authenticates and rejoins: seamless handover needs control-plane session resumption,
|
|
|
|
|
because the media keys come from the TLS exporter of the connection that was lost. The receive jitter buffer keeps a
|
2026-09-24 19:15:16 +02:00
|
|
|
one-frame depth floor, measures late and reordered arrivals, and can deepen mid-call, and a
|
|
|
|
|
stalled consumer now costs bounded audio rather than the live talkspurt.
|
|
|
|
|
|
2026-09-22 16:54:49 +02:00
|
|
|
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.
|
2026-09-22 14:11:36 +02:00
|
|
|
|
2026-09-19 22:40:48 +02:00
|
|
|
## Release gates
|
2026-09-19 00:39:04 +02:00
|
|
|
|
2026-09-25 20:56:31 +02:00
|
|
|
- Find why an iOS graph with voice processing intermittently starts and then stops within a
|
|
|
|
|
second, so voice-chat capture comes up on the first attempt rather than after a watchdog rebuild.
|
2026-09-26 20:30:24 +02:00
|
|
|
- On physical iOS 27 hardware, repeat account login after app restart, explicit disconnect and
|
|
|
|
|
reconnect, microphone permission denial, ReplayKit and ScreenCaptureKit sharing with and
|
|
|
|
|
without a joined microphone, and background/foreground transitions. Confirm the graph keeps
|
|
|
|
|
rendering and that `0xdead10cc` does not recur.
|
2026-09-20 16:25:30 +02:00
|
|
|
- Run real multi-person calls on Windows, macOS, and physical iOS hardware, including adaptive
|
2026-09-22 16:54:49 +02:00
|
|
|
20/40/60 ms buffering, duration-aware DRED/FEC, automatic packet-loss feedback, and mismatched
|
|
|
|
|
input/output endpoints.
|
2026-09-19 22:40:48 +02:00
|
|
|
- Complete NVDA and VoiceOver navigation/announcement passes.
|
2026-09-22 22:07:00 +02:00
|
|
|
- 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.
|
2026-09-19 22:40:48 +02:00
|
|
|
- Exercise iOS background/lock, interruption, Bluetooth, route-change, ReplayKit, and iOS 27
|
2026-09-23 21:37:24 +02:00
|
|
|
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`
|
2026-09-24 13:31:16 +02:00
|
|
|
counters (the render callback now paces the mix and the 20 ms capture handoff, and a watchdog
|
|
|
|
|
rebuilds a graph that stops calling back). Take a Siri or phone-call interruption while
|
|
|
|
|
backgrounded and confirm audio resumes without foregrounding. Complete a
|
2026-09-24 19:15:16 +02:00
|
|
|
30-minute iOS call and Wi-Fi/cellular switching with voice restoration (the switch is covered
|
|
|
|
|
by simulation in `NetworkImpairmentTests`; hardware confirms the real route change), plus extended
|
2026-09-23 21:37:24 +02:00
|
|
|
mono/stereo/voice-chat switching while joined. Verify Windows desktop/per-app stereo sharing.
|
2026-09-21 04:05:40 +02:00
|
|
|
- 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.
|
2026-09-19 22:40:48 +02:00
|
|
|
- Run the published Linux container and a 30-minute-or-longer server soak.
|
2026-09-16 17:34:16 +02:00
|
|
|
|
2026-09-19 22:40:48 +02:00
|
|
|
## Working rule
|
2026-09-16 16:48:06 +02:00
|
|
|
|
2026-09-21 00:11:01 +02:00
|
|
|
Keep this file short. It records only current state and open release gates. Git history is the
|
|
|
|
|
implementation diary.
|