Files
md-show/vergleichs.md
T

471 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Live Plugin (V8) vs Planned SDK/ServerLib Architecture
A **development-ready** side-by-side comparison of:
| Document side | What it is |
|---|---|
| **Live V8** | Shipping Conan Exiles proximity plugin (`tsmain`): a DLL loaded by the **retail** TeamSpeak 3 client |
| **Plan (Option B)** | New product on branch `ts3-Testing`: custom **ClientLib** app + custom **ServerLib** voice server |
This file answers: *which API does each use, in what order, who sends data to whom, and what actually changes.*
---
## Table of contents
1. [One-sentence difference](#1-one-sentence-difference)
2. [At-a-glance table](#2-at-a-glance-table)
3. [The two SDKs explained](#3-the-two-sdks-explained)
4. [Architecture diagrams](#4-architecture-diagrams)
5. [Lifecycle: boot order (Live V8)](#5-lifecycle-boot-order-live-v8)
6. [Lifecycle: boot order (Plan)](#6-lifecycle-boot-order-plan)
7. [API map: every callback](#7-api-map-every-callback)
8. [API map: every active call we make](#8-api-map-every-active-call-we-make)
9. [Data flow: position](#9-data-flow-position)
10. [Data flow: who hears whom](#10-data-flow-who-hears-whom)
11. [Data flow: 3D and audio effects](#11-data-flow-3d-and-audio-effects)
12. [Threading models](#12-threading-models)
13. [Module map](#13-module-map)
14. [Operations, license, scale](#14-operations-license-scale)
15. [What is reusable vs rewritten](#15-what-is-reusable-vs-rewritten)
16. [Conclusion](#16-conclusion)
---
## 1. One-sentence difference
> **Live V8** is a guest DLL inside retail TeamSpeak that edits voice **locally**.
> **The plan** is our own TeamSpeak-compatible voice stack where a **server** decides who receives whose packets.
Same English word "SDK". Two different TeamSpeak products. Not an upgrade — an architecture switch.
---
## 2. At-a-glance table
| Topic | Live V8 (today) | Plan (Option B) |
|---|---|---|
| Product shape | One DLL (`conan_exiles.dll`) | Client app + server process |
| SDK product | **Client Plugin SDK** (free) | **TeamSpeak 3 SDK** ClientLib + ServerLib (paid) |
| Headers | `sdk/include/ts3_functions.h` | `clientlib.h`, `serverlib.h` |
| Function prefixes | `ts3plugin_*`, `TS3Functions.*` | `ts3client_*`, `ts3server_*` |
| Voice host | Foreign retail `ts3server` | Our `conan-voice-server` |
| User runs | TeamSpeak 3 Client + our plugin | Our Conan Voice Client app |
| Who hears whom | Client PCM mute/gain | Server `ts3server_setClientWhisperList` |
| Position path | Peer-to-peer `sendPluginCommand("CEPOS:…")` | Client → server `CLIENT_META_DATA` |
| Packet bandwidth | All channel members always receive voice | Only audible targets receive voice |
| License | Free | Paid (eval free for development) |
| EOL risk | Tied to TS3 client | TS3 SDK EOL **2027-12-31** |
| Branch | `tsmain` | `ts3-Testing` (isolated) |
---
## 3. The two SDKs explained
### 3.1 Live V8 — Client Plugin SDK
Evidence in this repo:
```1:3:sdk/README.md
# TeamSpeak 3 Client Plugin SDK
Welcome to the official helper repository for creating native plugins for the TeamSpeak 3 Client.
```
- TeamSpeak loads our DLL and calls exported `ts3plugin_*` functions.
- We call back into TeamSpeak through `struct TS3Functions` filled by `ts3plugin_setFunctionPointers`.
- We **cannot** create a virtual server, set server-side whisper routing, or replace TeamSpeak.
- Proximity = edit PCM samples in `ts3plugin_onEditPlaybackVoiceDataEvent`.
There are **zero** `ts3client_*` / `ts3server_*` symbols in this repository.
### 3.2 Plan — TeamSpeak 3 SDK (ClientLib + ServerLib)
- Separate commercial download (not the Plugin SDK folder in this repo).
- We link **ServerLib** into `conan-voice-server` and **ClientLib** into our custom client.
- Retail TeamSpeak **cannot** connect to an SDK ServerLib server (community-confirmed error `0x0705`).
- Users install **our** client app (similar to how Mumble works), not TeamSpeak + a plugin.
```text
Plugin SDK (today) TeamSpeak 3 SDK (plan)
───────────────── ──────────────────────
ts3plugin_* ts3client_* (client app)
TS3Functions.* ts3server_* (our server)
retail TS loads DLL we host ServerLib ourselves
local PCM mix server whisper-list routing
```
---
## 4. Architecture diagrams
### 4.1 Live V8
```mermaid
sequenceDiagram
participant Game as Conan Mod
participant Plugin as Plugin DLL
participant Peer as Other Plugin
participant PCM as Playback PCM
participant Retail as Retail ts3server
Game->>Plugin: Pos.txt (x,y,z,yaw)
Plugin->>Retail: sendPluginCommand("CEPOS:...")
Retail->>Peer: relay plugin command
Peer->>Peer: player_table_put + proximity_math
Retail->>Plugin: voice packets from Peer
Plugin->>PCM: onEditPlaybackVoiceDataEvent gain/pan/filter
```
### 4.2 Plan (Option B)
```mermaid
sequenceDiagram
participant Game as Conan
participant Client as Conan Voice Client
participant Server as Conan Voice Server
participant Router as VoiceRouter
Game->>Client: IGameDataProvider position
Client->>Server: CLIENT_META_DATA + flushClientSelfUpdates
Server->>Server: PlayerManager.updatePos
Router->>Router: spatial hash -> audible set
Router->>Server: ts3server_setClientWhisperList(A,{B,C})
Note over Client,Server: A speaks - only B and C receive packets
Client->>Client: 3D attributes + optional local effects
```
---
## 5. Lifecycle: boot order (Live V8)
Retail TeamSpeak owns the process. Our plugin only hooks in.
```text
1. TeamSpeak loads conan_exiles.dll
2. ts3plugin_name / version / apiVersion / author / description
3. ts3plugin_setFunctionPointers(TS3Functions) -> ts3_adapter_set_functions
4. ts3plugin_registerPluginID(id) -> needed for sendPluginCommand
5. ts3plugin_init()
6. onConnectStatusChangeEvent(STATUS_CONNECTION_ESTABLISHED)
7. Runtime loop (callback thread + CEDRAIN + PCM):
- pos watcher reads Pos.txt
- CEPOS send/receive via onPluginCommandEvent
- proximity recompute on callback thread
- onEditPlaybackVoiceDataEvent applies mix
- systemset3DListenerAttributes / channelset3DAttributes
8. ts3plugin_shutdown() -> ts3_adapter_shutdown
```
Key files:
| Step | File |
|---|---|
| Exports | `src/ts/entry/ts3_exports.h`, `ts3_entry.c` |
| TS API wrapper | `src/ts/adapter/ts3_adapter.c` |
| CEPOS | `src/ts/proximity/ts3_cepos.c` |
| PCM mix | `src/ts/proximity/ts3_proximity_audio.c` |
| 3D | `src/ts/proximity/ts3_3d.c` |
| Position file | `src/core/mod_file/pos_file.c` |
---
## 6. Lifecycle: boot order (Plan)
### 6.1 Server process (`conan-voice-server`)
```text
1. Load config + start logger
2. memset(&ServerLibFunctions, 0, sizeof(...))
3. Assign callbacks (onClientConnected, onClientDisconnected, ...)
4. ts3server_initServerLib(&funcs, LogType_FILE|LogType_CONSOLE, logDir)
5. Create/load server keypair [VERIFY exact name]
6. ts3server_createVirtualServer(port, ip, name, keyPair, maxClients, &serverID)
7. Init PlayerManager, ProximityEngine, VoiceRouter
8. Event loop + routing tick (5-10 Hz)
9. Shutdown:
ts3server_stopVirtualServer(serverID)
ts3server_destroyServerLib()
```
Confirmed server APIs:
| Function | Role |
|---|---|
| `ts3server_initServerLib` | Start ServerLib with callback table |
| `ts3server_createVirtualServer` | Create the virtual server |
| `ts3server_stopVirtualServer` | Stop one virtual server |
| `ts3server_destroyServerLib` | Tear down ServerLib |
| `ts3server_setClientWhisperList` | **Core routing API** |
| `ts3server_getClientList` | Enumerate clients |
| `ts3server_getChannelList` | Enumerate channels |
| `ts3server_freeMemory` | Free SDK-allocated arrays |
### 6.2 Client app (`conan-voice-client`)
```text
1. Fill ClientUIFunctions callbacks
2. ts3client_initClientLib(...)
3. ts3client_spawnNewServerConnectionHandler(0, &scHandlerID)
4. ts3client_createIdentity (or load stored identity)
5. ts3client_openPlaybackDevice / openCaptureDevice
6. ts3client_startConnection(scHandlerID, identity, host, port, nick, ...)
7. Wait onConnectStatusChangeEvent == STATUS_CONNECTION_ESTABLISHED
8. Loop:
- read game position
- setClientSelfVariableAsString(CLIENT_META_DATA, packed)
- flushClientSelfUpdates
- apply 3D listener/speaker attributes
9. Shutdown:
ts3client_stopConnection
ts3client_destroyServerConnectionHandler
ts3client_destroyClientLib
```
---
## 7. API map: every callback
### Live V8 — `ts3plugin_*` (exported)
From `src/ts/entry/ts3_exports.h`:
| Callback | What V8 does with it |
|---|---|
| `ts3plugin_init` / `shutdown` | Start/stop plugin subsystems |
| `ts3plugin_setFunctionPointers` | Store `TS3Functions` into adapter |
| `ts3plugin_registerPluginID` | Required for `sendPluginCommand` |
| `onConnectStatusChangeEvent` | Adopt active connection / reset caches |
| `onPluginCommandEvent` | Receive CEPOS / CEDRAIN / plugin traffic |
| `onEditPlaybackVoiceDataEvent` | **Primary proximity mix** (gain/pan/filter) |
| `onCustom3dRolloffCalculationClientEvent` | Custom distance curve for 3D |
| `onClientMoveEvent` / `onClientMoveMovedEvent` | Hub ↔ ingame channel tracking |
| `onChannelDescriptionUpdateEvent` | Hub settings from root channel description |
| `onUpdateChannelEvent` / `onUpdateChannelEditedEvent` | Channel metadata refresh |
| `onTalkStatusChangeEvent` | Talk indicator / HUD hints |
| `onHotkeyEvent` | Voice-mode hotkeys |
### Plan — ClientLib + ServerLib callbacks
| Side | Callback | Role |
|---|---|---|
| Client | `onConnectStatusChangeEvent` | Connection lifecycle |
| Client | `onEditPlaybackVoiceDataEvent` | Local effects only (reverb/lowpass) |
| Client | `onCustom3dRolloffCalculationClientEvent` | Distance curve |
| Client | `onClientMoveEvent` | Channel visibility |
| Client | `onTalkStatusChangeEvent` | HUD |
| Server | `onClientConnected` | `PlayerManager.add` |
| Server | `onClientDisconnected` | remove + clear whisper list |
| Server | `onClientMoved` | channel tracking |
| Server | `onClientStartTalkingEvent` / `Stop` | diagnostics / HUD hints |
| Server | `onAccountingErrorEvent` | license/slot errors |
Names marked **VERIFY** in the plan must be confirmed against `serverlib.h` / `clientlib.h` in Phase 0.
---
## 8. API map: every active call we make
### Live V8 — through `TS3Functions` (`g_ts3.*` in `ts3_adapter.c`)
| Call | Wrapper | Why |
|---|---|---|
| `sendPluginCommand` | `ts3_send_plugin_command_server` | CEPOS positions + CEDRAIN wakeup |
| `requestUnmuteClientsTemporary` | `ts3_unmute_clients_for_pcm` | PCM hook only receives unmuted clients |
| `setClientVolumeModifier` | (inside unmute path) | Reset volume modifiers |
| `requestClientMove` | `ts3_request_client_move` | Hub ↔ ingame |
| `requestChannelDescription` | `ts3_request_channel_description` | Hub config |
| `getChannelDescription` | `ts3_get_channel_description` | Parse hub settings |
| `systemset3DSettings` | `ts3_set_3d_settings` | 3D global scale |
| `systemset3DListenerAttributes` | `ts3_set_3d_listener` | Listener pose |
| `channelset3DAttributes` | `ts3_set_3d_client` | Per-speaker 3D position |
| get channel/client lists, nicknames, printMessage, logMessage | various | channel manage / UI / logging |
**Missing in Live V8:** any server API that stops packets to non-audible clients.
### Plan — SDK calls
| Call | Side | Why |
|---|---|---|
| `ts3server_initServerLib` / `createVirtualServer` / `stop` / `destroy` | Server | Host voice |
| `ts3server_setClientWhisperList` | Server | **Who hears whom** |
| `ts3server_getClientList` / `getChannelList` / `freeMemory` | Server | Enumerate + free |
| `ts3client_initClientLib` / `spawnNewServerConnectionHandler` | Client | Host client |
| `ts3client_createIdentity` / `startConnection` / `stopConnection` | Client | Connect |
| `ts3client_setClientSelfVariableAsString(CLIENT_META_DATA)` | Client | Send position/state |
| `ts3client_flushClientSelfUpdates` | Client | Push metadata to server |
| `ts3client_systemset3DListenerAttributes` | Client | Listener 3D |
| `ts3client_channelset3DAttributes` | Client | Speaker 3D |
| `ts3client_openPlaybackDevice` / `openCaptureDevice` | Client | Audio devices |
---
## 9. Data flow: position
| Step | Live V8 | Plan |
|---|---|---|
| 1. Game source | Mod writes `Pos.txt` | Same idea via `IGameDataProvider` |
| 2. Read | `pos_file.c` watcher (~30 ms) | Game provider thread (~20–30 Hz) |
| 3. Pack | CEPOS 56-byte base64 | Compact binary/base64 in `CLIENT_META_DATA` (≤4096 B) |
| 4. Send | `sendPluginCommand("CEPOS:…")` to **all clients** | `setClientSelfVariableAsString` + `flushClientSelfUpdates` to **server** |
| 5. Receive | `onPluginCommandEvent` → `player_table_put` | Server reads metadata → `PlayerManager.updatePos` |
| 6. Distance math | **Each client** (`proximity_math`) | **Server** (`ProximityEngine`) |
| 7. Trust | Client-reported (spoofable) | Client-reported (spoofable); server still owns routing/permissions |
```text
Live V8: A ──CEPOS──▶ B,C,D (everyone learns A's position)
Plan: A ──META───▶ Server ──whisper lists──▶ only who should hear A
```
---
## 10. Data flow: who hears whom
### Live V8 (local presentation only)
```text
Retail server delivers everyone's voice in the channel
│
▼
onEditPlaybackVoiceDataEvent(clientID, samples[])
│
├─ distance far → multiply samples by ~0 (mute)
├─ distance near → gain + pan + lowpass/reverb
└─ must unmute via requestUnmuteClientsTemporary
otherwise PCM hook gets nothing
```
Result: **bandwidth still paid for every speaker**. Hearing is a local volume illusion.
### Plan (real network routing)
```text
VoiceRouter tick (5-10 Hz)
for each speaker S:
audible = proximity ∪ radio ∪ whisper ∪ global ∩ permissions
if audible changed:
ts3server_setClientWhisperList(serverID, S, NULL, audibleClientIds)
# or clear with (NULL, NULL)
```
Result: non-audible clients **never receive** S's voice packets.
> [!WARNING]
> With an active whisper list, normal channel talk for that client is disabled.
> Therefore **all** proximity/radio/whisper/global must be expressed as whisper lists.
---
## 11. Data flow: 3D and audio effects
| Concern | Live V8 | Plan |
|---|---|---|
| Listener pose | `systemset3DListenerAttributes` | `ts3client_systemset3DListenerAttributes` |
| Speaker pose | `channelset3DAttributes` | `ts3client_channelset3DAttributes` |
| Global 3D | `systemset3DSettings` | `ts3client_systemset3DSettings` |
| Custom curve | `onCustom3dRolloffCalculationClientEvent` | Same idea on ClientLib |
| Cave reverb / lowpass | PCM path in `ts3_proximity_audio.c` | Still client PCM; server may send env state (CAVE/NORMAL) |
**Portable:** 3D call pattern and effect DSP.
**Not portable:** using PCM mute as the *primary* "who hears whom" mechanism.
---
## 12. Threading models
### Live V8 (strict)
| Thread | May do | Must not |
|---|---|---|
| TS callback | All `TS3Functions` / CEDRAIN drain | Block |
| Wakeup | Only `sendPluginCommand("CEDRAIN:1")` | Other TS API |
| PCM audio | Read snapshots; apply gain/pan | TS API, locks |
| Pos watcher / UI | Set flags + wakeup | TS API |
### Plan
| Thread | May do | Must not |
|---|---|---|
| SDK server callbacks | Short handoff into our queues | Heavy proximity math inline |
| Routing tick (5–10 Hz) | Compute audible sets; call `setClientWhisperList` | Game file I/O |
| SDK client callbacks | Connection/PCM/3D | Block |
| Game provider (~20 Hz) | Read Conan; publish snapshot | Direct SDK calls without adapter |
Same discipline as V8: **one adapter owns all SDK calls**.
---
## 13. Module map
| Concern | Live V8 files | Plan modules |
|---|---|---|
| Entry / lifecycle | `ts3_entry.c` | `client/main.c`, `server/main.c` |
| TS API wrapper | `ts3_adapter.c` | `TeamSpeakClientAdapter`, `TeamSpeakServerAdapter` |
| Positions | `pos_file.c`, `ts3_cepos.c` | `IGameDataProvider`, `CLIENT_META_DATA` |
| Player table | `player_table.c` | `PlayerManager` (server) |
| Proximity math | `proximity_math.c`, `zone_resolve.c` | `ProximityEngine` (server) |
| Hearability | PCM + volume modifier | `VoiceRouter` + whisper lists |
| 3D | `ts3_3d.c` | ClientLib 3D calls |
| Hub config | `hub_parser.c`, `ts3_server_profile.c` | root-channel / server config |
| Voice modes | `voice_modes.c` | client state + server ranges |
| UI / HUD | `ui_main.c`, overlay | client HUD |
---
## 14. Operations, license, scale
| Topic | Live V8 | Plan |
|---|---|---|
| User install | DLL → `%AppData%\TS3Client\plugins\` | Install custom client |
| Server ops | None (use any retail TS server) | Own Linux process, systemd, monitoring |
| Build | MSVC + MinGW cross + gcc tests | CMake: client + server + shared |
| License | Free Plugin SDK | Paid SDK; evaluation for PoC |
| Scale target | ~200 players (512 table cap) | License slot cap + routing cost |
| EOL | TS3 client lifetime | **SDK EOL 2027-12-31** |
---
## 15. What is reusable vs rewritten
### Reuse (rewrite into new adapters — do not blind-copy)
- Proximity math / zones (`proximity_math`, `zone_resolve`)
- PCM effects (reverb/lowpass patterns from `ts3_proximity_audio.c`)
- 3D call sequencing ideas from `ts3_3d.c`
- Position acquisition ideas from `pos_file.c` / Mumble reference
- HUD / voice-mode UX concepts
### Must be new
- Entire ServerLib host process
- Entire ClientLib application shell
- Whisper-list router as the hearability authority
- `CLIENT_META_DATA` (or equivalent) transport replacing CEPOS P2P
- License/accounting handling
- Deployment (systemd, crash recovery)
### Explicitly abandoned for Option B
- Depending on retail TeamSpeak client
- CEPOS peer-to-peer as the primary position bus
- Local PCM mute as the primary routing mechanism
---
## 16. Conclusion
| | Live V8 | Plan |
|---|---|---|
| Strength | Ships today; free; users already have TeamSpeak | True server routing; central authority; bandwidth win |
| Weakness | Everyone still receives packets; client can spoof position; no server game logic | New client+server product; paid license; SDK EOL 2027; retail TS gone |
| Right next step | Continue maintaining on `tsmain` | On `ts3-Testing`: prove ServerLib boot + whisper routing **before** Conan code |
> [!IMPORTANT]
> Do not write Conan integration for Option B until Phase 0–3 succeed:
> SDK examples build → server starts/stops → two clients talk →
> `ts3server_setClientWhisperList` proves **A hears B, not C**.
---
*Related living plan:* [`.cursor/plans/voice_architecture_plan_ed3d8830.plan.md`](.cursor/plans/voice_architecture_plan_ed3d8830.plan.md)