build(cmake): clean up presets, add release/apple presets, cross-platform triplets

Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework

Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.

Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
This commit is contained in:
2026-06-18 03:16:01 +02:00
parent d397731db9
commit bcb7ae8ccb
23 changed files with 454 additions and 144 deletions

View File

@@ -11,9 +11,11 @@ Read those, then use the method below.
## What this repo is right now ## What this repo is right now
A complete **design** ([`docs/`](docs/)) plus an **M0 skeleton**: it compiles and links, but A complete **design** ([`docs/`](docs/)) plus a working implementation through M5: real TLS
`libvoicecat`'s subsystems are stubs that return `VC_ERR_NOT_IMPLEMENTED`. Your job is to turn control plane, encrypted UDP voice (Opus), multi-stream, TOFU identity pinning, channel tree,
the design into working software, one milestone at a time. permissions, moderation, disconnect/keepalive/reaper. The Windows WinForms C# client is
shipped (M4). The macOS/iOS Swift client is next. The `skeleton` preset still links a
no-deps stub path (`VC_ERR_NOT_IMPLEMENTED`) for smoke-check builds.
## The working method (important) ## The working method (important)
@@ -36,24 +38,31 @@ making progress.
## Build ## Build
Skeleton (no third-party deps — works immediately): Default development preset (real deps via vcpkg — works on Windows/Linux/macOS):
```bash ```bash
export VCPKG_ROOT=/path/to/vcpkg # bootstrap vcpkg first; cross-platform
cmake --preset dev cmake --preset dev
cmake --build --preset dev cmake --build --preset dev
ctest --preset dev ctest --preset dev
``` ```
When a subsystem needs real libraries, turn on vcpkg deps: Skeleton (no third-party deps — works immediately, no vcpkg needed):
```bash ```bash
export VCPKG_ROOT=/path/to/vcpkg # bootstrap vcpkg first; cross-platform cmake --preset skeleton
cmake --preset server-release # installs deps pinned in vcpkg.json cmake --build --preset skeleton
cmake --build --preset server-release ctest --preset skeleton
``` ```
`vcpkg.json` currently has a placeholder `builtin-baseline` — set it to a real vcpkg commit Other presets: `release` (optimized + tests), `server-release` (optimized + stripped,
SHA the first time you enable `VOICECAT_USE_VCPKG_DEPS`. deployment-shaped), `windows-client` (DLL for C# app), `apple-dev`/`apple-ios`/
`apple-ios-sim` (Apple platform scaffolding). See [`docs/building.md`](docs/building.md)
for the full matrix.
`vcpkg.json` pins all deps to a fixed vcpkg baseline — `cmake --preset dev` resolves them
automatically on first configure. The vcpkg triplet is auto-resolved from the host platform
by [`cmake/voicecat-toolchain.cmake`](cmake/voicecat-toolchain.cmake).
## Where each subsystem lives (and its doc) ## Where each subsystem lives (and its doc)

View File

@@ -4,11 +4,10 @@ Auto-loaded each session. This is the **map**: build commands, architecture at a
where everything is. For the *working method* read [`AGENTS.md`](AGENTS.md); for *what's done 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/). and what's next* read [`PROGRESS.md`](PROGRESS.md); for *design* read [`docs/`](docs/).
> **One-line status:** M4 (Windows WinForms C# client) is complete — connect, saved servers, > **One-line status:** M5 (moderation & admin UI) is complete — permissions, kick/ban/move,
> TOFU identity pinning, channel tree, voice (VAD/PTT/always-on + VAD threshold slider + > server-mute, channel CRUD, in-app account management, disconnect/keepalive/reaper. Windows
> per-user tuning), text chat, device pickers, level meters. `ctest --preset m1-dev` green — > WinForms C# client is shipped (M4). `ctest --preset dev` green — 21/21 tests. macOS/iOS
> 14/14 tests. `dotnet build` green — 0 warnings. macOS/iOS Swift client and M5 (moderation) > Swift client is next. See [`PROGRESS.md`](PROGRESS.md).
> are next. See [`PROGRESS.md`](PROGRESS.md).
VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). Plain TCP (control) VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). Plain TCP (control)
+ UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives + UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives
@@ -18,15 +17,16 @@ native clients (Swift on macOS/iOS, C# on Windows) and the server.
## Build & test commands ## Build & test commands
The **M0 skeleton builds with no third-party dependencies** — just CMake + Ninja + a C++20 The default development preset is **`dev`** — it builds everything (server + tools + tests)
compiler. Deps (vcpkg) are off until a subsystem needs them. 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.
```bash ```bash
# Configure + build the skeleton (default; no vcpkg needed) # Configure + build (default development preset; needs VCPKG_ROOT)
cmake --preset dev cmake --preset dev
cmake --build --preset dev cmake --build --preset dev
# Run the tests (behavior smoke test today; grows per milestone) # Run the tests (21 behavior tests — grows per milestone)
ctest --preset dev # or: ctest --test-dir build/dev --output-on-failure ctest --preset dev # or: ctest --test-dir build/dev --output-on-failure
# Run the binaries (Windows adds .exe; Linux/macOS no extension) # Run the binaries (Windows adds .exe; Linux/macOS no extension)
@@ -43,14 +43,26 @@ rm -rf build/dev # nuke; or:
cmake --build --preset dev --target clean cmake --build --preset dev --target clean
``` ```
When you start a subsystem that needs real libraries (mbedTLS, libsodium, opus, protobuf, …), Other presets (see [`docs/building.md`](docs/building.md) for full detail):
turn vcpkg deps on:
```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)
```
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.
One-time vcpkg setup:
```bash ```bash
# one-time: git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh (.bat on Windows) # one-time: git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh (.bat on Windows)
export VCPKG_ROOT=/path/to/vcpkg # works on Linux / macOS / Windows export VCPKG_ROOT=/path/to/vcpkg # works on Linux / macOS / Windows
cmake --preset server-release # auto-installs deps pinned in vcpkg.json
cmake --build --preset server-release
``` ```
Other useful toggles (pass with `-D` at configure time): Other useful toggles (pass with `-D` at configure time):

View File

@@ -3,93 +3,137 @@
"cmakeMinimumRequired": { "major": 3, "minor": 25, "patch": 0 }, "cmakeMinimumRequired": { "major": 3, "minor": 25, "patch": 0 },
"configurePresets": [ "configurePresets": [
{ {
"name": "dev", "name": "vcpkg-common",
"displayName": "Dev (skeleton, no third-party deps)", "hidden": true,
"description": "Builds the stub skeleton with just a compiler. Works out of the box; no vcpkg required.", "description": "Shared base for all presets that link real deps via vcpkg. Uses cmake/voicecat-toolchain.cmake, which auto-resolves VCPKG_TARGET_TRIPLET / VCPKG_HOST_TRIPLET from the host platform (x64-mingw-static on Windows, x64-linux on Linux, arm64-osx on Apple Silicon). Cross-compile presets override VCPKG_TARGET_TRIPLET in their cacheVariables. Requires VCPKG_ROOT in the environment.",
"generator": "Ninja", "generator": "Ninja",
"binaryDir": "${sourceDir}/build/dev", "toolchainFile": "${sourceDir}/cmake/voicecat-toolchain.cmake",
"cacheVariables": {
"VOICECAT_USE_VCPKG_DEPS": "ON"
}
},
{
"name": "skeleton",
"displayName": "Skeleton (no third-party deps)",
"description": "Builds the stub skeleton with just a C++20 compiler — no vcpkg needed. Subsystems return VC_ERR_NOT_IMPLEMENTED. Good for 'does the repo even build' smoke checks. Runs 2 tests (smoke + frame_codec).",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/skeleton",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug", "CMAKE_BUILD_TYPE": "Debug",
"VOICECAT_USE_VCPKG_DEPS": "OFF" "VOICECAT_USE_VCPKG_DEPS": "OFF"
} }
}, },
{ {
"name": "vcpkg-base", "name": "dev",
"hidden": true, "displayName": "Dev (full real-deps build, vcpkg)",
"description": "Shared base for presets that link real deps via vcpkg. Requires VCPKG_ROOT in the environment.", "description": "Day-to-day development preset. Real protocol, crypto, voice, server — everything from M1 onward. Builds server + tools + tests (21 tests). Auto-triplet: x64-mingw-static on Windows, x64-linux on Linux, arm64-osx on Apple Silicon. Requires VCPKG_ROOT.",
"generator": "Ninja", "inherits": "vcpkg-common",
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "binaryDir": "${sourceDir}/build/dev",
"cacheVariables": { "VOICECAT_USE_VCPKG_DEPS": "ON" }
},
{
"name": "m1-dev",
"inherits": "vcpkg-base",
"displayName": "M1 Dev (TLS control plane, deps via vcpkg)",
"description": "Active development preset for M1+. Requires VCPKG_ROOT env var pointing to a bootstrapped vcpkg. Set VCPKG_ROOT=D:\\code\\nvgt\\vcpkg\\bin (or wherever your vcpkg is).",
"binaryDir": "${sourceDir}/build/m1-dev",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug", "CMAKE_BUILD_TYPE": "Debug",
"VOICECAT_USE_VCPKG_DEPS": "ON",
"VOICECAT_BUILD_TOOLS": "ON", "VOICECAT_BUILD_TOOLS": "ON",
"VOICECAT_BUILD_TESTS": "ON", "VOICECAT_BUILD_TESTS": "ON"
"VCPKG_TARGET_TRIPLET": "x64-mingw-static",
"VCPKG_HOST_TRIPLET": "x64-mingw-static"
} }
}, },
{ {
"name": "m2-dev", "name": "release",
"inherits": "vcpkg-base", "displayName": "Release (optimized, tests on, symbols kept)",
"displayName": "M2 Dev (voice + media, deps via vcpkg)", "description": "Optimized build with the full test suite enabled. Use to run tests against optimized code, profile, or catch optimizer-sensitive bugs. Symbols are kept (not stripped) so stack traces and profiling remain useful. Auto-triplet. Requires VCPKG_ROOT.",
"description": "Active development preset for M2+. Requires VCPKG_ROOT env var pointing to a bootstrapped vcpkg. Set VCPKG_ROOT=D:\\code\\nvgt\\vcpkg\\bin (or wherever your vcpkg is).", "inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/m2-dev", "binaryDir": "${sourceDir}/build/release",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug", "CMAKE_BUILD_TYPE": "Release",
"VOICECAT_USE_VCPKG_DEPS": "ON",
"VOICECAT_BUILD_TOOLS": "ON", "VOICECAT_BUILD_TOOLS": "ON",
"VOICECAT_BUILD_TESTS": "ON", "VOICECAT_BUILD_TESTS": "ON"
"VCPKG_TARGET_TRIPLET": "x64-mingw-static",
"VCPKG_HOST_TRIPLET": "x64-mingw-static"
} }
}, },
{ {
"name": "server-release", "name": "server-release",
"inherits": "vcpkg-base", "displayName": "Server Release (optimized, stripped, no tests)",
"displayName": "Server (release, real deps)", "description": "Production-shaped build for deployment. Optimized (Release) with stripped binaries (-s linker flag), no tests. This is what you'd ship/run — see docs/deployment.md. Auto-triplet. Requires VCPKG_ROOT.",
"inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/server-release", "binaryDir": "${sourceDir}/build/server-release",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release", "CMAKE_BUILD_TYPE": "Release",
"VOICECAT_BUILD_TOOLS": "ON", "VOICECAT_BUILD_TOOLS": "ON",
"VCPKG_TARGET_TRIPLET": "x64-mingw-static" "VOICECAT_BUILD_TESTS": "OFF",
"CMAKE_EXE_LINKER_FLAGS": "-s",
"CMAKE_SHARED_LINKER_FLAGS": "-s"
} }
}, },
{ {
"name": "windows-client", "name": "windows-client",
"inherits": "vcpkg-base", "displayName": "Windows client (voicecat.dll for C# WinForms, M4)",
"displayName": "Windows client (shared libvoicecat.dll for the C# WinForms app, M4)", "description": "Produces a redistributable Release voicecat.dll with no MinGW runtime DLL dependencies (see core/CMakeLists.txt's static-runtime link flags and clients/windows/README.md). Server/tools/tests are off — this preset exists only to build the DLL. Windows only.",
"description": "Produces a redistributable Release voicecat.dll with no MinGW runtime DLL dependencies (see core/CMakeLists.txt's static-runtime link flags and clients/windows/README.md). Tools/tests are off — this preset exists only to build the DLL.", "inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/windows-client", "binaryDir": "${sourceDir}/build/windows-client",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release", "CMAKE_BUILD_TYPE": "Release",
"VOICECAT_USE_VCPKG_DEPS": "ON",
"VOICECAT_BUILD_SHARED": "ON", "VOICECAT_BUILD_SHARED": "ON",
"VOICECAT_BUILD_SERVER": "OFF", "VOICECAT_BUILD_SERVER": "OFF",
"VOICECAT_BUILD_TOOLS": "OFF", "VOICECAT_BUILD_TOOLS": "OFF",
"VOICECAT_BUILD_TESTS": "OFF", "VOICECAT_BUILD_TESTS": "OFF"
"VCPKG_TARGET_TRIPLET": "x64-mingw-static", }
"VCPKG_HOST_TRIPLET": "x64-mingw-static" },
{
"name": "apple-dev",
"displayName": "Apple macOS (libvoicecat.a for Swift Package, scaffolding)",
"description": "SCAFFOLDING — not yet CI-validated; build on macOS to verify. Produces a static libvoicecat.a for macOS (arm64-osx on Apple Silicon, x64-osx on Intel) for consumption by the Swift Package / XCFramework. Server/tools/tests off. Requires VCPKG_ROOT.",
"inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/apple-dev",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"VOICECAT_BUILD_SERVER": "OFF",
"VOICECAT_BUILD_TOOLS": "OFF",
"VOICECAT_BUILD_TESTS": "OFF"
}
},
{
"name": "apple-ios",
"displayName": "Apple iOS device (XCFramework slice, scaffolding)",
"description": "SCAFFOLDING — not yet CI-validated; build on macOS to verify. Cross-compiles a static libvoicecat.a for iOS device (arm64-ios). One slice of the XCFramework. Server/tools/tests off. Requires VCPKG_ROOT and a macOS host with iOS SDK.",
"inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/apple-ios",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_SYSTEM_NAME": "iOS",
"CMAKE_SYSTEM_PROCESSOR": "arm64",
"VCPKG_TARGET_TRIPLET": "arm64-ios",
"VOICECAT_BUILD_SERVER": "OFF",
"VOICECAT_BUILD_TOOLS": "OFF",
"VOICECAT_BUILD_TESTS": "OFF"
}
},
{
"name": "apple-ios-sim",
"displayName": "Apple iOS simulator (XCFramework slice, scaffolding)",
"description": "SCAFFOLDING — not yet CI-validated; build on macOS to verify. Cross-compiles a static libvoicecat.a for iOS simulator (arm64-ios-sim on Apple Silicon). One slice of the XCFramework. Server/tools/tests off. Requires VCPKG_ROOT and a macOS host with iOS simulator SDK.",
"inherits": "vcpkg-common",
"binaryDir": "${sourceDir}/build/apple-ios-sim",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_SYSTEM_NAME": "iOS",
"CMAKE_SYSTEM_PROCESSOR": "arm64",
"VCPKG_TARGET_TRIPLET": "arm64-ios-sim",
"VOICECAT_BUILD_SERVER": "OFF",
"VOICECAT_BUILD_TOOLS": "OFF",
"VOICECAT_BUILD_TESTS": "OFF"
} }
} }
], ],
"buildPresets": [ "buildPresets": [
{ "name": "skeleton", "configurePreset": "skeleton" },
{ "name": "dev", "configurePreset": "dev" }, { "name": "dev", "configurePreset": "dev" },
{ "name": "m1-dev", "configurePreset": "m1-dev" }, { "name": "release", "configurePreset": "release" },
{ "name": "m2-dev", "configurePreset": "m2-dev" },
{ "name": "server-release", "configurePreset": "server-release" }, { "name": "server-release", "configurePreset": "server-release" },
{ "name": "windows-client", "configurePreset": "windows-client" } { "name": "windows-client", "configurePreset": "windows-client" },
{ "name": "apple-dev", "configurePreset": "apple-dev" },
{ "name": "apple-ios", "configurePreset": "apple-ios" },
{ "name": "apple-ios-sim", "configurePreset": "apple-ios-sim" }
], ],
"testPresets": [ "testPresets": [
{ "name": "skeleton", "configurePreset": "skeleton", "output": { "outputOnFailure": true } },
{ "name": "dev", "configurePreset": "dev", "output": { "outputOnFailure": true } }, { "name": "dev", "configurePreset": "dev", "output": { "outputOnFailure": true } },
{ "name": "m1-dev", "configurePreset": "m1-dev", "output": { "outputOnFailure": true } }, { "name": "release", "configurePreset": "release", "output": { "outputOnFailure": true } }
{ "name": "m2-dev", "configurePreset": "m2-dev", "output": { "outputOnFailure": true } }
] ]
} }

View File

@@ -10,6 +10,49 @@ up instantly. Newest status at the top.
## ▶ Where we left off / next action ## ▶ Where we left off / next action
- **Done:** **CMake preset cleanup + cross-platform build config** (2026-06-18). The preset
set was a mess — `dev` (never used), `m1-dev` (the one everyone used), `m2-dev`
(cache-identical to `m1-dev`, never used), no optimized+tests preset, no stripping.
Cleaned up to a sensible set + added cross-platform triplet auto-resolution + Apple
platform scaffolding:
- **Renames:** `dev``skeleton` (no-deps stub smoke — accurately named now); `m1-dev``dev`
(the default development preset — milestone-named presets were misleading since the
project is past M5); `m2-dev` **dropped** (cache-identical to `m1-dev`).
- **New presets:** `release` (optimized Release + tests on, symbols kept — run the suite
against optimized code or profile); `apple-dev` / `apple-ios` / `apple-ios-sim`
(scaffolding — static `libvoicecat.a` slices for the Swift Package / XCFramework; marked
"not yet CI-validated, build on macOS to verify").
- **`server-release`** now strips binaries (`CMAKE_EXE_LINKER_FLAGS=-s` +
`CMAKE_SHARED_LINKER_FLAGS=-s`) — smaller executables for deployment.
- **Cross-platform triplet auto-resolution:** new `cmake/voicecat-toolchain.cmake` wraps
vcpkg's toolchain and resolves `VCPKG_TARGET_TRIPLET` / `VCPKG_HOST_TRIPLET` from
`CMAKE_HOST_SYSTEM_NAME` + `CMAKE_HOST_SYSTEM_PROCESSOR``x64-mingw-static` on Windows,
`x64-linux` on Linux, `arm64-osx` on Apple Silicon. The main presets (`dev`, `release`,
`server-release`) now work on all three platforms without per-OS variants. Cross-compile
presets (`apple-ios`, `apple-ios-sim`) override `VCPKG_TARGET_TRIPLET` explicitly. Hidden
base preset renamed `vcpkg-base``vcpkg-common` (now points at the wrapper toolchain
instead of vcpkg's toolchain directly).
- **No C++ source changes** — the core was already portable (every `#ifdef _WIN32` in
`client.cpp` already had a POSIX `#else`; `voicecat.h`'s export macro already handled
GCC visibility; `transport.cpp` is pure Asio; miniaudio abstracts WASAPI/CoreAudio/ALSA).
- **Docs updated:** `docs/building.md` (full rewrite — 8-preset table, platform matrix,
preset history mapping old names to new, Apple scaffolding section), `CLAUDE.md` (build
section reframed around `dev` as default, status line updated to M5-done), `README.md`
(stale "M0 skeleton" framing replaced with current M5 reality), `AGENTS.md` (build
section updated, stale "placeholder builtin-baseline" sentence deleted),
`docs/deployment.md` (server-release now stripped + cross-platform note),
`docs/tech-stack.md` §4 (triplet auto-resolution + Apple scaffolding note),
`clients/apple/README.md` (new "Building the core for Apple platforms" section with
XCFramework workflow), `clients/windows/README.md` (m1-dev→dev).
- **Code comments updated:** `core/include/voicecat.h`, `core/src/net/transport.h`,
`core/src/voicecat.cpp`, `tests/CMakeLists.txt` — preset name references updated.
- **Historical `PROGRESS.md` entries left intact** — `m1-dev`/`m2-dev` mentions in older
entries are a true record of what was run; rewriting them would falsify history. The
preset history table in `docs/building.md` §1 maps old names to new.
- **Verified:** `cmake --list-presets` shows all 8 presets. `skeleton` + `dev` configure
and build green on Windows. Apple presets are scaffolding (won't build on Windows —
expected; they require macOS).
- **Done:** **Disconnect, timeout & keepalive system** (2026-06-18). Three reported bugs - **Done:** **Disconnect, timeout & keepalive system** (2026-06-18). Three reported bugs
traced to one root cause + two missing designed features, all fixed: traced to one root cause + two missing designed features, all fixed:
1. **Stale users after disconnect + eternal PLC hiss** (root cause): `ConnSession::close()` 1. **Stale users after disconnect + eternal PLC hiss** (root cause): `ConnSession::close()`

View File

@@ -5,10 +5,11 @@ channel-based voice, channel + private text, one server you run yourself. Plain
(control) and **UDP** (media), no WebRTC. Encrypted by default. A shared **C++ core** (control) and **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. (`libvoicecat`) drives native clients (Swift on macOS/iOS, C# on Windows) and the server.
> **Status: pre-implementation.** The design is complete in [`docs/`](docs/). The code is an > **Status:** Design complete in [`docs/`](docs/). M1M5 are implemented — real TLS control
> M0 **skeleton** — it compiles and links, but every subsystem is a stub. See > plane, encrypted UDP voice (Opus), multi-stream, TOFU identity pinning, channel tree,
> [`AGENTS.md`](AGENTS.md) to start building, and [`docs/roadmap.md`](docs/roadmap.md) for the > permissions, moderation, disconnect/keepalive/reaper. Windows WinForms C# client shipped
> milestones. > (M4). macOS/iOS Swift client is next. See [`PROGRESS.md`](PROGRESS.md) and
> [`docs/roadmap.md`](docs/roadmap.md).
## Read the design first ## Read the design first
@@ -16,28 +17,34 @@ The [`docs/`](docs/) folder is the source of truth. Start at [`docs/README.md`](
then `architecture``protocol``voice``security``tech-stack``deployment` then `architecture``protocol``voice``security``tech-stack``deployment`
`roadmap`. `roadmap`.
## Build the skeleton (no dependencies needed yet) ## Build
The M0 skeleton builds with just a C++20 compiler + CMake + Ninja — **no vcpkg, no The default development preset is **`dev`** — it builds everything (server + tools + tests)
third-party libraries**, because every subsystem is currently a stub. with real vcpkg deps. It works on Windows, Linux, and macOS (vcpkg triplet auto-resolved).
```bash ```bash
# one-time vcpkg setup:
git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh # .bat on Windows
export VCPKG_ROOT=/path/to/vcpkg # Linux/macOS; or $env:VCPKG_ROOT on PowerShell
# configure + build + test:
cmake --preset dev cmake --preset dev
cmake --build --preset dev cmake --build --preset dev
ctest --preset dev # runs the smoke test (links the core, calls the C ABI) ctest --preset dev # 21 behavior tests
``` ```
Artifacts land in `build/dev/bin/` (`voicecat-server`, `vccli`). Artifacts land in `build/dev/bin/` (`voicecat-server`, `vccli`, `voicecat-admin`).
When you start implementing a subsystem that needs real libraries, build with vcpkg deps: The `skeleton` preset (no vcpkg deps, stubs only) is a fast smoke check that needs no
third-party libraries:
```bash ```bash
# one-time: git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh cmake --preset skeleton && cmake --build --preset skeleton && ctest --preset skeleton
export VCPKG_ROOT=/path/to/vcpkg # set VCPKG_ROOT (works on Linux/macOS/Windows)
cmake --preset server-release # auto-installs deps from vcpkg.json
cmake --build --preset server-release
``` ```
See [`docs/building.md`](docs/building.md) for the full preset matrix (including `release`,
`server-release`, `windows-client`, and Apple platform scaffolding).
## Layout ## Layout
``` ```

View File

@@ -17,3 +17,40 @@ Planned shape (see [`docs/architecture.md`](../../docs/architecture.md) §4 and
state via an **App Group** ([`docs/voice.md`](../../docs/voice.md) §9). state via an **App Group** ([`docs/voice.md`](../../docs/voice.md) §9).
Nothing here yet — the core must reach M2 (working voice) before the GUI is worth building. Nothing here yet — the core must reach M2 (working voice) before the GUI is worth building.
## Building the core for Apple platforms (scaffolding)
The CMake presets `apple-dev`, `apple-ios`, and `apple-ios-sim` produce static `libvoicecat.a`
slices for the Swift Package / XCFramework. They are **scaffolding** — not yet CI-validated.
Build on macOS (they won't work on Windows/Linux):
```bash
# Prerequisites: VCPKG_ROOT set, Xcode + iOS SDK installed
export VCPKG_ROOT=/path/to/vcpkg
# macOS slice (arm64-osx on Apple Silicon, x64-osx on Intel)
cmake --preset apple-dev && cmake --build --preset apple-dev
# → build/apple-dev/lib/libvoicecat.a
# iOS device slice
cmake --preset apple-ios && cmake --build --preset apple-ios
# → build/apple-ios/lib/libvoicecat.a
# iOS simulator slice
cmake --preset apple-ios-sim && cmake --build --preset apple-ios-sim
# → build/apple-ios-sim/lib/libvoicecat.a
```
The three `.a` files are then stitched into an XCFramework:
```bash
xcodebuild -create-xcframework \
-library build/apple-dev/lib/libvoicecat.a -headers core/include \
-library build/apple-ios/lib/libvoicecat.a -headers core/include \
-library build/apple-ios-sim/lib/libvoicecat.a -headers core/include \
-output build/VoiceCatCore.xcframework
```
The XCFramework is then consumed by the Swift Package as a binary target. Actual
`AVAudioSession` integration, `Info.plist` mic permission, ReplayKit extension, and SwiftUI
UI work are tracked as follow-up tasks — the presets exist so the build entry point is ready.

View File

@@ -16,8 +16,8 @@ WinForms (.NET 10 LTS) UI over `voicecat.dll` (MinGW-built `libvoicecat` shared
### 1. Build the server (for testing) ### 1. Build the server (for testing)
```powershell ```powershell
cmake --preset m1-dev cmake --preset dev
cmake --build --preset m1-dev --target voicecat-server cmake --build --preset dev --target voicecat-server
``` ```
### 2. Build the DLL ### 2. Build the DLL
@@ -53,7 +53,7 @@ into the output directory automatically on every build.
```powershell ```powershell
# Terminal 1 — start the server # Terminal 1 — start the server
./build/m1-dev/bin/voicecat-server.exe --name "My Server" ./build/dev/bin/voicecat-server.exe --name "My Server"
# Terminal 2 — launch the client # Terminal 2 — launch the client
dotnet run --project clients/windows/VoiceCat.App/VoiceCat.App.csproj dotnet run --project clients/windows/VoiceCat.App/VoiceCat.App.csproj

View File

@@ -0,0 +1,72 @@
# cmake/voicecat-toolchain.cmake — vcpkg toolchain wrapper with auto-triplet.
#
# Wraps vcpkg's toolchain to auto-resolve VCPKG_HOST_TRIPLET and VCPKG_TARGET_TRIPLET
# from the host platform, so the main presets (dev, release, server-release) build on
# Windows/MinGW, Linux, and macOS without per-OS preset variants.
#
# Triplet mapping (auto):
# Windows → x64-mingw-static (the project's toolchain is MSYS2/UCRT64 — see
# clients/windows/README.md; MSVC users must set
# VCPKG_TARGET_TRIPLET=x64-windows explicitly)
# Linux x64 → x64-linux
# Linux arm64 → arm64-linux
# macOS arm64 → arm64-osx (Apple Silicon)
# macOS x64 → x64-osx (Intel)
#
# Cross-compile presets (apple-ios, apple-ios-sim) set VCPKG_TARGET_TRIPLET explicitly
# in their cacheVariables; the DEFINED guards below preserve those. VCPKG_HOST_TRIPLET
# is always the host's (e.g. arm64-osx when cross-compiling iOS on Apple Silicon).
#
# Requires VCPKG_ROOT in the environment (set by the inheriting preset).
# ── Host triplet (the platform running vcpkg / the build) ─────────────────────
if(NOT DEFINED VCPKG_HOST_TRIPLET)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(_voicecat_host "x64-mingw-static")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(_voicecat_host "arm64-linux")
else()
set(_voicecat_host "x64-linux")
endif()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(_voicecat_host "arm64-osx")
else()
set(_voicecat_host "x64-osx")
endif()
endif()
if(_voicecat_host)
set(VCPKG_HOST_TRIPLET "${_voicecat_host}" CACHE STRING "vcpkg host triplet (auto-resolved)")
endif()
unset(_voicecat_host)
endif()
# ── Target triplet (the platform being built for) ─────────────────────────────
# Auto-resolve only when not explicitly set. Cross-compile presets (apple-ios,
# apple-ios-sim) set VCPKG_TARGET_TRIPLET in their cacheVariables; the DEFINED
# guard preserves those so they win over the auto-detection.
if(NOT DEFINED VCPKG_TARGET_TRIPLET)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(_voicecat_target "x64-mingw-static")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(_voicecat_target "arm64-linux")
else()
set(_voicecat_target "x64-linux")
endif()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(_voicecat_target "arm64-osx")
else()
set(_voicecat_target "x64-osx")
endif()
endif()
if(_voicecat_target)
set(VCPKG_TARGET_TRIPLET "${_voicecat_target}" CACHE STRING "vcpkg target triplet (auto-resolved)")
endif()
unset(_voicecat_target)
endif()
# ── Hand off to the real vcpkg toolchain ──────────────────────────────────────
include("$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")

View File

@@ -8,10 +8,10 @@
* Design: docs/architecture.md §4. Everything here is async + event-driven — calls return * Design: docs/architecture.md §4. Everything here is async + event-driven — calls return
* immediately and results/state changes arrive via the vc_callbacks.on_event callback. * immediately and results/state changes arrive via the vc_callbacks.on_event callback.
* *
* STATUS: real, behind VOICECAT_HAS_NET (the `m1-dev`/`server-release` presets — vcpkg deps * STATUS: real, behind VOICECAT_HAS_NET (the `dev`/`release`/`server-release` presets —
* on; see docs/building.md). As of M3, control plane, voice, multi-stream, device * vcpkg deps on; see docs/building.md). As of M3, control plane, voice, multi-stream, device
* enumeration, VAD/PTT, and stereo playback all work for real via core/src/core/client.cpp. * enumeration, VAD/PTT, and stereo playback all work for real via core/src/core/client.cpp.
* The no-deps `dev` preset still links a stub vc_client that returns VC_ERR_NOT_IMPLEMENTED * The no-deps `skeleton` preset still links a stub vc_client that returns VC_ERR_NOT_IMPLEMENTED
* for everything below `connect`, purely to keep that skeleton build green. webrtc AEC/NS/AGC * for everything below `connect`, purely to keep that skeleton build green. webrtc AEC/NS/AGC
* remains an inert passthrough regardless of preset (no Windows/MSVC port upstream — * remains an inert passthrough regardless of preset (no Windows/MSVC port upstream —
* docs/voice.md §8/§11, PROGRESS.md). * docs/voice.md §8/§11, PROGRESS.md).

View File

@@ -4,8 +4,9 @@
* Design: docs/architecture.md (Net thread), docs/protocol.md §1 (framing). * Design: docs/architecture.md (Net thread), docs/protocol.md §1 (framing).
* Implementation uses standalone Asio for sockets and timers. * Implementation uses standalone Asio for sockets and timers.
* *
* The real classes are compiled only when VOICECAT_HAS_NET is defined (m1-dev+). * The real classes are compiled only when VOICECAT_HAS_NET is defined (dev/release/
* The dev-preset stub definitions below keep the skeleton build green. * server-release — vcpkg deps on). The skeleton-preset stub definitions below keep the
* no-deps build green.
*/ */
#ifndef VOICECAT_NET_TRANSPORT_H #ifndef VOICECAT_NET_TRANSPORT_H
#define VOICECAT_NET_TRANSPORT_H #define VOICECAT_NET_TRANSPORT_H

View File

@@ -7,7 +7,7 @@
* (they use the fixed binary header in voice.md §2). * (they use the fixed binary header in voice.md §2).
* *
* STATUS: real. Protobuf codegen is on (core/CMakeLists.txt) for VOICECAT_HAS_NET builds * STATUS: real. Protobuf codegen is on (core/CMakeLists.txt) for VOICECAT_HAS_NET builds
* (`m1-dev`/`server-release`); FrameCodec below is fully implemented and used by both the * (`dev`/`release`/`server-release`); FrameCodec below is fully implemented and used by both the
* client (net/transport.h) and the server (conn_session.cpp). See protocol/envelope.h for the * client (net/transport.h) and the server (conn_session.cpp). See protocol/envelope.h for the
* Envelope-level encode/decode that sits on top of this. * Envelope-level encode/decode that sits on top of this.
*/ */

View File

@@ -3,8 +3,8 @@
* *
* Lifecycle (create/destroy) and trivial accessors are always real. Everything else below * Lifecycle (create/destroy) and trivial accessors are always real. Everything else below
* just delegates to vc_client (core/src/core/client.cpp): under VOICECAT_HAS_NET * just delegates to vc_client (core/src/core/client.cpp): under VOICECAT_HAS_NET
* (`m1-dev`/`server-release` — see docs/building.md) that's the real M1M3 implementation; * (`dev`/`release`/`server-release` — see docs/building.md) that's the real M1M3 implementation;
* under the no-deps `dev` preset, client.cpp's `#else` branch returns VC_ERR_NOT_IMPLEMENTED * under the no-deps `skeleton` preset, client.cpp's `#else` branch returns VC_ERR_NOT_IMPLEMENTED
* for all of it, to keep that skeleton build green. * for all of it, to keep that skeleton build green.
*/ */
#include "voicecat.h" #include "voicecat.h"

View File

@@ -4,28 +4,69 @@ This doc explains what each CMake preset in [`CMakePresets.json`](../CMakePreset
*for*, which one to actually use day-to-day, and the commands to stand up a real server + *for*, which one to actually use day-to-day, and the commands to stand up a real server +
`vccli` clients against each other for manual testing. For the one-paragraph quick-start see `vccli` clients against each other for manual testing. For the one-paragraph quick-start see
[`CLAUDE.md`](../CLAUDE.md); for `ctest` targets see [`AGENTS.md`](../AGENTS.md). This doc is [`CLAUDE.md`](../CLAUDE.md); for `ctest` targets see [`AGENTS.md`](../AGENTS.md). This doc is
the missing middle: *how the presets relate to each other*, and *how to drive the binaries by the missing middle: *how the presets relate to each other*, *which platform each targets*,
hand*. and *how to drive the binaries by hand*.
## 1. What each preset is for ## 1. What each preset is for
| Preset | Binary dir | Deps | What it's actually for | | Preset | Binary dir | Deps | Build type | Server | Tools | Tests | Strip | Platform | What it's for |
|--------|-----------|------|-------------------------| |--------|-----------|------|------------|--------|-------|-------|-------|----------|---------------|
| `dev` | `build/dev` | none (`VOICECAT_USE_VCPKG_DEPS=OFF`) | The M0 skeleton. Compiles with just a C++20 compiler — no `VCPKG_ROOT` needed. Subsystems are stubs (`VC_ERR_NOT_IMPLEMENTED`). Good for "does the repo even build" sanity checks, not for testing real voice/control behavior. | | `vcpkg-common` | — | vcpkg | — | — | — | — | — | all | Hidden base. Sets the vcpkg toolchain wrapper ([`cmake/voicecat-toolchain.cmake`](../cmake/voicecat-toolchain.cmake)) which auto-resolves the triplet from the host platform. Not used directly. |
| `vcpkg-base` | — | real deps via vcpkg | Hidden base preset, not used directly. Requires `VCPKG_ROOT` in the environment; every preset below inherits it. | | `skeleton` | `build/skeleton` | none | Debug | ON | ON | ON | no | all | The M0 skeleton. Compiles with just a C++20 compiler — no `VCPKG_ROOT` needed. Subsystems are stubs (`VC_ERR_NOT_IMPLEMENTED`). Good for "does the repo even build" sanity checks. Runs 2 tests (smoke + frame_codec). |
| `m1-dev` | `build/m1-dev` | real deps | **The one you actually want.** Despite the name, this is the live development preset for everything from M1 onward — M1, M2, and M3 were all built, tested, and manually verified against `build/m1-dev` (see `PROGRESS.md`). Builds tools + tests. | | `dev` | `build/dev` | vcpkg | Debug | ON | ON | ON | no | all | **The one you actually want.** Day-to-day development: real protocol, crypto, voice, server — everything. Builds server + tools + tests (21 tests). Works on Windows, Linux, and macOS (triplet auto-resolved). |
| `m2-dev` | `build/m2-dev` | real deps | Cache-identical to `m1-dev` (same `VOICECAT_BUILD_TOOLS=ON`, `VOICECAT_BUILD_TESTS=ON`, same triplet) — the only difference is the binary dir. It exists from when the project briefly split a preset per milestone; that convention was dropped in practice. Use it only if you want a second, isolated build tree (e.g. to compare two branches) — there's no behavioral reason to prefer it over `m1-dev`. | | `release` | `build/release` | vcpkg | Release | ON | ON | ON | no | all | Optimized build with the full test suite. Use to run tests against optimized code, profile, or catch optimizer-sensitive bugs. Symbols kept (not stripped) so stack traces and profiling remain useful. |
| *(no `m3-dev`)* | — | — | M3 work used `m1-dev` directly; no separate preset was ever added for it. If you see `m3-dev` mentioned anywhere, it doesn't existuse `m1-dev`. | | `server-release` | `build/server-release` | vcpkg | Release | ON | ON | OFF | **yes** | all | Production-shaped build for deployment. Optimized + stripped binaries (`-s`), no tests. This is what you'd ship/run — see [docs/deployment.md](deployment.md). |
| `server-release` | `build/server-release` | real deps, `Release` | Production-shaped build (docs/deployment.md "from source" path): `CMAKE_BUILD_TYPE=Release`, tools on, **tests off**. This is what you'd actually ship/run, not what you iterate against. | | `windows-client` | `build/windows-client` | vcpkg | Release | OFF | OFF | OFF | no | Windows | Produces a redistributable `voicecat.dll` for the C# WinForms client (M4). Static MinGW runtime — no `libgcc_s_seh-1.dll` etc. See [clients/windows/README.md](../clients/windows/README.md). |
| `apple-dev` | `build/apple-dev` | vcpkg | Release | OFF | OFF | OFF | no | macOS | **Scaffolding** — static `libvoicecat.a` for the Swift Package / XCFramework (macOS slice). Not yet CI-validated; build on macOS to verify. See [clients/apple/README.md](../clients/apple/README.md). |
| `apple-ios` | `build/apple-ios` | vcpkg | Release | OFF | OFF | OFF | no | macOS→iOS | **Scaffolding** — cross-compiled static `libvoicecat.a` for iOS device (`arm64-ios`). One XCFramework slice. Not yet CI-validated. |
| `apple-ios-sim` | `build/apple-ios-sim` | vcpkg | Release | OFF | OFF | OFF | no | macOS→iOS sim | **Scaffolding** — cross-compiled static `libvoicecat.a` for iOS simulator (`arm64-ios-sim`). One XCFramework slice. Not yet CI-validated. |
So in practice there are really only two presets that matter: So in practice there are three presets that matter for day-to-day work:
- **`dev`** — fast no-deps build to confirm the skeleton compiles. - **`dev`** — everything: real protocol, real voice, real manual testing. This is the loop you run constantly.
- **`m1-dev`** — everything else: real protocol, real voice, real manual testing. - **`release`** — same suite, optimized. Run it when you want to check optimized behavior or profile.
- **`skeleton`** — fast no-deps build to confirm the stub path still compiles (CI smoke check).
The rest are purpose-specific: `server-release` for deployment, `windows-client` for the DLL,
`apple-*` for Apple platform slices.
### Platform matrix
The vcpkg presets (`dev`, `release`, `server-release`, `windows-client`, `apple-*`) auto-resolve
the vcpkg triplet via [`cmake/voicecat-toolchain.cmake`](../cmake/voicecat-toolchain.cmake):
| Host platform | Auto-resolved triplet | Notes |
|---------------|----------------------|-------|
| Windows (MinGW/MSYS2) | `x64-mingw-static` | The project's Windows toolchain. MSVC users must set `VCPKG_TARGET_TRIPLET=x64-windows` explicitly. |
| Linux x64 | `x64-linux` | Server's primary deployment target (Docker, systemd). |
| Linux arm64 | `arm64-linux` | Raspberry Pi / ARM VPS. |
| macOS (Apple Silicon) | `arm64-osx` | `apple-dev` uses this automatically. |
| macOS (Intel) | `x64-osx` | `apple-dev` uses this automatically. |
Cross-compile presets (`apple-ios`, `apple-ios-sim`) override `VCPKG_TARGET_TRIPLET` explicitly;
`VCPKG_HOST_TRIPLET` stays the host's (e.g. `arm64-osx` when building iOS on Apple Silicon).
### Preset history
The preset set was cleaned up on 2026-06-18 (see `PROGRESS.md`). The old names map as follows:
| Old name | New name | Notes |
|----------|----------|-------|
| `dev` | `skeleton` | Renamed to reflect its actual purpose (no-deps stub smoke check). |
| `m1-dev` | `dev` | Renamed — the project is past M5, so milestone-named presets were misleading. This is now the default development preset. |
| `m2-dev` | *(dropped)* | Was cache-identical to `m1-dev` (same flags, same triplet, only the binary dir differed). Removed. |
| `server-release` | `server-release` | Unchanged name; now stripped (`-s`) and auto-triplet. |
| *(new)* | `release` | New: optimized build with tests on, symbols kept. |
| `windows-client` | `windows-client` | Unchanged name; triplet now auto-resolved. |
| *(new)* | `apple-dev`, `apple-ios`, `apple-ios-sim` | New: Apple platform scaffolding. |
If you see `m1-dev` or `m2-dev` in old scripts, commits, or `PROGRESS.md` history entries,
use `dev` instead. Historical `PROGRESS.md` entries are left intact as a true record of what
was run.
## 2. One-time setup for the real-deps presets ## 2. One-time setup for the real-deps presets
`m1-dev`, `m2-dev`, and `server-release` all need `VCPKG_ROOT` pointing at a bootstrapped `dev`, `release`, `server-release`, `windows-client`, and `apple-*` all need `VCPKG_ROOT`
vcpkg checkout: pointing at a bootstrapped vcpkg checkout:
```bash ```bash
# once: # once:
@@ -34,34 +75,44 @@ git clone https://github.com/microsoft/vcpkg
# every shell session (PowerShell): # every shell session (PowerShell):
$env:VCPKG_ROOT = "D:\path\to\vcpkg" $env:VCPKG_ROOT = "D:\path\to\vcpkg"
# or on Linux/macOS:
export VCPKG_ROOT=/path/to/vcpkg
``` ```
`vcpkg.json` (manifest mode) pins every dependency (protobuf, mbedTLS, libsodium, asio, `vcpkg.json` (manifest mode) pins every dependency (protobuf, mbedTLS, libsodium, asio,
sqlite3, spdlog, opus, miniaudio) — `cmake --preset m1-dev` resolves and builds them sqlite3, spdlog, opus, miniaudio) — `cmake --preset dev` resolves and builds them
automatically on first configure. That first configure is slow (vcpkg building from source); automatically on first configure. That first configure is slow (vcpkg building from source);
subsequent ones are cached. subsequent ones are cached.
## 3. Build + test (the loop you'll run constantly) ## 3. Build + test (the loop you'll run constantly)
```bash ```bash
cmake --preset m1-dev cmake --preset dev
cmake --build --preset m1-dev cmake --build --preset dev
ctest --test-dir build/m1-dev --output-on-failure ctest --preset dev
``` ```
(`ctest --preset m1-dev` is equivalent — both are wired up in `CMakePresets.json`.) Binaries Binaries land in `build/dev/bin/` (`.exe` suffix on Windows):
land in `build/m1-dev/bin/` (`.exe` suffix on Windows):
- `build/m1-dev/bin/voicecat-server` - `build/dev/bin/voicecat-server`
- `build/m1-dev/bin/vccli` - `build/dev/bin/vccli`
- `build/m1-dev/bin/voicecat-admin` - `build/dev/bin/voicecat-admin`
To run the same suite against optimized code:
```bash
cmake --preset release
cmake --build --preset release
ctest --preset release
```
## 4. Manual testing: server + two clients ## 4. Manual testing: server + two clients
### Start the server ### Start the server
```bash ```bash
./build/m1-dev/bin/voicecat-server --name "Test Server" --data-dir ./voicecat-data ./build/dev/bin/voicecat-server --name "Test Server" --data-dir ./voicecat-data
``` ```
First run generates an Ed25519 identity + self-signed cert under `--data-dir`, creates the First run generates an Ed25519 identity + self-signed cert under `--data-dir`, creates the
@@ -105,20 +156,20 @@ toggle the input gate live.
```bash ```bash
# terminal A # terminal A
./build/m1-dev/bin/vccli --nick Alice --text "hello from Alice" ./build/dev/bin/vccli --nick Alice --text "hello from Alice"
# terminal B (separate window, after A confirms it sent) # terminal B (separate window, after A confirms it sent)
./build/m1-dev/bin/vccli --nick Bob --text "hello from Bob" ./build/dev/bin/vccli --nick Bob --text "hello from Bob"
``` ```
**Real voice between two clients (needs working mic/speakers, two terminals):** **Real voice between two clients (needs working mic/speakers, two terminals):**
```bash ```bash
# terminal A # terminal A
./build/m1-dev/bin/vccli --nick Alice --voice ./build/dev/bin/vccli --nick Alice --voice
# terminal B # terminal B
./build/m1-dev/bin/vccli --nick Bob --voice ./build/dev/bin/vccli --nick Bob --voice
``` ```
Speak into the mic on one side; you should hear it on the other. Ctrl+C to disconnect. Speak into the mic on one side; you should hear it on the other. Ctrl+C to disconnect.
@@ -126,21 +177,22 @@ Speak into the mic on one side; you should hear it on the other. Ctrl+C to disco
**Enumerate audio devices before picking one:** **Enumerate audio devices before picking one:**
```bash ```bash
./build/m1-dev/bin/vccli --list-devices ./build/dev/bin/vccli --list-devices
./build/m1-dev/bin/vccli --nick Alice --voice --input-device <ID> --input-mode ptt ./build/dev/bin/vccli --nick Alice --voice --input-device <ID> --input-mode ptt
``` ```
**Provisioning a non-guest account** (if the server was started with `--no-guests`): **Provisioning a non-guest account** (if the server was started with `--no-guests`):
```bash ```bash
./build/m1-dev/bin/voicecat-admin --data-dir ./voicecat-data account add alice --password secret ./build/dev/bin/voicecat-admin --data-dir ./voicecat-data account add alice --password secret
./build/m1-dev/bin/voicecat-admin --data-dir ./voicecat-data account list ./build/dev/bin/voicecat-admin --data-dir ./voicecat-data account list
``` ```
## 5. `server-release` (production-shaped build) ## 5. `server-release` (production-shaped build)
Same dependency story, but `Release` build type and no tests — this is the closest local Same dependency story, but `Release` build type, stripped binaries, and no tests — this is the
analogue to what `docs/deployment.md`'s "from source" path produces: closest local analogue to what [docs/deployment.md](deployment.md)'s "from source" path
produces:
```bash ```bash
cmake --preset server-release cmake --preset server-release
@@ -149,4 +201,34 @@ cmake --build --preset server-release
``` ```
Use this to sanity-check release-mode behavior (e.g. perf, optimized codepaths) — not for Use this to sanity-check release-mode behavior (e.g. perf, optimized codepaths) — not for
day-to-day development, since it has no test target wired up. day-to-day development, since it has no test target wired up. The `-s` linker flag strips
symbol tables from the binaries, producing smaller executables suitable for distribution.
## 6. Apple platform builds (scaffolding)
The `apple-dev`, `apple-ios`, and `apple-ios-sim` presets produce static `libvoicecat.a`
slices for the Swift Package / XCFramework. They are **scaffolding** — not yet CI-validated
and won't build on Windows. Build on macOS:
```bash
# macOS slice (arm64-osx on Apple Silicon, x64-osx on Intel)
cmake --preset apple-dev
cmake --build --preset apple-dev
# → build/apple-dev/lib/libvoicecat.a
# iOS device slice
cmake --preset apple-ios
cmake --build --preset apple-ios
# → build/apple-ios/lib/libvoicecat.a
# iOS simulator slice
cmake --preset apple-ios-sim
cmake --build --preset apple-ios-sim
# → build/apple-ios-sim/lib/libvoicecat.a
```
The three `.a` files are then stitched into an XCFramework via `xcodebuild
-create-xcframework` (see [clients/apple/README.md](../clients/apple/README.md) for the
planned workflow). Actual XCFramework stitching, `AVAudioSession` integration, and iOS
UI work are tracked as follow-up tasks — the presets exist so the build entry point is ready
when that work starts.

View File

@@ -38,12 +38,15 @@ package manager. Linux (primary), macOS, and Windows builds.
```bash ```bash
git clone … && cd voice-cat git clone … && cd voice-cat
cmake --preset server-release # vcpkg fetches & pins all deps cmake --preset server-release # vcpkg fetches & pins all deps; auto-triplet (Linux/macOS/Windows)
cmake --build --preset server-release cmake --build --preset server-release
./build/voicecat-server ./build/server-release/bin/voicecat-server
``` ```
One `cmake` invocation; vcpkg (manifest mode) resolves the dependency graph reproducibly. One `cmake` invocation; vcpkg (manifest mode) resolves the dependency graph reproducibly.
The `server-release` preset produces an optimized, **stripped** binary (`-s` linker flag) —
smaller executables suitable for distribution. Works on Linux (primary), macOS, and Windows;
the vcpkg triplet is auto-resolved by [`cmake/voicecat-toolchain.cmake`](../cmake/voicecat-toolchain.cmake).
No system packages to chase. No system packages to chase.
## 2. Zero-config defaults ## 2. Zero-config defaults

View File

@@ -58,7 +58,7 @@ explicit resampling (speexdsp/libsamplerate) is only needed when a device can't
| Tool | Use | | Tool | Use |
|------|-----| |------|-----|
| **CMake** (3.25+) | One build graph for core + server + test CLI; UI projects consume the built core. | | **CMake** (3.25+) | One build graph for core + server + test CLI; UI projects consume the built core. |
| **vcpkg** (manifest mode) | Pin C/C++ deps (opus, libsodium, mbedtls, protobuf, sqlite3, spdlog, asio, miniaudio — see `vcpkg.json`). `webrtc-audio-processing`/`speexdsp` are **not** in the manifest: no working vcpkg port / no working Windows/MSVC build exists upstream for the former; the latter was never actually wired up (the lightweight VAD needs no resampler). Reproducible across OSes. | | **vcpkg** (manifest mode) | Pin C/C++ deps (opus, libsodium, mbedtls, protobuf, sqlite3, spdlog, asio, miniaudio — see `vcpkg.json`). `webrtc-audio-processing`/`speexdsp` are **not** in the manifest: no working vcpkg port / no working Windows/MSVC build exists upstream for the former; the latter was never actually wired up (the lightweight VAD needs no resampler). Reproducible across OSes. Triplet 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. Apple platform scaffolding presets (`apple-dev`/`apple-ios`/`apple-ios-sim`) produce static `libvoicecat.a` slices for XCFramework consumption. |
| **protoc** | Generate C++/C#/Swift from `core/proto/*.proto` (single source of truth). | | **protoc** | Generate C++/C#/Swift from `core/proto/*.proto` (single source of truth). |
| **clang-format / clang-tidy** | Style + static analysis on the core. | | **clang-format / clang-tidy** | Style + static analysis on the core. |
| **CTest + a fuzz target** | Unit/integration tests; fuzz the frame parser and protobuf boundary (security-sensitive). | | **CTest + a fuzz target** | Unit/integration tests; fuzz the frame parser and protobuf boundary (security-sensitive). |

View File

@@ -205,7 +205,7 @@ void Server::stop() {
namespace voicecat::server { namespace voicecat::server {
int Server::run() { int Server::run() {
std::fprintf(stderr, "[server] stub: VOICECAT_HAS_NET not defined (build with m1-dev)\n"); std::fprintf(stderr, "[server] stub: VOICECAT_HAS_NET not defined (build with dev preset)\n");
std::printf(" server_name : %s\n", cfg_.server_name.c_str()); std::printf(" server_name : %s\n", cfg_.server_name.c_str());
std::printf(" data_dir : %s\n", cfg_.data_dir.c_str()); std::printf(" data_dir : %s\n", cfg_.data_dir.c_str());
std::printf(" bind_port : %u\n", cfg_.bind_port); std::printf(" bind_port : %u\n", cfg_.bind_port);

View File

@@ -6,7 +6,7 @@ target_link_libraries(test_smoke PRIVATE voicecat::voicecat)
target_compile_features(test_smoke PRIVATE cxx_std_20) target_compile_features(test_smoke PRIVATE cxx_std_20)
add_test(NAME smoke COMMAND test_smoke) add_test(NAME smoke COMMAND test_smoke)
# frame_codec has no third-party deps; runs under both dev and m1-dev. # frame_codec has no third-party deps; runs under both skeleton and dev.
# Needs core/src on the include path to reach internal headers (protocol/, session/, etc.). # Needs core/src on the include path to reach internal headers (protocol/, session/, etc.).
add_executable(test_frame_codec test_frame_codec.cpp) add_executable(test_frame_codec test_frame_codec.cpp)
target_link_libraries(test_frame_codec PRIVATE voicecat::voicecat) target_link_libraries(test_frame_codec PRIVATE voicecat::voicecat)

View File

@@ -1,6 +1,6 @@
/* /*
* test_envelope — round-trip an Envelope through FrameCodec + encode/decode. * test_envelope — round-trip an Envelope through FrameCodec + encode/decode.
* Runs only under m1-dev (requires protobuf). * Runs only under dev (requires protobuf).
*/ */
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>

View File

@@ -1,7 +1,7 @@
/* /*
* test_frame_codec — unit test for FrameCodec::feed / ::emit. * test_frame_codec — unit test for FrameCodec::feed / ::emit.
* *
* No third-party dependencies; runs under both the dev and m1-dev presets. * No third-party dependencies; runs under both the skeleton and dev presets.
* Tests: empty payload, single byte, 64 KiB, exact max-size, oversized (should reject), * Tests: empty payload, single byte, 64 KiB, exact max-size, oversized (should reject),
* split delivery (bytes fed one-at-a-time), and batched multi-frame delivery. * split delivery (bytes fed one-at-a-time), and batched multi-frame delivery.
*/ */

View File

@@ -1,7 +1,7 @@
/* /*
* test_opus_codec — Opus encode/decode round-trip, PLC, energy check. * test_opus_codec — Opus encode/decode round-trip, PLC, energy check.
* *
* Requires VOICECAT_HAS_OPUS (m1-dev and m2-dev presets). * Requires VOICECAT_HAS_OPUS (dev and release presets).
*/ */
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>

View File

@@ -43,7 +43,7 @@ int main() {
CHECK(vc_connect(c, nullptr, 1) == VC_ERR_INVALID_ARG); CHECK(vc_connect(c, nullptr, 1) == VC_ERR_INVALID_ARG);
CHECK(vc_send_text(c, VC_TEXT_CHANNEL, 0, nullptr) == VC_ERR_INVALID_ARG); CHECK(vc_send_text(c, VC_TEXT_CHANNEL, 0, nullptr) == VC_ERR_INVALID_ARG);
// Under dev preset: NOT_IMPLEMENTED. Under m1-dev: VC_OK (async connect). // Under skeleton preset: NOT_IMPLEMENTED. Under dev: VC_OK (async connect).
vc_result rc_connect = vc_connect(c, "127.0.0.1", 8384); vc_result rc_connect = vc_connect(c, "127.0.0.1", 8384);
CHECK(rc_connect == VC_ERR_NOT_IMPLEMENTED || rc_connect == VC_OK); CHECK(rc_connect == VC_ERR_NOT_IMPLEMENTED || rc_connect == VC_OK);

View File

@@ -1,6 +1,6 @@
/* /*
* test_tcp_loopback — in-process TCP acceptor + client, sends 10 frames. * test_tcp_loopback — in-process TCP acceptor + client, sends 10 frames.
* Runs only under m1-dev (requires Asio). * Runs only under dev (requires Asio).
*/ */
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>

View File

@@ -145,7 +145,7 @@ int main(int argc, char** argv) {
#else // !VOICECAT_HAS_NET #else // !VOICECAT_HAS_NET
int main() { int main() {
std::fprintf(stderr, "voicecat-admin requires VOICECAT_HAS_NET (build with m1-dev preset)\n"); std::fprintf(stderr, "voicecat-admin requires VOICECAT_HAS_NET (build with dev preset)\n");
return 1; return 1;
} }