From 845f99582615acdfe8d7c349087e8a9370726e80 Mon Sep 17 00:00:00 2001 From: Talon Date: Tue, 16 Jun 2026 16:30:07 +0200 Subject: [PATCH] docs: add build/manual-testing guide, fix stale M0 stub claims in headers - docs/building.md: explains what each CMake preset (dev, m1-dev, m2-dev, server-release) is actually for, and how to build voicecat-server + vccli for manual testing. Linked from CLAUDE.md's doc index. - core/include/voicecat.h, core/src/voicecat.cpp, core/src/protocol/protocol.h, server/src/main.cpp: doc-header comments still claimed M0-skeleton/stub behavior (VC_ERR_NOT_IMPLEMENTED everywhere, "prints what it would do", protobuf codegen "commented") that M1-M3 made real. Updated to describe current behavior, with the dev-preset stub fallback noted explicitly where it still applies. --- CLAUDE.md | 1 + core/include/voicecat.h | 9 ++- core/src/protocol/protocol.h | 5 +- core/src/voicecat.cpp | 12 +-- docs/building.md | 152 +++++++++++++++++++++++++++++++++++ server/src/main.cpp | 8 +- 6 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 docs/building.md diff --git a/CLAUDE.md b/CLAUDE.md index dbaf005..9d3d03c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -121,6 +121,7 @@ Read [`docs/`](docs/) before changing behavior. Order: 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 --- diff --git a/core/include/voicecat.h b/core/include/voicecat.h index 5fe9903..81693c0 100644 --- a/core/include/voicecat.h +++ b/core/include/voicecat.h @@ -8,8 +8,13 @@ * 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. * - * STATUS: M0 skeleton. Implementations live in core/src and currently return - * VC_ERR_NOT_IMPLEMENTED. The shapes below are the contract to build against. + * STATUS: real, behind VOICECAT_HAS_NET (the `m1-dev`/`server-release` presets — 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. + * The no-deps `dev` 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 + * remains an inert passthrough regardless of preset (no Windows/MSVC port upstream — + * docs/voice.md §8/§11, PROGRESS.md). */ #ifndef VOICECAT_H #define VOICECAT_H diff --git a/core/src/protocol/protocol.h b/core/src/protocol/protocol.h index 236fd58..e7cd3fe 100644 --- a/core/src/protocol/protocol.h +++ b/core/src/protocol/protocol.h @@ -6,7 +6,10 @@ * request_id ↔ response, and dispatches to handlers. Media frames do NOT come through here * (they use the fixed binary header in voice.md §2). * - * STATUS: M0 stub — protobuf codegen is wired in CMake (commented) and turned on in M1. + * 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 + * 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. */ #ifndef VOICECAT_PROTOCOL_PROTOCOL_H #define VOICECAT_PROTOCOL_PROTOCOL_H diff --git a/core/src/voicecat.cpp b/core/src/voicecat.cpp index fa4ecbb..8773d8f 100644 --- a/core/src/voicecat.cpp +++ b/core/src/voicecat.cpp @@ -1,9 +1,11 @@ /* - * voicecat.cpp — C ABI implementation (M0 skeleton). + * voicecat.cpp — C ABI implementation. * - * Lifecycle (create/destroy) and trivial accessors are real. Everything that needs a - * subsystem (net/crypto/codec/protocol/session/audio) returns VC_ERR_NOT_IMPLEMENTED for - * now and is the work of M1+ (see AGENTS.md / docs/roadmap.md). + * 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 + * (`m1-dev`/`server-release` — see docs/building.md) that's the real M1–M3 implementation; + * under the no-deps `dev` preset, client.cpp's `#else` branch returns VC_ERR_NOT_IMPLEMENTED + * for all of it, to keep that skeleton build green. */ #include "voicecat.h" @@ -48,7 +50,7 @@ vc_client* vc_client_create(const vc_config* cfg, vc_callbacks cb) { void vc_client_destroy(vc_client* c) { delete c; } -/* ── Everything below delegates to the (stub) client. ─────────────────────── */ +/* ── Everything below delegates to vc_client (real or stub, per preset above). ───────── */ vc_result vc_connect(vc_client* c, const char* host, uint16_t port) { if (c == nullptr || host == nullptr) return VC_ERR_INVALID_ARG; diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 0000000..3c517f9 --- /dev/null +++ b/docs/building.md @@ -0,0 +1,152 @@ +# Building & Manual Testing + +This doc explains what each CMake preset in [`CMakePresets.json`](../CMakePresets.json) is +*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 +[`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 +hand*. + +## 1. What each preset is for + +| Preset | Binary dir | Deps | What it's actually 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-base` | — | real deps via vcpkg | Hidden base preset, not used directly. Requires `VCPKG_ROOT` in the environment; every preset below inherits it. | +| `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. | +| `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`. | +| *(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 exist — use `m1-dev`. | +| `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. | + +So in practice there are really only two presets that matter: +- **`dev`** — fast no-deps build to confirm the skeleton compiles. +- **`m1-dev`** — everything else: real protocol, real voice, real manual testing. + +## 2. One-time setup for the real-deps presets + +`m1-dev`, `m2-dev`, and `server-release` all need `VCPKG_ROOT` pointing at a bootstrapped +vcpkg checkout: + +```bash +# once: +git clone https://github.com/microsoft/vcpkg +./vcpkg/bootstrap-vcpkg.sh # .bat on Windows + +# every shell session (PowerShell): +$env:VCPKG_ROOT = "D:\path\to\vcpkg" +``` + +`vcpkg.json` (manifest mode) pins every dependency (protobuf, mbedTLS, libsodium, asio, +sqlite3, spdlog, opus, miniaudio) — `cmake --preset m1-dev` resolves and builds them +automatically on first configure. That first configure is slow (vcpkg building from source); +subsequent ones are cached. + +## 3. Build + test (the loop you'll run constantly) + +```bash +cmake --preset m1-dev +cmake --build --preset m1-dev +ctest --test-dir build/m1-dev --output-on-failure +``` + +(`ctest --preset m1-dev` is equivalent — both are wired up in `CMakePresets.json`.) Binaries +land in `build/m1-dev/bin/` (`.exe` suffix on Windows): + +- `build/m1-dev/bin/voicecat-server` +- `build/m1-dev/bin/vccli` +- `build/m1-dev/bin/voicecat-admin` + +## 4. Manual testing: server + two clients + +### Start the server + +```bash +./build/m1-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 +SQLite store, and creates a default "Lobby" channel. Other server flags: + +``` +--port control+media port (default 8384) +--data-dir data directory (default ./voicecat-data) +--name server name +--no-guests disable guest access (then provision accounts via voicecat-admin) +--print-config print effective config and exit +--version print version and exit +``` + +### Drive it with `vccli` + +`vccli` is the headless client used to exercise the protocol by hand. Full flag list: + +``` +vccli [--host H] [--port P] [--nick NAME] [--channel ID] + [--voice] [--mute] [--text MSG] [--list-devices] + [--input-device ID] [--input-mode vad|ptt] [--share-screen-audio] + + --host H server host (default 127.0.0.1) + --port P server TCP port (default 8384) + --nick NAME guest nickname (default vccli-test) + --channel ID channel to join after auth (default 1, Lobby) + --voice start a MIC stream and stay connected until Ctrl+C + --mute start with the mic muted (only meaningful with --voice) + --text MSG send MSG to the channel, then exit + --list-devices print input/output devices (vc_list_devices) and exit + --input-device ID use device ID (from --list-devices) for the MIC stream + --input-mode vad|ptt send-side input gate mode (default vad) + --share-screen-audio also start a SCREEN_AUDIO stream (WASAPI loopback on Windows) +``` + +While `--voice` is running, stdin accepts `ptt on`, `ptt off`, `mode vad`, `mode ptt` to +toggle the input gate live. + +**Smoke test — two clients talking:** + +```bash +# terminal A +./build/m1-dev/bin/vccli --nick Alice --text "hello from Alice" + +# terminal B (separate window, after A confirms it sent) +./build/m1-dev/bin/vccli --nick Bob --text "hello from Bob" +``` + +**Real voice between two clients (needs working mic/speakers, two terminals):** + +```bash +# terminal A +./build/m1-dev/bin/vccli --nick Alice --voice + +# terminal B +./build/m1-dev/bin/vccli --nick Bob --voice +``` + +Speak into the mic on one side; you should hear it on the other. Ctrl+C to disconnect. + +**Enumerate audio devices before picking one:** + +```bash +./build/m1-dev/bin/vccli --list-devices +./build/m1-dev/bin/vccli --nick Alice --voice --input-device --input-mode ptt +``` + +**Provisioning a non-guest account** (if the server was started with `--no-guests`): + +```bash +./build/m1-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 +``` + +## 5. `server-release` (production-shaped build) + +Same dependency story, but `Release` build type and no tests — this is the closest local +analogue to what `docs/deployment.md`'s "from source" path produces: + +```bash +cmake --preset server-release +cmake --build --preset server-release +./build/server-release/bin/voicecat-server +``` + +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. diff --git a/server/src/main.cpp b/server/src/main.cpp index 17f5b8b..d7eea54 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -1,8 +1,10 @@ /* - * voicecat-server entry point (M0 skeleton). + * voicecat-server entry point. * - * Goal (docs/deployment.md): one command, zero config, encrypted + listening. Today it - * parses a few flags and prints what it would do. + * Goal (docs/deployment.md): one command, zero config, encrypted + listening. Parses flags + * (see docs/building.md for the full list + manual-testing walkthrough) and hands off to + * Server::run() (server.cpp), which really does generate the identity/cert, open the SQLite + * store, and bind the TCP/TLS + UDP listeners. */ #include #include