Files
md-show/vergleichs.md
T

18 KiB
Raw Blame History

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
  2. At-a-glance table
  3. The two SDKs explained
  4. Architecture diagrams
  5. Lifecycle: boot order (Live V8)
  6. Lifecycle: boot order (Plan)
  7. API map: every callback
  8. API map: every active call we make
  9. Data flow: position
  10. Data flow: who hears whom
  11. Data flow: 3D and audio effects
  12. Threading models
  13. Module map
  14. Operations, license, scale
  15. What is reusable vs rewritten
  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:

# 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.
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

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)

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.

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)

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)

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
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)

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)

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