6.7 KiB
VoiceCat .NET rewrite
The first slice targets .NET 10: protobuf, control framing, voice headers, and media encryption, TLS 1.3, persisted TOFU pins, server credentials, and an initial managed control server. Media relay, client state, audio, and UI migration are next. The existing C++ implementation remains the conformance oracle.
Codec/DSP wrappers now cover Opus, DRED recovery, RNNoise, and energy VAD. Build the desktop native library before running their tests (CMake and a C compiler required):
./dotnet/build-native.ps1
The script downloads upstream Opus 1.5.2 with a pinned SHA-256, builds DRED-enabled
Opus and the existing vendored RNNoise model, and stages voicecat_media plus license
notices under dotnet/artifacts/native/. It builds independently of the C++ core and
vcpkg. On Windows, Visual Studio's C++ workload works with the default generator;
for this repository's MinGW toolchain use:
./dotnet/build-native.ps1 -Generator Ninja -CCompiler C:/tools/msys64/ucrt64/bin/cc.exe
Linux/macOS can run the same script with PowerShell, or use CMake directly:
cmake -S dotnet/native -B dotnet/artifacts/native-build -DCMAKE_BUILD_TYPE=Release
cmake --build dotnet/artifacts/native-build --target voicecat_media --parallel 2
cmake --install dotnet/artifacts/native-build --component DotnetMedia --prefix dotnet/artifacts/native
MSBuild copies the staged library into managed build/publish output for the selected
RID. Override VoiceCatNativeRid or VoiceCatNativeDirectory for explicit staging;
RuntimeIdentifier takes priority over the SDK's host RID. Cross-compilation is not
automatic. iOS static linking and audio-device shims belong to later client phases.
Native codec/DSP tests require this library; they do not silently skip.
From the repository root:
dotnet restore dotnet/VoiceCat.slnx --locked-mode
dotnet build dotnet/VoiceCat.slnx -c Release --no-restore
dotnet test dotnet/VoiceCat.slnx -c Release --no-build
Dependencies are pinned in project files and lock files. Generated protobuf is build
output; the schema remains core/proto/voicecat.proto. Production dependencies are
Google.Protobuf (BSD-3-Clause), BouncyCastle.Cryptography (MIT), and the build-only
Grpc.Tools (Apache-2.0). No GPL/LGPL dependencies are permitted.
C# conventions
Use file-scoped namespaces, standard .NET naming, immutable values where useful, and spans for binary data. Invalid arguments throw; invalid network packets use parsing results or protocol exceptions. Async APIs accept cancellation tokens.
Comments explain constraints that cannot be made clear in code. Avoid banners,
implementation history, and narration. Keep durable design explanations in docs/.
Regenerating C++ fixtures
The optional oracle target calls the existing C++ protobuf, header serializer, and libsodium media implementation. From the root, with the development dependencies:
cmake --preset dev -DVOICECAT_BUILD_DOTNET_ORACLE=ON
cmake --build --preset dev --target voicecat-dotnet-oracle
New-Item -ItemType Directory -Force dotnet/tests/VoiceCat.Tests/Fixtures
./build/dev/bin/voicecat-dotnet-oracle.exe dotnet/tests/VoiceCat.Tests/Fixtures/cpp-wire.json
git diff -- dotnet/tests/VoiceCat.Tests/Fixtures/cpp-wire.json
On Linux/macOS, omit .exe and create the directory with mkdir -p.
The oracle writes deterministic JSON directly, avoiding shell output encoding.
Fixtures contain a framed ClientHello and media packets at counters 0, 1, 65535,
and 65536. Keys contain bytes 0–31; payload bytes count upward from zero. The
20-byte header has type 1, marker flag, codec 0, SSRC 0xcafebabe, timestamp 960.
Both managed crypto backends must match these bytes.
The DSP oracle calls the existing C++ ApmProcessor with 200 deterministic noise
frames and records the final 960 samples. Regenerate its fixture with:
cmake --build --preset dev --target voicecat-dotnet-dsp-oracle
./build/dev/bin/voicecat-dotnet-dsp-oracle.exe dotnet/tests/VoiceCat.Tests/Fixtures/cpp-noise.json
The managed test allows a one-unit PCM difference for floating-point rounding.
TLS interoperability
The optional TLS oracle uses the existing mbedTLS context and libsodium media crypto. The test authenticates an encrypted challenge in both directions, proving exporter compatibility without sending raw keys. It also loads the C++ server's credential files.
cmake --build --preset dev --target voicecat-dotnet-tls-oracle
$env:VOICECAT_TLS_ORACLE = (Resolve-Path build/dev/bin/voicecat-dotnet-tls-oracle.exe).Path
dotnet test dotnet/VoiceCat.slnx -c Release --no-restore
On Linux/macOS, set VOICECAT_TLS_ORACLE to the absolute executable path without
.exe. Without that variable, only this native interoperability test is skipped;
managed TLS loopback, rejection, persistence, and wire tests still run. CI's C++
conformance job requires the native test. See docs/api-dotnet.md for ownership
and certificate acceptance requirements.
Managed server checkpoint
Run the TLS control server on loopback (optional arguments: data directory, TCP port):
dotnet run --project dotnet/src/VoiceCat.Server -c Release -- ./voicecat-data 7443
./build/dev/bin/vccli.exe --host 127.0.0.1 --port 7443 --nick Guest --text "hello"
It creates or imports server_identity.key, server.crt, server.key, and
voicecat.db. An empty channel table gets Lobby and Music Room; existing channels
are preserved. Guests are enabled by the CLI; hosting VoiceServer directly can
disable them. Existing accounts authenticate without resetting passwords. Account
creation is currently available through AccountStore; bootstrap/admin CLI and
wire administration are pending.
Tests cover real TLS sockets, authentication retries, snapshots, channel moves, text routing, sender attribution, ping, and disconnect events. Enable native checks:
cmake --build --preset dev --target voicecat-dotnet-password-oracle voicecat-dotnet-database-oracle vccli
$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
The database oracle creates an account/channel using the shipped C++ database code;
managed code imports and authenticates it, then C++ authenticates a managed-created
account. CI also regenerates the libsodium password fixture. Native checks require
the optional VOICECAT_BUILD_DOTNET_ORACLE=ON configure flag and a real-deps build.
Phase 4 remains in progress: UDP/SFU relay, streams, protected channel joins, administration, moderation, and production configuration are the next server work.