Talon 118ca5129f fix(protocol): deliver self-initiated state changes to the actor too
A connected Windows client would randomly snap from its joined channel
back to Lobby. Root cause was a state-sync inconsistency, not a drop:
the server delivered self-initiated state changes (channel join/leave,
stream announce/stop) only as a private *Result to the actor and
broadcast the authoritative UserEvent::UPDATED to everyone else. The
core never applied the result to its SessionModel, so vc_list_users()
kept self in the old channel; the Windows HandleUserUpdated rebuilds
_currentChannelId from vc_list_users() on any user's UPDATED event, so
the next unrelated event surfaced the stale self-channel.

Fix, per the response-vs-broadcast contract now documented in
docs/protocol.md §6: the *Result is pure ack/correlation/actor-private
payload; the resulting state change is broadcast to every client
INCLUDING the actor, and clients apply it to their local model rather
than re-deriving own state from a *Result.

- server: join/leave/stream announce+stop broadcast with exclude=0
- server: text fan-out includes the sender (channel + private echo)
- core: response handlers no longer mutate session_model_
- windows: drop optimistic text echo; render own message via the relay
- docs/protocol.md §6: document the response-vs-broadcast contract

Registry-level admin broadcasts (move/mute/kick/channel CRUD) already
used exclude=0 and were correct. ctest build/m1-dev 18/18 green;
VoiceCat.App builds 0 warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:48:50 +02:00
2026-06-17 00:52:02 +02:00

VoiceCat

Self-hosted, native voice & text chat in the spirit of classic TeamSpeak / Mumble — channel-based voice, channel + private text, one server you run yourself. Plain TCP (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.

Status: pre-implementation. The design is complete in docs/. The code is an M0 skeleton — it compiles and links, but every subsystem is a stub. See AGENTS.md to start building, and docs/roadmap.md for the milestones.

Read the design first

The docs/ folder is the source of truth. Start at docs/README.md, then architectureprotocolvoicesecuritytech-stackdeploymentroadmap.

Build the skeleton (no dependencies needed yet)

The M0 skeleton builds with just a C++20 compiler + CMake + Ninja — no vcpkg, no third-party libraries, because every subsystem is currently a stub.

cmake --preset dev
cmake --build --preset dev
ctest --preset dev            # runs the smoke test (links the core, calls the C ABI)

Artifacts land in build/dev/bin/ (voicecat-server, vccli).

When you start implementing a subsystem that needs real libraries, build with vcpkg deps:

# one-time: git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh
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

Layout

docs/         design spec (read this)
core/         libvoicecat — the shared C++ core
  include/    voicecat.h  (the C ABI all clients call)
  proto/      voicecat.proto  (control-plane wire format, source of truth)
  src/        net/ crypto/ codec/ protocol/ session/ audio/  (stubs today)
server/       voicecat-server (headless; links the core)
tools/vccli/  headless test client — drives the protocol from M1 on
clients/      apple/ (Swift, M4)   windows/ (C#, M4)   — placeholders for now
tests/        CTest targets

License

Permissive-only dependencies (no GPL/LGPL) so the project can be redistributed freely, including closed-source. Project license: TBD (see docs/tech-stack.md §5).

Description
Native voice chat server and client
Readme 12 MiB
Languages
C++ 43.9%
Swift 30.6%
C# 17.5%
Shell 3.6%
CMake 2.1%
Other 2.3%