Retire legacy sources and verify managed iOS deployment
This commit is contained in:
@@ -1,194 +1,53 @@
|
||||
# CLAUDE.md — agent hub for VoiceCat
|
||||
# VoiceCat developer guide
|
||||
|
||||
Auto-loaded each session. This is the **map**: build commands, architecture at a glance, and
|
||||
where everything is. For the *working method* read [`AGENTS.md`](AGENTS.md); for *what's done
|
||||
and what's next* read [`PROGRESS.md`](PROGRESS.md); for *design* read [`docs/`](docs/).
|
||||
VoiceCat is a self-hosted encrypted voice and text chat system. The supported implementation
|
||||
is .NET 10. Read `AGENTS.md` for working rules and `PROGRESS.md` for the current short status.
|
||||
|
||||
> **One-line status:** M5 (moderation & admin UI) is complete — permissions, kick/ban/move,
|
||||
> server-mute, channel CRUD, in-app account management, disconnect/keepalive/reaper. Windows
|
||||
> WinForms C# client shipped (M4). **macOS AppKit client shipped** — `VoiceCatMac.xcodeproj`
|
||||
> at `clients/apple/macOS/`. **iOS SwiftUI client shipped** — `VoiceCatiOS.xcodeproj` at
|
||||
> `clients/apple/iOS/`. `ctest --preset dev` green — 29/29 tests.
|
||||
> External PCM feed/tap API (`vc_stream_feed_pcm` + `vc_set_pcm_sink`) shipped.
|
||||
> **Screen-audio sharing shipped on macOS (ScreenCaptureKit) and iOS (ReplayKit Broadcast
|
||||
> Upload Extension → host App Group ring → `vc_stream_feed_pcm`).**
|
||||
> The managed C# AppKit replacement now implements the Swift macOS feature surface and has a
|
||||
> validated ad-hoc Release bundle. Swift remains the release oracle until VoiceOver, live-call,
|
||||
> and credentialed notarization gates pass; see `clients/apple/dotnet/README.md`.
|
||||
> **Noise suppression shipped (RNNoise, vendored at `third_party/rnnoise/`)** — both send-side
|
||||
> mic NR (`vc_set_input_noise_reduction`) and per-listener receive NR; client on/off toggles ship
|
||||
on all three clients (receive NR now denoises stereo mic streams too — fixed 2026-06-23).
|
||||
> See [`PROGRESS.md`](PROGRESS.md).
|
||||
## Build and test
|
||||
|
||||
VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). TLS over TCP (control)
|
||||
+ UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives
|
||||
native clients (Swift on macOS/iOS, C# on Windows) and the server.
|
||||
|
||||
---
|
||||
|
||||
## Build & test commands
|
||||
|
||||
The .NET rewrite lives under `dotnet/`. Build and test its wire/crypto, TLS, codec/DSP, and managed control/UDP server slices
|
||||
alongside the existing C++ tree:
|
||||
|
||||
```powershell
|
||||
./dotnet/build-native.ps1 # CMake + C compiler; pinned Opus with DRED + RNNoise
|
||||
```bash
|
||||
./dotnet/build-native.ps1
|
||||
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
|
||||
./dotnet/check-licenses.ps1
|
||||
```
|
||||
|
||||
See `dotnet/README.md` for C# conventions and required native voice/CLI conformance,
|
||||
and `docs/api-dotnet.md` for managed interfaces. The managed server, CLI, audio/client core,
|
||||
Windows cutover, and macOS functional surface are implemented. The Windows and macOS apps
|
||||
contain only the permitted media shim. Accessibility/manual endurance validation, macOS
|
||||
notarization, the iOS rewrite, and broad server deployment work remain.
|
||||
|
||||
The default development preset is **`dev`** — it builds everything (server + tools + tests)
|
||||
with real vcpkg deps. The `skeleton` preset (no deps, stubs only) is a fast smoke check; see
|
||||
[`docs/building.md`](docs/building.md) for the full preset matrix.
|
||||
Apple client builds require macOS, Xcode, and the .NET macOS/iOS workloads:
|
||||
|
||||
```bash
|
||||
# Configure + build (default development preset; needs VCPKG_ROOT)
|
||||
cmake --preset dev
|
||||
cmake --build --preset dev
|
||||
|
||||
# Run the tests (21 behavior tests — grows per milestone)
|
||||
# NOTE on Windows: run ctest via PowerShell, NOT Git Bash — MinGW binaries fail in Git Bash
|
||||
# with exit 0xc0000139 (STATUS_ENTRYPOINT_NOT_FOUND). PowerShell runs them correctly.
|
||||
ctest --preset dev # or: ctest --test-dir build/dev --output-on-failure
|
||||
|
||||
# Run the binaries — same Windows rule: use PowerShell, not Git Bash
|
||||
./build/dev/bin/vccli # headless test client
|
||||
./build/dev/bin/voicecat-server --help
|
||||
./build/dev/bin/voicecat-server --name "My Server"
|
||||
|
||||
# Build a single target / be verbose
|
||||
cmake --build --preset dev --target vccli
|
||||
cmake --build --preset dev --verbose
|
||||
|
||||
# Clean
|
||||
rm -rf build/dev # nuke; or:
|
||||
cmake --build --preset dev --target clean
|
||||
./dotnet/build-native-ios.sh
|
||||
dotnet restore clients/apple/dotnet/VoiceCat.Apple.slnx
|
||||
dotnet build clients/apple/dotnet/VoiceCat.Apple.slnx -c Debug --no-restore
|
||||
```
|
||||
|
||||
Other presets (see [`docs/building.md`](docs/building.md) for full detail):
|
||||
Windows publishing uses `clients/windows/publish-client.ps1`. Server publishing uses
|
||||
`dotnet/publish-server.ps1`. See `docs/building.md` while it is being rewritten; prefer the
|
||||
scripts themselves when historical text disagrees with them.
|
||||
|
||||
```bash
|
||||
cmake --preset skeleton # no-deps stub smoke (no VCPKG_ROOT needed) — 2 tests
|
||||
cmake --preset release # optimized + tests on, symbols kept (profile/debug-friendly)
|
||||
cmake --preset server-release # optimized + stripped, no tests (deployment-shaped)
|
||||
cmake --preset windows-client # voicecat.dll for the C# WinForms client (Windows only)
|
||||
cmake --preset apple-dev # libvoicecat.a for macOS Swift Package (scaffolding, macOS only)
|
||||
```
|
||||
## Current architecture
|
||||
|
||||
Vcpkg triplet is auto-resolved from the host platform by
|
||||
[`cmake/voicecat-toolchain.cmake`](cmake/voicecat-toolchain.cmake) — `x64-mingw-static` on
|
||||
Windows, `x64-linux` on Linux, `arm64-osx` on Apple Silicon. See docs/building.md §1
|
||||
"Platform matrix" for details.
|
||||
- `proto/voicecat.proto` is the control-plane wire schema.
|
||||
- `dotnet/src/VoiceCat.Protocol` owns protobuf framing and generated types.
|
||||
- `dotnet/src/VoiceCat.Crypto` owns TLS, TOFU, media AEAD, identity, and password hashing.
|
||||
- `dotnet/src/VoiceCat.Server` owns the TLS/UDP server and SQLite state.
|
||||
- `dotnet/src/VoiceCat.Core` owns client connection and protocol state.
|
||||
- `dotnet/src/VoiceCat.Audio`, `.Codec`, and `.Dsp` own voice processing.
|
||||
- `dotnet/src/VoiceCat.Cli` is the supported headless client.
|
||||
- `clients/windows` is the WinForms client.
|
||||
- `clients/apple/dotnet` contains the AppKit and UIKit clients.
|
||||
- `native/media` and `native/rnnoise` are the required Opus/RNNoise native boundary.
|
||||
- `native/apple/broadcast` is the required Swift ReplayKit extension.
|
||||
|
||||
vcpkg is bundled as a git submodule at `vcpkg/`, pinned to the commit in `vcpkg.json`'s
|
||||
`builtin-baseline`. One-time setup after cloning:
|
||||
The old C++ implementation and old Swift applications are unsupported retirement sources.
|
||||
They are not architectural authorities and compatibility with them is not a requirement.
|
||||
|
||||
```bash
|
||||
git submodule update --init vcpkg
|
||||
./vcpkg/bootstrap-vcpkg.sh # .bat on Windows
|
||||
```
|
||||
## Invariants
|
||||
|
||||
To use an external vcpkg checkout instead (e.g. one shared across projects), set
|
||||
`VCPKG_ROOT` — it always takes priority over the bundled submodule:
|
||||
|
||||
```bash
|
||||
export VCPKG_ROOT=/path/to/vcpkg # works on Linux / macOS / Windows
|
||||
```
|
||||
|
||||
Other useful toggles (pass with `-D` at configure time):
|
||||
|
||||
```bash
|
||||
cmake --preset dev -DVOICECAT_BUILD_SHARED=ON # build libvoicecat as a .dll/.so/.dylib (for the C# client)
|
||||
cmake --preset dev -DVOICECAT_BUILD_SERVER=OFF # core + tools only
|
||||
cmake --preset dev -DVOICECAT_BUILD_TESTS=OFF
|
||||
```
|
||||
|
||||
Formatting: `clang-format` config is `.clang-format` (Google base, 100 cols, 4-space).
|
||||
|
||||
```bash
|
||||
git ls-files '*.cpp' '*.h' | xargs clang-format -i
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture at a glance
|
||||
|
||||
Full detail: [`docs/architecture.md`](docs/architecture.md). The short version:
|
||||
|
||||
```
|
||||
Swift (macOS/iOS) ─┐ ┌─ C# (Windows)
|
||||
├──▶ libvoicecat (C ABI: voicecat.h) ◀──┤
|
||||
voicecat-server ───┘ net · crypto · codec · protocol · └─ all UIs are thin
|
||||
(links core) session · audio the core owns audio
|
||||
```
|
||||
|
||||
- **One core, many faces.** Protocol, Opus, crypto, networking, jitter buffer, and mixing
|
||||
live once in C++. Clients call the **C ABI** (`core/include/voicecat.h`); the server links
|
||||
the same core, so framing/crypto never drift between ends.
|
||||
- **Two transports.** TCP + **TLS 1.3** (control, protobuf `Envelope`) and UDP + **exported-key
|
||||
ChaCha20-Poly1305 AEAD** (media, fixed binary voice frame). Encryption is mandatory.
|
||||
- **Threading.** Real-time audio threads never allocate/lock/block; they exchange data with
|
||||
the net thread via lock-free ring buffers; a worker pool absorbs blocking work.
|
||||
|
||||
### Subsystem map (code ↔ design doc)
|
||||
|
||||
| Path | Subsystem | Design |
|
||||
|------|-----------|--------|
|
||||
| `core/include/voicecat.h` | The C ABI (client/server contract) | architecture.md §4 |
|
||||
| `core/proto/voicecat.proto` | Control-plane wire format (source of truth) | protocol.md |
|
||||
| `core/src/net/` | Asio TCP/UDP transport, `[u32 len][payload]` framing | protocol.md §1, voice.md §2 |
|
||||
| `core/src/crypto/` | TLS 1.3 (mbedTLS), media AEAD (libsodium), anti-replay | security.md |
|
||||
| `core/src/codec/` | Opus encode/decode, FEC/DTX | voice.md §3–4 |
|
||||
| `core/src/protocol/` | Envelope (de)serialize, request/response, dispatch | protocol.md |
|
||||
| `core/src/session/` | Channels, users, streams, permissions, ephemeral text | protocol.md §5 |
|
||||
| `core/src/audio/` | miniaudio I/O, APM DSP, jitter buffer, mixer | voice.md §8–11 |
|
||||
| `core/src/core/` | `vc_client` — the handle behind the C ABI | architecture.md §4 |
|
||||
| `server/` | Connection mgr, session registry, SFU relay, SQLite | architecture.md §5 |
|
||||
| `tools/vccli/` | Headless client that drives/verifies the protocol | — |
|
||||
| `clients/apple/`, `clients/windows/` | Native GUIs (M4) | architecture.md §4 |
|
||||
|
||||
---
|
||||
|
||||
## Documentation index (source of truth)
|
||||
|
||||
Read [`docs/`](docs/) before changing behavior. Order:
|
||||
|
||||
1. [docs/README.md](docs/README.md) — overview, locked decisions, glossary
|
||||
2. [docs/architecture.md](docs/architecture.md) — core, C ABI, threading, server
|
||||
3. [docs/protocol.md](docs/protocol.md) — control plane, Envelope, message catalog
|
||||
4. [docs/voice.md](docs/voice.md) — UDP media, Opus, multi-stream, two-sided NR, VAD/PTT
|
||||
5. [docs/security.md](docs/security.md) — mandatory encryption, TLS+AEAD, accounts, threat model
|
||||
6. [docs/tech-stack.md](docs/tech-stack.md) — libraries, permissive-license rule, tooling
|
||||
7. [docs/deployment.md](docs/deployment.md) — zero-config self-host (Docker / binary / source)
|
||||
8. [docs/roadmap.md](docs/roadmap.md) — milestones + resolved decisions
|
||||
9. [docs/building.md](docs/building.md) — what each CMake preset is for + manual server/`vccli` testing
|
||||
|
||||
---
|
||||
|
||||
## Keeping track of progress
|
||||
|
||||
**[`PROGRESS.md`](PROGRESS.md) is the living status file.** When you finish a task, check it
|
||||
off there and note the next step, so the next agent can pick up instantly. Treat it as part of
|
||||
the work, not an afterthought — update it in the same commit as the code.
|
||||
|
||||
---
|
||||
|
||||
## House rules (hard constraints)
|
||||
|
||||
- **A clean compile is the floor, not the goal.** "Done" = the milestone's observable exit
|
||||
criterion in [`docs/roadmap.md`](docs/roadmap.md) passes (e.g. M1 = two `vccli` actually chat
|
||||
over TLS). Encode it as a test. See [`AGENTS.md`](AGENTS.md).
|
||||
- **No GPL/LGPL dependencies, ever** (closed-source redistribution is a goal). docs/tech-stack.md §5.
|
||||
- **Encryption is mandatory** — never add a plaintext transport path. docs/security.md.
|
||||
- **Real-time audio threads** never allocate, lock, or block. docs/architecture.md §3.
|
||||
- **Keep docs + code in sync.** Changing a wire format (`voicecat.proto`) or the C ABI
|
||||
(`voicecat.h`) is a deliberate, versioned act — update the doc in the same commit (protocol.md §8).
|
||||
- Every commit must build (`cmake --build --preset dev`) and pass `ctest --preset dev`.
|
||||
- TLS control and encrypted UDP media are mandatory; do not add plaintext transports.
|
||||
- No GPL or LGPL dependencies.
|
||||
- Audio callbacks must not allocate, lock, block, or perform network I/O.
|
||||
- Treat `proto/voicecat.proto`, persisted database formats, and the ReplayKit ring layout as
|
||||
explicit versioned contracts.
|
||||
- A passing build is not enough: add or update behavior tests for observable changes.
|
||||
- Keep `PROGRESS.md` concise; do not append a historical changelog.
|
||||
|
||||
Reference in New Issue
Block a user