Files
md-show/vergleichs.md
T

11 KiB

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)

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)

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.