Files
md-show/vergleichs.md
T

219 lines
11 KiB
Markdown

# Live Plugin (V8) vs. Planned SDK/ServerLib Architecture
A detailed, side-by-side comparison of **what the shipping plugin does today** (V8, branch `tsmain`)
versus **what the new plan proposes** (branch `ts3-Testing`, "Option B"): which API each uses,
what stays the same, and what fundamentally changes.
> [!IMPORTANT]
> Both use "a TeamSpeak SDK" — but **two completely different ones**.
> **Today:** the *Client Plugin SDK* (a guest inside the retail TeamSpeak client).
> **Plan:** the *TeamSpeak 3 SDK* (ClientLib + ServerLib — your own client and your own server).
> Same word, opposite architecture.
---
## 1. At a glance
| Topic | Live V8 (today) | Plan (Option B) |
|---|---|---|
| SDK used | **Client Plugin SDK** | **TeamSpeak 3 SDK** (ClientLib + ServerLib) |
| Header(s) | `sdk/include/ts3_functions.h` (`TS3Functions`) | `clientlib.h` + `serverlib.h` |
| Function family | `ts3plugin_*` (callbacks), `ts3Functions->*` | `ts3client_*` and `ts3server_*` |
| What "the server" is | Retail `ts3server` (foreign) | **Our own** `conan-voice-server` (ServerLib) |
| What "the client" is | Retail TeamSpeak loads our DLL | **Our own** app embedding ClientLib |
| Who decides "who hears whom" | The client, locally (volume/mute) | The **server** (`ts3server_setClientWhisperList`) |
| Position exchange | Peer-to-peer via `sendPluginCommand` (CEPOS) | Client to server via `CLIENT_META_DATA` |
| Audio control | `onEditPlaybackVoiceDataEvent` (edits samples) | Server-side whisper routing + client-side 3D/PCM |
| 3D sound | `systemset3D*` / `channelset3DAttributes` (in plugin) | Same `ts3client_*3D*` functions (in our app) |
| Needs retail TeamSpeak | **Yes** (users already have it) | **No** — a custom client app is required |
| License | Free | **Paid** (free evaluation for dev only) |
| Lifecycle | Tied to TS3 | TS3 SDK **EOL 2027-12-31** |
| "Who hears whom" reach | Local volume only; everyone still gets packets | Real packet routing (B/C never receive A) |
| Effort | Exists, ships today | Build **both** a client and a server |
---
## 2. The two SDKs — the root of the confusion
The word "SDK" refers to two different TeamSpeak products.
### 2a. Today: Client Plugin SDK
- Proof in the repo: `sdk/README.md`, line 1 = "TeamSpeak 3 Client Plugin SDK".
- We ship a **DLL** that the **retail TeamSpeak client loads**.
- We are a guest: we react to events (`ts3plugin_*`) and trigger a few client actions
through the function table `TS3Functions`.
- We **cannot** route voice at the server level. We can only alter incoming voice
**locally** (quieter, pan, filter).
### 2b. Plan: TeamSpeak 3 SDK (ClientLib + ServerLib)
- A separate download, different libraries, different function families
(`ts3client_*` and `ts3server_*`).
- We **host our own voice server** (ServerLib) and **build our own client** (ClientLib).
- The retail TeamSpeak client is no longer involved — and in fact **cannot** connect to
an SDK server (error `0x0705`, per TeamSpeak docs).
> [!NOTE]
> This is not an "update" — it is an architecture switch: from "a plugin guest inside
> TeamSpeak" to "a standalone client + server product".
---
## 3. Architecture, side by side
### Live V8 (today)
```mermaid
flowchart TD
mod["Conan Exiles mod"] -->|"Pos.txt"| plugin["Our plugin (DLL inside retail TeamSpeak)"]
plugin -->|"sendPluginCommand CEPOS"| peers["Other clients"]
peers -->|"CEPOS packets"| plugin
plugin -->|"onEditPlaybackVoiceDataEvent: gain/pan/filter"| out["Local audio output"]
ts["Retail ts3server"] -.->|"transport + channels only, no game logic"| plugin
```
- Each client computes **for itself** how loud it hears the others.
- Positions travel **peer-to-peer** via plugin commands (the retail server just relays them).
- "Who hears whom" is really just a **volume**: voice packets still reach everyone in the
channel; they are only mixed quiet/muted locally.
### Plan (Option B)
```mermaid
flowchart TD
game["Conan Exiles"] -->|"local IPC"| client["Conan Voice Client (custom app, ClientLib)"]
client -->|"CLIENT_META_DATA = position"| server["Conan Voice Server (custom process, ServerLib)"]
server -->|"PlayerManager + ProximityEngine + VoiceRouter"| router["setClientWhisperList A to B,C"]
router --> transport["TeamSpeak voice transport (SDK)"]
transport -->|"A's voice only to B and C"| listeners["Clients B, C (D gets nothing)"]
```
- The **server** decides centrally who hears whom, and enforces it via whisper lists (real routing).
- Positions go **client to server** (no longer peer-to-peer).
---
## 4. API comparison — concrete functions
### 4a. Callbacks (events we react to)
| Purpose | Live V8 (`ts3plugin_*`) | Plan (`ts3client_*` / `ts3server_*`) |
|---|---|---|
| Connection status | `onConnectStatusChangeEvent` | Client: `onConnectStatusChangeEvent` |
| Our own data transfer | `onPluginCommandEvent` (CEPOS/CEDRAIN) | Server: read `CLIENT_META_DATA` change |
| Alter audio | `onEditPlaybackVoiceDataEvent` | Client: `onEditPlaybackVoiceDataEvent` (local effects only) |
| 3D rolloff | `onCustom3dRolloffCalculationClientEvent` | Client: `onCustom3dRolloffCalculationClientEvent` |
| Client moves | `onClientMoveEvent` / `onClientMoveMovedEvent` | Server: `onClientMoved`; Client: `onClientMoveEvent` |
| Channel description (hub) | `onChannelDescriptionUpdateEvent`, `onUpdateChannelEvent`, `onUpdateChannelEditedEvent` | Handled differently (root-channel config) |
| Who is talking | `onTalkStatusChangeEvent` | Server: `onClientStartTalkingEvent` / `onClientStopTalkingEvent` |
| Connect/disconnect (server) | not available to us | Server: `onClientConnected` / `onClientDisconnected` |
*Evidence: `src/ts/entry/ts3_exports.h`, `src/ts/entry/ts3_entry.c`.*
### 4b. Functions we actively call (what we trigger)
| Purpose | Live V8 (`TS3Functions`, `g_ts3.*`) | Plan (SDK) |
|---|---|---|
| Send our own data | `sendPluginCommand("CEPOS:...")` | Client: `setClientSelfVariableAsString(CLIENT_META_DATA)` + `flushClientSelfUpdates` |
| Wakeup / tick | `sendPluginCommand("CEDRAIN:1")` | Own event loop in the server |
| Unmute clients | `requestUnmuteClientsTemporary` | Not needed (routing is server-side) |
| Per-client volume | `setClientVolumeModifier` | Mainly via whisper routing; fine gain optionally local |
| Move into channel (hub) | `requestClientMove` | Server: `ts3server_*` channel ops |
| 3D global | `systemset3DSettings` | Client: `ts3client_systemset3DSettings` |
| 3D listener (self) | `systemset3DListenerAttributes` | Client: `ts3client_systemset3DListenerAttributes` |
| 3D per speaker | `channelset3DAttributes` | Client: `ts3client_channelset3DAttributes` |
| **Who hears whom (routing)** | **does not exist** (local volume only) | **Server: `ts3server_setClientWhisperList`** |
| Start server | not applicable | `ts3server_initServerLib` then `ts3server_createVirtualServer` |
| Stop server | not applicable | `ts3server_stopVirtualServer` then `ts3server_destroyServerLib` |
| Start client | (retail client does this) | `ts3client_initClientLib` then `spawnNewServerConnectionHandler` then `startConnection` |
*Evidence: `src/ts/adapter/ts3_adapter.c` (around lines 427, 653-690, 737-768).*
> [!TIP]
> The 3D functions (`systemset3DListenerAttributes`, `channelset3DAttributes`,
> `systemset3DSettings`) are named almost identically in **both** SDKs, so that part is
> largely portable. The **big** difference is routing: `ts3server_setClientWhisperList`
> exists only in the ServerLib.
---
## 5. Data flow in detail
### 5a. Position exchange
| | Live V8 | Plan |
|---|---|---|
| Source | `Pos.txt` (game mod) via `pos_file.c` | `IGameDataProvider` (ported from Mumble/V8) |
| Packing | CEPOS, 56 bytes, base64 | compact binary/base64 in `CLIENT_META_DATA` (max 4096 B) |
| Path | Client to **all** clients (peer-to-peer, `sendPluginCommand`) | Client to **server** (`CLIENT_META_DATA`) |
| Who computes distance | **each client itself** | **the server** (authoritative) |
| Trust | Client reports its position (spoofable) | Client reports position (spoofable) — server is still the authority for routing/permissions |
### 5b. "Who hears whom"
- **Live V8:** purely client-side. All voice packets arrive; the plugin only makes remote
speakers **quieter or muted** (`onEditPlaybackVoiceDataEvent` + `setClientVolumeModifier`).
Bandwidth: every packet always flows.
- **Plan:** server-side. The `VoiceRouter` builds a target list per speaker and calls
`ts3server_setClientWhisperList(A, ..., {B,C})`. Anyone not on the list never receives A's
voice at all.
> [!WARNING]
> While a whisper list is active, that client's normal channel talk path is disabled.
> Therefore **everything** must be routed through whisper lists for routed players.
### 5c. Audio effects (cave reverb, lowpass)
- **Live V8:** applied directly on the samples in `onEditPlaybackVoiceDataEvent`
(`ts3_proximity_audio.c`, lock-free snapshot pattern).
- **Plan:** the same logic stays **client-side** (the custom app also has
`onEditPlaybackVoiceDataEvent`), driven by a server-provided environment state
(NORMAL/CAVE/...). So the effect code is **reusable**.
---
## 6. Operations, deployment, license
| Topic | Live V8 | Plan |
|---|---|---|
| User install | DLL into `%AppData%\TS3Client\plugins\` | Install/run a custom client app |
| Server operation | none (retail server is enough) | Own process (Linux/systemd), monitoring, crash recovery |
| Build | MSVC + MinGW cross, gcc unit tests | CMake for client + server + shared |
| License | free (Plugin SDK) | paid, case by case; evaluation free for dev only |
| Lifecycle | as long as TS3 lives | TS3 SDK **EOL 2027-12-31** — keep an `IVoiceTransport` seam as exit |
| Scale | callback thread + PCM, ~200 players target | server-side routing, but slot cap per license |
---
## 7. What stays the same / is reusable
- **Proximity math** (`proximity_math`, `zone_resolve`) → port into the ServerLib engine (rewrite, don't copy).
- **Audio effects** (reverb/lowpass in `ts3_proximity_audio.c`) → usable almost as-is, client-side.
- **3D calls** (`systemset3D*`, `channelset3DAttributes`) → nearly identical names.
- **Position source** (`pos_file.c`, path detection) → wrap as `IGameDataProvider`.
- **HUD / voice modes / config / hub-parser ideas** → carry over as logic.
## 8. What is fundamentally different
1. **Two new processes** (a custom client **and** a custom server) instead of one DLL.
2. **Routing moves from client to server** (whisper lists instead of local volume).
3. **Position path reverses**: no longer peer-to-peer, but client to server.
4. **Retail TeamSpeak disappears** — users need our app.
5. **License and EOL** become new concerns.
---
## 9. Conclusion
- Live V8 is a **plugin inside someone else's TeamSpeak**: easy to distribute, free, but
"who hears whom" is only a **local volume** (all packets always flow).
- The plan is a **standalone voice product** on the TeamSpeak **server** library: **real**
server-side routing, at the cost of building a client and server, a paid license, and a
2027 EOL date.
- Reusable above all: **proximity math, audio effects, and 3D calls**. New and risky:
**ServerLib hosting, whisper routing, data transport (`CLIENT_META_DATA`), and licensing**.
> [!IMPORTANT]
> The plan only makes sense once the PoC (phases 0-3) proves that the ServerLib starts
> cleanly and whisper routing "A hears B, not C" actually works. Before that, no Conan code
> is worth writing.