Add managed codec DSP and initial control server

This commit is contained in:
2026-09-15 22:51:33 +02:00
parent 2df79cdd4c
commit 4067bab7c2
52 changed files with 2503 additions and 20 deletions
+133
View File
@@ -10,6 +10,139 @@ up instantly. Newest status at the top.
## ▶ Where we left off / next action
- **In progress (2026-09-15): Phase 4 managed server control plane.** Added TLS socket
orchestration, bounded framing/queues, guest and password authentication, persisted
channels, state snapshots, channel joins, text routing, ping and disconnect events.
The existing C++ CLI authenticates and sends text through the managed server.
Managed Argon2id verification passes libsodium fixtures, including UTF-8 and embedded
NUL passwords. The C++ database oracle proves existing account/channel import and
C++ verification of managed-created accounts without password resets. **Verified:**
142/142 managed tests with all native interoperability checks enabled, warning-free
Release build, regenerated password fixtures identical, and 22 permissive package
licenses; native dev build and 29/29 CTest tests green. Locked restore passes.
CI requires CLI/database checks in its C++ conformance job. Codec/DSP and the first
server slice are committed together on `dotnet/foundations` as a validated checkpoint.
**Next:** encrypted UDP binding/SFU relay and stream signaling.
UDP voice, streams, administration, protected channel joins and production configuration
remain pending; this is the first control-plane checkpoint, not Phase 4 completion.
### .NET handoff / discoveries (2026-09-15)
- **Working tree:** stay on `dotnet/foundations`, tracking `origin/dotnet/foundations`.
Foundation `b76181d` and TLS checkpoint `2df79cd` were committed and pushed.
The codec/DSP port and first managed server checkpoint were subsequently committed
together, including new projects, native bindings/oracles, tests and docs.
See the latest checkpoint commit; no push is requested for this session.
- **Style/scope:** write idiomatic .NET in `dotnet/`; do not copy C++ code or comment
style. The existing implementation is the behavior/wire oracle. No wire changes
were made. Read `docs/porting-to-dotnet.md`, `docs/api-dotnet.md`, `dotnet/README.md`
and the relevant protocol/security/voice sections before the next subsystem.
- **Implemented projects:** `VoiceCat.Protocol` (existing protobuf + framing),
`VoiceCat.Crypto` (media crypto/replay, TLS/exporters, identity/TOFU, password hashing),
`VoiceCat.Codec` (Opus/PLC/DRED), `VoiceCat.Dsp` (RNNoise/energy VAD), and
`VoiceCat.Server` (real TLS control server + compatible SQLite account/channel store).
`dotnet/oracle/` contains optional native wire, TLS, DSP, password and database
conformance executables. `ServerTests` exercises real sockets and the existing CLI;
`AccountStoreTests` proves native database import and password verification both ways.
- **TLS discovery:** BouncyCastle destroys exporter secrets after its handshake
callback. Export keys inside `NotifyHandshakeComplete`, not after the socket loop
notices readiness. Preserve label `voicecat media v1` and contexts `[0]` / `[1]`.
A `TlsSession` has one owner; the control connection loop owns all TLS calls.
Certificate acceptance is a synchronous leaf-SHA256 pin gate, not normal PKI.
New certificates carry the Ed25519 public key in their SAN, but verification of
the ServerHello identity against that SAN remains pending. Partial credential
sets must fail rather than silently generate a new server identity.
- **Native codec discoveries:** the actual pinned Opus is **1.5.2**, despite older
design comments referring to 1.6. Standalone builds use checksum-pinned upstream
sources with DRED/Deep PLC enabled. DRED needs a **30 ms minimum** in this release;
20 ms produces no redundancy. DRED encoding at 8/12 kHz is explicitly unsupported;
decoding works at all five rates. Recovery offset defaults to one missing frame's
samples before the next packet's start (the older C++ zero offset is not a guide).
Fixed-signature C wrappers avoid the Apple ARM64 varargs ABI issue with Opus CTLs.
Windows DLL staging must omit the MinGW `lib` prefix. MinGW and MSVC builds pass;
iOS needs later static packaging. Device audio callbacks/rings are not implemented.
- **DSP behavior:** RNNoise processes complete 480-sample mono chunks at 48 kHz;
other rates pass through, and partial chunks at 48 kHz are rejected. Native C++
conformance allows one PCM unit for rounding. VAD hang time uses monotonic
`TimeProvider` timestamps, starts closed and does not replace noise suppression.
The combined allocation test proves zero managed allocations across 1,000 cycles.
- **Password/database discoveries:** use the existing BouncyCastle Argon2 engine
with strict libsodium PHC parsing; no additional Konscious dependency or password
reset is needed. Keep UTF-8 bytes unchanged, including embedded NUL. New hashes use
Argon2id v19, 64 MiB, two iterations, parallelism one, salt 16/output 32 bytes.
Verification is bounded to 128 MiB, ten iterations, parallelism four and 1024 UTF-8
password bytes; excessive imported costs fail closed. Two per-store password
workers bound CPU/memory use. Failed login does not update `last_login`.
Keep SQLite schema v2; accept v1 migration and reject unknown versions.
**Seed both default channels only when the entire channel table is empty**;
an existing single Lobby is an intentional configuration and must be preserved.
- **SQLite dependency discovery:** the initial `Microsoft.Data.Sqlite` 10.0.5 bundle
pulled an older vulnerable SQLite native dependency, rejected by warnings-as-errors
restore. The implementation uses `Microsoft.Data.Sqlite.Core` 10.0.5,
SQLitePCLRaw bundle 3.0.2 and explicitly pinned SourceGear SQLite 3.50.4.2 instead.
SourceGear's native package lacks a NuGet license expression; the audit has an
exact-version/repository-identity exception for its public-domain SQLite build.
NativeAOT publishing/trimming has not been verified for this solution.
- **Server checkpoint limits:** CLI binds loopback; positional arguments are data
directory and TCP port. Guests are enabled there, and the hosting API can disable
them. Accounts can be provisioned through `AccountStore` or native administration;
automatic bootstrap/admin CLI is pending. Authentication enters unprotected Lobby
id 1 subject to capacity. Server owns text sender ids/timestamps. Connections cap
at 64; queues cap at 32 incoming/64 outgoing envelopes, payloads at 64 KiB (shared
framer allows 16 MiB). Slow consumers disconnect. TLS handshake timeout is 15 s;
receive-idle timeout after handshake is 60 s. No UDP port/media features are
advertised, and voice subscription fails explicitly. Protected joins, channel CRUD,
streams, SFU, moderation/admin handlers, configuration compatibility and full reaper
behavior remain pending. **Do not mark Phase 4 or voice interoperability complete.**
To reproduce the last successful validation on Windows, run in **PowerShell**:
```powershell
./dotnet/build-native.ps1 -Generator Ninja -CCompiler C:/tools/msys64/ucrt64/bin/cc.exe
cmake --preset dev -DVOICECAT_BUILD_DOTNET_ORACLE=ON
cmake --build --preset dev
ctest --preset dev
dotnet restore dotnet/VoiceCat.slnx --locked-mode
$env:VOICECAT_TLS_ORACLE = (Resolve-Path build/dev/bin/voicecat-dotnet-tls-oracle.exe).Path
$env:VOICECAT_DATABASE_ORACLE = (Resolve-Path build/dev/bin/voicecat-dotnet-database-oracle.exe).Path
$env:VOICECAT_VCCLI = (Resolve-Path build/dev/bin/vccli.exe).Path
dotnet test dotnet/VoiceCat.slnx -c Release --no-restore
./dotnet/check-licenses.ps1
```
Last results: **142/142 managed tests, no skips with those variables set; 29/29 native
CTest tests; warning-free Release build; 22 package licenses approved; locked restore
and `git diff --check` passed.** Without the variables, native interoperability tests
skip; that is not equivalent verification. Desktop CI stages codec/DSP bindings on
Windows/Linux/macOS. Its Linux C++ job requires TLS, CLI and database interoperability
and regenerates wire/password/DSP fixtures. Only Windows was run locally this session.
**Next behavior to implement:** read `docs/protocol.md`, `docs/security.md` and the
existing UDP binding/relay/session handlers. Write a real-client test for authenticated
UDP binding and encrypted relay between two clients, preserving SSRC/timestamp/flags
and encoded Opus while resealing with each recipient's directional key/counter.
Then implement binding tokens, stream announce/stop/subscription and channel routing.
Reject unauthenticated/replayed media and verify channel/subscription isolation.
Never decode audio on the SFU. Phase 4 exits only when two existing C++ clients can
exchange voice through the managed server as well as authenticate, join and chat.
- **Done (2026-09-15): Codec/DSP desktop port.** TLS checkpoint `2df79cd` committed
and pushed to `origin/dotnet/foundations`. Added span-based Opus wrappers, safe native
handle ownership, RNNoise processing, monotonic energy VAD, and fixed-signature
native bindings. Round-trip/PLC behavior passes across 40 supported formats with
the existing Opus build. Independent native staging builds checksum-pinned upstream
Opus 1.5.2 with DRED enabled and the existing RNNoise model. Actual dropped-frame
DRED recovery passes across 40 decoder formats; DRED encoding at 8/12 kHz is
explicitly rejected (tests encode those packets at 16 kHz). This release requires
a 30 ms redundancy floor; the older 20 ms setting emits no DRED. C++ denoising
conformance is within one PCM unit, and 1,000 codec/DSP cycles allocate zero managed
bytes. **Verified:** Release build with no warnings; 127/127 managed tests with
native TLS interoperability enabled; native dev build and 29/29 CTest tests green;
16 permissive NuGet licenses. MinGW and Visual Studio native builds pass. Desktop
CI now builds/stages the bindings before testing. iOS static packaging and device
audio remain later phases. **Next:** Phase 4 managed server; prove persisted
libsodium Argon2id hash compatibility before account/database implementation.
- **Done (2026-09-15): TLS exporter interoperability and persisted credentials.** Foundation commit
`b76181d` pushed to `origin/dotnet/foundations`. Added a nonblocking managed TLS 1.3
session with certificate acceptance gate and directional media factories. Managed