diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..b3397df --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,190 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to the Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by the Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Copyright 2024-2026 Chanora Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..a5e0bf0 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024-2026 Chanora Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/governance/codebase-analysis-2026-06-11.md b/docs/governance/codebase-analysis-2026-06-11.md new file mode 100644 index 0000000..b4912b7 --- /dev/null +++ b/docs/governance/codebase-analysis-2026-06-11.md @@ -0,0 +1,542 @@ +# Chanora Codebase Analysis Report + +**Date:** 2026-06-11 +**Branch:** `docs/codebase-analysis-v2` +**Scope:** Full codebase analysis — functions, tests, documentation, dead code, duplication, architecture, external research + +--- + +## Table of Contents + +1. [Executive Summary](#1-executive-summary) +2. [Function Inventory](#2-function-inventory) +3. [Test Coverage](#3-test-coverage) +4. [Documentation Coverage](#4-documentation-coverage) +5. [Dead Code Analysis](#5-dead-code-analysis) +6. [Useless/Redundant Code](#6-uselessredundant-code) +7. [Duplicated Code](#7-duplicated-code) +8. [Document Link Coverage](#8-document-link-coverage) +9. [Git History & Issue Patterns](#9-git-history--issue-patterns) +10. [PR Analysis](#10-pr-analysis) +11. [API Gap Analysis](#11-api-gap-analysis) +12. [Crate Architecture Analysis](#12-crate-architecture-analysis) +13. [Document Staleness Analysis](#13-document-staleness-analysis) +14. [Test Environment Requirements](#14-test-environment-requirements) +15. [External Research](#15-external-research) +16. [Recommendations](#16-recommendations) + +--- + +## 1. Executive Summary + +### Key Metrics + +| Metric | Value | +|--------|-------| +| **Total Rust public functions** | ~428 | +| **Total Flutter/Dart functions** | ~586 | +| **Rust test count** | 359 | +| **Flutter test count** | 221 | +| **Total test count** | 580 | +| **Overall test coverage** | 75% of modules | +| **Documentation coverage (Rust)** | 30% of functions have doc comments | +| **Documentation coverage (Flutter)** | 58% of classes documented | +| **Dead code items** | ~20 (5 definitely dead, 11 likely dead, 4 conditionally dead) | +| **Duplicated code patterns** | 10 major patterns | +| **Broken doc links** | 6 (all from missing LICENSE files) | +| **Orphaned docs** | 14 files | +| **Stale documents** | 5/8 major docs need updates | +| **PRs analyzed** | 42 (34 merged, 8 closed) | +| **Issues documented in history** | 45 significant issues | + +### Critical Findings + +1. **iOS audio is the #1 problem area** — 15+ issues, AVAudioSession lifecycle is the most recurring root cause +2. **chanora_audio has 168 public functions but only 24% documented** — largest crate, most complex +3. **chanora_bridge has 0 tests** — the Flutter-Rust boundary is completely untested +4. **53 SysRS requirements (SysRS-258–310) lack SysDes allocation** — breaks traceability +5. **Several features exist without requirements** — poke, file transfer, hard-mute, cache +6. **engine.rs is 3,244 lines** — monolithic, needs splitting +7. **main.dart is 2,910 lines** — monolithic, needs splitting +8. **~39 production `unwrap()` calls in engine.rs** — crash risk on poisoned mutex + +--- + +## 2. Function Inventory + +### Summary by Component + +| Component | Type | Total `pub fn` | Documented | Coverage | +|---|---|---|---|---| +| **chanora_core** | Rust lib | 68 | 65 | 96% | +| **chanora_audio** | Rust crate | 168 | ~40 | 24% | +| **chanora_bridge** | Rust crate | 65 | ~10 | 15% | +| **chanora_protocol** | Rust crate | 35 | 33 | 94% | +| **chanora_state** | Rust crate | 16 | ~8 | 50% | +| **chanora_storage** | Rust crate | 20 | ~12 | 60% | +| **chanora_cache** | Rust crate | 7 | 7 | 100% | +| **chanora_resolver** | Rust crate | 15 | ~8 | 50% | +| **chanora_diagnostics** | Rust crate | 27 | ~15 | 50% | +| **chanora_prefetch** | Rust crate | 7 | 4 | 57% | +| **Flutter app** | Dart | ~586 | ~5 | <1% | + +### Potentially Unused Functions + +Functions defined but never called from outside their module: + +| Crate | Function | File:Line | +|---|---|---| +| chanora_core | `ChanoraSession::protocol_events_snapshot()` | lib.rs:788 | +| chanora_audio | `AudioEngine::capture_active()` | engine.rs:1621 | +| chanora_audio | `AudioEngine::frames_sent()` | engine.rs:1626 | +| chanora_audio | `AudioEngine::frames_received()` | engine.rs:1631 | +| chanora_audio | `HpfProcessor::process_sample()` | dsp/hpf.rs:63 | +| chanora_audio | `CoreMlWorker::reset_state()` | apple_coreml.rs:140 | +| chanora_audio | `PttCapabilityLevel::is_global()` | ptt.rs:72 | +| chanora_bridge | `handle_media_services_reset_with_route()` | api.rs:696 | +| chanora_bridge | `handle_interruption_began()` | api.rs:703 | +| chanora_state | `ServerState::replace_from_snapshot()` | lib.rs:114 | +| chanora_state | `ServerState::channel_count()` | lib.rs:148 | +| chanora_state | `ServerState::client_count()` | lib.rs:153 | +| chanora_storage | `BookmarkStore::upsert_or_add()` | lib.rs:891 | +| chanora_resolver | `normalize_args()` | lib.rs:778 | +| chanora_resolver | `validate_args()` | lib.rs:785 | + +--- + +## 3. Test Coverage + +### Summary by Component + +| Component | Source Modules | Modules w/ Tests | Coverage % | Test Count | +|---|---|---|---|---| +| **chanora_audio** | 43 | 35 | 81% | 221 | +| **chanora_bridge** | 5 | 0 | **0%** | 0 | +| **chanora_cache** | 1 | 1 | 100% | 7 | +| **chanora_diagnostics** | 1 | 1 | 100% | 19 | +| **chanora_prefetch** | 1 | 1 | 100% | 6 | +| **chanora_protocol** | 4 | 2 | 50% | 23 | +| **chanora_resolver** | 1 | 1 | 100% | 14 | +| **chanora_state** | 2 | 2 | 100% | 27 | +| **chanora_storage** | 1 | 1 | 100% | 15 | +| **chanora_core** | 5 | 4 | 80% | 27 | +| **Flutter (services)** | 24 | 22 | 92% | 124 | +| **Flutter (widgets)** | 25 | 14 | 56% | 97 | +| **TOTAL** | **113** | **85** | **75%** | **580** | + +### Critical Untested Areas + +| Component | Module | Risk | +|---|---|---| +| **chanora_bridge** | All 5 modules | **High** — FFI boundary, zero tests | +| **Flutter widgets** | `voice_bar`, `voice_settings`, `connect_widgets` | **High** — core UI | +| **chanora_protocol** | `dto` module | **Medium** — serialization bugs | +| **chanora_core** | `events` module | **Medium** — event system | + +--- + +## 4. Documentation Coverage + +### Doc Comment Coverage (Rust) + +| Crate | Functions | With Doc Comments | Coverage | +|---|---|---|---| +| chanora_core | 68 | 65 | 96% | +| chanora_audio | 168 | ~40 | 24% | +| chanora_bridge | 65 | ~10 | 15% | +| chanora_protocol | 35 | 33 | 94% | +| chanora_cache | 7 | 7 | 100% | +| chanora_state | 16 | ~8 | 50% | +| chanora_storage | 20 | ~12 | 60% | +| chanora_resolver | 15 | ~8 | 50% | +| chanora_diagnostics | 27 | ~15 | 50% | +| chanora_prefetch | 7 | 4 | 57% | + +### Missing README Files + +| Directory | Status | +|---|---| +| crates/chanora_audio/ | **MISSING** | +| crates/chanora_bridge/ | **MISSING** | +| crates/chanora_cache/ | **MISSING** | +| crates/chanora_diagnostics/ | **MISSING** | +| crates/chanora_prefetch/ | **MISSING** | +| crates/chanora_protocol/ | **MISSING** | +| crates/chanora_state/ | **MISSING** | +| crates/chanora_storage/ | **MISSING** | +| core/chanora_core/ | **MISSING** | + +Only `crates/chanora_resolver/README.md` exists. + +--- + +## 5. Dead Code Analysis + +### Definitely Dead (safe to remove) + +| Item | File:Line | Evidence | +|------|-----------|----------| +| `AudioFrame10ms` struct | frame.rs:21 | Never referenced outside tests | +| `AudioFrame20ms` struct | frame.rs:28 | Never referenced outside tests | +| `AudioFrame10ms::dbfs()` | frame.rs:58 | Never called anywhere | +| `disable_failed_vad_backend()` | audio_processing.rs:216 | Only called in tests | +| `import 'package:share_plus/share_plus.dart'` | main.dart:55 | `Share` class never used | + +### Likely Dead (no production callers) + +| Item | File:Line | +|------|-----------| +| `AudioEngine::output_muted()` | engine.rs:1707 | +| `AudioEngine::output_gain()` | engine.rs:1720 | +| `AudioEngine::capture_active()` | engine.rs:1621 | +| `AudioEngine::transmit_gate()` | engine.rs:1614 | +| `AudioEngine::set_transmit_active()` | engine.rs:1601 | +| `AudioEngine::android_diagnostics()` | engine.rs:1694 | +| `TransmitModeSelector::gate()` | transmit_selector.rs:253 | +| `TransmitModeSelector::in_channel()` | transmit_selector.rs:198 | +| `TransmitModeSelector::ptt_held()` | transmit_selector.rs:226 | +| `ReleaseTailTimer::cancel()` | release_tail.rs:133 | +| `ReleaseTailTimer::arm()` | release_tail.rs:70 | + +### `#[allow(dead_code)]` Annotated Items + +| Item | Status | +|------|--------| +| `AudioCommand::RemoveClient` | TODO: "Wire to client disconnect path" | +| `android_render_ring` module | Conditionally dead (non-Android) | +| `audio_event_queue` module | Conditionally dead (non-Android) | +| `capture_accumulator` module | Conditionally dead (non-Android) | + +--- + +## 6. Useless/Redundant Code + +### TODO/FIXME/HACK Inventory (12 entries, 14 occurrences) + +| File | Line | Content | +|------|------|---------| +| engine.rs | 2348 | TODO: realtime-audio callback concern | +| mobile_voice_backend.rs | 16 | TODO(SDD-117): back-fill IosVoiceUnit | +| audio_event_queue.rs | 27 | TODO: Wire to client disconnect path | +| audio_lifecycle_service.dart | 151,156 | TODO: macosDefaultDeviceChanged (×2) | +| poke_notification_service.dart | 33-168 | TODO(event-sounds) (×10) | + +### Risky Code + +| Risk | Location | Count | +|------|----------|-------| +| Production `unwrap()` | engine.rs | ~39 | +| `unsafe impl Send/Sync` | Various | 8 | +| `unimplemented!("")` in FRB | frb_generated.rs | 23 | + +### Complexity Warnings + +| File | Lines | Risk | +|------|-------|------| +| engine.rs | 3,244 | **High** — monolithic audio engine | +| main.dart | 2,910 | **High** — monolithic Flutter entry | +| adapter.rs | 2,504 | Medium | +| api.rs | 2,432 | Medium | + +--- + +## 7. Duplicated Code + +### Major Patterns + +| # | Pattern | Files | Lines Saved | Priority | +|---|---------|-------|-------------|----------| +| 1 | AudioProcessingConfig 4× construction | 1 Dart | ~50 | High | +| 2 | Audio processing toggle UI duplication | 2 Dart | ~150 | High | +| 3 | `.map_err(format!)` boilerplate | 5 Rust | ~85 closures | Medium | +| 4 | PttCapability event construction | 1 Rust | ~15 | Medium | +| 5 | DnsFailed/ServerRejected error mirroring | 2 Rust | ~20 | Medium | +| 6 | Platform detection scatter | 6 Dart | ~35 checks | Medium | +| 7 | Host normalization `trim().to_lowercase()` | 3 Rust | ~5 sites | Low | +| 8 | `create_dir_all` pattern | 2 Rust | ~3 sites | Low | +| 9 | `Io(String)` error variant | 3 Rust | ~10 | Low | +| 10 | StateEvent ↔ Delta mirror | 1 Rust | ~5 | Low | + +--- + +## 8. Document Link Coverage + +| Metric | Value | +|--------|-------| +| Total links checked | 38 | +| Valid links | 32 | +| Broken links | 6 | +| Health rate | 84.2% | +| Orphaned docs | 14 / 65 (21.5%) | + +### Broken Links + +All 6 broken links stem from missing `LICENSE-APACHE` and `LICENSE-MIT` files at project root. + +### Orphaned Documentation (14 files) + +Mostly in `docs/superpowers/plans/` and `docs/superpowers/specs/` — not linked from any index document. + +--- + +## 9. Git History & Issue Patterns + +### Issue Categories (45 significant issues) + +| Category | Count | Severity | +|----------|-------|----------| +| iOS audio (AVAudioSession/VPIO) | 15+ | Most problematic | +| Realtime thread safety (Mutex) | 5+ | Cross-platform | +| Build toolchain (Xcode Archive) | 4+ | CI-blocking | +| Platform-specific build | 5+ | Cross-compilation | +| Flutter framework bugs | 3+ | Workarounds needed | +| Protocol failures | 3+ | Silent failures | + +### Key Patterns + +1. **iOS AVAudioSession has 7+ interacting configuration dimensions** — each fix reveals the next layer +2. **Realtime audio callbacks must NEVER use `Mutex::lock()`** — always `try_lock()` with silence fallback +3. **Always verify with `xcodebuild archive`** — not just `flutter build` +4. **Every protocol command should surface errors to UI** — fire-and-forget hides failures + +--- + +## 10. PR Analysis + +### PR Summary (42 total) + +| Type | Count | Merged | +|------|-------|--------| +| Features | 15 | 7 | +| Bug fixes | 15 | 12 | +| Refactoring | 4 | 3 | +| Documentation | 1 | 1 | +| Build/Chore | 4 | 4 | +| Performance | 1 | 1 | + +### Most Active Areas + +| Area | PR Count | +|------|----------| +| iOS Audio | 10+ | +| macOS Audio | 5 | +| Voice/VAD | 6 | +| Flutter UI | 8 | +| Protocol/State | 5 | + +### Development Patterns + +- **Self-review via "Oracle" agent** — effective quality gate +- **Local CI mirroring** — GitHub Actions billing broken +- **PR stacking complexity** — need better branch management +- **Follow-up fix pattern** — PRs stay focused + +--- + +## 11. API Gap Analysis + +### Requirements with NO or Minimal Implementation + +| Requirement | ID | Status | +|---|---|---| +| UI settings persistence | SysRS-143, SRS-087 | **Missing** | +| Per-user mute persistence | SysRS-145, SRS-088 | **Missing** | +| Event replay tool | SysRS-171, SRS-098 | **Missing** | +| Audio loopback test tool | SysRS-073, SRS-083 | **Missing** | SRS-083 covers both loopback and processing test tools | +| Audio processing test tool | SysRS-074, SRS-083 | **Missing** | SRS-083 shared with SysRS-073 | +| Protocol probe tool | SysRS-128, SRS-123 | **Missing** | +| Notification permission | SysRS-166, SRS-109 | **Missing** | +| Recent server management | SysRS-141, SRS-085 | **Partial** | +| Per-user volume persistence | SysRS-144, SRS-088 | **Partial** | +| Input validation | SysRS-157, SRS-094 | **Partial** | + +### Missing Bridge Functions + +| Capability | Gap | +|---|---| +| `is_hard_muted()` | Missing read for hard-mute state | +| `get_output_gain()` | Missing gain read-back | +| `get_client_volume()` | Missing per-client volume read | +| `connection_state()` | UI must derive from events only | +| `reconnect()` | No manual trigger | + +### Hardcoded Implementations + +| Location | Issue | +|---|---| +| `adapter.rs:141` | `pick_client_version()` returns Windows version for ALL platforms | +| `api.rs:350-356` | `log_file_path()` Android returns `None` | +| `chanora_storage` | `keyring_load()` on Android returns `Ok(None)` always | + +--- + +## 12. Crate Architecture Analysis + +### Current Dependency Graph + +``` +chanora_bridge + └─ chanora_core + ├─ chanora_audio ────── chanora_protocol ───── chanora_resolver + ├─ chanora_state ────── chanora_protocol + ├─ chanora_storage (standalone) + ├─ chanora_cache (standalone) + ├─ chanora_diagnostics (standalone) + └─ chanora_prefetch ── chanora_resolver +``` + +**No circular dependencies.** Max depth: 3 levels. + +### Crate Size + +| Crate | Source Lines | Files | +|-------|-------------|-------| +| **chanora_audio** | **18,895** | 26 | +| chanora_bridge | 7,579 | 5 | +| chanora_protocol | 3,372 | 4 | +| chanora_core | 2,716 | 5 | +| chanora_state | 1,870 | 2 | +| chanora_resolver | 1,434 | 1 | +| chanora_storage | 1,332 | 1 | +| chanora_diagnostics | 1,118 | 1 | +| chanora_cache | 359 | 1 | +| chanora_prefetch | 312 | 1 | + +### chanora_audio Split Recommendation + +**Option A — Extract platform backends (recommended):** + +| New Crate | Contents | Lines | +|---|---|---| +| `chanora_audio` (core) | engine, frame types, transmit, VAD, DSP, PTT trait | ~8,000 | +| `chanora_audio_android` | android_voice_unit, render_ring, event_queue, Oboe | ~3,200 | +| `chanora_audio_apple` | ios_voice_unit, coreaudio-rs | ~1,400 | +| `chanora_audio_desktop` | cpal, sdl_output, Windows/Linux PTT | ~3,500 | + +**Rationale:** Platform backends are 100% cfg-gated. Splitting removes heavy platform dependencies from core. + +### Common Code Extraction + +**Not justified at this time.** Patterns are too small for a `chanora_common` crate. + +--- + +## 13. Document Staleness Analysis + +### Freshness Scores + +| Document | Score | Status | +|---|---|---| +| docs/sysrs.md | 8/10 | Mostly current | +| docs/srs.md | 7/10 | Missing newer requirements | +| docs/sysdes.md | 6/10 | Missing 53 SysRS allocations | +| docs/architecture/sdd.md | 5/10 | Missing many modules | +| docs/architecture/sad.md | 5/10 | Missing components | +| docs/verification/verification-master-plan.md | 6/10 | Stale evidence source | +| docs/governance/traceability-matrix.md | 5/10 | SRS ID mismatches | +| docs/implementation-status-2026-05-28.md | 3/10 | 14 days stale | + +### Critical Staleness Issues + +1. **53 SysRS requirements (SysRS-258–310) lack SysDes allocation** — breaks traceability +2. **Multiple features without requirements** — poke, file transfer, hard-mute, cache +3. **SRS numbering mismatches** in traceability matrix +4. **Implementation status 14 days stale** — missing v0.3.0 features + +--- + +## 14. Test Environment Requirements + +### Current CI Coverage + +| Platform | CI Status | +|----------|-----------| +| Ubuntu (Rust + Flutter) | ✅ Automated | +| macOS (iOS unsigned build) | ✅ Automated | +| Android | ❌ Not in CI | +| Windows | ❌ Not in CI | +| macOS (native) | ❌ Not in CI | +| Linux (non-Ubuntu) | ❌ Not in CI | + +### Physical Devices Needed + +| Device | Purpose | Est. Cost | +|---|---|---| +| iPhone 14+ | iOS audio, CoreML VAD | $600-800 | +| Android phone (arm64) | Android audio, Oboe | $200-400 | +| Windows PC | Windows PTT, audio | $500-800 | +| Linux PC | GNOME/Wayland, PipeWire | $500-800 | +| Audio peripherals | USB/BT headset testing | $100 | +| **Total** | | **$2,400-4,200** | + +### Implementation Roadmap + +| Phase | Timeline | Focus | +|-------|----------|-------| +| Foundation | Weeks 1-4 | Android/Windows/macOS CI builds | +| Device Integration | Weeks 5-8 | Physical devices, audio loopback | +| Full Automation | Weeks 9-12 | E2E tests, audio quality, Firebase | + +--- + +## 15. External Research + +### TeaSpeak + +- **Status:** Effectively unmaintained since ~2022 +- **Architecture:** Closed-source server, TypeScript web client, C++ music bot +- **Lesson for Chanora:** Open-source client + formal engineering process is the right approach +- **Market validation:** TeaSpeak's abandonment creates opportunity for Chanora + +### ReSpeak + +- **Status:** Active, 16 repositories, tsclientlib is the core library +- **Chanora dependency:** Uses `tsclientlib` (forked) for protocol implementation +- **Key repos:** `tsclientlib` (protocol), `tsdeclarations` (protocol spec), `quicklz` (compression) +- **Recommendation:** Continue using tsclientlib, consider upstreaming p256 fix + +### yat.qa (YaTQA) + +- **What it is:** Windows GUI tool for TeamSpeak 3 ServerQuery management (NOT a testing/QA site) +- **Relevance:** Low — management tool, not testing framework +- **Useful resources:** Unofficial ServerQuery docs, server error codes, permission IDs, anti-flood mechanics + +--- + +## 16. Recommendations + +### P0 — Critical (do immediately) + +1. **Add `chanora_bridge` tests** — 0/5 modules tested, FFI boundary is highest risk +2. **Replace `Mutex::lock().unwrap()` in engine.rs** — ~39 calls, crash risk +3. **Update implementation-status document** — 14 days stale, primary evidence source +4. **Allocate SysRS-258–310 in SysDes** — breaks traceability chain +5. **Fix traceability matrix SRS numbering** — IDs don't match actual SRS + +### P1 — High Priority (next sprint) + +6. **Add Android/Windows/macOS CI builds** — currently only Ubuntu +7. **Add missing bridge functions** — `get_hard_mute()`, `get_connection_state()`, `reconnect()` +8. **Add README files to all 8 crates + core** +9. **Split engine.rs** (3,244 lines) into smaller modules +10. **Add requirements for implemented features** — poke, file transfer, hard-mute, cache + +### P2 — Medium Priority + +11. **Extract platform backends from chanora_audio** — compile-time benefit +12. **Add doc comments to chanora_audio** (24% → 80% target) +13. **Fix `pick_client_version()` hardcoded to Windows** +14. **Implement per-user volume/mute persistence** +15. **Add UI settings store** + +### P3 — Low Priority + +16. **Clean up dead code** (25+ items) +17. **Deduplicate code patterns** (10 major patterns) +18. **Fix broken doc links** (create LICENSE files) +19. **Link orphaned documentation** +20. **Add protocol probe tool** + +--- + +*Generated by codebase analysis agents on 2026-06-11* diff --git a/docs/governance/issue-history-analysis.md b/docs/governance/issue-history-analysis.md new file mode 100644 index 0000000..b35a3f5 --- /dev/null +++ b/docs/governance/issue-history-analysis.md @@ -0,0 +1,157 @@ +# Issue History Analysis + +**Date:** 2026-06-11 +**Scope:** All git history, PRs, and issue patterns + +--- + +## 1. Issue Categories + +### iOS Audio (15+ issues) — Most Problematic Area + +| Commit | Issue | Root Cause | Fix | +|--------|-------|------------|-----| +| #42 (OPEN) | AVAudioSession not activated before connect | Auto-join spawns VPIO before session in playAndRecord mode | Activate session BEFORE rust.connect | +| #41 | iOS Debug builds blocked | Debug.xcconfig missing `-u` flags; verify script checked wrong Mach-O | Mirror Release xcconfig; check correct dylib | +| #38 | Audio session dead after "already in channel" | Server response 0x0302 treated as failure | Keep session active on already-in-channel | +| #33 | App kills other apps' audio while idle | Held `.playAndRecord` from launch | Idle baseline now `.ambient`; escalate during calls | +| #28 | False underrun counters when muted | `peak_i16 == 0` check didn't gate on muted state | Gate underrun on `!muted` | +| #26 | Silero exports stripped in Xcode Archive | `ld -dead_strip` removed unreferenced symbols | `-exported_symbol` whitelist in xcconfigs | +| #10 | Voice join stuck at "Connecting" | Audio startup blocking connect critical path | Move audio startup off connect path | + +**Pattern:** iOS AVAudioSession has 7+ interacting configuration dimensions. Each fix reveals the next layer. + +### Realtime Thread Safety (5+ issues) + +| Commit | Issue | Root Cause | Fix | +|--------|-------|------------|-----| +| #20 | Android audio output stutter | Mutex contention in audio callback | Oboe config tuning + lock-free callback | +| #27 | macOS audio event queue | Lock contention in render path | Lock-free ArrayQueue pattern | +| engine.rs:39 | ~39 `unwrap()` calls on Mutex | Poisoned mutex will panic engine | Need `try_lock()` or `parking_lot::Mutex` | + +**Pattern:** Realtime audio callbacks must NEVER use `Mutex::lock()` — always `try_lock()` with silence fallback. + +### Build Toolchain (4+ issues) + +| Commit | Issue | Root Cause | Fix | +|--------|-------|------------|-----| +| #41 | iOS Debug builds fail | Debug.xcconfig diverged from Release | Mirror Release settings in Debug | +| #26 | Silero exports stripped | `ld -dead_strip` + install-time `strip` | `-exported_symbol` whitelist + `STRIP_STYLE = non-global` | +| #37 | MSVC CRT mismatch | cmake linking wrong CRT | `cmake-msvc-release-crt.cmd` | + +**Pattern:** Always verify with `xcodebuild archive`, not just `flutter build`. + +### Protocol Issues (3+ issues) + +| Commit | Issue | Root Cause | Fix | +|--------|-------|------------|-----| +| #16 | Speaking state incorrect for non-self clients | Client profiles not refreshed before mapping | Refresh non-self profiles | +| #16 | Server-query clients missing | Missing protocol DTO fields | Add ping deviation through full stack | +| #5 | UI crashes on unexpected state transitions | Missing null/mounted guards | Guard deferred side effects | + +**Pattern:** Every protocol command should surface errors to UI — fire-and-forget hides failures. + +--- + +## 2. PR Development Patterns + +### PR Summary (42 total, 34 merged, 8 closed) + +| Type | Count | Merged | +|------|-------|--------| +| Features | 14 | 10 | +| Bug fixes | 12 | 12 | +| Refactoring | 4 | 3 | +| Documentation | 1 | 1 | +| Build/Chore | 4 | 4 | +| Performance | 1 | 1 | +| Dependency | 1 | 0 | +| Closed (superseded) | 5 | 0 | + +### Most Active Areas + +| Area | PR Count | Notes | +|------|----------|-------| +| iOS Audio | 10+ | Most recurring issues | +| macOS Audio | 5 | Lock-free architecture | +| Voice/VAD | 6 | CoreML, ONNX, WebRTC | +| Flutter UI | 8 | Event-driven, responsive | +| Protocol/State | 5 | State reducers, events | + +### Quality Patterns + +1. **Self-review via "Oracle" agent** — catches real issues pre-merge +2. **Local CI mirroring** — GitHub Actions billing broken +3. **PR stacking** — need better branch management workflow +4. **Follow-up fix pattern** — PRs stay focused + +--- + +## 3. Test Cases for Known Issues + +### iOS Audio Session Lifecycle + +```dart +// Test: Session activates before connect +test('voice_join activates AVAudioSession before starting voice', () async { + // Verify session state transitions: ambient → playAndRecord → ambient +}); + +// Test: Already-in-channel response keeps session active +test('voice_join keeps session active on already-in-channel response', () async { + // Mock server response code 0x0302 + // Verify session remains in playAndRecord state +}); + +// Test: Idle app doesn't kill other audio +test('app uses ambient mode when not in voice channel', () async { + // Verify session mode is .ambient + .mixWithOthers when idle +}); +``` + +### Realtime Thread Safety + +```rust +// Test: Audio callback doesn't panic on poisoned mutex +#[test] +fn audio_callback_survives_poisoned_mutex() { + // Verify try_lock fallback produces silence, not panic +} +``` + +### Protocol Error Surfacing + +```dart +// Test: Server errors surface to UI +test('server error messages are forwarded as UI events', () async { + // Mock protocol error + // Verify UI receives error event +}); +``` + +### Build Verification + +```bash +# Test: iOS Debug build succeeds +xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner -configuration Debug build + +# Test: iOS Archive build preserves Silero exports +xcodebuild archive -workspace ios/Runner.xcworkspace -scheme Runner +# Verify: nm -g archive.xcarchive/Products/Applications/Chanora.app/Chanora | grep silero +``` + +--- + +## 4. Root Cause Patterns + +| Pattern | Frequency | Prevention | +|---------|-----------|------------| +| iOS AVAudioSession lifecycle | 8+ PRs | Document state machine, add integration tests | +| Mutex on realtime threads | 5+ issues | Use `try_lock()` or `parking_lot::Mutex` | +| Xcode Archive vs build divergence | 4+ issues | Always test with `xcodebuild archive` | +| Silent protocol failures | 3+ issues | Surface all errors to UI | +| Platform-specific build quirks | 5+ issues | CI on all target platforms | + +--- + +*Generated by git history analysis agents on 2026-06-11* diff --git a/docs/governance/master-todo-list-2026-06-11.md b/docs/governance/master-todo-list-2026-06-11.md new file mode 100644 index 0000000..8a6c9ad --- /dev/null +++ b/docs/governance/master-todo-list-2026-06-11.md @@ -0,0 +1,692 @@ +# Master TODO List + +**Date:** 2026-06-11 +**Branch:** `docs/codebase-analysis-v2` +**Sources:** +- `docs/governance/codebase-analysis-2026-06-11.md` — main codebase analysis +- `docs/governance/issue-history-analysis.md` — git history patterns and root causes +- `docs/verification/test-environment-requirements.md` — test environment setup needs +- `docs/references/external-research-2026-06-11.md` — external research findings + +--- + +## Summary + +| Category | P0 | P1 | P2 | P3 | Total | +|---|---|---|---|---|---| +| Dead Code Removal | 0 | 0 | 0 | 5 | 5 | +| Code Quality | 2 | 2 | 3 | 2 | 9 | +| Test Coverage | 2 | 3 | 2 | 0 | 7 | +| Architecture | 0 | 2 | 2 | 1 | 5 | +| Documentation | 3 | 2 | 3 | 2 | 10 | +| Missing APIs / Requirements | 0 | 2 | 7 | 2 | 11 | +| Infrastructure | 0 | 3 | 5 | 1 | 9 | +| External Research Follow-up | 0 | 1 | 2 | 2 | 5 | +| Protocol Implementation | 0 | 2 | 8 | 3 | 13 | +| Reference Document Improvements | 0 | 0 | 9 | 1 | 10 | +| Additional Traceability Gaps | 0 | 0 | 3 | 1 | 4 | +| **Total** | **7** | **17** | **44** | **20** | **88** | + +--- + +## 1. Dead Code Removal + +### TODO-001 — Remove dead AudioFrame structs +- **Priority:** P3 +- **Source:** codebase-analysis §5 +- **Description:** `AudioFrame10ms` and `AudioFrame20ms` structs and `AudioFrame10ms::dbfs()` are never referenced outside tests. Safe to delete. +- **Effort:** S +- **Dependencies:** None + +### TODO-002 — Remove dead `disable_failed_vad_backend()` +- **Priority:** P3 +- **Source:** codebase-analysis §5 +- **Description:** Function only called in tests. Remove from production code. +- **Effort:** S +- **Dependencies:** None + +### TODO-003 — Remove unused `share_plus` import +- **Priority:** P3 +- **Source:** codebase-analysis §5 +- **Description:** `import 'package:share_plus/share_plus.dart'` in main.dart:55 — `Share` class never used. +- **Effort:** S +- **Dependencies:** None + +### TODO-004 — Audit and remove likely-dead functions (16 across 5 crates) +- **Priority:** P3 +- **Source:** codebase-analysis §2, §5 +- **Description:** 16 functions have no production callers. From §5: 11 AudioEngine/TransmitModeSelector/ReleaseTailTimer methods (output_muted, output_gain, capture_active, transmit_gate, set_transmit_active, android_diagnostics, gate, in_channel, ptt_held, cancel, arm) + `AudioEngine::frames_sent()` and `AudioEngine::frames_received()`. From §2: `ChanoraSession::protocol_events_snapshot()` (chanora_core), `ServerState::replace_from_snapshot()/channel_count()/client_count()` (chanora_state), `BookmarkStore::upsert_or_add()` (chanora_storage), `normalize_args()/validate_args()` (chanora_resolver), `HpfProcessor::process_sample()` (chanora_audio), `CoreMlWorker::reset_state()` (chanora_audio), `PttCapabilityLevel::is_global()` (chanora_audio), `handle_media_services_reset_with_route()/handle_interruption_began()` (chanora_bridge). Confirm with call-graph then remove or wire. +- **Effort:** M +- **Dependencies:** None + +### TODO-005 — Decide fate of `#[allow(dead_code)]` items +- **Priority:** P3 +- **Source:** codebase-analysis §5 +- **Description:** `AudioCommand::RemoveClient` has TODO to wire to client disconnect path. Three Android-only modules are conditionally dead. Decide: wire, remove, or keep annotated. +- **Effort:** M +- **Dependencies:** None + +--- + +## 2. Code Quality + +### TODO-006 — Replace ~39 `Mutex::lock().unwrap()` calls in engine.rs +- **Priority:** P0 +- **Source:** codebase-analysis §6, issue-history §1 (realtime thread safety) +- **Description:** Production `unwrap()` on Mutex locks will panic on poisoned mutex. Replace with `try_lock()` + silence fallback or `parking_lot::Mutex`. +- **Effort:** L +- **Dependencies:** None + +### TODO-007 — Audit 8 `unsafe impl Send/Sync` blocks +- **Priority:** P0 +- **Source:** codebase-analysis §6 +- **Description:** 8 unsafe Send/Sync impls across various files. Each needs safety proof comment and review. +- **Effort:** M +- **Dependencies:** None + +### TODO-008 — Resolve 14 TODO/FIXME/HACK entries in codebase +- **Priority:** P1 +- **Source:** codebase-analysis §6 +- **Description:** 14 occurrences across engine.rs, mobile_voice_backend.rs, audio_event_queue.rs, audio_lifecycle_service.dart, poke_notification_service.dart. Address or convert to tracked issues. +- **Effort:** L +- **Dependencies:** None + +### TODO-009 — Audit 23 `unimplemented!("")` in frb_generated.rs +- **Priority:** P1 +- **Source:** codebase-analysis §6 +- **Description:** Flutter-Rust Bridge generated stubs contain 23 `unimplemented!("")` calls that will panic at runtime if hit. Audit and implement or guard each one. +- **Effort:** M +- **Dependencies:** None + +### TODO-010 — Fix `pick_client_version()` hardcoded to Windows +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** `adapter.rs:141` returns Windows client version for ALL platforms. Must return platform-appropriate version strings. +- **Effort:** S +- **Dependencies:** None + +### TODO-011 — Fix Android stubs returning None/Ok(None) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** `log_file_path()` on Android returns `None` (api.rs:350-356), `keyring_load()` on Android returns `Ok(None)` always. These silently hide functionality gaps. +- **Effort:** S +- **Dependencies:** None + +### TODO-012 — Deduplicate AudioProcessingConfig construction (4x) +- **Priority:** P2 +- **Source:** codebase-analysis §7 +- **Description:** AudioProcessingConfig is constructed identically in 4 places in Dart. Extract to factory or shared config. +- **Effort:** S +- **Dependencies:** None + +### TODO-013 — Deduplicate audio processing toggle UI +- **Priority:** P3 +- **Source:** codebase-analysis §7 +- **Description:** Audio processing toggle UI duplicated across 2 Dart files (~150 lines). Extract shared widget. +- **Effort:** S +- **Dependencies:** None + +### TODO-014 — Deduplicate low-priority code patterns (7 patterns) +- **Priority:** P3 +- **Source:** codebase-analysis §7 +- **Description:** PttCapability event construction (1 Rust, ~15 lines), DnsFailed/ServerRejected error mirroring (2 Rust, ~20 lines), host normalization (3 Rust files), create_dir_all (2 Rust files), Io(String) variant (3 crates), StateEvent/Delta mirror (1 Rust file), platform detection scatter (6 Dart, ~35 checks). +- **Effort:** M +- **Dependencies:** None + +--- + +## 3. Test Coverage + +### TODO-015 — Add chanora_bridge tests (0/5 modules tested) +- **Priority:** P0 +- **Source:** codebase-analysis §3 +- **Description:** The Flutter-Rust FFI boundary has zero tests. This is the highest-risk untested area. Need unit tests for all 5 bridge modules. +- **Effort:** XL +- **Dependencies:** None + +### TODO-016 — Add poisoned-mutex survival test for audio callbacks +- **Priority:** P0 +- **Source:** issue-history §3 +- **Description:** Verify `try_lock()` fallback produces silence rather than panic when mutex is poisoned. Directly tests the fix for TODO-006. +- **Effort:** M +- **Dependencies:** TODO-006 + +### TODO-017 — Add Flutter widget tests for untested core UI +- **Priority:** P1 +- **Source:** codebase-analysis §3 +- **Description:** `voice_bar`, `voice_settings`, `connect_widgets` modules have no tests. These are core UI components at 56% widget coverage. +- **Effort:** L +- **Dependencies:** None + +### TODO-018 — Add chanora_protocol dto module tests +- **Priority:** P1 +- **Source:** codebase-analysis §3 +- **Description:** Protocol dto module is untested. Serialization bugs here cause silent protocol failures. +- **Effort:** M +- **Dependencies:** None + +### TODO-019 — Add chanora_core events module tests +- **Priority:** P1 +- **Source:** codebase-analysis §3 +- **Description:** Events module is untested (80% coverage overall, but events gap). Event system is central to app behavior. +- **Effort:** M +- **Dependencies:** None + +### TODO-020 — Add iOS audio session lifecycle integration tests +- **Priority:** P2 +- **Source:** issue-history §3 +- **Description:** Test session transitions (ambient → playAndRecord → ambient), already-in-channel response handling, idle audio mode. 15+ historical issues justify this. +- **Effort:** L +- **Dependencies:** TODO-030 (device test infrastructure) + +### TODO-021 — Add protocol error surfacing tests +- **Priority:** P2 +- **Source:** issue-history §3 +- **Description:** Verify server errors are forwarded as UI events, not silently swallowed. Fire-and-forget hides failures. +- **Effort:** M +- **Dependencies:** None + +--- + +## 4. Architecture + +### TODO-022 — Split engine.rs (3,244 lines) into smaller modules +- **Priority:** P1 +- **Source:** codebase-analysis §6, §12 +- **Description:** Monolithic audio engine file. Split into engine core, capture, render, transmit, diagnostics modules. +- **Effort:** L +- **Dependencies:** None + +### TODO-023 — Split main.dart (2,910 lines) into smaller modules +- **Priority:** P1 +- **Source:** codebase-analysis §6 +- **Description:** Monolithic Flutter entry point. Extract into feature-based modules/screens. +- **Effort:** L +- **Dependencies:** None + +### TODO-024 — Extract platform backends from chanora_audio into separate crates +- **Priority:** P2 +- **Source:** codebase-analysis §12 +- **Description:** Split into `chanora_audio` (core ~8K lines), `chanora_audio_android` (~3.2K), `chanora_audio_apple` (~1.4K), `chanora_audio_desktop` (~3.5K). Platform backends are already cfg-gated. +- **Effort:** XL +- **Dependencies:** TODO-022 (split engine.rs first) + +### TODO-025 — Reduce `.map_err(format!)` boilerplate across 5 Rust crates +- **Priority:** P2 +- **Source:** codebase-analysis §7 +- **Description:** ~85 repeated closure patterns. Introduce a `WrapErr` trait or macro to reduce boilerplate. +- **Effort:** L +- **Dependencies:** None + +### TODO-026 — Reduce adapter.rs (2,504 lines) and api.rs (2,432 lines) +- **Priority:** P3 +- **Source:** codebase-analysis §6 +- **Description:** Both files exceed 2,400 lines. Consider splitting by feature area. +- **Effort:** L +- **Dependencies:** TODO-022, TODO-023 + +--- + +## 5. Documentation + +### TODO-027 — Update implementation-status document +- **Priority:** P0 +- **Source:** codebase-analysis §13 +- **Description:** `docs/implementation-status-2026-05-28.md` is 14 days stale, missing v0.3.0 features. This is the primary evidence source for verification. +- **Effort:** M +- **Dependencies:** None + +### TODO-028 — Allocate SysRS-258–310 in SysDes +- **Priority:** P0 +- **Source:** codebase-analysis §13 +- **Description:** 53 SysRS requirements lack SysDes allocation, breaking the traceability chain from requirements to design. +- **Effort:** L +- **Dependencies:** None + +### TODO-029 — Fix traceability matrix SRS numbering mismatches +- **Priority:** P0 +- **Source:** codebase-analysis §13 +- **Description:** SRS IDs in traceability matrix don't match actual SRS document. Needs manual reconciliation. +- **Effort:** M +- **Dependencies:** None + +### TODO-030 — Add README files to 8 crates + core +- **Priority:** P1 +- **Source:** codebase-analysis §4 +- **Description:** Only `chanora_resolver` has a README. The other 9 directories need one describing purpose, architecture, and public API. +- **Effort:** M +- **Dependencies:** None + +### TODO-031 — Improve chanora_audio doc comments (24% → 80%) +- **Priority:** P2 +- **Source:** codebase-analysis §4 +- **Description:** Largest crate (168 pub fn, 18,895 lines) at only 24% documentation. Target 80% coverage. +- **Effort:** XL +- **Dependencies:** None + +### TODO-032 — Fix 6 broken doc links (create LICENSE files) +- **Priority:** P3 +- **Source:** codebase-analysis §8 +- **Description:** All 6 broken links point to missing `LICENSE-APACHE` and `LICENSE-MIT` files at project root. LICENSE files have been created — verify links resolve. +- **Effort:** S +- **Dependencies:** None + +### TODO-033 — Link 14 orphaned documentation files +- **Priority:** P3 +- **Source:** codebase-analysis §8 +- **Description:** 14 files in `docs/superpowers/plans/` and `docs/superpowers/specs/` are not linked from any index document. +- **Effort:** S +- **Dependencies:** None + +### TODO-034 — Update SDD (docs/architecture/sdd.md) +- **Priority:** P2 +- **Source:** codebase-analysis §13 +- **Description:** Software Design Description scored 5/10 freshness. Missing many modules added since initial write. +- **Effort:** L +- **Dependencies:** None + +### TODO-035 — Update SAD (docs/architecture/sad.md) +- **Priority:** P2 +- **Source:** codebase-analysis §13 +- **Description:** Software Architecture Description scored 5/10 freshness. Missing components and interfaces. +- **Effort:** L +- **Dependencies:** None + +### TODO-036 — Update Verification Master Plan +- **Priority:** P1 +- **Source:** codebase-analysis §13 +- **Description:** Verification Master Plan scored 6/10, stale evidence sources and missing verification methods. +- **Effort:** M +- **Dependencies:** None + +--- + +## 6. Missing APIs / Requirements + +### TODO-037 — Add missing bridge read-back functions +- **Priority:** P1 +- **Source:** codebase-analysis §11 +- **Description:** `is_hard_muted()`, `get_output_gain()`, `get_client_volume()`, `connection_state()`, `reconnect()` are missing from bridge. UI must derive state from events only. +- **Effort:** M +- **Dependencies:** None + +### TODO-038 — Write requirements for implemented features +- **Priority:** P1 +- **Source:** codebase-analysis §13 +- **Description:** Poke, file transfer, hard-mute, and cache features exist in code but have no SysRS/SRS requirements. Breaks traceability. +- **Effort:** L +- **Dependencies:** None + +### TODO-039 — Implement UI settings persistence (SysRS-143, SRS-087) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Settings persistence is a documented requirement with no implementation. +- **Effort:** M +- **Dependencies:** None + +### TODO-040 — Implement per-user mute/volume persistence (SysRS-145/144, SRS-088) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Per-user mute and volume persistence requirements are partially implemented. Needs completion. +- **Effort:** M +- **Dependencies:** None + +### TODO-041 — Implement notification permission handling (SysRS-166, SRS-109) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Notification permission requirement has no implementation. +- **Effort:** M +- **Dependencies:** None + +### TODO-042 — Complete recent server management (SysRS-141, SRS-085) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Recent server management is partially implemented. Needs completion per spec. +- **Effort:** M +- **Dependencies:** None + +### TODO-043 — Implement event replay tool (SysRS-171, SRS-098) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Event replay tool is a documented requirement with no implementation. +- **Effort:** L +- **Dependencies:** None + +### TODO-044 — Implement audio processing test tool (SysRS-074, SRS-083) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Audio processing test tool is a documented requirement with no implementation. +- **Effort:** L +- **Dependencies:** None + +### TODO-045 — Complete input validation (SysRS-157, SRS-094) +- **Priority:** P2 +- **Source:** codebase-analysis §11 +- **Description:** Input validation is partially implemented. Needs completion per spec. +- **Effort:** M +- **Dependencies:** None + +### TODO-046 — Implement audio loopback test tool (SysRS-073, SRS-083) +- **Priority:** P3 +- **Source:** codebase-analysis §11 +- **Description:** Audio loopback test tool is a documented requirement with no implementation. +- **Effort:** L +- **Dependencies:** TODO-054 (audio loopback harness) + +### TODO-047 — Implement protocol probe tool (SysRS-128, SRS-123) +- **Priority:** P3 +- **Source:** codebase-analysis §11 +- **Description:** Protocol probe tool is a documented requirement with no implementation. +- **Effort:** L +- **Dependencies:** None + +--- + +## 7. Infrastructure + +### TODO-048 — Add Android CI build job +- **Priority:** P1 +- **Source:** test-environment-requirements §9 Phase 1 +- **Description:** No Android CI build exists. Add NDK + cargo-ndk + multi-ABI build to GitHub Actions. +- **Effort:** M +- **Dependencies:** None + +### TODO-049 — Add Windows and macOS CI build jobs +- **Priority:** P1 +- **Source:** test-environment-requirements §9 Phase 1 +- **Description:** Windows and macOS builds are not in CI. Add windows-latest and macOS runners for build verification. +- **Effort:** M +- **Dependencies:** None + +### TODO-050 — Add xcodebuild Archive verification to CI +- **Priority:** P1 +- **Source:** issue-history §1 +- **Description:** 4+ historical issues caused by `flutter build` passing but `xcodebuild archive` failing. Add xcodebuild archive step to CI. +- **Effort:** M +- **Dependencies:** None + +### TODO-051 — Enable clippy as blocking CI check +- **Priority:** P2 +- **Source:** test-environment-requirements §9 Phase 1 +- **Description:** Clippy is currently advisory only. Make it a blocking PR gate. +- **Effort:** S +- **Dependencies:** None + +### TODO-052 — Add Linux multi-distro build matrix +- **Priority:** P2 +- **Source:** test-environment-requirements §9 Phase 1 +- **Description:** Add Docker-based CI matrix for Ubuntu, Fedora, Arch to catch distro-specific PipeWire/Portal/DBus issues. +- **Effort:** M +- **Dependencies:** None + +### TODO-053 — Add `cargo llvm-cov` coverage reporting +- **Priority:** P2 +- **Source:** test-environment-requirements §9 Phase 1 +- **Description:** No code coverage reporting exists. Add `cargo llvm-cov` to CI for trend tracking. +- **Effort:** M +- **Dependencies:** None + +### TODO-054 — Implement audio loopback test harness +- **Priority:** P2 +- **Source:** test-environment-requirements §9 Phase 2 +- **Description:** Build virtual audio device loopback for CI audio quality testing. Use BlackHole (macOS), VB-Audio (Windows), snd-aloop (Linux). +- **Effort:** L +- **Dependencies:** TODO-048, TODO-049 + +### TODO-055 — Implement test environment Phase 2 (device integration) +- **Priority:** P2 +- **Source:** test-environment-requirements §9 Phase 2 +- **Description:** Set up self-hosted runners for device tests, Flutter integration tests with platform channels, Firebase Test Lab for Android, network condition test suite. +- **Effort:** XL +- **Dependencies:** TODO-048, TODO-049 + +### TODO-056 — Implement test environment Phase 3 (full automation) +- **Priority:** P3 +- **Source:** test-environment-requirements §9 Phase 3 +- **Description:** Benchmark regression gates, iOS TestFlight automation, signed build automation, weekly audio quality regression, Android multi-device testing. +- **Effort:** XL +- **Dependencies:** TODO-055 + +--- + +## 8. External Research Follow-up + +### TODO-057 — Upstream p256 coordinate padding fix to ReSpeak +- **Priority:** P1 +- **Source:** external-research §2 (ReSpeak) +- **Description:** Chanora forks `tsclientlib` for a p256 fix. Submit PR upstream to reduce fork maintenance burden. +- **Effort:** M +- **Dependencies:** None + +### TODO-058 — Monitor tsdeclarations for TS5 protocol updates +- **Priority:** P2 +- **Source:** external-research §2 (ReSpeak) +- **Description:** No full TS5 client protocol exists yet. Watch `tsdeclarations` repo for updates that may affect Chanora compatibility. +- **Effort:** S +- **Dependencies:** None (ongoing) + +### TODO-059 — Build auto-reconnect logic internally +- **Priority:** P2 +- **Source:** external-research §2 (ReSpeak) +- **Description:** tsclientlib explicitly notes auto-reconnect is "not yet there." Chanora must build this independently. +- **Effort:** L +- **Dependencies:** None + +### TODO-060 — Extract server error codes from YaTQA for error handling +- **Priority:** P3 +- **Source:** external-research §3 (YaTQA) +- **Description:** YaTQA's `/ressourcen/` section has comprehensive unofficial server error codes. Extract for Chanora error handling reference. +- **Effort:** S +- **Dependencies:** None + +### TODO-061 — Extract anti-flood/rate-limiting reference from YaTQA +- **Priority:** P3 +- **Source:** external-research §3 (YaTQA) +- **Description:** YaTQA documents anti-flood mechanics and rate limiting. Use as reference when implementing Chanora's rate limiting. +- **Effort:** S +- **Dependencies:** None + +--- + +## 9. Protocol Implementation (from Reference Documents) + +### TODO-062 — Implement DNS resolution chain (SRV→TSDNS→DNS) +- **Priority:** P1 +- **Source:** yatqa-offline-reference §8.5 +- **Description:** YaTQA documents the full DNS resolution order: SRV `_ts3._udp` → SRV TSDNS → TSDNS TCP port 41144 → DNS AAAA/A. First successful resolution wins, NO fallback on connection failure. Critical for connection reliability. +- **Effort:** M +- **Dependencies:** None + +### TODO-063 — Handle TS character encoding quirks (UTF-8 vs UCS-2 vs CESU-8) +- **Priority:** P1 +- **Source:** yatqa-offline-reference §1.3 +- **Description:** TS claims UTF-8 but uses UCS-2 (BMP only). Mobile apps use CESU-8. Chanora must handle encoding conversion to avoid display bugs with nicknames, channel names, and messages containing characters outside BMP. +- **Effort:** M +- **Dependencies:** None + +### TODO-064 — Implement client-side anti-flood point awareness +- **Priority:** P2 +- **Source:** yatqa-offline-reference §5 +- **Description:** YaTQA documents complete point costs per action (channelsubscribe=158pts, connect=80pts, etc.). Design Chanora's client-side anti-flood awareness to avoid accidental server bans. Tick-based point reduction model. +- **Effort:** M +- **Dependencies:** None + +### TODO-065 — Implement badge fetching and display +- **Priority:** P2 +- **Source:** yatqa-offline-reference §8.9, respeak-protocol-reference §5 +- **Description:** Badges fetched from `badges-content.teamspeak.com` in Protobuf format, cached locally, refreshed every 24h. Chanora needs badge Protobuf parsing, caching, and UI display. +- **Effort:** L +- **Dependencies:** None + +### TODO-066 — Implement TSDNS protocol support +- **Priority:** P2 +- **Source:** yatqa-offline-reference §8.4 +- **Description:** TSDNS protocol: TCP port 41144, lowercase domain + magic bytes. Required for `ts3server://` URL resolution and server bookmark handling. +- **Effort:** M +- **Dependencies:** TODO-062 + +### TODO-067 — Implement TS3 file transfer protocol +- **Priority:** P2 +- **Source:** yatqa-offline-reference §8.3, external-research §2 (ReSpeak gap) +- **Description:** Raw file transfer: send key from `ftinitupload`/`ftinitdownload` to server IP:port, then raw data. No escaping. ReSpeak has no file transfer implementation — Chanora must build this independently. +- **Effort:** L +- **Dependencies:** None + +### TODO-068 — Evaluate tsdeclarations machine-readable files for code generation +- **Priority:** P2 +- **Source:** respeak-protocol-reference §9 +- **Description:** Messages.toml, Book.toml, Enums.toml, MessagesToBook.toml, BookToMessages.toml could automate protocol struct and event generation. Evaluate feasibility for Chanora's build pipeline. +- **Effort:** M +- **Dependencies:** None + +### TODO-069 — Extract Permission IDs into Chanora's permission system +- **Priority:** P2 +- **Source:** respeak-protocol-reference §3, yatqa-offline-reference §1.2 +- **Description:** Both ReSpeak (tsdeclarations) and YaTQA provide comprehensive permission ID lists with Skip/Negate/Grant logic. Map these to Chanora's permission implementation for full TS3 compatibility. +- **Effort:** L +- **Dependencies:** None + +### TODO-070 — Document protocol implementation traps +- **Priority:** P2 +- **Source:** yatqa-offline-reference §1.4, §1.5, §3.1 +- **Description:** Several implementation traps documented in YaTQA: icon IDs signed/unsigned mismatch, avatar flag is MD5 hash not boolean, channel subscription limited to ONE at a time, line terminator is `0x0A 0x0D` (reversed Windows). Compile into Chanora developer notes. +- **Effort:** S +- **Dependencies:** None + +### TODO-071 — Handle IPv6 blacklist canonicalization bug +- **Priority:** P3 +- **Source:** yatqa-offline-reference §8.7 +- **Description:** TS3 server 3.1.6-3.1.7 has IPv6 canonicalization bug in Blacklist2 protocol. Chanora should be aware when connecting to older servers. +- **Effort:** S +- **Dependencies:** None + +### TODO-072 — Establish connection/message performance benchmarks +- **Priority:** P3 +- **Source:** respeak-protocol-reference §10 +- **Description:** tsclientlib benchmarks: ~199ms connect, ~189µs/message. Use as baseline for Chanora's performance testing. +- **Effort:** S +- **Dependencies:** None + +### TODO-073 — Assess web client feasibility +- **Priority:** P3 +- **Source:** teaspeak-offline-reference §10, external-research §1 +- **Description:** TeaSpeak's web client was a compelling installation-less option. Evaluate whether a future Chanora web client makes sense. Not current scope. +- **Effort:** S +- **Dependencies:** None + +--- + +## 10. Reference Document Improvements + +### TODO-074 — Fix respeak reference: malformed badge table row +- **Priority:** P2 +- **Source:** respeak-protocol-reference review (line 1309) +- **Description:** MIFCOM badge row has 6 columns (5 pipes) but table header has 5 columns. "Entered Performance" is a misplaced column. Fix table formatting. +- **Effort:** S +- **Dependencies:** None + +### TODO-075 — Fix respeak reference: section numbering placeholder +- **Priority:** P2 +- **Source:** respeak-protocol-reference review (line 764) +- **Description:** Section "4.? Differences between Query and Full Client" has a `?` placeholder. Assign correct section number (4.9 or similar). +- **Effort:** S +- **Dependencies:** None + +### TODO-076 — Fix respeak reference: duplicate section numbering +- **Priority:** P2 +- **Source:** respeak-protocol-reference review +- **Description:** Both the protocol spec section and reference data sections start at `# 2.`, making "Section 2" ambiguous. Separate into Part I (Protocol) and Part II (Reference Data) or renumber. +- **Effort:** S +- **Dependencies:** None + +### TODO-077 — Resolve teaspeak reference: godmode permission contradiction +- **Priority:** P2 +- **Source:** teaspeak-offline-reference review (lines 401 vs 414) +- **Description:** `b_virtualserver_select_godmode` listed as active permission in "Other Permissions" table (line 401) AND as "removed" in "Removed Permissions" table (line 414). Resolve: remove from one location or clarify version-based behavior. +- **Effort:** S +- **Dependencies:** None + +### TODO-078 — Resolve teaspeak reference: music bot command contradiction +- **Priority:** P2 +- **Source:** teaspeak-offline-reference review (lines 499 vs 1229) +- **Description:** Music bot queue commands (`musicbotqueuelist`, `musicbotqueueadd`, etc.) listed in active Music Bot Query Commands table (lines 499-501) AND in "Removed Commands" section (lines 1229-1236). Clarify which version removed them. +- **Effort:** S +- **Dependencies:** None + +### TODO-079 — Add Chanora relevance section to teaspeak reference +- **Priority:** P2 +- **Source:** teaspeak-offline-reference review +- **Description:** TeaSpeak reference has no section connecting features to Chanora's needs. Add "Relevance to Chanora" section mapping TeaSpeak features to Chanora SRS requirements and identifying protocol divergence points. +- **Effort:** M +- **Dependencies:** None + +### TODO-080 — Backfill YaTQA reference: complete variable parameters tables +- **Priority:** P2 +- **Source:** yatqa-offline-reference review +- **Description:** Variable parameters section severely condensed: ~15 of 50+ client vars, ~15 of 35+ channel vars, ~7 of 70+ server vars. Backfill from `yat.qa/ressourcen/variablen-parameter/`. +- **Effort:** L +- **Dependencies:** None + +### TODO-081 — Backfill YaTQA reference: complete anti-flood action table +- **Priority:** P2 +- **Source:** yatqa-offline-reference review +- **Description:** Anti-flood section reduced ~80 individual actions to summary tiers. Replace with complete itemized table from `yat.qa/ressourcen/voice-client-anti-flood/`. +- **Effort:** M +- **Dependencies:** None + +### TODO-082 — Backfill YaTQA reference: missing error codes and truncated messages +- **Priority:** P2 +- **Source:** yatqa-offline-reference review +- **Description:** ~28 error codes missing, several messages truncated (errors 1030, 1035, 522). Add missing codes and fix truncated messages. +- **Effort:** S +- **Dependencies:** None + +### TODO-083 — Backfill YaTQA reference: expand ServerQuery notify events +- **Priority:** P2 +- **Source:** yatqa-offline-reference review +- **Description:** Missing events: `notifychanneldescriptionchanged`, `notifychannelpasswordchanged`. Most events listed by name only with no field details. Expand with full field lists and behavioral notes. +- **Effort:** M +- **Dependencies:** None + +### TODO-084 — Cross-reference YaTQA and ReSpeak error codes +- **Priority:** P3 +- **Source:** yatqa-offline-reference review, respeak-protocol-reference review +- **Description:** YaTQA §9 and ReSpeak Errors.csv may have discrepancies. Cross-reference and note differences. +- **Effort:** S +- **Dependencies:** None + +--- + +## 11. Additional Traceability Gaps + +### TODO-085 — Add Flutter app documentation +- **Priority:** P2 +- **Source:** codebase-analysis §4 +- **Description:** Flutter app has <1% documentation coverage (~586 functions, ~5 documented). Add dart doc comments to core services and widgets. +- **Effort:** XL +- **Dependencies:** None + +### TODO-086 — Add chanora_bridge doc comments (15% coverage) +- **Priority:** P2 +- **Source:** codebase-analysis §4 +- **Description:** chanora_bridge has 65 pub fn at 15% documentation. This is the FFI boundary — every function should be documented. +- **Effort:** L +- **Dependencies:** None + +### TODO-087 — Track Flutter framework upstream bugs and workarounds +- **Priority:** P2 +- **Source:** codebase-analysis §9, issue-history §1 +- **Description:** 3+ historical issues required Flutter framework workarounds. Create tracking document for upstream Flutter bugs that affect Chanora and document current workarounds. +- **Effort:** S +- **Dependencies:** None + +### TODO-088 — Improve branch management workflow +- **Priority:** P3 +- **Source:** codebase-analysis §10, issue-history §2 +- **Description:** PR stacking complexity and local CI mirroring noted as development pain points. Evaluate git-worktree or branch management tooling. +- **Effort:** M +- **Dependencies:** None + +--- + +*Generated from codebase analysis on 2026-06-11. 88 items across 11 categories.* diff --git a/docs/references/external-research-2026-06-11.md b/docs/references/external-research-2026-06-11.md new file mode 100644 index 0000000..24d61b2 --- /dev/null +++ b/docs/references/external-research-2026-06-11.md @@ -0,0 +1,268 @@ +# External Research: TeaSpeak, ReSpeak, YaTQA + +**Date:** 2026-06-11 +**Purpose:** Competitive analysis, dependency analysis, protocol documentation research + +--- + +## 1. TeaSpeak + +### Overview + +| Attribute | Details | +|---|---| +| **Name** | TeaSpeak | +| **Website** | teaspeak.de (currently down, archived) | +| **Repository** | github.com/TeaSpeak/TeaSpeak (issue tracker only) | +| **License** | Mixed: Web Client (MPL-2.0), Server (Proprietary), TeaMusic (Open Source C++) | +| **Status** | **Effectively unmaintained** — TeaWeb archived July 2025, last server release ~2022 | +| **Stars** | 120 (main repo), 49 (TeaWeb), 7 (TeaMusic) | +| **Languages** | TypeScript (84%), SCSS, HTML, WebAssembly (web client); C++ (music bot) | + +### Architecture + +``` +TeaSpeak Server (closed-source binary, Linux x64 only) + │ + ├── TeaSpeak Web Client (TypeScript, open source, MPL-2.0) + ├── TeaSpeak Native Client (closed-source binary, Win/Linux x64) + └── TeaMusic (C++ music bot, open source) +``` + +### Feature Comparison + +| Feature | TeaSpeak | Chanora | +|---|---|---| +| Voice (Opus) | ✅ | ✅ | +| Text Chat | ✅ (markdown) | ✅ | +| Video/Screen Sharing | ✅ (buggy, VP8) | Not planned | +| Music Bot | ✅ (built-in) | Not in scope | +| Channels | ✅ | ✅ | +| Permissions | ✅ (advanced) | Partial | +| File Transfer | ✅ | ✅ (v0.3.0) | +| Web Client | ✅ | Not in scope | +| Native Client | ✅ (closed source) | ✅ (Flutter + Rust) | +| Cross-platform | Partial (Win/Linux) | ✅ (5 platforms) | +| Push-to-Talk | Unknown | ✅ | +| i18n | ✅ (8 languages) | ✅ | + +### Lessons for Chanora + +**What to learn:** +- Web client as installation-less option is compelling +- Built-in music bot is popular feature +- Hidden/private channels valued by users +- Markdown in chat is well-received +- Multi-language support is expected + +**What to avoid:** +- Closed-source server prevents community maintenance +- Monolithic architecture limits extensibility +- Poor maintenance (abandoned since ~2022) +- Buggy video/screen sharing (multiple open issues) +- No ARM support (frequently requested) +- Mixed tech stack (React + jQuery) creates maintenance burden + +### Market Opportunity + +TeaSpeak's abandonment creates a clear opportunity for Chanora: +- Users seeking open-source TeamSpeak-compatible clients +- TeaSpeak's feature set validates market need +- Chanora's formal engineering process prevents abandonment + +--- + +## 2. ReSpeak Organization + +### Overview + +| Attribute | Details | +|---|---| +| **URL** | https://github.com/ReSpeak | +| **Mission** | Reverse-engineering and reimplementing TS3 protocol in Rust | +| **Activity** | 16 public repositories, 11 contributors | +| **Language focus** | Rust (primary), C, C#, Python, Svelte/TypeScript | +| **License** | Apache-2.0 / MIT dual-license | + +### Repository Inventory + +| Repository | Purpose | Stars | Status | +|---|---|---|---| +| **tsclientlib** | Core TS3 protocol library | 140 | Active | +| **tsdeclarations** | Machine-readable protocol declarations | 94 | Active | +| **TS3Hook** | DLL injection for packet decryption | 70 | Archived | +| **rust-ts3plugin** | Rust bindings for TS3 plugin API | 14 | Active | +| **SimpleBot** | Chat bot with custom reactions | 14 | Maintenance | +| **quicklz** | QuickLZ compression for TS3 protocol | 7 | Stable | +| **tomcrypt-rs** | Rust bindings for libtomcrypt | 6 | Dormant | +| **ts3stats** | User statistics from server logs | 6 | Dormant | +| **t4rust** | T4-like template engine for Rust | 5 | Active | +| **Qint** | Full cross-platform TS3 client (Tauri) | 5 | Active | +| **ts3tts** | Text-to-speech plugin | 3 | Maintenance | +| **TsPressor** | Message compressor | 2 | Dormant | +| **rust-ts3plugin-sys** | FFI bindings for TS3 plugin API | 0 | Active | +| **MahTsIdentity** | Identity management | 0 | Dormant | +| **pyTSon** | Python plugin interface | 0 | Dormant | +| **TsVersionChecker** | Client version verification | 1 | Dormant | + +### Key Library: tsclientlib + +**Architecture (monorepo):** + +| Crate | Purpose | +|---|---| +| `tsclientlib` | High-level client API | +| `tsproto` | Low-level protocol (UDP, encryption, fragmentation) | +| `ts-bookkeeping` | State tracking | +| `tsproto-packets` | Packet parsing | +| `tsproto-structs` | Auto-generated structs | +| `tsproto-types` | Basic types | + +**Key capabilities:** +- Full TS3 protocol handshake (Init1 RSA puzzle, ECDH key exchange) +- Encryption: EAX mode (AES-128-CTR + OMAC) +- Compression: QuickLZ level 1 +- Packet fragmentation and reassembly +- Voice/Opus audio handling + +**Performance:** +- ~199ms connection time (RSA puzzle dominant) +- ~189μs per message send + +### Chanora's Dependency on ReSpeak + +| Dependency | How Chanora Uses It | +|---|---| +| `tsclientlib` | Protocol adapter (`chanora_protocol`) | +| `tsproto` | Network layer, encryption | +| `tsproto-types` | Basic TS3 types | +| `tsproto-packets` | Packet parsing | +| `tsproto-structs` | Command/event structs | +| `ts-bookkeeping` | Server state tracking | +| `AudioHandler` | Voice decode, jitter buffer | + +**Note:** Chanora uses a **fork** (`EdisonJwa/tsclientlib`) for a p256 coordinate padding fix. + +### Protocol Documentation + +`tsdeclarations/ts3protocol.md` is the most comprehensive open TS3 protocol specification: + +1. **Low-level packets:** 9 packet types (Voice, VoiceWhisper, Command, CommandLow, Ping, Pong, Ack, AckLow, Init1) +2. **Encryption:** EAX mode (AES-128-CTR + OMAC) +3. **Compression:** QuickLZ level 1 +4. **Handshake:** 5-step Init1 (RSA puzzle), then ECDH key exchange +5. **Voice:** Opus codec at 48kHz, whisper targeting modes +6. **Identity:** EC key pairs (prime256v1), hashcash proof-of-work + +### Gaps in ReSpeak + +| Gap | Impact on Chanora | +|---|---| +| Server code | Not needed (client only) | +| TS5 protocol | No full TS5 client protocol | +| File transfer | No implementation | +| Auto-reconnect | "Not yet there" in README | +| IPv6 support | Not documented | +| Documentation | Sparse code comments | + +### Recommendations + +**Continue using:** +- `tsclientlib` as primary protocol dependency +- `tsdeclarations` for protocol understanding + +**Consider contributing:** +- p256 coordinate padding fix upstream +- Auto-reconnect logic if implemented + +**Build internally:** +- File transfer (no existing implementation) +- Auto-reconnect logic +- TS5 compatibility (monitor `tsdeclarations`) + +--- + +## 3. YaTQA (yat.qa) + +### Overview + +| Attribute | Details | +|---|---| +| **Name** | YaTQA — Yet Another TeamSpeak³ Query App | +| **URL** | https://yat.qa/ | +| **Author** | Janni "Яedeemer" K. from northern Germany | +| **First release** | June 29, 2011 | +| **Latest version** | v3.9.9b (March 1, 2023) | +| **Language** | Delphi 2009 (~50,000+ lines) | +| **Purpose** | GUI alternative to raw ServerQuery telnet commands | + +**Note:** "qa" stands for **Query App**, not "Quality Assurance." + +### What It Is + +YaTQA is a Windows GUI tool for managing TeamSpeak 3 servers via the ServerQuery interface. It is NOT a testing framework. + +### Useful Resources + +The `/ressourcen/` section contains valuable unofficial documentation: + +| Resource | Value for Chanora | +|---|---| +| Server error codes | Comprehensive error handling reference | +| Permission IDs | Permission feature implementation | +| Client versions | Protocol compatibility reference | +| DNS resolver behavior | Server resolution reference | +| Anti-flood mechanics | Rate limiting design | +| Codec configuration | Audio codec handling reference | +| Snapshot format | Server migration features | +| Voice client anti-flood | Rate limiting implementation | +| Other protocols | File transfer, TSDNS, blacklist, weblist, badges | + +### Relevance to Chanora + +**Low direct relevance** — management tool, not testing framework. + +**What to extract:** +1. Unofficial ServerQuery documentation (mostly German) +2. Server error codes for comprehensive error handling +3. Permission IDs for permission features +4. Anti-flood mechanics for rate limiting design + +### Codec Reference + +YaTQA documents TeamSpeak's codec configuration: +- Six codecs: Speex 8kHz, Speex 16kHz, Speex 32kHz, CELT 48kHz, Opus Voice, Opus Music +- 11 quality levels per codec (0–10) +- Latency settings for Speex/CELT (20–60ms) +- Opus is VBR (variable bitrate) + +--- + +## 4. Summary: What Chanora Can Learn + +### From TeaSpeak +- ✅ Open-source client is the right approach +- ✅ Cross-platform support is expected +- ✅ i18n is important +- ❌ Avoid closed-source components +- ❌ Avoid monolithic architecture +- ❌ Avoid mixed tech stacks + +### From ReSpeak +- ✅ `tsclientlib` is the right protocol foundation +- ✅ Protocol declarations are valuable reference +- ⚠️ Keep fork in sync with upstream +- ⚠️ Monitor for TS5 protocol updates +- 🔨 Need to build file transfer internally +- 🔨 Need to build auto-reconnect internally + +### From YaTQA +- 📚 Unofficial protocol docs are valuable reference +- 📚 Server error codes for error handling +- 📚 Permission IDs for permission features +- 📚 Anti-flood mechanics for rate limiting +- ❌ Not a testing framework — don't try to use it as one + +--- + +*Generated by external research agents on 2026-06-11* diff --git a/docs/references/respeak-protocol-reference.md b/docs/references/respeak-protocol-reference.md new file mode 100644 index 0000000..498a209 --- /dev/null +++ b/docs/references/respeak-protocol-reference.md @@ -0,0 +1,2028 @@ +# ReSpeak TeamSpeak Protocol Reference + +> Comprehensive offline reference compiled from [ReSpeak/tsdeclarations](https://github.com/ReSpeak/tsdeclarations) and [ReSpeak/tsclientlib](https://github.com/ReSpeak/tsclientlib). + +--- + +## Table of Contents + +1. [TS3 Protocol Specification](#1-ts3-protocol-specification) +2. [Error Codes](#2-error-codes) +3. [Permissions](#3-permissions) +4. [Client Versions](#4-client-versions) +5. [Badges](#5-badges) +6. [Enums](#6-enums) +7. [Book (State Tracking) Definitions](#7-book-state-tracking-definitions) +8. [Packet Definitions](#8-packet-definitions) +9. [tsdeclarations README](#9-tsdeclarations-readme) +10. [tsclientlib Architecture & API](#10-tsclientlib-architecture--api) + +--- + +# 1. TS3 Protocol Specification + +## 0. Naming Conventions +- `(Client -> Server)` denotes packets from client to server. +- `(Client <- Server)` denotes packets from server to client. +- All datatypes are sent in network order (Big Endian) unless otherwise specified. +- Datatypes are declared with a prefixing `u` or `i` for unsigned and signed and a number for the bitlength. + For example `u8` would be the C equivalent of `uint8` or `unsigned char` +- Arrays are represented by the underlying datatype in square brackets, additionally if the length is known it is added in the brackets, separated by a semicolon. Eg: `[u8]`, `[i32; 16]` +- Array ranges (parts of an array) are specified in square brackets with the included lower bound, two points (`..`) and the excluded upper bound. Eg: `[0..10]` + +## 1. Low-Level Packets + +### 1.1 Packet structure +- The packets are build in a fixed scheme, though have differences depending in which direction. +- Every column here represents 1 byte. +- The entire packet size must be at max 500 bytes. + +#### 1.1.1 (Client -> Server) +``` ++--+--+--+--+--+--+--+--+--+--+--+--+--+---------//----------+ +| MAC | PId | CId |PT| Data | ++--+--+--+--+--+--+--+--+--+--+--+--+--+---------//----------+ +| \ Meta | +\ Header / +``` + +| Name | Size | Datatype | Explanation | +|------|-------------|----------|---------------------------------| +| MAC | 8 bytes | [u8] | EAX Message Authentication Code | +| PId | 2 bytes | u16 | Packet Id | +| CId | 2 bytes | u16 | Client Id | +| PT | 1 byte | u8 | Packet Type + Flags | +| Data | ≤487 bytes | [u8] | The packet payload | + +#### 1.1.2 (Client <- Server) +``` ++--+--+--+--+--+--+--+--+--+--+--+------------//-------------+ +| MAC | PId |PT| Data | ++--+--+--+--+--+--+--+--+--+--+--+------------//-------------+ +| \ Meta | +\ Header / +``` + +| Name | Size | Datatype | Explanation | +|------|-------------|----------|---------------------------------| +| MAC | 8 bytes | [u8] | EAX Message Authentication Code | +| PId | 2 bytes | u16 | Packet Id | +| PT | 1 byte | u8 | Packet Type + Flags | +| Data | ≤489 bytes | [u8] | The packet payload | + +### 1.2 Packet Types +- `0x00` Voice +- `0x01` VoiceWhisper +- `0x02` Command +- `0x03` CommandLow +- `0x04` Ping +- `0x05` Pong +- `0x06` Ack +- `0x07` AckLow +- `0x08` Init1 + +### 1.3 Packet Type + Flags byte +The final byte then looks like this: +``` +MSB LSB ++--+--+--+--+--+--+--+--+ +|UE|CP|NP|FR| Type | ++--+--+--+--+--+--+--+--+ +``` + +| Name | Size | Hex | Explanation | +|------|-------|------|-----------------| +| UE | 1 bit | 0x80 | Unencrypted | +| CP | 1 bit | 0x40 | Compressed | +| NP | 1 bit | 0x20 | Newprotocol | +| FR | 1 bit | 0x10 | Fragmented | +| Type | 4 bit | 0-8 | The packet type | + +### 1.4 Packet Compression +To reduce packet size, the data can be compressed. When the data is compressed the `Compressed` flag must be set. The algorithm "QuickLZ" with Level 1 is used for compression. + +### 1.5 Packet Splitting +When the packet payload exceeds the maximum datablock size the data can be split up across multiple packets. +The current protocol only allows `Command` and `CommandLow` to be split and/or compressed. +When splitting occurs, the `Fragmented` flag must be set on the first and the last packet. +The `Unencrypted` and `Compressed` flag, if set in the original packet, are only set on the first packet. (Though commands always have to be encrypted) +The `Newprotocol` flag has to be set on all commands and therefore also has to be applied on all splitted command packets. +The data can additionally be compressed *before* splitting. + +*Example*: The packet to split has the following flags: +``` +[__|CP|NP|__] Packet Id: 42 +``` +it must be split into: +``` +[__|CP|NP|FR] Packet Id: 42 +[__|__|NP|__] Packet Id: 43 +[__|__|NP|FR] Packet Id: 44 +``` + +### 1.6 Packet Encryption +When a packet is not encrypted the `Unencrypted` flag is set. For encrypted packets the flag gets cleared. +Packets get encrypted with EAX mode (AES_128_CTR with OMAC). +The en/decryption parameters are generated for each packet as follows: + +#### 1.6.1 Inputs +| Name | Type | Explanation | +|------|----------|---------------------------------| +| PT | u8 | Packet Type | +| PId | u16 | Packet Id | +| PGId | u32 | Packet GenerationId (see 1.9.2) | +| PD | bool | Packet Direction | +| SIV | [u8; 20] | Shared IV (see 3.2) | + +#### 1.6.2 Generation pseudocode +Note that the `temporary` variable will have a different length depending on the result from the crypto init handshake. The old protocol SharedIV (see 3.2.1) will be 20 bytes long, since it is generated with sha1, while the new protocol SharedIV (see 3.2.2) will have 64 bytes, since it is generated with sha512. + +``` +let temporary: [u8; 26] OR [u8; 70] +temporary[0] = 0x30 if (Client <- Server) + 0x31 if (Client -> Server) +temporary[1] = PT +temporary[2..6] = (PGId in network order)[0..4] +if SIV.length == 20 + temporary[6..26] = SIV[0..20] +else + temporary[6..70] = SIV[0..64] + +let keynonce: [u8; 32] +keynonce = sha256(temporary) + +key: [u8; 16] = keynonce[ 0..16] +nonce: [u8; 16] = keynonce[16..32] +key[0] = key[0] xor ((PId & 0xFF00) >> 8) +key[1] = key[1] xor ((PId & 0x00FF) >> 0) +``` + +> Note: The key and nonce can be cached for each tuple of (PT, PD, PGId) which will require 8 * 2 = 16 entries. And must only be recalculated each time the PG changes. For each packet to encrypt only the first 2 bytes must be xor'd with the PId as shown in the pseudocode. + +#### 1.6.3 Encryption +The data can now be encrypted with the `key` and `nonce` from (see 1.6.2) as the EAX key and nonce and the packet `Meta` as defined in (see 1.1) as the EAX header (sometimes called "Associated Text"). The resulting EAX mac (sometimes called "Tag") will be stored in the `MAC` field as defined in (see 1.1.1). + +#### 1.6.4 Not encrypted packets +When a packet is not encrypted, no MAC can be generated by EAX. In this case the SharedMac (see 3.2) will be used instead. + +### 1.7 Packet Stack Wrap-up +This stack is a reference for the execution order of the set data operations. For incoming packets the stack is executed bot to top, for outgoing packets top to bot. + +``` + Send Receive ++-----------+ +-----------+ +| Data | | Λ | Data | ++-----------+ | | +-----------+ +| Compress | | | | Decompress| ++-----------+ | | +-----------+ +| Split | | | | Merge | ++-----------+ | | +-----------+ +| Encrypt | V | | Decrypt | ++-----------+ +-----------+ +``` + +### 1.8 Packet Types Data Structures + +#### 1.8.1.1 Voice (Client -> Server) +``` ++--+--+--+---------//---------+ +| VId |C | Data | ++--+--+--+---------//---------+ +``` + +| Name | Type | Explanation | +|------|------|-----------------| +| VId | u16 | Voice Packet Id | +| C | u8 | Codec Type | +| Data | var | Voice Data | + +#### 1.8.1.2 Voice (Client <- Server) +``` ++--+--+--+--+--+---------//---------+ +| VId | CId |C | Data | ++--+--+--+--+--+---------//---------+ +``` + +| Name | Type | Explanation | +|------|------|-----------------| +| VId | u16 | Voice Packet Id | +| CId | u16 | Talking Client | +| C | u8 | Codec Type | +| Data | var | Voice Data | + +#### 1.8.2.1 VoiceWhisper (Client -> Server) +For direct user/channel targeting (The `Newprotocol` Flag must be *unset*): +``` ++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ +| VId |C |N |M | U* | T* | Data | ++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ +``` + +| Name | Type | Explanation | +|------|-------|---------------------------------------| +| VId | u16 | Voice Packet Id | +| C | u8 | Codec Type | +| N | u8 | Count of ChannelIds to send to | +| M | u8 | Count of ClientIds to send to | +| U | [u64] | Targeted ChannelIds, repeated N times | +| T | [u16] | Targeted ClientIds, repeated M times | +| Data | var | Voice Data | + +For targeting special groups (The `Newprotocol` Flag must be *set*): +``` ++--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ +| VId |C |TY|TA| U | Data | ++--+--+--+--+--+--+--+--+--+--+--+--+--+---------//---------+ +``` + +| Name | Type | Explanation | +|------|-------|---------------------------------------------------------| +| VId | u16 | Voice Packet Id | +| C | u8 | Codec Type | +| TY | u8 | GroupWhisperType (see below) | +| TA | u8 | GroupWhisperTarget (see below) | +| U | u64 | the targeted channelId or groupId (0 if not applicable) | +| Data | var | Voice Data | + +```c +enum GroupWhisperType : u8 +{ + ServerGroup = 0, /* U = servergroup targetId */ + ChannelGroup = 1, /* U = channelgroup targetId */ + ChannelCommander = 2, /* U = 0 (ignored) */ + AllClients = 3, /* U = 0 (ignored) */ +} + +enum GroupWhisperTarget : u8 +{ + AllChannels = 0, + CurrentChannel = 1, + ParentChannel = 2, + AllParentChannel = 3, + ChannelFamily = 4, + CompleteChannelFamily = 5, + Subchannels = 6, +} +``` + +#### 1.8.2.2 VoiceWhisper (Client <- Server) +``` ++--+--+--+--+--+---------//---------+ +| VId | CId |C | Data | ++--+--+--+--+--+---------//---------+ +``` + +| Name | Type | Explanation | +|------|------|-----------------| +| VId | u16 | Voice Packet Id | +| CId | u16 | Talking Client | +| C | u8 | Codec Type | +| Data | var | Voice Data | + +#### 1.8.3-4 Command and CommandLow +The TeamSpeak3 Query like command string encoded in UTF-8. + +#### 1.8.5 Ping +Empty. + +#### 1.8.6-8 Pong, Ack and AckLow +``` ++--+--+ +| PId | ++--+--+ +``` + +| Name | Type | Explanation | +|------|------|------------------------------------| +| PId | u16 | The packet id that is acknowledged | + +- In case of `Pong` a matching ping packet id is acknowledged. +- In case of `Ack` or `AckLow` a matching `Command` or `CommandLow` packet id respectively is acknowledged. + +#### 1.8.9 Init1 +(see 2.1)-(see 2.5) + +### 1.9 Packet Ids and Generations + +#### 1.9.1 Packet Ids +Each packet type and packet direction must be maintained by an own packet id counter. This means the client has 9 different packet id counter for outgoing packets. For each new packet the counter gets increased by 1. This also applies to split packets. The client must also maintain packet ids for incoming packets in case of packets arriving out of order. All Packet Ids start at 1 unless otherwise specified. + +#### 1.9.2 Generations +Packet Ids are stored as u16, this means they range from 0 up to 65535 included. When the packet id overflows from 65535 to 0 at a packet, the generation counter for this packet type gets increased by 1. Note that the new generation id immediately applies to the 'overflowing' packet. The generation id counter is solely used for encryption (see 1.6). + +### 1.10 Packet Acknowledgement / Packet Loss +In order to reliably send packets over UDP some packet types must get acknowledged when received (see 1.11). The protocol uses selective repeat for lost packets. This means each packet has its own timeout. Already acknowledged later packets must not be resent. When a packet times out, the exact same packet should be resent until properly acknowledged by the server. If after 30 seconds no resent packet gets acknowledged the connection should be closed. Packet resend timeouts should be calculated with an exponential backoff to prevent network congestion. + +### 1.11 Wrap-up + +| Type | Acknowledged (by) | Resend | Encrypted | Splittable | Compressible | +|--------------|-------------------|--------|-----------|------------|--------------| +| Voice | ✗ | ✗ | Optional | ✗ | ✗ | +| VoiceWhisper | ✗ | ✗ | Optional | ✗ | ✗ | +| Command | ✓ (Ack) | ✓ | ✓ | ✓ | ✓ | +| CommandLow | ✓ (AckLow) | ✓ | ✓ | ✓ | ✓ | +| Ping | ✓ (Pong) | ✗ | ✗ | ✗ | ✗ | +| Pong | ✗ | ✗ | ✗ | ✗ | ✗ | +| Ack | ✗ | ✓ | ✓ | ✗ | ✗ | +| AckLow | ✗ | ✓ | ✓ | ✗ | ✗ | +| Init1 | ✓ (next Init1) | ✓ | ✗ | ✗ | ✗ | + +## 2. The (Low-Level) Initiation/Handshake + +A connection is started from the client by sending the first handshake packet. The handshake process consists of 5 different init packets. This includes the so called RSA puzzle to prevent DOS attacks. + +The packet header values are set as following for all packets here: + +| Parameter | Value | +|-----------|--------------------------------------------------------| +| MAC | [u8]{ 0x54, 0x53, 0x33, 0x49, 0x4E, 0x49, 0x54, 0x31 } | +| key | N/A | +| nonce | N/A | +| Type | Init1 | +| Encrypted | ✗ | +| Packet Id | u16: 101 | +| Client Id | u16: 0 | + +Init packets from the client contain a version field, which is the build timestamp of the client. This is a unix timestamp subtracted with 1356998400. The unix timestamp 1461588969 (date 2016-04-25) is encoded as 1461588969 - 1356998400 = 0x063bece9 = { 0x06, 0x3b, 0xec, 0xe9 }. + +### 2.1 Packet 0 (Client -> Server) +``` +04 bytes : Version of the TeamSpeak client as timestamp + Example: { 0x06, 0x3b, 0xec, 0xe9 } +01 bytes : Init-packet step number + Const: 0x00 +04 bytes : Current timestamp in unix format +04 bytes : Random bytes := [A0] +08 bytes : Zeros, reserved. +``` + +### 2.2 Packet 1 (Client <- Server) +``` +01 bytes : Init-packet step number + Const: 0x01 +16 bytes : Server stuff := [A1] +04 bytes : The bytes from [A0] in reversed order (not always) := [A0r] +``` + +This packets usually contains the bytes from [A0] in reversed order, except when connecting from some networks for a yet unknown reason. + +### 2.3 Packet 2 (Client -> Server) +``` +04 bytes : Version of the TeamSpeak client as timestamp +01 bytes : Init-packet step number + Const: 0x02 +16 bytes : The bytes from [A1] +04 bytes : The bytes from [A0r] +``` + +### 2.4 Packet 3 (Client <- Server) +``` +01 bytes : Init-packet step number + Const: 0x03 +64 bytes : 'x', an unsigned BigInteger +64 bytes : 'n', an unsigned BigInteger +04 bytes : 'level' a u32 +100 bytes : Server stuff := [A2] +``` + +Note: Sometimes, instead of sending an init with step 3, the server responds with an init that contains 127 as step number. In that case, the client has to restart the connection by sending packet 0 again. + +### 2.5 Packet 4 (Client -> Server) +``` +04 bytes : Version of the TeamSpeak client as timestamp +01 bytes : Init-packet step number + Const: 0x04 +64 bytes : the received 'x' +64 bytes : the received 'n' +04 bytes : the received 'level' +100 bytes : The bytes from [A2] +64 bytes : 'y' which is the result of x ^ (2 ^ level) % n as an unsigned + BigInteger. Padded from the lower side with '0x00' when shorter + than 64 bytes. + Example: { 0x00, 0x00, data ... data} +var bytes : The clientinitiv command data as explained in (see 3.1) +``` + +Note: +- `^` in this context means 'power to' +- To calculate the power of such a high number use a language integrated function like `ModPow` or similar, when available. If you don't have this function available you can multiply x iteratively and apply the modulo operation after each multiplication. + +## 3. The (High-Level) Initiation/Handshake + +In this phase the client and server exchange basic information and agree on/calculate the symmetric AES encryption key with the ECDH public/private key exchange technique. + +Both the client and the server will need a EC public/private key. This key is also the identity which the server uses to recognize a user again. The curve used is 'prime256v1'. + +All high level packets specified in this chapter are sent as `Command` Type packets as explained in (see 2.8.3). Additionally the `Newprotocol` flag (see 2.3) must be set on all `Command`, `CommandLow` and `Init1` packets. + +All commands are specified in the `Messages.txt` file. + +The packet header/encryption values for (see 3.1) and (see 3.2) are as following: + +| Parameter | Value | +|-----------|------------------------------------------------------------------------------------------------------| +| MAC | (Generated by EAX) | +| key | [u8]{0x63, 0x3A, 0x5C, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x5C, 0x73, 0x79, 0x73, 0x74, 0x65} | +| nonce | [u8]{0x6D, 0x5C, 0x66, 0x69, 0x72, 0x65, 0x77, 0x61, 0x6C, 0x6C, 0x33, 0x32, 0x2E, 0x63, 0x70, 0x6C} | +| Type | Command | +| Encrypted | ✓ | +| Packet Id | u16: 0 | +| Client Id | u16: 0 | + +The acknowledgement packets use the same parameters as the commands, except with the Type `Ack`. + +### 3.1 clientinitiv (Client -> Server) +The first packet is sent (Client -> Server) although this is only sent for legacy reasons since newer servers (at least 3.0.13.0?) use the data part embedded in the last `Init1` packet from the low-level handshake (see 2.5). + +``` +clientinitiv alpha={alpha} omega={omega} ot={ot} ip={ip} +``` + +- `alpha` is set to `base64(random[u8; 10])` which are 10 random bytes for entropy. +- `omega` is set to `base64(publicKey[u8])` omega is an ASN.1-DER encoded public key from the ECDH parameters as following: + + | Type | Value | Explanation | + |------------|----------------|-------------------------------------------| + | BIT STRING | 1bit, Value: 0 | LibTomCrypt uses 0 for a public key | + | INTEGER | 32 | The LibTomCrypt used keysize | + | INTEGER | publicKey.x | The affine X-Coordinate of the public key | + | INTEGER | publicKey.y | The affine Y-Coordinate of the public key | + +- `ot` should always be `1` +- `ip` should be set to the final resolved ip address of the server you are actually connecting to. + +### 3.2 initivexpand/initivexpand2 (Client <- Server) +Depending on the server version the server will send a different init request. +- TS3 server <3.1 will send `initivexpand`. Continue with (see 3.2.1) +- TS3 server ≥3.1 will send `initivexpand2`. Continue with (see 3.2.2) + +If you want to support both protocol standards you don't need to check/know the server version. The client just has to act accordingly depending on which packet the server sends. + +#### 3.2.1 initivexpand (Client <- Server) +The server responds with this command. + +``` +initivexpand alpha={alpha} beta={beta} omega={omega} +``` + +- `alpha` must have the same value as sent to the server in the previous step. +- `beta` is set to `base64(random[u8; 10])` by the server. +- `omega` is set to `base64(publicKey[u8])` with the public key from the server, encoded same as in (see 3.1) + +With this information the client now must calculate the shared secret. + +``` +let sharedSecret: ECPoint +let x: [u8] +let sharedData: [u8; 32] +let SharedIV: [u8; 20] +let SharedMac: [u8; 8] +let ECDH(A, B) := (A * B).Normalize + +sharedSecret = ECDH(serverPublicKey, ownPrivateKey) +x = sharedSecret.x.AsByteArray() +if x.length < 32 + sharedData[ 0..(32-x.length)] = [0..0] + sharedData[(32-x.length)..32] = x[0..x.length] +elseif x.length == 32 + sharedData[0..32] = x[0..32] +elseif x.length > 32 + sharedData[0..32] = x[(x.length-32)..x.length] +SharedIV = sha1(sharedData) +SharedIV[0..10] = SharedIV[0..10] xor alpha.decode64() +SharedIV[10..20] = SharedIV[10..20] xor beta.decode64() +SharedMac[0..8] = sha1(SharedIV)[0..8] +``` + +#### 3.2.2 initivexpand2 (Client <- Server) +The server responds with this command. + +``` +initivexpand2 l={l} beta={beta} omega={omega} ot={ot} proof={proof} tvd={tvd} +``` + +- `l` the server license (see 3.2.2.2) +- `beta` is set to `base64(random[u8; 54])` by the server. +- `omega` is a `base64(publicKey[u8])` with the public key from the server, encoded same as in (see 3.1) +- `ot` should always be `1` +- `proof` is a `base64(ecdh_sign(l))` +- `tvd` (base64, unknown; only set on servers with a license) + +##### 3.2.2.1 Verify integrity +This step **must** be done to verify the integrity of the connection. + +The `proof` parameter is the sign of the `l` parameter (*not* base64 encoded). The client can verify the `l` parameter with the public key of the server which is sent in `omega`. + +Both proofs which are exchanged (the one you received in (see 3.2.2), and the one sent in (see 3.2.2.5)) use 'prime256v1 with sha256, DER encoded'. +Note that the identity keys from client/server already should be keys on 'prime256v1' as noted in (see 3). + +##### 3.2.2.2 Parsing the license +The license has a small header continued by a list of blocks. Each block may vary in length and must be parsed sequentially therefore. + +The license header: +``` +01 bytes : License version + Const: 0x01 +``` + +The block base layout: +``` +01 bytes : Key type + Const: 0x00 (public key) +32 bytes : Block public key +01 bytes : License block type +04 bytes : Not valid before date +04 bytes : Not valid after date +var bytes : (Content from the block type) +``` + +There are currently 4 different `License block type`s used: +- `00` Intermediate. + `content`: + ``` + 04 bytes : Unknown + var bytes : A null terminated string, which describes the issuer of this certificate. + ``` +- `01` Website/`03` Code + `content`: + ``` + var bytes : A null terminated string, which describes the issuer of this certificate. + ``` +- `02` TS3 Server + `content`: + ``` + 01 bytes : Server License Type + 04 bytes : Max clients allowed on the server + var bytes : A null terminated string, which describes the issuer of this certificate. + ``` +- `08` TS5 Server + `content`: + ``` + 01 bytes : Server License Type + 01 bytes : Property count + var bytes : Properties, see following description on how each property is encoded + + Per property: + 01 bytes : Length of following data + 01 bytes : Property Id + 01 bytes : Data Type + var bytes : Content depending on data type, see below + ``` + + Data Types: + - `00`: Null-terminated string + - `01`/`03`: 4 byte data + - `02`/`04`: 8 byte data + + Property Id: + - `01` (type `01`): Unknown + - `02` (type `00`): Issuer of the certificate + - `03` (type `01`): Max clients allowed on the server, defaults to 32 if not present + +- `32` Ephemeral + `content`: none + +Both dates are stored in BigEndian, when read you must add `0x50e22700` to the number and import as a unix timestamp. + +Each `Not valid before` and `Not valid after` timespan must be within the range of the parent license block. + +The license must consist of `2 ≤ count ≤ 8` blocks. The second to last block must be of type `Server` and the last block must be of type `Ephemeral`. + +##### 3.2.2.4 Calculating the shared secret +All elliptic curve operations for this step are done on the Curve25519. You might find more tools looking for Ed25519 but keep in mind that Ed25519 describes an EdDsa signing/verify operation and is not the curve itself. + +To calculate the shared secret each license block now must be processed sequentially the following way: + +``` +next_key = public_key * clamp(sha512(block[1..])[0..32]) + parent +``` + +Where: +- `public_key` is the `Block public key` taken from the current license block. This array must be imported as a compressed Curve25519 EC point. +- `sha512(block[1..])[0..32]` is the sha512 of the current license block. Note that the first byte (`Key type`) is skipped for the sha calculation. For the result only the first 32 bytes are used. This resulting array must be imported as a Curve25519 private key. +- `parent` which is the resulting `next_key` from the previous block. This is a compressed Curve25519 EC point. +- `clamp(num)` is a function describing `abs(num) mod B` where `B` is the base point of Curve25519. This function can usually be implemented conveniently on the number buffer like this: + ``` + let buffer: [u8; 32] + buffer[0] &= 0xF8 + buffer[31] &= 0x3F + buffer[31] |= 0x40 + ``` + +Since the first block has no predecessor, a fixed 'root' key is used as `parent`. This key must be imported as a compressed Curve25519 EC point. + +``` +[u8; 32] {0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, + 0xfd, 0x8f, 0x68, 0xb3, 0xdc, 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, + 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a} +``` + +The last `next_key` is now used as the public key from the server (see pseudocode below). + +The client now has to create a temporary Curve25519 public/private keypair. We will call them `client_public_key` and `client_private_key`. + +Now the `SharedIV` and `SharedMac` which will be used in the encryption, just as in the old protocol, can be calculated. + +``` +let SharedIV: [u8; 64] +let SharedMac: [u8; 8] +let sharedData: [u8; 32] + +sharedData = next_key * client_private_key +SharedIV = sha512(sharedData[0..32]) +SharedIV[ 0..10] = SharedIV[ 0..10] xor alpha.decode64() +SharedIV[10..64] = SharedIV[10..64] xor beta.decode64() +SharedMac[0..8] = sha1(SharedIV)[0..8] +``` + +##### 3.2.2.5 clientek (Client -> Server) +``` +clientek ek={ek} proof={proof} +``` + +- `ek` is `base64(client_public_key)` which the ephemeral (temporary) key created in (see 3.2.2.4) by the client. This should obviously be the public key part only. +- `proof` is `base64(client_public_key + beta)` which is a sign of the client_public_key (the `ek`) concatenated with the `beta` parameter from the `initivexpand2` command. The sign must be done with the private key from the identity keypair. + +The normal packet id counting starts with this packet. This means that `clientek` already has the packet id `1` and the next command will continue with `2`. + +### 3.2.3 Notes +- Only `SharedIV` and `SharedMac` are needed. The other values can (and should) be discarded. +- The crypto handshake is now completed. The normal encryption scheme (see 1.6) is from now on used. +- All `Command`, `CommandLow`, `Ack` and `AckLow` packets must get encrypted. +- `Voice` packets (and `VoiceWhisper` when wanted) should be encrypted when the channel encryption or server wide encryption flag is set. +- `Ping` and `Pong` must not be encrypted. + +### 3.3 clientinit (Client -> Server) +``` +clientinit client_nickname client_version client_platform client_input_hardware client_output_hardware client_default_channel client_default_channel_password client_server_password client_meta_data client_version_sign client_key_offset client_nickname_phonetic client_default_token hwid +``` + +- `client_nickname` the desired nickname +- `client_version` the client version +- `client_platform` the client platform +- `client_input_hardware` whether an input device is available +- `client_output_hardware` whether an output device is available +- `client_default_channel` the default channel to join. This can be a channel path or `/` (eg `/1`) for a channel id. +- `client_default_channel_password` the password for the join channel, prepared the following way `base64(sha1(password))` +- `client_server_password` the password to enter the server, prepared the following way `base64(sha1(password))` +- `client_meta_data` (can be left empty) +- `client_version_sign` a cryptographic sign to verify the genuinity of the client +- `client_key_offset` the number offset used to calculate the hashcash (see 4.1) value of the used identity +- `client_nickname_phonetic` the phonetic nickname for text-to-speech +- `client_default_token` permission token to be used when connecting to a server +- `hwid` hardware identification string + +**Notes**: +- Since client signs are only generated and distributed by TeamSpeak systems, this is the recommended client triple, as it is the reference for this paper: + - Version: `3.0.19.3 [Build: 1466672534]` + - Platform: `Windows` + - Sign: `a1OYzvM18mrmfUQBUgxYBxYz2DUU6y5k3/mEL6FurzU0y97Bd1FL7+PRpcHyPkg4R+kKAFZ1nhyzbgkGphDWDg==` +- The `hwid` usually consists of two 32 char strings concatenated with `,` and looks like `87056c6e1268aaf5055abf8256415e0e,408978b6d98810cc03f0aa16a4c75600` but even empty strings are accepted. + On windows the hwid seems to be generated from a registry key (`HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId`). + On linux and macOS it seems to derive from the MAC address of the primary Ethernet/Wifi adapter. +- Parameters which are empty or not used must be declared but left without value and the `=` character + +### 3.4 initserver (Client <- Server) +The server sends the `initserver` command. + +Note: From this point on the client knows his client id, therefore it must be set in the header of each packet. Newer versions of the server send parts of the `clientinit` command in the `initserver` command. + +### 3.5 Further notifications +The server will now send all needed information to display the entire server properly. Those notifications are in no fixed order, although they are most of the time sent in the here declared order. + +#### 3.5.1 channellist and channellistfinished +The `channellist` notification type will be sent multiple times as needed to transfer the entire server structure. After the last `channellist` notification the server will send `channellistfinished`. + +#### 3.5.2 notifycliententerview +The `notifycliententerview` notification will be sent multiple times as needed for each client currently connected. This is the same notification as when a new client connects. + +## 4. Further Concepts + +### 4.1 Hashcash +To prevent client spamming (connecting to a server with many different clients) the server requires a certain hashcash level on each identity. This level has a exponentially growing calculation time with increasing level. This ensures that a user wanting to spam a certain server needs to invest some time into calculating the required level. + +- The publicKey is a string encoded as in (see 3.1) the omega value. +- The key offset is a u64 number, which gets converted to a string when concatenated. + +The first step is to calculate a hash as following: +``` +let data: [u8; 20] = sha1(publicKey + keyOffset) +``` + +The level can now be calculated by counting the continuous leading zero bits in the data array. The bytes in the array get counted from 0 to 20 and the bits in each byte from least significant to most significant. + +### 4.2 Uid +To calculate the uid of an identity the public key is required. Therefore you can only calculate the uid of your own identity and the servers identity you are connecting to. + +The publicKey is a string encoded as in (see 3.1) the omega value. + +The uid can be calculated as following: +``` +let uid: string = base64(sha1(publicKey)) +``` + +### 4.3 Ping/Pong +The server will regularly send ping packets to check if a client is still alive. The client must answer them with the according pong packet. The client should also send ping packets to the server to check for connection. They will be answered with according pong packets. Sending ping packets from the client side should not be started before the crypto handshake has been completed (see 3.3). + +### 4.4 Passwords +All passwords when sent are hashed and encoded with `base64(sha1(password))` + +### 4.5 Importing/Deobfuscating Identities from the TeamSpeak3 Client +The TeamSpeak3 Client exports identities the following way: + +``` + + 'V' + +``` + +(For an explanation of the key offset (see 4.1)) + +```ts +const staticObfucationKey = b"b9dfaa7bee6ac57ac7b65f1094a1c155e747327bc2fe5d51c512023fe54a280201004e90ad1daaae1075d53b7d571c30e063b5a62a4a017bb394833aa0983e6e" +let ident = obfuscaded_identity.decode64() +let sha_part = ident[20..] +let idx = sha_part.indexof('\0') // where '\0' is the null-byte +let sha = sha1(sha_part[..idx]) +ident[0..20] = ident[0..20] xor sha[0..20] +let xorlen = min(ident.length, 100) +ident[0..xorlen] = ident[0..xorlen] xor staticObfucationKey[0..xorlen] +``` + +### 4.6 Audio +When the Opus codec is used, Voice and VoiceWhisper packets are using a sampling rate of 48 kHz. A voice packet without audio data signals the end of a stream. + +### 4.7 Permissions +`permissionlist` requests the list of all permissions of the server. `notifypermissionlist` returns the list of permissions and a grouping as a list of `group_id_end`s. The end ids are excluding, so a `group_id_end=6` for the first group means the first 6 permissions (`perms[0..6]`) are in this group. + +### 4.8 Channel Subscription +Clients can subscribe channels, so they get notifications when someone enters or leaves from a subscribed channel. If a new channel is subscribed, the server usually sends a notification, except in some cases: +- If the client server groups or permissions change, it stays subscribed, even if it does not have the power anymore +- If the channel permissions change, the server sends a notification if the subscription status changed +- If a client enters a channel, it gets subscribed but there is no notification +- If a client leaves a channel, there is a notification that it unsubscribed +- If a new channel is created, clients are not automatically subscribed + +### 4.? Differences between Query and Full Client +- notifyconnectioninforequest +- => setconnectioninfo + +--- + +# 2. Error Codes + +| Name | Doc | Hex | +|------|-----|-----| +| ok | unknown error code | 0x0000 | +| undefined | undefined error | 0x0001 | +| not_implemented | not implemented | 0x0002 | +| ok_no_update | | 0x0003 | +| dont_notify | | 0x0004 | +| lib_time_limit_reached | library time limit reached | 0x0005 | +| command_not_found | command not found | 0x0100 | +| unable_to_bind_network_port | unable to bind network port | 0x0101 | +| no_network_port_available | no network port available | 0x0102 | +| client_invalid_id | invalid clientID | 0x0200 | +| client_nickname_inuse | nickname is already in use | 0x0201 | +| client_invalid_error_code | invalid error code | 0x0202 | +| client_protocol_limit_reached | max clients protocol limit reached | 0x0203 | +| client_invalid_type | invalid client type | 0x0204 | +| client_already_subscribed | already subscribed | 0x0205 | +| client_not_logged_in | not logged in | 0x0206 | +| client_could_not_validate_identity | could not validate client identity | 0x0207 | +| client_invalid_password | invalid loginname or password | 0x0208 | +| client_too_many_clones_connected | too many clones already connected | 0x0209 | +| client_version_outdated | client version outdated, please update | 0x020a | +| client_is_online | client is online | 0x020b | +| client_is_flooding | client is flooding | 0x020c | +| client_hacked | client is modified | 0x020d | +| client_cannot_verify_now | can not verify client at this moment | 0x020e | +| client_login_not_permitted | client is not permitted to log in | 0x020f | +| client_not_subscribed | client is not subscribed to the channel | 0x0210 | +| channel_invalid_id | invalid channelID | 0x0300 | +| channel_protocol_limit_reached | max channels protocol limit reached | 0x0301 | +| channel_already_in | already member of channel | 0x0302 | +| channel_name_inuse | channel name is already in use | 0x0303 | +| channel_not_empty | channel not empty | 0x0304 | +| channel_can_not_delete_default | can not delete default channel | 0x0305 | +| channel_default_require_permanent | default channel requires permanent | 0x0306 | +| channel_invalid_flags | invalid channel flags | 0x0307 | +| channel_parent_not_permanent | permanent channel can not be child of non permanent channel | 0x0308 | +| channel_maxclients_reached | channel maxclient reached | 0x0309 | +| channel_maxfamily_reached | channel maxfamily reached | 0x030a | +| channel_invalid_order | invalid channel order | 0x030b | +| channel_no_filetransfer_supported | channel does not support filetransfers | 0x030c | +| channel_invalid_password | invalid channel password | 0x030d | +| channel_is_private_channel | channel is private channel | 0x030e | +| channel_invalid_security_hash | invalid security hash supplied by client | 0x030f | +| server_invalid_id | invalid serverID | 0x0400 | +| server_running | server is running | 0x0401 | +| server_is_shutting_down | server is shutting down | 0x0402 | +| server_maxclients_reached | server maxclient reached | 0x0403 | +| server_invalid_password | invalid server password | 0x0404 | +| server_deployment_active | deployment active | 0x0405 | +| server_unable_to_stop_own_server | unable to stop own server in your connection class | 0x0406 | +| server_is_virtual | server is virtual | 0x0407 | +| server_wrong_machineid | server wrong machineID | 0x0408 | +| server_is_not_running | server is not running | 0x0409 | +| server_is_booting | server is booting up | 0x040a | +| server_status_invalid | server got an invalid status for this operation | 0x040b | +| server_modal_quit | server modal quit | 0x040c | +| server_version_outdated | server version is too old for command | 0x040d | +| database | database error | 0x0500 | +| database_empty_result | database empty result set | 0x0501 | +| database_duplicate_entry | database duplicate entry | 0x0502 | +| database_no_modifications | database no modifications | 0x0503 | +| database_constraint | database invalid constraint | 0x0504 | +| database_reinvoke | database reinvoke command | 0x0505 | +| parameter_quote | invalid quote | 0x0600 | +| parameter_invalid_count | invalid parameter count | 0x0601 | +| parameter_invalid | invalid parameter | 0x0602 | +| parameter_not_found | parameter not found | 0x0603 | +| parameter_convert | convert error | 0x0604 | +| parameter_invalid_size | invalid parameter size | 0x0605 | +| parameter_missing | missing required parameter | 0x0606 | +| parameter_checksum | invalid checksum | 0x0607 | +| vs_critical | virtual server got a critical error | 0x0700 | +| connection_lost | Connection lost | 0x0701 | +| not_connected | not connected | 0x0702 | +| no_cached_connection_info | no cached connection info | 0x0703 | +| currently_not_possible | currently not possible | 0x0704 | +| failed_connection_initialisation | failed connection initialization | 0x0705 | +| could_not_resolve_hostname | could not resolve hostname | 0x0706 | +| invalid_server_connection_handler_id | invalid server connection handler ID | 0x0707 | +| could_not_initialise_input_manager | could not initialize Input Manager | 0x0708 | +| clientlibrary_not_initialised | client library not initialized | 0x0709 | +| serverlibrary_not_initialised | server library not initialized | 0x070a | +| whisper_too_many_targets | too many whisper targets | 0x070b | +| whisper_no_targets | no whisper targets found | 0x070c | +| file_invalid_name | invalid file name | 0x0800 | +| file_invalid_permissions | invalid file permissions | 0x0801 | +| file_already_exists | file already exists | 0x0802 | +| file_not_found | file not found | 0x0803 | +| file_io_error | file input/output error | 0x0804 | +| file_invalid_transfer_id | invalid file transfer ID | 0x0805 | +| file_invalid_path | invalid file path | 0x0806 | +| file_no_files_available | no files available | 0x0807 | +| file_overwrite_excludes_resume | overwrite excludes resume | 0x0808 | +| file_invalid_size | invalid file size | 0x0809 | +| file_already_in_use | file already in use | 0x080a | +| file_could_not_open_connection | could not open file transfer connection | 0x080b | +| file_no_space_left_on_device | no space left on device (disk full?) | 0x080c | +| file_exceeds_file_system_maximum_size | file exceeds file system's maximum file size | 0x080d | +| file_transfer_connection_timeout | file transfer connection timeout | 0x080e | +| file_connection_lost | lost file transfer connection | 0x080f | +| file_exceeds_supplied_size | file exceeds supplied file size | 0x0810 | +| file_transfer_complete | file transfer complete | 0x0811 | +| file_transfer_canceled | file transfer canceled | 0x0812 | +| file_transfer_interrupted | file transfer interrupted | 0x0813 | +| file_transfer_server_quota_exceeded | file transfer server quota exceeded | 0x0814 | +| file_transfer_client_quota_exceeded | file transfer client quota exceeded | 0x0815 | +| file_transfer_reset | file transfer reset | 0x0816 | +| file_transfer_limit_reached | file transfer limit reached | 0x0817 | +| sound_preprocessor_disabled | preprocessor disabled | 0x0900 | +| sound_internal_preprocessor | internal preprocessor | 0x0901 | +| sound_internal_encoder | internal encoder | 0x0902 | +| sound_internal_playback | internal playback | 0x0903 | +| sound_no_capture_device_available | no capture device available | 0x0904 | +| sound_no_playback_device_available | no playback device available | 0x0905 | +| sound_could_not_open_capture_device | could not open capture device | 0x0906 | +| sound_could_not_open_playback_device | could not open playback device | 0x0907 | +| sound_handler_has_device | ServerConnectionHandler has a device registered | 0x0908 | +| sound_invalid_capture_device | invalid capture device | 0x0909 | +| sound_invalid_playback_device | invalid playback device | 0x090a | +| sound_invalid_wave | invalid wave file | 0x090b | +| sound_unsupported_wave | wave file type not supported | 0x090c | +| sound_open_wave | could not open wave file | 0x090d | +| sound_internal_capture | internal capture | 0x090e | +| sound_device_in_use | device still in use | 0x090f | +| sound_device_already_registerred | device already registerred | 0x0910 | +| sound_unknown_device | device not registered/known | 0x0911 | +| sound_unsupported_frequency | unsupported frequency | 0x0912 | +| sound_invalid_channel_count | invalid channel count | 0x0913 | +| sound_read_wave | read error in wave | 0x0914 | +| sound_need_more_data | sound need more data | 0x0915 | +| sound_device_busy | sound device was busy | 0x0916 | +| sound_no_data | there is no sound data for this period | 0x0917 | +| sound_channel_mask_mismatch | Channelmask set bits count (speakers) is not the same as (count) | 0x0918 | +| permission_invalid_group_id | invalid group ID | 0x0a00 | +| permission_duplicate_entry | duplicate entry | 0x0a01 | +| permission_invalid_perm_id | invalid permission ID | 0x0a02 | +| permission_empty_result | empty result set | 0x0a03 | +| permission_default_group_forbidden | access to default group is forbidden | 0x0a04 | +| permission_invalid_size | invalid size | 0x0a05 | +| permission_invalid_value | invalid value | 0x0a06 | +| permissions_group_not_empty | group is not empty | 0x0a07 | +| permissions_client_insufficient | insufficient client permissions | 0x0a08 | +| permissions_insufficient_group_power | insufficient group modify power | 0x0a09 | +| permissions_insufficient_permission_power | insufficient permission modify power | 0x0a0a | +| permission_template_group_is_used | template group is currently used | 0x0a0b | +| permissions | permission error | 0x0a0c | +| accounting_virtualserver_limit_reached | virtualserver limit reached | 0x0b00 | +| accounting_slot_limit_reached | max slot limit reached | 0x0b01 | +| accounting_license_file_not_found | license file not found | 0x0b02 | +| accounting_license_date_not_ok | license date not ok | 0x0b03 | +| accounting_unable_to_connect_to_server | unable to connect to accounting server | 0x0b04 | +| accounting_unknown_error | unknown accounting error | 0x0b05 | +| accounting_server_error | accounting server error | 0x0b06 | +| accounting_instance_limit_reached | instance limit reached | 0x0b07 | +| accounting_instance_check_error | instance check error | 0x0b08 | +| accounting_license_file_invalid | license file invalid | 0x0b09 | +| accounting_running_elsewhere | virtualserver is running elsewhere | 0x0b0a | +| accounting_instance_duplicated | virtualserver running in same instance already | 0x0b0b | +| accounting_already_started | virtualserver already started | 0x0b0c | +| accounting_not_started | virtualserver not started | 0x0b0d | +| accounting_to_many_starts | | 0x0b0e | +| message_invalid_id | invalid message id | 0x0c00 | +| ban_invalid_id | invalid ban id | 0x0d00 | +| connect_failed_banned | connection failed, you are banned | 0x0d01 | +| rename_failed_banned | rename failed, new name is banned | 0x0d02 | +| ban_flooding | flood ban | 0x0d03 | +| tts_unable_to_initialize | unable to initialize tts | 0x0e00 | +| privilege_key_invalid | invalid privilege key | 0x0f00 | +| voip_pjsua | | 0x1000 | +| voip_already_initialized | | 0x1001 | +| voip_too_many_accounts | | 0x1002 | +| voip_invalid_account | | 0x1003 | +| voip_internal_error | | 0x1004 | +| voip_invalid_connectionId | | 0x1005 | +| voip_cannot_answer_initiated_call | | 0x1006 | +| voip_not_initialized | | 0x1007 | +| provisioning_invalid_password | invalid password | 0x1100 | +| provisioning_invalid_request | invalid request | 0x1101 | +| provisioning_no_slots_available | no(more) slots available | 0x1102 | +| provisioning_pool_missing | pool missing | 0x1103 | +| provisioning_pool_unknown | pool unknown | 0x1104 | +| provisioning_unknown_ip_location | unknown ip location(perhaps LAN ip?) | 0x1105 | +| provisioning_internal_tries_exceeded | internal error(tried exceeded) | 0x1106 | +| provisioning_too_many_slots_requested | too many slots requested | 0x1107 | +| provisioning_too_many_reserved | too many reserved | 0x1108 | +| provisioning_could_not_connect | could not connect to provisioning server | 0x1109 | +| provisioning_auth_server_not_connected | authentication server not connected | 0x1110 | +| provisioning_auth_data_too_large | authentication data too large | 0x1111 | +| provisioning_already_initialized | already initialized | 0x1112 | +| provisioning_not_initialized | not initialized | 0x1113 | +| provisioning_connecting | already connecting | 0x1114 | +| provisioning_already_connected | already connected | 0x1115 | +| provisioning_not_connected | | 0x1116 | +| provisioning_io_error | io_error | 0x1117 | +| provisioning_invalid_timeout | | 0x1118 | +| provisioning_ts3server_not_found | | 0x1119 | +| provisioning_no_permission | unknown permissionID | 0x111A | + +--- + +# 3. Permissions + +| Name | Doc | +|------|-----| +| unknown | May occur on error returns with no associated permission | +| b_serverinstance_help_view | Retrieve information about ServerQuery commands | +| b_serverinstance_version_view | Retrieve global server version (including platform and build number) | +| b_serverinstance_info_view | Retrieve global server information | +| b_serverinstance_virtualserver_list | List virtual servers stored in the database | +| b_serverinstance_binding_list | List active IP bindings on multi-homed machines | +| b_serverinstance_permission_list | List permissions available on the server instance | +| b_serverinstance_permission_find | Search permission assignments by name or ID | +| b_virtualserver_create | Create virtual servers | +| b_virtualserver_delete | Delete virtual servers | +| b_virtualserver_start_any | Start any virtual server in the server instance | +| b_virtualserver_stop_any | Stop any virtual server in the server instance | +| b_virtualserver_change_machine_id | Change a virtual servers machine ID | +| b_virtualserver_change_template | Edit virtual server default template values | +| b_serverquery_login | Login to ServerQuery | +| b_serverinstance_textmessage_send | Send text messages to all virtual servers at once | +| b_serverinstance_log_view | Retrieve global server log | +| b_serverinstance_log_add | Write to global server log | +| b_serverinstance_stop | Shutdown the server process | +| b_serverinstance_modify_settings | Edit global settings | +| b_serverinstance_modify_querygroup | Edit global ServerQuery groups | +| b_serverinstance_modify_templates | Edit global template groups | +| b_virtualserver_select | Select a virtual server | +| b_virtualserver_info_view | Retrieve virtual server information | +| b_virtualserver_connectioninfo_view | Retrieve virtual server connection information | +| b_virtualserver_channel_list | List channels on a virtual server | +| b_virtualserver_channel_search | Search for channels on a virtual server | +| b_virtualserver_client_list | List clients online on a virtual server | +| b_virtualserver_client_search | Search for clients online on a virtual server | +| b_virtualserver_client_dblist | List client identities known by the virtual server | +| b_virtualserver_client_dbsearch | Search for client identities known by the virtual server | +| b_virtualserver_client_dbinfo | Retrieve client information | +| b_virtualserver_permission_find | Find permissions | +| b_virtualserver_custom_search | Find custom fields | +| b_virtualserver_start | Start own virtual server | +| b_virtualserver_stop | Stop own virtual server | +| b_virtualserver_token_list | List privilege keys available | +| b_virtualserver_token_add | Create new privilege keys | +| b_virtualserver_token_use | Use a privilege keys to gain access to groups | +| b_virtualserver_token_delete | Delete a privilege key | +| b_virtualserver_log_view | Retrieve virtual server log | +| b_virtualserver_log_add | Write to virtual server log | +| b_virtualserver_join_ignore_password | Join virtual server ignoring its password | +| b_virtualserver_notify_register | Register for server notifications | +| b_virtualserver_notify_unregister | Unregister from server notifications | +| b_virtualserver_snapshot_create | Create server snapshots | +| b_virtualserver_snapshot_deploy | Deploy server snapshots | +| b_virtualserver_permission_reset | Reset the server permission settings to default values | +| b_virtualserver_modify_name | Modify server name | +| b_virtualserver_modify_welcomemessage | Modify welcome message | +| b_virtualserver_modify_maxclients | Modify servers max clients | +| b_virtualserver_modify_reserved_slots | Modify reserved slots | +| b_virtualserver_modify_password | Modify server password | +| b_virtualserver_modify_default_servergroup | Modify default Server Group | +| b_virtualserver_modify_default_channelgroup | Modify default Channel Group | +| b_virtualserver_modify_default_channeladmingroup | Modify default Channel Admin Group | +| b_virtualserver_modify_channel_forced_silence | Modify channel force silence value | +| b_virtualserver_modify_complain | Modify individual complain settings | +| b_virtualserver_modify_antiflood | Modify individual antiflood settings | +| b_virtualserver_modify_ft_settings | Modify file transfer settings | +| b_virtualserver_modify_ft_quotas | Modify file transfer quotas | +| b_virtualserver_modify_hostmessage | Modify individual hostmessage settings | +| b_virtualserver_modify_hostbanner | Modify individual hostbanner settings | +| b_virtualserver_modify_hostbutton | Modify individual hostbutton settings | +| b_virtualserver_modify_port | Modify server port | +| b_virtualserver_modify_autostart | Modify server autostart | +| b_virtualserver_modify_needed_identity_security_level | Modify required identity security level | +| b_virtualserver_modify_priority_speaker_dimm_modificator | Modify priority speaker dimm modificator | +| b_virtualserver_modify_log_settings | Modify log settings | +| b_virtualserver_modify_min_client_version | Modify min client version | +| b_virtualserver_modify_icon_id | Modify server icon | +| b_virtualserver_modify_weblist | Modify web server list reporting settings | +| b_virtualserver_modify_codec_encryption_mode | Modify codec encryption mode | +| b_virtualserver_modify_temporary_passwords | Modify temporary serverpasswords | +| b_virtualserver_modify_temporary_passwords_own | Modify own temporary serverpasswords | +| b_virtualserver_modify_channel_temp_delete_delay_default | Modify default temporary channel delete delay | +| b_virtualserver_modify_nickname | Modify server nicknames | +| b_virtualserver_modify_integrations | Modify integrations | +| i_channel_min_depth | Min channel creation depth in hierarchy | +| i_channel_max_depth | Max channel creation depth in hierarchy | +| b_channel_group_inheritance_end | Stop inheritance of channel group permissions | +| i_channel_permission_modify_power | Modify channel permission power | +| i_channel_needed_permission_modify_power | Needed modify channel permission power | +| b_channel_info_view | Retrieve channel information | +| b_channel_create_child | Create sub-channels | +| b_channel_create_permanent | Create permanent channels | +| b_channel_create_semi_permanent | Create semi-permanent channels | +| b_channel_create_temporary | Create temporary channels | +| b_channel_create_private | Create private channel | +| b_channel_create_with_topic | Create channels with a topic | +| b_channel_create_with_description | Create channels with a description | +| b_channel_create_with_password | Create password protected channels | +| b_channel_create_modify_with_codec_speex8 | Create channels using Speex Narrowband (8 kHz) codecs | +| b_channel_create_modify_with_codec_speex16 | Create channels using Speex Wideband (16 kHz) codecs | +| b_channel_create_modify_with_codec_speex32 | Create channels using Speex Ultra-Wideband (32 kHz) codecs | +| b_channel_create_modify_with_codec_celtmono48 | Create channels using the CELT Mono (48 kHz) codec | +| b_channel_create_modify_with_codec_opusvoice | Create channels using OPUS (voice) codec | +| b_channel_create_modify_with_codec_opusmusic | Create channels using OPUS (music) codec | +| i_channel_create_modify_with_codec_maxquality | Create channels with custom codec quality | +| i_channel_create_modify_with_codec_latency_factor_min | Create channels with minimal custom codec latency factor | +| b_channel_create_with_maxclients | Create channels with custom max clients | +| b_channel_create_with_maxfamilyclients | Create channels with custom max family clients | +| b_channel_create_with_sortorder | Create channels with custom sort order | +| b_channel_create_with_default | Create default channels | +| b_channel_create_with_needed_talk_power | Create channels with needed talk power | +| b_channel_create_modify_with_force_password | Create new channels only with password | +| i_channel_create_modify_with_temp_delete_delay | Max delete delay for temporary channels | +| b_channel_modify_parent | Move channels | +| b_channel_modify_make_default | Make channel default | +| b_channel_modify_make_permanent | Make channel permanent | +| b_channel_modify_make_semi_permanent | Make channel semi-permanent | +| b_channel_modify_make_temporary | Make channel temporary | +| b_channel_modify_name | Modify channel name | +| b_channel_modify_topic | Modify channel topic | +| b_channel_modify_description | Modify channel description | +| b_channel_modify_password | Modify channel password | +| b_channel_modify_codec | Modify channel codec | +| b_channel_modify_codec_quality | Modify channel codec quality | +| b_channel_modify_codec_latency_factor | Modify channel codec latency factor | +| b_channel_modify_maxclients | Modify channels max clients | +| b_channel_modify_maxfamilyclients | Modify channels max family clients | +| b_channel_modify_sortorder | Modify channel sort order | +| b_channel_modify_needed_talk_power | Change needed channel talk power | +| i_channel_modify_power | Channel modify power | +| i_channel_needed_modify_power | Needed channel modify power | +| b_channel_modify_make_codec_encrypted | Make channel codec encrypted | +| b_channel_modify_temp_delete_delay | Modify temporary channel delete delay | +| b_channel_delete_permanent | Delete permanent channels | +| b_channel_delete_semi_permanent | Delete semi-permanent channels | +| b_channel_delete_temporary | Delete temporary channels | +| b_channel_delete_flag_force | Force channel delete | +| i_channel_delete_power | Delete channel power | +| i_channel_needed_delete_power | Needed delete channel power | +| b_channel_join_permanent | Join permanent channels | +| b_channel_join_semi_permanent | Join semi-permanent channels | +| b_channel_join_temporary | Join temporary channels | +| b_channel_join_ignore_password | Join channel ignoring its password | +| b_channel_join_ignore_maxclients | Ignore channels max clients limit | +| i_channel_join_power | Channel join power | +| i_channel_needed_join_power | Needed channel join power | +| i_channel_subscribe_power | Channel subscribe power | +| i_channel_needed_subscribe_power | Needed channel subscribe power | +| i_channel_description_view_power | Channel description view power | +| i_channel_needed_description_view_power | Channel needed description view power | +| i_icon_id | Group icon identifier | +| i_max_icon_filesize | Max icon filesize in bytes | +| b_icon_manage | Enables icon management | +| b_group_is_permanent | Group is permanent | +| i_group_auto_update_type | Group auto-update type | +| i_group_auto_update_max_value | Group auto-update max value | +| i_group_sort_id | Group sort id | +| i_group_show_name_in_tree | Show group name in tree depending on selected mode | +| b_virtualserver_servergroup_list | List server groups | +| b_virtualserver_servergroup_permission_list | List server group permissions | +| b_virtualserver_servergroup_client_list | List clients from a server group | +| b_virtualserver_channelgroup_list | List channel groups | +| b_virtualserver_channelgroup_permission_list | List channel group permissions | +| b_virtualserver_channelgroup_client_list | List clients from a channel group | +| b_virtualserver_client_permission_list | List client permissions | +| b_virtualserver_channel_permission_list | List channel permissions | +| b_virtualserver_channelclient_permission_list | List channel client permissions | +| b_virtualserver_servergroup_create | Create server groups | +| b_virtualserver_channelgroup_create | Create channel groups | +| i_group_modify_power | Group modify power | +| i_group_needed_modify_power | Needed group modify power | +| i_group_member_add_power | Group member add power | +| i_group_needed_member_add_power | Needed group member add power | +| i_group_member_remove_power | Group member delete power | +| i_group_needed_member_remove_power | Needed group member delete power | +| i_permission_modify_power | Permission modify power | +| b_permission_modify_power_ignore | Ignore needed permission modify power | +| b_virtualserver_servergroup_delete | Delete server groups | +| b_virtualserver_channelgroup_delete | Delete channel groups | +| i_client_permission_modify_power | Client permission modify power | +| i_client_needed_permission_modify_power | Needed client permission modify power | +| i_client_max_clones_uid | Max additional connections per client identity | +| i_client_max_idletime | Max idle time in seconds | +| i_client_max_avatar_filesize | Max avatar filesize in bytes | +| i_client_max_channel_subscriptions | Max channel subscriptions | +| b_client_is_priority_speaker | Client is priority speaker | +| b_client_skip_channelgroup_permissions | Ignore channel group permissions | +| b_client_force_push_to_talk | Force Push-To-Talk capture mode | +| b_client_ignore_bans | Ignore bans | +| b_client_ignore_antiflood | Ignore antiflood measurements | +| b_client_issue_client_query_command | Issue query commands from client | +| b_client_use_reserved_slot | Use an reserved slot | +| b_client_use_channel_commander | Use channel commander | +| b_client_request_talker | Allow to request talk power | +| b_client_avatar_delete_other | Allow deletion of avatars from other clients | +| b_client_is_sticky | Client will be sticked to current channel | +| b_client_ignore_sticky | Client ignores sticky flag | +| b_client_info_view | Retrieve client information | +| b_client_permissionoverview_view | Retrieve client permissions overview | +| b_client_permissionoverview_own | Retrieve clients own permissions overview | +| b_client_remoteaddress_view | View client IP address and port | +| i_client_serverquery_view_power | ServerQuery view power | +| i_client_needed_serverquery_view_power | Needed ServerQuery view power | +| b_client_custom_info_view | View custom fields | +| i_client_kick_from_server_power | Client kick power from server | +| i_client_needed_kick_from_server_power | Needed client kick power from server | +| i_client_kick_from_channel_power | Client kick power from channel | +| i_client_needed_kick_from_channel_power | Needed client kick power from channel | +| i_client_ban_power | Client ban power | +| i_client_needed_ban_power | Needed client ban power | +| i_client_move_power | Client move power | +| i_client_needed_move_power | Needed client move power | +| i_client_complain_power | Complain power | +| i_client_needed_complain_power | Needed complain power | +| b_client_complain_list | Show complain list | +| b_client_complain_delete_own | Delete own complains | +| b_client_complain_delete | Delete complains | +| b_client_ban_list | Show banlist | +| b_client_ban_create | Add a ban | +| b_client_ban_delete_own | Delete own bans | +| b_client_ban_delete | Delete bans | +| i_client_ban_max_bantime | Max bantime | +| i_client_private_textmessage_power | Client private message power | +| i_client_needed_private_textmessage_power | Needed client private message power | +| b_client_server_textmessage_send | Send text messages to virtual server | +| b_client_channel_textmessage_send | Send text messages to channel | +| b_client_offline_textmessage_send | Send offline messages to clients | +| i_client_talk_power | Client talk power | +| i_client_needed_talk_power | Needed client talk power | +| i_client_poke_power | Client poke power | +| i_client_needed_poke_power | Needed client poke power | +| b_client_set_flag_talker | Set the talker flag for clients and allow them to speak | +| i_client_whisper_power | Client whisper power | +| i_client_needed_whisper_power | Client needed whisper power | +| b_client_modify_description | Edit a clients description | +| b_client_modify_own_description | Allow client to edit own description | +| b_client_modify_dbproperties | Edit a clients properties in the database | +| b_client_delete_dbproperties | Delete a clients properties in the database | +| b_client_create_modify_serverquery_login | Create or modify own ServerQuery account | +| b_ft_ignore_password | Browse files without channel password | +| b_ft_transfer_list | Retrieve list of running filetransfers | +| i_ft_file_upload_power | File upload power | +| i_ft_needed_file_upload_power | Needed file upload power | +| i_ft_file_download_power | File download power | +| i_ft_needed_file_download_power | Needed file download power | +| i_ft_file_delete_power | File delete power | +| i_ft_needed_file_delete_power | Needed file delete power | +| i_ft_file_rename_power | File rename power | +| i_ft_needed_file_rename_power | Needed file rename power | +| i_ft_file_browse_power | File browse power | +| i_ft_needed_file_browse_power | Needed file browse power | +| i_ft_directory_create_power | Create directory power | +| i_ft_needed_directory_create_power | Needed create directory power | +| i_ft_quota_mb_download_per_client | Download quota per client in MByte | +| i_ft_quota_mb_upload_per_client | Upload quota per client in MByte | + +--- + +# 4. Client Versions + +Format: `version,platform,hash` + +This list contains 1536 known client version entries with their version hashes. Below is a representative sample spanning major releases from 3.0.11 through 5.0.0-alpha: + +| Version | Platform | Hash | +|---------|----------|------| +| 3.0.11 [Build: 1374563791] | Windows | hQCwiLP5f4GIcDG5KQ1T+CNFGqRxyw5MXCHE8KjWRIgkjCuGSryK4vpPy70EURH3blQ8TKrax8BEorHlpnpdAQ== | +| 3.0.11.1 [Build: 1375773286] | Linux | JMTTCSHw+ibyhqCDCWRgby/oJ5uAYHk0/QOwqqI5rNHCKTkb+ce6N+4J38WXAnRmtcEaMb0s30s3ipQBokrqDw== | +| 3.0.11.1 [Build: 1375773286] | OS X | BngQ1112epNzhND5v7uDdbClbP9dSWczXKxvi1iRQo+xWt7WLYKJu/05MrW/CtPVtKwlT4PnbfI0Trvw+HvUCA== | +| 3.0.16 [Build: 1407159763] | Linux | 8776GitHAgkFPfOLxEh5x+Luuh4NrYPEJUdsUzNKndcAuWMYjwQTZkmeZOeG/swdn/p2Cg2pRfZfsIFSOAUWCQ== | +| 3.0.16 [Build: 1407159763] | OS X | vLAH2cYjkF/3sQCgr/zSmtffXcH2flI2vOnUP3uNIDSm8gKO61Q2hOdQaUzXE1yekLSMx2E9RYz+OQjQ868KAw== | +| 3.0.18.2 [Build: 1445516611] | iOS | TEC965pHLJhoiNA2N95xBjQfh2n6uasS3BRFraucFv/+WgAKCKeoUYb3tu6feO5zvTEEiH6YCsedQdhbU1FFCw== | +| 3.0.19.3 [Build: 1466672534] | Windows | a1OYzvM18mrmfUQBUgxYBxYz2DUU6y5k3/mEL6FurzU0y97Bd1FL7+PRpcHyPkg4R+kKAFZ1nhyzbgkGphDWDg== | +| 3.0.19.4 [Build: 1468491418] | Linux | jvhhk75EV3nCGeewx4Y5zZmiZSN07q5ByKZ9Wlmg85aAbnw7c1jKq5/Iq0zY6dfGwCEwuKod0I5lQcVLf2NTCg== | +| 3.0.19.4 [Build: 1468491418] | OS X | Pvcizdk3HRQMzTLt7goUYBmmS5nbAS1g2E6HIypLU+9eXTqGTBLim0UUtKc0s867TFHbK91GroDrTtv0aMUGAw== | +| 3.1 [Build: 1471417187] | Windows | Vr9F7kbVorcrkV5b/Iw+feH9qmDGvfsW8tpa737zhc1fDpK5uaEo6M5l2DzgaGqqOr3GKl5A7PF9Sj6eTM26Aw== | +| 3.1 [Build: 1475158080] | Linux | G0j7r7DswTMF+Fuqroy6/BR+tn02AOy0IZPlg9ZIW6r2m79yudZgrbm1TB4XoUpiFfex3ImdjOQnaFRQPONpBg== | +| 3.1 [Build: 1481641346] | iOS | SDH0QNTA1wDQdfIU0HbcRugD3qkkPHnvlSq/IeW/I4A2myFQnDbzm8ilEGR0vOU4NoTae8CH5XsBmRqwyPIeBA== | +| 3.1.0 [Build: 1481889010] | Android | eH8svg9XpltTbw+UYkQ4ixfqpbEAhwO9nmDDUWuI11swEU3Ye5HKGlFv70LxHZSgYlEqEH/N1J9U4ygptbPIDg== | +| 3.1.7 [Build: 1512665843] | Android | J04O7RCgM3ZlecpZz5H8IgWggyCJQB5KG4/MEEB5/mrW6XJEK4J5IpU3jKztkvy54B8Nrj9tbwMaRujZfILSAg== | +| 3.2.0 [Build: 1530859847] | Android | pjvK4iy+bB5X90mQI/Rzbkes27EokJjSOoGSXCqpjuPFj8Pe6BXt3M2E9VH/1Ec2hf8h51mr3D+cycGQpHq+DA== | +| 3.2.0 [Build: 1533739581] | Linux | Vt+iPp952TU4uKwGXY0L61mXgBNfXg+1+16fnS0snPU9fhkfOKzdPN4rBELOwJ5XzZc33KdVC8rzZGYzlQceBg== | +| 3.2.2 [Build: 1536587534] | iOS | 4rsRo3H9Uw0kui/cQkaBiqYy8ox6/gC6jDUVktcB6I71m1TeqUYy/IYMYbNSBtv0bmKntvcA0ZU79+zoXUkSAg== | +| 3.2.5 [Build: 1555517253] | Linux | +nqAMBv2NxHYfPwHyRmleALMU/2gpiv1LAV6dmrLjNXaTS3BwLBVuysSuqHsuiK3/Xff0IRRFANz8qT1ztJqDQ== | +| 3.3.0 [Build: 1555590310] | OS X | 4K5QbIPYfu42+ytMNgJOvYHB0kY/S+su1vsJ7zuLVlMs+XHbNhJEtjMANjDJAxfJ+fJ77VLBHf1Jo6Q5pSJFBA== | +| 3.3.0 [Build: 1559834030] | Android | Ux59iejFFnEANHPjL4dmwUgXKhvnV7dPqjzAIqYMNs0RoF9RyhsgxEaJO72IgNt7D3yaD+4lGtYfcEFG8WDKCg== | +| 3.3.1 [Build: 1561236585] | Linux | 2WaGpMt2Ky110SIh+byPcwkS+Dn9U2l7VffcJsoq2PNy0ZQ+o+N2i9wR4/7kEgtgB4SHIdoA7W8rQW2LLqUaAA== | +| 5.0.0-alpha206 [Build: 1556530824] | Linux | jIng2diWQpiV/D0tMDJSoA24IB2kB1weMJi16NdXRVKaULISROJHhbZKVZwOvl7Dm2yQFneUXguxzUE5bHWXAA== | +| 5.0.0-alpha206 [Build: 1556530824] | macOS | AaYqqXfOM9YSHTCNw/dVBrLUx8e/Kb+m7WmcRfEOrI+gqxS+EyqINxPQxpohpf7SW3OU2p2ic3BqaR89AFCqDQ== | +| 5.0.0-alpha293 [Build: 1564586764] | Windows | ZT9k6ShVBg3ZF/koi55DJttu1vcI8AmZcULRfN8YhGQa9fEkS9qIpj3gP6HKq7fh9dESvoKksRORq59RiH8xBQ== | + +> **Note**: The complete list contains 1536 entries covering versions from 3.0.11 through 5.0.0-alpha293+ across Windows, Linux, OS X, macOS, Android, and iOS platforms. See the original `Versions.csv` in the [tsdeclarations repository](https://github.com/ReSpeak/tsdeclarations/blob/master/Versions.csv) for the full list. + +--- + +# 5. Badges + +| UID | Name | Description | Filename | Codes | +|-----|------|-------------|----------|-------| +| 4b27be5a-b92a-4b30-8b2d-14b59653f427 | 20th Anniversary | Celebrating 20 Years of TeamSpeak | 20_years | | +| f81ad44d-e931-47d1-a3ef-5fd160217cf8 | 4Netplayers | 4Netplayers customer | 4netplayers | | +| b78a0f3e-8758-4572-b102-42a79b4a0342 | ???? | Reads between the line | hat | | +| 2bf80270-8efe-46dc-a472-3280a0479145 | Alpha Tester | Helped to test our software. THANK YOU! | Alpha | | +| 05114019-6b46-4b13-b5a1-e5179ef69fb5 | April Fools! | Roses are red, gaming is fun, you are carrying too much to be able to run :( | rpg | | +| 1a518885-520c-4f54-9f49-8b1acb674771 | Braindance | I'm chippin' in | Braindance | P4TEKZ80PZ | +| cbf5aafd-2554-4053-80bb-0cf82ec0a430 | Bright Idea | TeamSpeak took my idea on board | FeatureBadge_Lightbulb | | +| d6062d9c-42a3-49c9-91dd-8c43a5a46805 | Bug Catcher | I found a bug! | BugBadge_Splat | | +| dfc70674-0fd0-431e-b3a1-edc32d7b09b2 | Challenge Accepted | Unlocked at SCILL Play — Challenges, tournaments and more! | scill | | +| afed63f4-82f1-4479-ab02-0ef053f55723 | Communities Early Adopter | Thank you for your Support! | communities_early_adopter | | +| 54be472d-3163-4076-9059-7f46128d937e | Communities Purchase | Purchased a TeamSpeak Community | communities_purchase | | +| f85f7e21-753a-4566-b26a-4e3e9155d2ef | Cyberpunk | We have a city to burn | Cyberpunk | | +| c028298c-84ff-4e22-be4e-b8c17552b4bb | Digi | Digi joined your channel #DIGWIN | digi | | +| 56df5ce2-6c5a-4a24-90e2-29e497e26170 | Drone Champions League | I follow the Drone Champions League | DCL_Badge | DRONECHAMP | +| 935e5a2a-954a-44ca-aa7a-55c79285b601 | E3 2018 - Winner | Discovered at E3 2018 | E3-2018 | | +| 61723e54-3da2-4f19-a33f-fcdc8ef5eaa0 | Father's Day 2022 | Not all heroes wear capes | fathersday2022 | | +| b9c7d6ad-5b99-40fb-988c-1d02ab6cc130 | Found Tim Speak | Found Tim Speak at Gamescom 2018 | met_tim | XJN4WJZEJN | +| 809bdd5a-2601-4152-82ff-a21d23d8fd46 | G2 Esports | Aged 20 years being a G2 fan | G2_Esports | | +| 62444179-0d99-42ba-a45c-c6b1557d079a | Gamescom 2014 | Registered at Gamescom 2014 | gamescom_2014 | | +| 50bbdbc8-0f2a-46eb-9808-602225b49627 | Gamescom 2016 | Registered during Gamescom 2016 | gamescom_2016 | | +| 534c9582-ab02-4267-aec6-2d94361daa2a | Gamescom 2017 | Visited TeamSpeak at Gamescom 2017 | gamescom_2017 | DK9JGRJH1Q | +| 4eef1ecf-a0ea-423d-bfd0-496543a00305 | Gamescom 2018 | Visited TeamSpeak at Gamescom 2018 | gamescom_2018 | 8CXB49KPJ4 | +| b82a45a5-b235-4926-be77-de102222e5eb | Gamescom 2019 | Visited TeamSpeak at Gamescom 2019 | Gamescom19 | PNKCB76VZ8 | +| 34dbfa8f-bd27-494c-aa08-a312fc0bb240 | Gamescom Hero 2017 | Gaming Hero at Gamescom 2017 | hero_2017 | | +| 24512806-f886-4440-b579-9e26e4219ef6 | Gamescom Hero 2018 | Gamescom Exclusive Gaming Hero 2018 | gamescom_2018_played | BJCFQBU53C | +| d49fd07e-99fb-41de-8d7b-c98064713171 | GommeHD.net | Your #1 Minecraft Network for over 10 years | GMHD | | +| c565972a-3912-457b-826f-84820c1ba6ca | Halloween 2021 | Happy Halloween 2021 | halloween21 | | +| 133595e7-950f-4ef2-b113-f91a68b5770d | Halloween 2021 Special | Earned by participating in our Halloween 2021 special stream | halloween21_special | | +| fb154277-5fe7-428a-85a4-43c0bdcdda3d | Halloween 2022 | Spooky_Scary_Skeletons.mp4 | halloween22 | | +| e6679ce2-d458-493c-8ffb-5660e47ac99f | Happy Hanami | Enjoy the view | hanami2023 | | +| de7bd960-eb02-47e1-9ce2-a44f6e255d8f | Happy Holidays 2019 | Happy holidays from everyone at TeamSpeak! | Happy_Holidays | | +| d4ea0251-ba46-4c1a-83b7-59db3f89e52c | Happy New Year 2021 | Survived the great toilet paper crisis of 2020 | firework_2020 | | +| 1519e001-06a0-458c-9195-a8a6d0ec87fc | Happy New Year 2023 | Aw man, here we go again | 2023_NewYear | | +| 834d4cc1-cd80-48d6-96c4-23d131d78649 | Happy Summer 2023 | heat death of the universe | happy_summer_2023 | | +| c68bcc52-7aeb-4868-b4d2-e7b20716f9ba | Heatwave 2022 | I'm melting... help | summer_icecream | | +| 94242c4e-6742-4540-8b66-ce951ed57159 | Helping Hand | pushed some buttons *beep* *bop* ~ thanks! | homebase | | +| 288a56c6-4da3-48de-9c9f-bd9eede5d832 | Immortal Roleplay | This is your life. | Immortal_Roleplay | | +| 69bfffc8-e9c0-4f70-8a37-47cb8c73fb1d | International Peace Day | United we stand, divided we fall | peaceday2022 | | +| 9ea23c77-8755-4d82-b30c-92f4aac109ef | International Women's Day 2021 | To all the mums, sisters, aunties, nieces and beyond, Happy Women's Day! | wft | | +| 7d9fa2b1-b6fa-47ad-9838-c239a4ddd116 | MIFCOM | MIFCOM | Entered Performance | mifcom | +| ed85bdff-2a2b-4bea-a1a5-4d06fcc0d776 | Merry Christmas 2019 | It's the most wonderful 'Tim' of the Year | Christmas | | +| c6480fe2-ee25-4ee8-9853-243652c8ec54 | Merry Christmas 2020 | Let it snow, let it snow, let it snow! | Christmas2020 | | +| 0581aa0f-8c2d-4681-bb9f-8492fec49977 | Merry Christmas 2021 | Look what Santa's left under the server tree! | christmas2021 | | +| d4875b30-9908-43cb-a1eb-1a958e226078 | Merry Christmas 2022 | There's snow place like home | christmas2022 | | +| 87ccf9ea-67c9-45e5-adbc-77e210e6128a | Met Tim | Met Tim Speak IRL | tim_irl | | +| 0d98391c-ecdf-4f26-931a-49bfd669cda7 | Mind Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_MindEgg | | +| 2fdda3c6-20e0-48f1-9c12-f39239a2ed02 | Mother's Day 2022 | Thanks for bearing with us | rose | | +| c3f823eb-5d5c-40f9-9dbd-3437d59a539d | Official TeamSpeak Gamer | New myTeamSpeak member | TS-2018 | | +| 8dfa37ac-b40d-4466-b393-ff2184a9adf3 | Overwatch League | I follow the Overwatch League | OWL_Badge | | +| 4ce435d1-6ac5-4530-b81d-6d14ddaaa1ac | PGL Antwerp 2022 | Watched the PGL CS:GO Major | PGLant | | +| fa3ece28-64df-431f-b1b3-90844bfdd2d9 | Paris Games Week 2014 | Registered at Paris Games Week 2014 | paris_gamesweek_2014 | | +| d95f9901-c42d-4bac-8849-7164fd9e2310 | Paris Games Week 2016 | Registered during Paris Games Week 2016 | paris_gamesweek_2016 | | +| 0005232e-538e-4cb2-93b6-d7d83e873829 | PietSmiet | Werde Snob auf PietSmiet.de ;) | PietSmiet | | +| be932556-dfa9-4dc6-afd0-98de0ab25777 | PolTeamgeist | WooOOHoohOOHooo | PolTeamgeist | | +| 5f6d49e4-35c8-4809-8c81-6e71f7f749e9 | Power Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_PowerEgg | | +| ceee2445-4fbf-4f06-9421-286f0f4e875a | Pride | Never be afraid to show your colors. | pride | | +| 1aa375e8-7207-45bf-8b80-556bafafc834 | Reality Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_RealityEgg | | +| f22c22f1-8e2d-4d99-8de9-f352dc26ac5b | Rocket Beans TV | Rocket Beans TV Community | rbtv | RWGE2NURJZ | +| 2c9698c1-1fec-4baa-a28f-4845f045f42f | Soul Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_SoulEgg | | +| 641a4d85-2351-482c-97a1-02fc3b6abbb5 | Space Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_SpaceEgg | | +| 63261116-4359-4842-873e-56820afbe068 | SpartaTheOriginal | Olaf Toast @ twitch.tv/SpartaTheOriginal | Toast | | +| ef567ec5-f46e-4520-be07-6021023cf6bd | Sponsorship License | Sponsored by TeamSpeak | Sponsorship | | +| 7a627d47-5496-4d68-83b5-2c4eafff9b30 | Stay Home, Stay Safe | Playing Apart, Staying Connected | StaySafeStayHome | | +| 7262a528-c7df-4369-bc2c-d34bf5853d7b | TS Chat Alpha Tester | Helped us test our new mobile app, thanks! | slim_golden | | +| 6eee759e-b1e9-4937-b023-07fc778532a2 | TS Gameday Participant | At least i tried... | silvered | | +| e1447b99-53b0-448a-98b7-ee7bad8bd268 | TS Gameday Winner | As shiny as the golden frying pan | goldenjoystick | | +| 1cb07348-34a4-4741-b50f-c41e584370f7 | TeamSpeak Addon Author | Creator of TeamSpeak Addons | addon_author | | +| 450f81c1-ab41-4211-a338-222fa94ed157 | TeamSpeak Addon Developer (Bronze) | Creator of at least 1 TeamSpeak Addon | addon_author_bronze | | +| 94ec66de-5940-4e38-b002-970df0cf6c94 | TeamSpeak Addon Developer (Gold) | Creator of at least 5 TeamSpeak Addons | addon_author_gold | | +| c9e97536-5a2d-4c8e-a135-af404587a472 | TeamSpeak Addon Developer (Silver) | Creator of at least 3 TeamSpeak Addons | addon_author_silver | | +| 9cd152a7-bf65-4ece-aeba-62d27678f79a | TeamSpeak Competition Winner Badge | TeamSpeak Competition Winner | CompWinnerBadge | | +| 64221fd1-706c-4bb2-ba55-996c39effa79 | TeamSpeak Jedi | myTeamSpeak early adopter | TS-OG | | +| 6b187e83-873b-46b0-b2c2-a31af15e76a4 | TeamSpeak Merch Badge | TeamSpeak Merch Owner - 1st Edition | cap_red | | +| 22b9ec39-7694-453e-864c-dfc7b1b0d7c7 | TeamSpeak Merch Badge 2.0 | TeamSpeak Merch Owner - 2nd Edition | topper | | +| 205916f3-a953-4754-8905-bc15069b1f91 | TeamSpeak Merch Badge 3.0 | TeamSpeak Merch Owner — 3rd Edition | Merch3 | | +| 8d843dfa-c51a-407f-87b3-94cfc8f03e96 | TeamSpeak Staff | Official Staff Member | teamspeak_staff | | +| c2368518-3728-4260-bcd1-8b85e9f8984c | Test | Testing, Testing. | Testing | | +| 4086a249-a503-4f31-9e83-8a0a8e3089bd | Tim-o'-Lantern | Mwuhaahaahaahaahaa | Tim-O-Lantern | JQGCTAQWHT | +| 089c7295-3aa2-48b0-b2f1-2dd1bec12caf | Time Egg | Found in the TeamSpeak 2020 Easter Egg Hunt | E_TimeEgg | | +| 904e232c-f369-44db-87f7-5142e15620cc | Time Machine | Worked like a machine to update addons in super-quick time. | time_machine | | +| 4c61af66-22ef-4897-b0bb-25fcef2acf60 | Undead Nightmare | I'm the last of my kind | undead_nightmare | | +| b0a36aea-3e46-4e83-a455-6e92ae1b9d94 | Undead Nightmare | I'm the last of my kind | undead_nightmare | | +| 0cd924ed-c5ea-459e-b60a-4f1bc0b65f07 | Up, Up and Away! | Find me on Mount Chiliad | up,_up_and_away! | | +| 4b0fd4f5-d456-4294-973d-853a1db5c7d8 | Valentim's Day 2019 | Valentim's Day 2019 | Valentines_Badge | | +| 92801833-e721-4b7e-84d4-6c02dbb332b9 | Valentim's Day 2020 | Valentim's Day 2020 | Valentim2020 | | +| 958f904b-8260-48a4-a961-f786cbd39411 | Valentine's Day 2023 | Love you like my Tamagotchi | ValentinesDay23 | | +| a676c708-da67-4784-ba7f-3fb7e8d2e865 | Valentines Day 2021 | Roses are red, TS is blue, Servers are Sweet and so are you. | valentine21 | | +| c54a9f92-07f7-4214-90f3-eafeea8005da | World Backup Day | Don't be an April Fool. Back up your data! | backupday_2023 | | +| 448a6d13-4e08-46a1-aafa-b4ff6d6c2d06 | World Bonsai Day | harmony, balance, patience | bonsai_day | | +| 0f976a27-ddf5-447c-b79c-0644a8e8a297 | Year of the Dragon 2024 | Arise, Shenron! | year_of_the_dragon_2024 | | +| 8c22fe26-30ac-4231-8b31-67d8a75c808a | Year of the Ox 2021 | Only listen to the fortune cookie; disregard all other fortune telling units. | ox21 | | +| 970c70e6-00a1-41c1-ac5c-81c89a06c7a6 | Year of the Rabbit 2023 | Do a barrel roll! | chineseNY2023 | | +| 92356386-0451-4a97-87d9-10ff4f43260c | Year of the Tiger 2022 | Rocky sends his regards | tiger | | + +--- + +# 6. Enums + +## PermissionType +| Variant | Doc | +|---------|-----| +| ServerGroup | Server group permission. (id1: ServerGroupId, id2: 0) | +| GlobalClient | Client specific permission. (id1: ClientDbId, id2: 0) | +| Channel | Channel specific permission. (id1: ChannelId, id2: 0) | +| ChannelGroup | Channel group permission. (id1: ChannelId, id2: ChannelGroupId) | +| ChannelClient | Channel-client specific permission. (id1: ChannelId, id2: ClientDbId) | + +## TextMessageTargetMode +| Variant | Doc | +|---------|-----| +| Unknown | Maybe to all servers? | +| Client | Send to specific client | +| Channel | Send to current channel | +| Server | Send to server chat | + +## HostMessageMode +| Variant | Doc | +|---------|-----| +| None | Dont display anything | +| Log | Display message inside log | +| Modal | Display message inside a modal dialog | +| Modalquit | Display message inside a modal dialog and quit/close server/connection | + +## HostBannerMode +| Variant | Doc | +|---------|-----| +| NoAdjust | Do not adjust | +| AdjustIgnoreAspect | Adjust and ignore aspect ratio | +| AdjustKeepAspect | Adjust and keep aspect ratio | + +## Codec +| Variant | Doc | +|---------|-----| +| SpeexNarrowband | Mono, 16bit, 8kHz, bitrate dependent on the quality setting | +| SpeexWideband | Mono, 16bit, 16kHz, bitrate dependent on the quality setting | +| SpeexUltrawideband | Mono, 16bit, 32kHz, bitrate dependent on the quality setting | +| CeltMono | Mono, 16bit, 48kHz, bitrate dependent on the quality setting | +| OpusVoice | Mono, 16bit, 48kHz, bitrate dependent on the quality setting, optimized for voice | +| OpusMusic | Stereo, 16bit, 48kHz, bitrate dependent on the quality setting, optimized for music | + +## CodecEncryptionMode +| Variant | Doc | +|---------|-----| +| PerChannel | Voice encryption is configured per channel | +| ForcedOff | Voice encryption is globally off | +| ForcedOn | Voice encryption is globally on | + +## Reason +| Variant | Doc | +|---------|-----| +| None | No reason data | +| Moved | Has invoker | +| Subscription | No reason data | +| LostConnection | Timeout | +| KickChannel | Has invoker | +| KickServer | Has invoker | +| KickServerBan | Has invoker, bantime | +| Serverstop | | +| Clientdisconnect | | +| Channelupdate | No reason data | +| Channeledit | Has invoker | +| ClientdisconnectServerShutdown | | + +## GroupNamingMode +| Variant | Doc | +|---------|-----| +| None | No group name is displayed. | +| Before | Group name is displayed before the client name. | +| After | Group name is displayed after the client name. | + +## GroupType +| Variant | Doc | +|---------|-----| +| Template | Template group (used for new virtual servers). | +| Regular | Regular group (used for regular clients). | +| Query | Global query group (used for server query clients). | + +## LicenseType +| Variant | Doc | +|---------|-----| +| NoLicense | No licence | +| Offline | Offline/LAN license | +| Sdk | TeamSpeak SDK license | +| SdkOffline | TeamSpeak SDK offline license | +| Npl | Non-Profit License (NPL) | +| Athp | Authorised TeamSpeak Host Provider License (ATHP) | +| Aal | Annual activation license (AAL) | +| Default | Default license with 32 slots | +| Gamer | Gamer license | +| Sponsorship | Licenses sponsored by TeamSpeak | +| Commercial | For use inside corporates | + +## ChannelType +| Variant | Doc | +|---------|-----| +| Permanent | Normal channel | +| SemiPermanent | Deleted when the server restarts | +| Temporary | Deleted when empty | + +## TokenType +| Variant | Doc | +|---------|-----| +| ServerGroup | Server group token (`id1={groupId}, id2=0`) | +| ChannelGroup | Channel group token (`id1={groupId}, id2={channelId}`) | + +## PluginTargetMode +| Variant | Doc | +|---------|-----| +| CurrentChannel | Send to all clients in the current channel. | +| Server | Send to all clients on the server. | +| Client | Send to all given clients ids. | +| CurrentChannelSubsribedClients | Send to all given clients which are subscribed to the current channel (i.e. which see the this client). | + +## LogLevel +| Variant | Value | Doc | +|---------|-------|-----| +| Error | 1 | Everything that is really bad. | +| Warning | | Everything that might be bad. | +| Debug | | Output that might help find a problem. | +| Info | | Informational output. | + +## ChannelPermissionHint (Bitflag) +| Variant | Value | Doc | +|---------|-------|-----| +| Join | 1 | b_channel_join_* | +| Modify | 2 | i_channel_modify_power | +| ForceDelete | 4 | b_channel_delete_flag_force | +| Delete | 8 | b_channel_delete_* | +| Subscribe | 16 | i_channel_subscribe_power | +| ViewDescription | 32 | i_channel_description_view_power | +| FileUpload | 64 | i_ft_file_upload_power | +| FileDownload | 128 | i_ft_needed_file_download_power | +| FileDelete | 256 | i_ft_file_delete_power | +| FileRename | 512 | i_ft_file_rename_power | +| FileBrowse | 1024 | i_ft_file_browse_power | +| FileDirectoryCreate | 2048 | i_ft_directory_create_power | +| ModifyPermissions | 4096 | i_channel_permission_modify_power | + +## ClientPermissionHint (Bitflag) +| Variant | Value | Doc | +|---------|-------|-----| +| KickServer | 1 | i_client_kick_from_server_power | +| KickChannel | 2 | i_client_kick_from_channel_power | +| Ban | 4 | i_client_ban_power | +| MoveClient | 8 | i_client_move_power | +| PrivateMessage | 16 | i_client_private_textmessage_power | +| Poke | 32 | i_client_poke_power | +| Whisper | 64 | i_client_whisper_power | +| Complain | 128 | i_client_complain_power | +| ModifyPermissions | 256 | i_client_permission_modify_power | + +--- + +# 7. Book (State Tracking) Definitions + +The Book defines structures for keeping track of all things which happen on a server. + +## ServerGroup +- **Doc**: Get in notifyservergrouplist +- **ID**: ServerGroup.Id + +| Property | Type | Doc | +|----------|------|-----| +| Id | ServerGroupId | | +| Name | str | | +| GroupType | GroupType | | +| Icon | IconId | | +| IsPermanent | bool | If the group is saved to the server database | +| SortId | i32 | | +| NamingMode | GroupNamingMode | | +| NeededModifyPower | i32 | | +| NeededMemberAddPower | i32 | | +| NeededMemberRemovePower | i32 | (optional) | + +## ChannelGroup +- **Doc**: Get in notifychannelgrouplist +- **ID**: ChannelGroup.Id + +| Property | Type | Doc | +|----------|------|-----| +| Id | ChannelGroupId | | +| Name | str | | +| GroupType | GroupType | | +| Icon | IconId | | +| IsPermanent | bool | If the group is saved to the server database | +| SortId | i32 | | +| NamingMode | GroupNamingMode | | +| NeededModifyPower | i32 | | +| NeededMemberAddPower | i32 | | +| NeededMemberRemovePower | i32 | (optional) | + +## OptionalChannelData +- **Doc**: Get in notifychanneledited by channelgetdescription +- **ID**: Channel.Id +- **Optional**: Yes + +| Property | Type | +|----------|------| +| Description | str | + +## Channel +- **Doc**: Get in channellist +- **ID**: Channel.Id + +| Property | Type | Doc | +|----------|------|-----| +| Id | ChannelId | | +| Guid | str | (optional) | +| Parent | ChannelId | 0 means root channel | +| Name | str | | +| Topic | str | (optional) | +| Codec | Codec | | +| CodecQuality | u8 | (optional) | +| MaxClients | MaxClients | (optional) The maximum number of clients in the channel. | +| MaxFamilyClients | MaxClients | (optional) Maximum number of clients in this and all child channels. | +| Order | ChannelId | The preceding channel id. | +| ChannelType | ChannelType | | +| IsDefault | bool | (optional) Whether it is the default channel | +| HasPassword | bool | (optional) Whether this channel has a password | +| CodecLatencyFactor | i32 | (optional) | +| IsUnencrypted | bool | (optional) | +| DeleteDelay | Duration | (optional) | +| NeededTalkPower | i32 | (optional) | +| ForcedSilence | bool | | +| PhoneticName | str | (optional) | +| Icon | IconId | (optional) | +| IsPrivate | bool | (optional) | +| StorageQuota | u32 | (optional) | +| Subscribed | bool | | +| PermissionHints | ChannelPermissionHint | (optional) | +| OptionalData | OptionalChannelData | (optional) | + +## OptionalClientData +- **Doc**: Get in notifyclientupdated by clientgetvariables +- **ID**: Client.Id +- **Optional**: Yes + +| Property | Type | +|----------|------| +| Version | str | +| VersionSign | str | (optional) | +| Platform | str | +| LoginName | str | (optional) Set only for server queries | +| Created | DateTime | +| LastConnected | DateTime | +| ConnectionsTotal | u32 | +| BytesUploadedMonth | u64 | +| BytesDownloadedMonth | u64 | +| BytesUploadedTotal | u64 | +| BytesDownloadedTotal | u64 | + +## ConnectionClientData +- **Doc**: Get in notifyconnectioninfo by getconnectioninfo +- **ID**: Client.Id +- **Optional**: Yes + +| Property | Type | Doc | +|----------|------|-----| +| Ping | Duration | (optional) | +| PingDeviation | Duration | (optional) | +| ConnectedTime | Duration | (optional) | +| ClientAddress | SocketAddr | (optional) Only available if we have the permission to view it | +| PacketsSentSpeech | u64 | (optional) | +| PacketsSentKeepalive | u64 | (optional) | +| PacketsSentControl | u64 | (optional) | +| BytesSentSpeech | u64 | (optional) | +| BytesSentKeepalive | u64 | (optional) | +| BytesSentControl | u64 | (optional) | +| PacketsReceivedSpeech | u64 | (optional) | +| PacketsReceivedKeepalive | u64 | (optional) | +| PacketsReceivedControl | u64 | (optional) | +| BytesReceivedSpeech | u64 | (optional) | +| BytesReceivedKeepalive | u64 | (optional) | +| BytesReceivedControl | u64 | (optional) | +| ServerToClientPacketlossSpeech | f32 | (optional) | +| ServerToClientPacketlossKeepalive | f32 | (optional) | +| ServerToClientPacketlossControl | f32 | (optional) | +| ServerToClientPacketlossTotal | f32 | (optional) | +| ClientToServerPacketlossSpeech | f32 | | +| ClientToServerPacketlossKeepalive | f32 | | +| ClientToServerPacketlossControl | f32 | | +| ClientToServerPacketlossTotal | f32 | | +| BandwidthSentLastSecondSpeech | u64 | (optional) | +| BandwidthSentLastSecondKeepalive | u64 | (optional) | +| BandwidthSentLastSecondControl | u64 | (optional) | +| BandwidthSentLastMinuteSpeech | u64 | (optional) | +| BandwidthSentLastMinuteKeepalive | u64 | (optional) | +| BandwidthSentLastMinuteControl | u64 | (optional) | +| BandwidthReceivedLastSecondSpeech | u64 | (optional) | +| BandwidthReceivedLastSecondKeepalive | u64 | (optional) | +| BandwidthReceivedLastSecondControl | u64 | (optional) | +| BandwidthReceivedLastMinuteSpeech | u64 | (optional) | +| BandwidthReceivedLastMinuteKeepalive | u64 | (optional) | +| BandwidthReceivedLastMinuteControl | u64 | (optional) | +| FiletransferBandwidthSent | u64 | (optional) | +| FiletransferBandwidthReceived | u64 | (optional) | +| IdleTime | Duration | | + +## Client +- **Doc**: Get in notifycliententerview +- **ID**: Client.Id + +| Property | Type | Doc | +|----------|------|-----| +| Id | ClientId | | +| Channel | ChannelId | | +| Uid | Uid | (optional) Unique Identifier | +| Name | str | | +| InputMuted | bool | `true` if muted, `false` otherwise | +| OutputMuted | bool | `true` if muted, `false` otherwise | +| OutputOnlyMuted | bool | `true` if muted, `false` otherwise | +| InputHardwareEnabled | bool | `true` if enabled, `false` if disabled | +| OutputHardwareEnabled | bool | `true` if enabled, `false` if disabled | +| TalkPowerGranted | bool | If the client is granted talk power | +| Metadata | str | Set by client | +| IsRecording | bool | Whether the client is recording | +| DatabaseId | ClientDbId | | +| ChannelGroup | ChannelGroupId | | +| ServerGroups | ServerGroupId | (set) | +| AwayMessage | str | (optional) Contains the away message if the client is away | +| ClientType | ClientType | If this client is a server query or not | +| AvatarHash | str | MD5 hash of the avatar, used to retrieve the avatar | +| TalkPower | i32 | | +| TalkPowerRequest | TalkPowerRequest | (optional) Contains a message and timestamp from the client if he requests talk power | +| Description | str | | +| IsPrioritySpeaker | bool | | +| UnreadMessages | u32 | | +| PhoneticName | str | | +| NeededServerqueryViewPower | i32 | | +| Icon | IconId | | +| IsChannelCommander | bool | | +| CountryCode | str | Like US, DE | +| InheritedChannelGroupFromChannel | ChannelId | | +| Badges | str | | +| UserTag | str | (optional) | +| PermissionHints | ClientPermissionHint | (optional) | +| OptionalData | OptionalClientData | (optional) | +| ConnectionData | ConnectionClientData | (optional) | + +## OptionalServerData +- **Doc**: Get by notifyserverupdated after requested by servergetvariables +- **Optional**: Yes + +| Property | Type | Doc | +|----------|------|-----| +| Uptime | Duration | | +| HasPassword | bool | | +| DefaultChannelAdminGroup | ChannelGroupId | The channel group which will be given to channel creators | +| MaxDownloadBandwidthTotal | u64 | | +| MaxUploadBandwidthTotal | u64 | | +| ComplainAutobanCount | u32 | | +| ComplainAutobanTime | Duration | | +| ComplainRemoveTime | Duration | | +| MinClientsInChannelBeforeForcedSilence | u32 | How many clients can be in a server before silence is forced | +| AntifloodPointsTickReduce | u32 | | +| AntifloodPointsToCommandBlock | u32 | | +| AntifloodPointsToIpBlock | u32 | | +| AntifloodPointsToPluginBlock | u32 | | +| ConnectionCountTotal | u64 | The amount of connections on this server. | +| ChannelCount | u64 | The amount of channels on the server | +| ClientCount | u16 | The amount of clients which are online on the server | +| QueryCountTotal | u64 | Amount of server queries connected to the server | +| QueryCount | u32 | Amount of server queries connected and online/visible on the server | +| DownloadQuota | u64 | | +| UploadQuota | u64 | | +| BytesDownloadedMonth | u64 | | +| BytesUploadedMonth | u64 | | +| BytesDownloadedTotal | u64 | | +| BytesUploadedTotal | u64 | | +| Port | u16 | | +| Autostart | bool | | +| MachineId | str | | +| NeededIdentitySecurityLevel | u8 | | +| LogClient | bool | | +| LogQuery | bool | | +| LogChannel | bool | | +| LogPermissions | bool | | +| LogServer | bool | | +| LogFiletransfer | bool | | +| MinClientVersion | DateTime | | +| ReservedSlots | u16 | | +| TotalPacketlossSpeech | f32 | | +| TotalPacketlossKeepalive | f32 | | +| TotalPacketlossControl | f32 | | +| TotalPacketloss | f32 | | +| TotalPing | Duration | | +| WeblistEnabled | bool | | +| MinAndroidVersion | DateTime | | +| MinIosVersion | DateTime | | + +## ConnectionServerData +- **Doc**: Get by notifyserverconnectioninfo after serverrequestconnectioninfo +- **Optional**: Yes + +| Property | Type | +|----------|------| +| FiletransferBandwidthSent | u64 | +| FiletransferBandwidthReceived | u64 | +| FiletransferBytesSentTotal | u64 | +| FiletransferBytesReceivedTotal | u64 | +| PacketsSentTotal | u64 | +| BytesSentTotal | u64 | +| PacketsReceivedTotal | u64 | +| BytesReceivedTotal | u64 | +| BandwidthSentLastSecondTotal | u64 | +| BandwidthSentLastMinuteTotal | u64 | +| BandwidthReceivedLastSecondTotal | u64 | +| BandwidthReceivedLastMinuteTotal | u64 | +| ConnectedTimeTotal | Duration | +| PacketlossTotal | f32 | +| Ping | Duration | + +## Server +- **Doc**: Get in initserver + +| Property | Type | Doc | +|----------|------|-----| +| PublicKey | EccKeyPubP256 | | +| Id | u64 | The virtual server id | +| Name | str | | +| Nickname | str | (optional) | +| WelcomeMessage | str | Welcome message when connecting to a server | +| Platform | str | | +| Version | str | | +| MaxClients | u16 | The maximum number of clients on the server | +| Created | DateTime | Seems to be always 0 | +| CodecEncryptionMode | CodecEncryptionMode | | +| Hostmessage | str | | +| HostmessageMode | HostMessageMode | | +| DefaultServerGroup | ServerGroupId | | +| DefaultChannelGroup | ChannelGroupId | | +| HostbannerUrl | str | | +| HostbannerGfxUrl | str | | +| HostbannerGfxInterval | Duration | How often the hostbanner should be updated | +| PrioritySpeakerDimmModificator | f32 | | +| HostbuttonTooltip | str | | +| HostbuttonUrl | str | | +| HostbuttonGfxUrl | str | | +| PhoneticName | str | | +| Icon | IconId | Should be an u32, sometimes the server sends an u64 or an i32 for reasons which has to be cut to 32 bit | +| Ips | IpAddr | (array) A list of listen ips, can be empty | +| AskForPrivilegekey | bool | | +| HostbannerMode | HostBannerMode | | +| TempChannelDefaultDeleteDelay | Duration | | +| ProtocolVersion | u16 | | +| License | LicenseType | | +| AdministrativeDomain | str | (optional) | +| OptionalData | OptionalServerData | (optional) | +| ConnectionData | ConnectionServerData | (optional) | + +## Connection +- **Doc**: A connection from our client to a server + +| Property | Type | Doc | +|----------|------|-----| +| OwnClient | ClientId | The id of our own client on the server | +| Server | Server | The server of this connection | +| Clients | Client | (map, key=ClientId) All clients which are visible for us | +| Channels | Channel | (map, key=ChannelId) All channels on the server | +| ServerGroups | ServerGroup | (map, key=ServerGroupId) All server groups on the server | +| ChannelGroups | ChannelGroup | (map, key=ChannelGroupId) All channel groups on the server | + +--- + +# 8. Packet Definitions + +Formal packet structure definitions from `Packets.txt`: + +## Header +``` +Packet + Header + mac [u8; 8] // EAX Message Authentication Code + p_id u16 // Packet id + ?c_id u16 // Client id (only from_client) + flags - // 0x80 Unencrypted, 0x40 Compressed, 0x20 Newprotocol, 0x10 Fragmented + p_type u8 // Packet type (lower nibble) + flags (upper nibble) +``` + +## Packet Types +- 0x0 Voice +- 0x1 Voice whisper +- 0x2 Command +- 0x3 Command low +- 0x4 Ping +- 0x5 Pong +- 0x6 Ack +- 0x7 Ack low +- 0x8 Init + +## C2SInit +``` +C2SInit + Init0 + version u32 // Teamspeak version as timestamp + - u8 0 // Init packet step number + timestamp u32 // Current timestamp + random0 [u8; 4] + - [u8; 8] [0; 8] // Reserved + + Init2 + version u32 + - u8 2 + random1 [u8; 16] + random0_r [u8; 4] + + Init4 + version u32 + - u8 4 + x [u8; 64] + n [u8; 64] + level u32 + random2 [u8; 100] + y [u8; 64] // y = x ^ (2 ^ level) % n + command Command // Must be "clientinitiv" with alpha and omega args +``` + +## S2CInit +``` +S2CInit + Init1 + - u8 1 + random1 [u8; 16] + random0_r [u8; 4] // Reversed random0 + + Init3 + - u8 3 + x [u8; 64] + n [u8; 64] + level u32 + random2 [u8; 100] + + Init127 + - u8 127 + - u8 0 +``` + +## Voice Packets +``` +VoiceC2S + id u16 + codec_type u8 + voice_data Vec + +VoiceS2C + id u16 + from_id u16 // The id of the talking client + codec_type u8 + voice_data Vec +``` + +## VoiceWhisper Packets +``` +VoiceWhisperC2S (legacy, !newprotocol) + id u16 + codec_type u8 + channel_count u8 + client_count u8 + data Vec // [u64; channel_count], [u16; client_count], voice_data + +VoiceWhisperNewC2S (newprotocol) + id u16 + codec_type u8 + whisper_type u8 + whisper_target u8 + target_id u64 // The targeted channel or group id (or 0 if not applicable) + voice_data Vec + +VoiceWhisperS2C + id u16 + from_id u16 // The id of the talking client + codec_type u8 + voice_data Vec +``` + +## Command/Ack Packets +``` +Command Command // PacketType::Command +CommandLow Command // PacketType::CommandLow +Ping // PacketType::Ping (empty) +Pong u16 // PacketType::Pong (acknowledged packet id) +Ack u16 // PacketType::Ack (acknowledged packet id) +AckLow u16 // PacketType::AckLow (acknowledged packet id) +``` + +--- + +# 9. tsdeclarations README + +This repository contains all kind of data which is related to TeamSpeak. This data is used for code generation in various projects, therefore all the data is machine readable. + +**Files**: +- `Errors.csv`: The error codes of TeamSpeak +- `Permissions.csv`: The permissions in TeamSpeak +- `Messages.toml`: Commands, sent over TeamSpeak connections +- `Book.toml`: Declarations for keeping track of all things which happen on a server +- `Enums.toml`: Various enums used in commands +- `MessagesToBook.toml`: Mappings from commands to book structs that allow to automatically update the tracked state +- `BookToMessages.toml`: Functions that can be called on book structs and generate commands +- `Versions.csv`: A bunch of client versions where the versionHash is known +- `Badges.csv`: List of known badges +- `ts3protocol.md`: The low level TeamSpeak protocol description + +**License**: Apache License, Version 2.0 OR MIT license + +--- + +# 10. tsclientlib Architecture & API + +TsClientlib is a library that enables you to write voip clients and bots using the TeamSpeak protocol. + +## Dependencies +- Rust (preferred installation method is rustup) +- OpenSSL 1.1 (linux only) + +## Getting Started +An example of a simple chat bot can be found at https://github.com/ReSpeak/SimpleBot + +## Clone +This repository embeds the declarations as submodule: +``` +git clone https://github.com/ReSpeak/tsclientlib.git --recurse-submodules +``` + +## Build and run examples +``` +cd tsclientlib +cargo run --example simple +cd tsclientlib +cargo run --example audio +``` + +## Projects + +- `tsclientlib`: The main product — a simple to use TeamSpeak library +- `tsproto`: The low level library that does the network part + +### Utils +- `ts-bookkeeping`: Keeps book of the currently connected clients and channels of a server +- `tsproto-packets`: Parse packets and commands +- `tsproto-structs`: Contains parsed versions of the tsdeclarations +- `tsproto-types`: Contains basic types for TeamSpeak, e.g. versions and error codes + +## How this works +`tsproto` implements the basic TeamSpeak protocol stuff — creating a connection, making sure that UDP packets are delivered, encrypting and compressing the communication and giving access to all these low-level things. + +The convenient client library on top is `tsclientlib`. It uses all the versions, messages, structures and errors which are written down in a machine readable format and provides a nice and safe API. + +## Performance +On an i7-5280K with 6 cores/12 threads @3.6 GHz (single thread): +- 199 ms for creating one connection (6.5 connections/sec) — bottleneck is RSA puzzle solving +- 189 µs for sending a message (5300 messages/sec) + +## License +Apache License, Version 2.0 OR MIT license + +--- + +*Compiled from ReSpeak repositories on 2026-06-11. Source: https://github.com/ReSpeak/tsdeclarations, https://github.com/ReSpeak/tsclientlib* diff --git a/docs/references/teaspeak-offline-reference.md b/docs/references/teaspeak-offline-reference.md new file mode 100644 index 0000000..fbcdfb4 --- /dev/null +++ b/docs/references/teaspeak-offline-reference.md @@ -0,0 +1,1286 @@ +# TeaSpeak Offline Reference Document + +> Compiled from GitHub repositories (TeaSpeak, TeaWeb, TeaMusic) and archived website (teaspeak.de). +> Last updated: June 2026 + +--- + +## Table of Contents + +1. [Project Overview](#project-overview) +2. [Architecture](#architecture) +3. [Feature Comparison](#feature-comparison) +4. [Complete Feature List](#complete-feature-list) +5. [Protocol Implementation Details](#protocol-implementation-details) +6. [Audio/Codec Support](#audiocodec-support) +7. [Channel Types and Properties](#channel-types-and-properties) +8. [Permissions System](#permissions-system) +9. [Server Configuration](#server-configuration) +10. [Music Bot System](#music-bot-system) +11. [Chat System](#chat-system) +12. [Token System](#token-system) +13. [ServerQuery Notify System](#serverquery-notify-system) +14. [Ban System](#ban-system) +15. [Web Client Architecture](#web-client-architecture) +16. [Music Bot Architecture (TeaMusic)](#music-bot-architecture-teamusic) +17. [Server Binary Distribution](#server-binary-distribution) +18. [License Information](#license-information) +19. [Known Issues and Limitations](#known-issues-and-limitations) +20. [Properties Reference](#properties-reference) +21. [Feature Support Commands](#feature-support-commands) + +--- + +## Project Overview + +**TeaSpeak** is a free-to-use, community-driven VoIP (Voice over IP) communication platform consisting of a server and multiple client implementations. It is designed as an alternative to TeamSpeak with enhanced features, no license fees, and open-source components. + +### Components + +| Component | Repository | Language | Description | +|-----------|-----------|----------|-------------| +| **TeaSpeak Server** | [TeaSpeak/TeaSpeak](https://github.com/TeaSpeak/TeaSpeak) | C++ (proprietary binary) | The server daemon (issue tracker + docs in repo) | +| **TeaWeb** | [TeaSpeak/TeaWeb](https://github.com/TeaSpeak/TeaWeb) | TypeScript (84.1%), SCSS, HTML | Web client (open source, MPL-2.0) | +| **TeaMusic** | [TeaSpeak/TeaMusic](https://github.com/TeaSpeak/TeaMusic) | C++ (99.3%), CMake | Music bot provider plugins (open source) | +| **TeaClient** | Not open source | Native | Desktop client for Windows/Linux | + +### Key Design Principles + +- Free to use (no license fees) +- Community-driven development +- Self-hostable server +- Web client (installation-less) +- Built-in music bots +- Hidden/invisible channel system +- Extended ServerQuery interface +- Compatible with TeamSpeak 3 protocol + +--- + +## Architecture + +### Server Architecture + +The TeaSpeak server is a single binary (`TeaSpeakServer`) written in C++ that handles: + +- **Voice connections** via UDP (native TeamSpeak protocol) and WebRTC (for web clients) +- **ServerQuery** via TCP telnet-like interface (default port 10101) +- **File transfer** via HTTP/HTTPS (default port 30303) +- **Web client hosting** via built-in web server +- **Music bot management** with provider plugin system +- **Database** using SQLite (default) or MySQL +- **Instance management** supporting multiple virtual servers + +### Network Architecture + +``` +┌─────────────────┐ ┌──────────────────┐ +│ Native Clients │────▶│ UDP Voice │ +│ (TeaClient/TS3)│ │ (Port 9987) │ +└─────────────────┘ └──────────────────┘ + │ +┌─────────────────┐ ┌──────────────────┐ +│ Web Clients │────▶│ WebRTC Bridge │ +│ (Browser) │ │ (via HTTPS) │ +└─────────────────┘ └──────────────────┘ + │ +┌─────────────────┐ ┌──────────────────┐ +│ Query Clients │────▶│ ServerQuery │ +│ (YaTQA, bots) │ │ (Port 10101) │ +└─────────────────┘ └──────────────────┘ + │ +┌─────────────────┐ ┌──────────────────┐ +│ File Transfer │────▶│ HTTP/HTTPS │ +│ │ │ (Port 30303) │ +└─────────────────┘ └──────────────────┘ +``` + +### Threading Model (1.5.4+) + +As of version 1.5.4, the server merges the web, query, and voice client network event loops into fewer threads, reducing resource usage. + +--- + +## Feature Comparison + +From the archived teaspeak.de website: + +| Feature | TeaSpeak | TeamSpeak | Discord | Skype | +|---------|----------|-----------|---------|-------| +| Community and non-commercial driven | ✅ | ❌ | ❌ | ❌ | +| Spam/Ad free | ✅ | ✅ | ❌ | ❌ | +| Web Client / Installation-less Client | ✅ | ❌ | ✅ | ❌ | +| Host your own private server | ✅ | ✅ | ❌ | ❌ | +| High quality video and screen sharing | ✅ | ✅ | ✅ | ✅ | +| Built in music bots | ✅ | ❌ | ❌ | ❌ | +| Ability to hide channels | ✅ | ❌ | ❌ | ❌ | +| Cross and permanent channel chat | ✅ | ❌ | ✅ | ✅ | +| Built in unlimited file transfer | ✅ | ✅ | ❌ | ✅ | +| High quality OPUS voice transmission | ✅ | ✅ | ✅ | ✅ | +| Offline / LAN functionality | ✅ | ✅ | ❌ | ❌ | +| Advanced permissions system | ✅ | ✅ | ✅ | ❌ | +| Easy to use chat box with markdown support | ✅ | ❌ | ✅ | ✅ | +| Open Source | Partial | ❌ | ❌ | ❌ | +| Direct Messaging | ✅ | ✅ | ✅ | ✅ | + +--- + +## Complete Feature List + +### Server Features (Unique to TeaSpeak) + +1. **Built-in Music Bots** - High-quality, low bandwidth music bots with playlist management +2. **Invisible/Hidden Channels** - Channels hidden based on `i_channel_view_power` +3. **Customizable Messages** - Customize server stop messages, default descriptions, version display, license type, query MOTD, country flags +4. **Built-in Console** - Stdout commands: `end|shutdown`, `chat`, `permgrant`, `passwd` +5. **VPN Detection** - `b_client_ignore_vpn` permission to bypass +6. **Scheduled Shutdowns** - `serverprocessstop type=schedule time=60 msg=` +7. **Increased Slot Count** - Up to 1024 slots per virtual server (unlimited virtual servers) +8. **Per-Server Binding** - Individual binding options per virtual server +9. **Global Ban System** - Instance-wide bans with `sid=0` +10. **Ban Enforcement List** - Log of all ban enforcements (`bantriggerlist`) +11. **Ban Editing** - Direct ban editing (not delete+recreate) +12. **HWID Bans** - Ban by hardware ID +13. **Encrypted Query** - SSL/TLS encrypted ServerQuery connections +14. **Extended ServerQuery Notifies** - Almost all events available to query clients +15. **Global Group Assignment** - Instance-wide group assignment via `use 0` +16. **Channel Chat Conversations** - Persistent cross-channel chat +17. **SNI Certificate Support** - Different certificates for different server names +18. **WebRTC for Web Clients** - Native WebRTC voice bridge +19. **Video Broadcasting** - Camera and screen sharing via WebRTC +20. **Automatic Permission Updates** - New permissions auto-applied via `i_group_auto_update_type` +21. **Channel Creation Limits** - Per-client limits on temporary/semi/permanent channels +22. **Customizable Token System** - Configurable token values and actions +23. **Multiple IP Bindings** - IPv4 and IPv6 multi-binding support +24. **Compressed Snapshots** - Server snapshot compression +25. **IP Range Whitelists/Blacklists** - For query and file transfer + +### TeamSpeak Compatibility + +TeaSpeak implements the TeamSpeak 3 Server Query protocol and voice protocol, making it compatible with: +- TeamSpeak 3 clients (native voice) +- YaTQA (query administration) +- SinusBot (music bot) +- Other TS3-compatible tools + +--- + +## Protocol Implementation Details + +### Voice Protocol + +- **Transport**: UDP for native clients, WebRTC for web clients +- **Codec**: OPUS only (all non-OPUS codecs dropped in 1.5.0) + - Speex 8/16/32kbps: Removed + - CELT-Mono 48kbps: Removed + - OPUS Voice: Default + - OPUS Music: Available +- **Encryption**: Configurable per channel (`channel_codec_is_unencrypted`) and server-wide (`virtualserver_codec_encryption_mode`) +- **Video Codecs**: VP8 (default, better with packet loss), H264 available +- **Packet handling**: Control commands separated from voice/keepalive (1.4.7+) for reliability +- **RTO**: 200ms (matching Linux kernel TCP/IP RFC 6298) +- **WebRTC**: Uses libnice for ICE/STUN, thread pool for bridges (not per-client threads) + +### ServerQuery Protocol + +- **Transport**: TCP (plain text) or TLS/SSL encrypted +- **Default port**: 10101 +- **Newline**: `\n` (changed from `\n\r` in 1.4.14-beta6) +- **Max command length**: Configurable via `config.yml` +- **Flood protection**: Configurable commands/time/ban_time +- **Authentication**: Server admin password, token-based, or name-based + +### File Transfer Protocol + +- **Transport**: HTTP/HTTPS +- **Default port**: 30303 +- **Commands**: `ftcreatedir`, `ftgetfilelist`, `ftgetfileinfo`, `ftdeletefile`, `ftinitupload`, `ftinitdownload`, `ftrenamefile`, `ftlist`, `ftstop` +- **Bulk support**: `ftdeletefile` and `ftgetfileinfo` support bulks +- **Bandwidth limits**: Per-transfer and server-wide configurable + +--- + +## Audio/Codec Support + +### Voice Codecs (Server 1.5.0+) + +| Codec | Status | Notes | +|-------|--------|-------| +| OPUS Voice | ✅ Default | Primary codec | +| OPUS Music | ✅ Supported | Higher quality for music | +| Speex 8/16/32kbps | ❌ Removed | Permissions removed | +| CELT-Mono 48kbps | ❌ Removed | Permission removed | + +### Video Codecs + +| Codec | Status | Notes | +|-------|--------|-------| +| VP8 | ✅ Default | Better with packet loss | +| H264 | ✅ Available | Poor performance with packet loss | + +### Video Permissions + +- `b_video_screen` - Screen sharing permission +- `b_video_camera` - Camera permission +- `i_video_max_kbps` - Max video bitrate +- `i_video_max_streams` - Max total video streams +- `i_video_max_screen_streams` - Max screen share streams +- `i_video_max_camera_streams` - Max camera streams + +### Audio Processing (Web Client) + +- Voice Activity Detection (VAD) - Default mode +- Push-to-Talk (PTT) with configurable delay +- Threshold-based audio filtering +- Echo test support +- Whisper support +- Native audio encoding/decoding (Rust-based worker, replaced Emscripten) + +--- + +## Channel Types and Properties + +### Channel Types + +| Type | Flag | Description | +|------|------|-------------| +| Permanent | `channel_flag_permanent=1` | Persists after all users leave | +| Semi-Permanent | `channel_flag_semi_permanent=1` | Persists until deleted | +| Temporary | Both flags `0` | Auto-deleted when empty (with configurable delay) | +| Default | `channel_flag_default=1` | Landing channel for new connections | +| Password-Protected | `channel_flag_password=1` | Requires password to join | +| Private/Hidden | `channel_flag_private=1` | Invisible to unauthorized users | + +### Conversation Modes (1.4.22+) + +| Value | Mode | Description | +|-------|------|-------------| +| 0 | None | Shows channel description instead of conversation | +| 1 | Public | Default conversation mode | +| 2 | Private | Only accessible while in the channel | + +### Sidebar Modes (1.5.0+) + +| Value | Mode | Description | +|-------|------|-------------| +| 0 | Public | Default sidebar mode | + +### Channel Properties (Key) + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `channel_name` | string | - | Channel name | +| `channel_topic` | string | empty | Channel topic | +| `channel_description` | string | empty | Channel description | +| `channel_password` | string | empty | Channel password | +| `channel_codec` | number | 4 (OPUS) | Audio codec | +| `channel_codec_quality` | number | 7 | Codec quality (0-10) | +| `channel_maxclients` | number | -1 (-1=unlimited) | Max clients | +| `channel_maxfamilyclients` | number | -1 | Max clients including sub-channels | +| `channel_needed_talk_power` | number | 0 | Required talk power | +| `channel_forced_silence` | bool | 0 | Force silence in channel | +| `channel_delete_delay` | number | 0 | Delay before temp channel deletion | +| `channel_conversation_history_length` | number | 1500 | Chat history length (-1=none, 0=unlimited) | +| `channel_conversation_mode` | number | 1 | Conversation mode | +| `channel_sidebar_mode` | number | 0 | Sidebar mode | +| `channel_created_at` | number | - | Creation timestamp | +| `channel_created_by` | number | - | Creator database ID | +| `channel_last_left` | number | - | Last time a user left | + +### Channel Name Spacers + +TeaSpeak supports `[spacerX]` channel name spacers for visual organization in the channel tree. + +--- + +## Permissions System + +### Permission Calculation Flow + +TeaSpeak uses a multi-layer permission system: + +1. **Server Groups** - Global permissions from server group membership +2. **Channel Groups** - Channel-specific permissions +3. **Client Permissions** - Per-client overrides +4. **Channel Client Permissions** - Per-client per-channel overrides +5. **Playlist Permissions** - Music bot playlist permissions + +Each permission has: +- **Value** - The granted power level +- **Negate** - If set, the permission is denied regardless +- **Skip** - If set, skips this permission in calculation + +### TeaSpeak-Specific Permissions + +#### General Permissions + +| Permission | Description | +|------------|-------------| +| `b_client_allow_invalid_badges` | Bypass server kick for invalid badges | +| `b_client_allow_invalid_packet` | Bypass server kick for empty packets | +| `b_client_even_textmessage_send` | Allow sending private messages to self | +| `b_client_ignore_vpn` | Bypass VPN check | +| `b_client_music_server_list` | List all music bots on server | +| `b_client_music_channel_list` | List music bots in current channel | +| `b_client_music_create` | Create music bots | +| `b_client_music_delete_own` | Delete own music bots | +| `i_client_music_delete_power` | Power to delete music bots | +| `i_client_music_needed_delete_power` | Needed power to delete music bots | +| `i_client_music_info` | Power for `.mbot info` | +| `i_client_music_needed_info` | Needed info power for bot | +| `i_client_music_play_power` | Power for `.mbot play` | +| `i_client_music_needed_play_power` | Needed play power for bot | +| `i_client_music_rename_power` | Power for `.mbot rename` | +| `i_client_music_needed_rename_power` | Needed rename power for bot | +| `i_client_music_limit` | Max music bots per client | +| `i_client_max_clones_hwid` | Max clones with same HWID | +| `i_client_max_clones_ip` | Max clones with same IP | +| `b_virtualserver_modify_music_bot_limit` | Modify server music bot limit | + +#### Channel View Permissions + +| Permission | Description | +|------------|-------------| +| `i_channel_view_power` | Channel view power | +| `b_channel_ignore_view_power` | Bypass visibility check | +| `i_channel_needed_view_power` | Required view power for channel | + +#### Group Management Permissions + +| Permission | Description | +|------------|-------------| +| `i_channel_group_member_add_power` | Power to set channel group | +| `i_channel_group_needed_member_add_power` | Needed power to add to channel group | +| `i_channel_group_member_remove_power` | Power to remove channel group | +| `i_channel_group_needed_member_remove_power` | Needed power to remove channel group | +| `i_channel_group_modify_power` | Power to modify channel group | +| `i_channel_group_needed_modify_power` | Needed power to modify channel group | +| `i_server_group_self_add_power` | Power to add self to server group | +| `i_server_group_self_remove_power` | Power to remove self from server group | +| `i_channel_group_self_add_power` | Power to add self to channel group | +| `i_channel_group_self_remove_power` | Power to remove self from channel group | + +#### Ban Permissions + +| Permission | Description | +|------------|-------------| +| `b_client_ban_create_global` | Create global ban rules | +| `b_client_ban_delete_global` | Delete any global ban rules | +| `b_client_ban_delete_own_global` | Delete own global ban rules | +| `b_client_ban_edit` | Edit local ban rules | +| `b_client_ban_edit_global` | Edit global ban rules | +| `b_client_ban_list_global` | List global ban rules | + +#### Channel Limit Permissions + +| Permission | Description | +|------------|-------------| +| `i_client_max_channels` | Max channels per client | +| `i_client_max_temporary_channels` | Max temporary channels | +| `i_client_max_semi_channels` | Max semi-permanent channels | +| `i_client_max_permanent_channels` | Max permanent channels | + +#### Chat/Conversation Permissions + +| Permission | Description | +|------------|-------------| +| `b_channel_create_modify_conversation_private` | Modify conversation private flag | +| `b_channel_create_modify_conversation_history_length` | Modify history length (value = max) | +| `b_channel_create_modify_conversation_history_unlimited` | Set unlimited history | +| `b_channel_create_modify_conversation_mode_private` | Create/modify private conversation mode | +| `b_channel_create_modify_conversation_mode_public` | Create/modify public conversation mode | +| `b_channel_create_modify_conversation_mode_none` | Create/modify none conversation mode | + +#### Other Permissions + +| Permission | Description | +|------------|-------------| +| `b_channel_ignore_description_view_power` | Bypass description view power | +| `b_channel_ignore_subscribe_power` | Bypass subscribe power | +| `b_virtualserver_modify_country_code` | Edit server country code | +| `b_virtualserver_select_godmode` | Query can select server without binding | +| `i_channel_subscribe_power` (-1) | Prevent channel subscription | +| `b_channel_create_modify_sidebar_mode` | Modify channel sidebar mode | +| `b_channel_modify_temp_delete_delay` | Modify temp delete delay | +| `b_channel_create_modify_force_password` | Force password on channel creation | + +### Removed Permissions (1.5.0+) + +- `b_channel_create_modify_with_codec_speex8` +- `b_channel_create_modify_with_codec_speex16` +- `b_channel_create_modify_with_codec_speex32` +- `b_channel_create_modify_with_codec_celtmono48` +- `b_channel_create_private` (replaced by conversation modes) +- `b_virtualserver_select_godmode` (removed, queries always visible) + +--- + +## Server Configuration + +### config.yml Options + +The server uses a YAML configuration file with the following key sections: + +#### Instance Properties + +| Property | Default | Description | +|----------|---------|-------------| +| `serverinstance_filetransfer_host` | `0.0.0.0,[::]` | File transfer bind address | +| `serverinstance_filetransfer_port` | `30303` | File transfer port | +| `serverinstance_filetransfer_max_connections` | `100` | Max file transfer connections | +| `serverinstance_filetransfer_max_connections_per_ip` | `20` | Max file transfer connections per IP | +| `serverinstance_query_host` | `0.0.0.0,[::]` | Query bind address | +| `serverinstance_query_port` | `10101` | Query port | +| `serverinstance_query_max_connections` | `100` | Max query connections | +| `serverinstance_query_max_connections_per_ip` | `3` | Max query connections per IP | +| `serverinstance_serverquery_flood_commands` | `3` | Flood protection commands | +| `serverinstance_serverquery_flood_time` | `1` | Flood protection time (seconds) | +| `serverinstance_serverquery_ban_time` | `600` | Query ban time (seconds) | +| `serverinstance_virtual_server_id_index` | `1` | Starting virtual server ID | + +#### Customizable Messages (config.yml) + +| Config Key | Description | +|------------|-------------| +| Server stop/crash message | Message shown when server stops | +| Default channel/client description | Fallback descriptions | +| Idle kick message | Message for idle timeout kicks | +| Server version/platform | Displayed version info | +| License type display | No Licence, ATHP, LAN, NPL, or auto modes | +| Query MOTD | Message of the day for query clients | +| Query newline character | `\n` (default) or `\n\r` | +| Default country flag | Flag when no valid country detected | + +#### Other Notable Config Options + +| Option | Description | +|--------|-------------| +| `allow_session_reinitialize` | Allow session re-initialization | +| `suppress_myts_warnings` | Suppress MyTeamSpeak warnings | +| `notifymute` | Notify on mute | +| `connect_limit` | Connection limit | +| `client_connect_limit` | Per-client connection limit | +| `strict_ut8_mode` | Strict UTF-8 mode | +| `show_invisible_clients` | Show invisible clients | +| `default_music_bot` | Default music bot settings | +| `virtualserver_max_channels` | Max channels per virtual server | + +### Runtime Terminal Commands + +| Command | Description | +|---------|-------------| +| `end\|shutdown ` | Stop the server | +| `chat ` | Send chat message | +| `permgrant ` | Fix permissions | +| `passwd ` | Change admin password | +| `reload config` | Reload config.yml | + +--- + +## Music Bot System + +### Quick Setup + +1. Grant yourself music-related permissions +2. Type `.mbot` in channel chat +3. Use query commands for advanced control + +### Music Bot Query Commands + +| Command | Description | +|---------|-------------| +| `musicbotcreate [cid=]` | Create a music bot | +| `musicbotdelete bot_id=` | Delete a music bot | +| `musicbotsetsubscription bot_id=` | Subscribe to bot events | +| `musicbotplayerinfo bot_id=` | Get player info | +| `musicbotplayeraction bot_id= action=` | Control playback | +| `musicbotqueueadd bot_id= type= url=` | Add song to queue | +| `musicbotqueueadd bot_id= type=2 url=cid=\sname=\spath` | Add file from channel | +| `musicbotqueuelist bot_id= [-bulk]` | List queue entries | +| `musicbotqueueremove bot_id= song_id= [-skip_error]` | Remove queue entry | +| `musicbotqueuereorder bot_id= song_id= index=` | Reorder queue | + +### Player Actions + +| Value | Action | Description | +|-------|--------|-------------| +| 0 | Stop | Stop the player | +| 1 | Play | Play current song | +| 2 | Pause | Pause current song | +| 3 | Forward | Skip to next song | +| 4 | Rewind | Jump to last song (limited support) | + +### Player States + +| Value | State | Description | +|-------|-------|-------------| +| 0 | Sleeping | Waiting for new song | +| 1 | Loading | Loading current song | +| 2 | Playing | Playing current song | +| 3 | Paused | Playback paused | +| 4 | Stopped | Playback stopped | + +### Song Loader Types + +| Value | Type | Description | +|-------|------|-------------| +| 0 | YouTube-DL | Resolve URL via youtube-dl | +| 1 | FFMPEG | Direct FFMPEG playback | +| 2 | Channel File | Play from channel file system | + +### Playlist System + +| Command | Description | +|---------|-------------| +| `playlistcreate` | Create playlist | +| `playlistdelete` | Delete playlist | +| `playlistlist` | List playlists | +| `playlistinfo` | Get playlist info | +| `playlistedit` | Edit playlist properties | +| `playlistsonglist` | List songs in playlist | +| `playlistsongadd` | Add song to playlist | +| `playlistsongremove` | Remove song from playlist | +| `playlistsongreorder` | Reorder songs | +| `playlistsongsetcurrent` | Set current song | +| `musicbotplaylistassign` | Assign playlist to bot | +| `playlistclientlist` | List client playlists | +| `playlistclientpermlist` | List client permissions | +| `playlistclientaddperm` | Add client permission | +| `playlistclientdelperm` | Remove client permission | + +### Playlist Properties + +| Property | Type | Description | +|----------|------|-------------| +| `playlist_id` | number | Playlist identifier | +| `playlist_title` | string | Playlist title | +| `playlist_description` | string | Playlist description | +| `playlist_type` | number | 0=bot-bound, 1=global | +| `playlist_owner_dbid` | number | Owner database ID | +| `playlist_max_songs` | number | Max songs (-1=unlimited) | +| `playlist_flag_delete_played` | bool | Delete played songs | +| `playlist_flag_finished` | bool | Playlist finished flag | +| `playlist_replay_mode` | number | 0=normal, 1=loop, 2=loop-single, 3=shuffle | +| `playlist_current_song_id` | number | Current song ID | + +### Music Bot Permissions + +| Permission | Description | +|------------|-------------| +| `i_max_playlists` | Max playlists per client | +| `i_max_playlist_size` | Max songs per playlist | +| `i_playlist_view_power` / `i_playlist_needed_view_power` | View power | +| `i_playlist_modify_power` / `i_playlist_needed_modify_power` | Modify power | +| `i_playlist_delete_power` / `i_playlist_needed_delete_power` | Delete power | +| `i_playlist_song_add_power` / `i_playlist_song_needed_add_power` | Add song power | +| `i_playlist_song_remove_power` / `i_playlist_song_needed_remove_power` | Remove song power | +| `i_playlist_song_move_power` / `i_playlist_song_needed_move_power` | Move song power | + +### Music Bot Chat Commands + +Type in channel chat: +- `.mbot` - Show help +- `.mbot play` - Start playback +- `.mbot info` - Show bot info +- `.mbot rename ` - Rename bot + +### Music Bot Events + +| Event | Description | +|-------|-------------| +| `notifymusicqueueadd` | Song added to queue | +| `notifymusicqueueremove` | Song removed from queue | +| `notifymusicqueueorderchange` | Queue order changed | +| `notifymusicplayersongchange` | Current song changed | +| `notifymusicstatusupdate` | Player status update (every second when subscribed) | + +--- + +## Chat System + +### Overview + +TeaSpeak's chat system is channel-based, using voice channel tree channels as chat rooms. Features: + +- Each voice channel can be used as a chat room +- Conversations are persistent (saved to database) +- Offline users can read missed messages +- Cross-channel messaging (if you have join permission) +- Password-protected channels require active channel membership for chat + +### Chat Properties + +| Property | Range | Description | +|----------|-------|-------------| +| `channel_conversation_history_length` | -1 to 65535 | -1=no history, 0=unlimited, N=max messages | +| `channel_flag_conversation_private` | bool | Private = only accessible while in channel | + +### Chat Commands (ServerQuery) + +| Command | Description | +|---------|-------------| +| `sendtextmessage target= targetmode= msg= [cid=]` | Send message | +| `conversationhistory cid=` | Get conversation history | +| `conversationfetch cid=` | Fetch conversation | +| `conversationmessagedelete` | Delete message | +| `conversationsetsubscription` | Set subscription | + +### Supported Chat Features + +- BBCode formatting +- Markdown support +- Emoji support +- Image preview +- YouTube video embeds +- URL detection and linking +- Tables, headings, lists, horizontal rules +- Code blocks +- Blockquotes + +--- + +## Token System + +### Overview + +Tokens are long, random-generated keys that trigger actions when used. Their main purpose is granting extra permissions. + +### Token Properties + +| Property | Description | +|----------|-------------| +| `token_max_uses` | Maximum uses (-1 = unlimited) | +| `token_expired` | Expiration timestamp (seconds since epoch) | +| `token` | Custom token value (optional, auto-generated if not set) | + +### Token Actions + +| Action | ID | ID1 | ID2 | Text | +|--------|-----|-----|-----|------| +| Add server group | `0x01` | Server group ID | unused | unused | +| Remove server group | `0x02` | Server group ID | unused | unused | +| Set channel group | `0x03` | Channel group ID | Channel ID | unused | +| Allow channel join | `0x04` | unused | Channel ID | Channel password | + +### Token Commands + +| Command | Description | +|---------|-------------| +| `tokenadd` | Create token | +| `tokendelete` | Delete token | +| `tokenlist [-new]` | List tokens | +| `tokenuse` | Use a token | +| `tokenedit` | Edit token (new system) | +| `tokenactionlist` | List token actions (new system) | + +### New Token System (1.5.1+) + +- Token length increased from 20 to 32 characters +- `-new` switch for new token system +- `tokenuse` no longer requires permissions +- `tokendelete` no longer requires permissions for own tokens +- Tokens given on join are taken into account + +--- + +## ServerQuery Notify System + +### Registration + +``` +servernotifyregister event=all specifier=all # All events +servernotifyregister event=server specifier={edit} # Server edit +servernotifyregister event=client specifier={poke|update|command|join|switch|leave|add|remove|change} +servernotifyregister event=chat specifier={composing|receive_server|receive_channel|receive_private|close} +servernotifyregister event=channel specifier={create|edit|desc|move|delete} +servernotifyregister event=music specifier={queue|player} +``` + +### Server Events + +| Event | Command | Description | +|-------|---------|-------------| +| Server Edit | `notifyserverupdated` | Server settings changed | + +### Client Events + +| Event | Command | Description | +|-------|---------|-------------| +| Client Poke | `notifyclientpoke` | Received a poke | +| Client Updated | `notifyclientupdated` | Client property changed | +| Client Command | `notifyplugincmd` | Plugin message received | +| Client Join | `notifycliententerview` | Client entered view | +| Client Switch | `notifyclientmoved` | Client moved channels | +| Client Leave | `notifyclientleftview` | Client left/kicked/banned | +| Group Add | `notifyservergroupclientadded` | Added to server group | +| Group Remove | `notifyservergroupclientdeleted` | Removed from server group | +| Channel Group Change | `notifyclientchannelgroupchanged` | Channel group changed | + +### Chat Events + +| Event | Command | Description | +|-------|---------|-------------| +| Composing | `notifyclientchatcomposing` | Client is typing | +| Receive | `notifytextmessage` | Message received | +| Close | `notifyclientchatclosed` | Chat closed | + +### Channel Events + +| Event | Command | Description | +|-------|---------|-------------| +| Create | `notifychannelcreated` | Channel created | +| Edit | `notifychanneledited` | Channel edited | +| Description Changed | `notifychanneldescriptionchanged` | Description changed | +| Password Changed | `notifychannelpasswordchanged` | Password changed | +| Moved | `notifychannelmoved` | Channel moved | +| Deleted | `notifychanneldeleted` | Channel deleted | + +--- + +## Ban System + +### Standard Ban Commands + +| Command | Description | +|---------|-------------| +| `banadd` | Add ban rule | +| `bandel` | Delete ban rule | +| `banedit` | Edit ban rule (TeaSpeak-specific) | +| `banlist` | List ban rules | +| `banclient` | Ban client (supports database ID) | +| `bantriggerlist` | List ban enforcements | + +### Global Bans + +Use `sid=0` for instance-wide bans: +``` +banadd sid=0 ip=8.8.8.8 reason=Global\sban +``` + +### HWID Bans + +``` +banadd hwid=, +banadd hwid= # Ban empty HWIDs +``` + +### Ban Properties + +- IP-based bans +- Name-based bans +- HWID-based bans +- Configurable auto-ban on complain threshold +- Ban time in seconds +- Global (instance-wide) or local (per-server) + +--- + +## Web Client Architecture + +### Technology Stack + +| Technology | Version | Purpose | +|------------|---------|---------| +| TypeScript | 4.2+ | Primary language (84.1%) | +| React | 16.x | UI framework | +| SCSS | - | Styling (10.8%) | +| Webpack | 5.x | Build system | +| Rust/WASM | - | Audio processing worker | +| WebRTC | - | Voice/video communication | + +### Key Dependencies + +| Package | Purpose | +|---------|---------| +| `react` / `react-dom` | UI rendering | +| `react-grid-layout` | Drag-and-drop layouts | +| `react-player` | Media playback | +| `remarkable` | Markdown rendering | +| `emoji-mart` | Emoji picker | +| `twemoji` | Twitter emoji support | +| `highlight.js` | Code syntax highlighting | +| `sdp-transform` | SDP parsing for WebRTC | +| `webrtc-adapter` | WebRTC cross-browser support | +| `dompurify` | HTML sanitization | +| `crypto-js` / `webcrypto-liner` | Cryptography | +| `jquery` | Legacy DOM manipulation | +| `moment` | Date/time handling | +| `detect-browser` | Browser detection | + +### Project Structure + +``` +TeaWeb/ +├── client-api/ # PHP API endpoint (legacy) +├── client/ # Native client wrapper code +├── documentation/ # i18n documentation +├── loader/ # Initial loader (ES5 compatible) +├── scripts/ # Build/install scripts +├── shared/ # Shared code between web/client +├── tools/ # Development tools +├── vendor/ # Vendor dependencies +├── web/ # Main web application +│ ├── css/ # SCSS styles +│ ├── html/ # HTML templates +│ └── ts/ # TypeScript source +│ ├── client/ # Client-side code +│ ├── connection/ # Server connection +│ ├── ui/ # UI components (React) +│ └── voice/ # Voice/audio handling +├── webpack/ # Webpack configurations +├── webpack-web.config.ts +├── webpack-client.config.ts +├── package.json +└── tsconfig.json +``` + +### Build Commands + +```bash +npm install # Install dependencies +./scripts/install_dependencies.sh # Install rustup, wasm-pack +npm start web # Start dev server (http://localhost:8081) +npm run build-web # Build for production +npm run build-client # Build native client +./scripts/web_package.sh rel # Package into .zip +``` + +### Browser Support + +| Browser | Supported | +|---------|-----------| +| Chrome | ✅ Yes | +| Firefox | ✅ Yes | +| Opera | ✅ Yes | +| Safari | ✅ Yes | +| MS Edge (Chromium) | ✅ Yes | +| MS Edge (Legacy) | ⚠️ Partial | +| Internet Explorer | ❌ No | + +### Key Web Client Features + +- Multi-server tabs (connect to multiple servers) +- Popoutable modals (detached windows) +- CSS variable editor for theming +- Dark theme +- Responsive design (font-size based) +- Bookmark system with import/export +- Auto-connect on startup +- Channel tree with React rendering +- Video spotlight mode (multiple simultaneous videos) +- Screen sharing +- Watch-together mode +- Image preview in chat +- Drag-and-drop for clients +- Context menus +- Hotkey system +- Volume controls (master + per-client) +- Identity management with auto-generation +- Auto-reconnect system + +--- + +## Music Bot Architecture (TeaMusic) + +### Technology + +- **Language**: C++ (99.3%), CMake (0.7%) +- **Standard**: C++17 +- **Build**: CMake with shared library providers + +### Provider System + +TeaMusic uses a plugin-based provider architecture: + +``` +TeaMusic/ +├── include/teaspeak/ # Headers (MusicPlayer.h) +├── providers/ +│ ├── ffmpeg/ # FFMPEG provider (000 prefix = load first) +│ │ ├── FFMpegProvider.cpp +│ │ ├── FFMpegMusicPlayer.cpp +│ │ ├── FFMpegMusicProcess.cpp +│ │ └── FFMpegStream.cpp +│ ├── yt/ # YouTube-DL provider (001 prefix = load second) +│ │ ├── YTProvider.cpp +│ │ ├── YTVManager.cpp +│ │ ├── YoutubeMusicPlayer.cpp +│ │ └── YTRegex.cpp +│ └── shared/ # Shared utilities +│ ├── libevent.cpp +│ └── CommandWrapper.cpp +├── helpers/ # Development helpers +└── CMakeLists.txt +``` + +### Provider Details + +| Provider | Prefix | Dependencies | Description | +|----------|--------|--------------|-------------| +| FFMPEG | `000` | libevent, threadpool, StringVariables | Direct audio playback via FFMPEG | +| YouTube-DL | `001` | FFMPEG provider, jsoncpp, threadpool, StringVariables | YouTube/video URL resolution + playback | + +### Build Options + +```cmake +BUILD_PROVIDER_YT=ON # Build YouTube-DL provider +BUILD_PROVIDER_FFMPEG=ON # Build FFMPEG provider +BUILD_HELPERS=ON # Build development helpers +``` + +### Music Provider Features + +- Automatic reconnect (3 attempts) on stream disconnect +- Shuffle mode +- Song change notifications +- Configurable announce messages +- Volume control per bot +- Playlist persistence across restarts +- YouTube URL resolution via youtube-dl +- FFMPEG direct stream playback +- Channel file system playback + +--- + +## Server Binary Distribution + +### Download Sources (Archived) + +| Platform | URL Pattern | +|----------|-------------| +| Linux x64 (stable) | `https://repo.teaspeak.de/server/linux/amd64_stable/TeaSpeak-.tar.gz` | +| Linux x64 (nightly) | `https://repo.teaspeak.de/server/linux/amd64_nightly/` | +| Docker (TeaWeb) | `https://hub.docker.com/r/teaspeak/web` | +| Web Client Releases | `https://github.com/TeaSpeak/TeaWeb/releases` | +| TeaClient Releases | `https://clientapi.teaspeak.de/files/release/` | + +### TeaClient Versions (Archived) + +| Platform | Format | Version | +|----------|--------|---------| +| Linux x64 | .deb installer | 1.5.3-2 | +| Linux x64 | .tar.gz | 1.5.3-2 | +| Windows x64 | .exe installer | 1.5.3-2 | +| Windows x64 | .tar.gz | 1.5.3-2 | + +### Installation + +**Server:** +```bash +# Download +wget https://repo.teaspeak.de/server/linux/amd64_stable/TeaSpeak-.tar.gz +# Extract +tar -xzf TeaSpeak-*.tar.gz +# Run +./teastart.sh start +``` + +**Docker (Web Client):** +```bash +docker pull teaspeak/web +``` + +### teastart.sh Commands + +```bash +./teastart.sh start # Start server +./teastart.sh stop # Stop server +./teastart.sh status # Returns 0 if running, 1 if not +./teastart.sh reload # Reload config +./teastart.sh execute # Execute command +``` + +### Supported Architectures + +- x86_64 (primary) +- armv32v7 (since 1.4.5, with web client since 1.4.6) + +--- + +## License Information + +### TeaWeb (Web Client) + +**License**: Mozilla Public License 2.0 (MPL-2.0) + +Key terms: +- Source code modifications must remain under MPL-2.0 +- Can be combined with other code under different licenses +- Must provide source for MPL-covered portions +- No warranty, no liability + +### TeaMusic (Music Bot Providers) + +**License**: Not explicitly stated in repository (likely open source based on public GitHub presence) + +### TeaSpeak Server + +**License**: Proprietary / Not open source + +The server binary is distributed freely but is not open source. The issue tracker and documentation are public. + +### TeaClient (Desktop Client) + +**License**: Not open source (distributed as binary) + +--- + +## Known Issues and Limitations + +### Open Issues (as of compilation) + +From the GitHub issue tracker (61 open issues on TeaSpeak/TeaSpeak): + +| Issue | Title | Status | +|-------|-------|--------| +| #723 | Arch Linux core dump | Open | +| #722 | Screen share not working, project unmaintained | Open | +| #721 | Server crashes | Open | +| #720 | Video sharing erratic and crashing | Open | +| #719 | Can't start server on Windows WSL2 | Open | +| #718 | Failed to parse VP8 header, screen share failed | Open | +| #717 | Raspberry Pi setup | Open | +| #716 | Can't download | Open | +| #715 | None of available versions working | Open | +| #714 | Server binary for Raspberry Pi (ARM) | Open | +| #713 | Packet resend failed | Open | +| #712 | Feature discussion | Open | + +### Web Client Issues (TeaWeb, 15 open) + +The TeaWeb repository is archived (read-only since Jul 9, 2025). + +### Known Limitations + +1. **Non-OPUS codecs removed** - All Speex and CELT codecs dropped in 1.5.0 +2. **VP8 parsing issues** - Screen sharing can fail with VP8 header parsing errors +3. **ARM support limited** - Raspberry Pi builds not consistently available +4. **WebRTC stability** - Some video streaming instability reported +5. **Project maintenance** - Appears unmaintained since ~2022 +6. **Video performance** - H264 performs poorly with packet loss +7. **Windows WSL2** - Server startup issues on WSL2 +8. **Music bot queue** - Some features marked as "unimplemented" in documentation +9. **YouTube-DL dependency** - Requires separate youtube-dl installation +10. **Snapshot version** - Version 2 introduced breaking changes for music bot data + +### Critical Fixes (Historical) + +- **1.4.12-beta4**: Fixed critical server crash due to malformed packets +- **1.4.12-beta4**: Fixed crash from missing "providers" directory +- **1.3.26b**: Fixed out-of-order packet sending ("invalid clientID disconnect") +- **1.3.17b**: Fixed deeply rooted protocol bug (generation ID miscalculation) +- **1.3.14b**: Fixed voice encryption issue + +--- + +## Properties Reference + +### Instance Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `serverinstance_database_version` | uint | 0 | Database version | +| `serverinstance_permissions_version` | uint | 0 | Permissions version | +| `serverinstance_filetransfer_host` | string | `0.0.0.0,[::]` | File transfer host | +| `serverinstance_filetransfer_port` | uint | 30303 | File transfer port | +| `serverinstance_filetransfer_max_connections` | uint | 100 | Max connections | +| `serverinstance_filetransfer_max_connections_per_ip` | uint | 20 | Max per IP | +| `serverinstance_query_host` | string | `0.0.0.0,[::]` | Query host | +| `serverinstance_query_port` | uint | 10101 | Query port | +| `serverinstance_query_max_connections` | uint | 100 | Max query connections | +| `serverinstance_query_max_connections_per_ip` | uint | 3 | Max per IP | +| `serverinstance_max_download_total_bandwidth` | int | -1 | Download bandwidth limit | +| `serverinstance_max_upload_total_bandwidth` | int | -1 | Upload bandwidth limit | +| `serverinstance_serverquery_flood_commands` | uint | 3 | Flood commands | +| `serverinstance_serverquery_flood_time` | uint | 1 | Flood time | +| `serverinstance_serverquery_ban_time` | uint | 600 | Ban time | +| `serverinstance_virtual_server_id_index` | uint | 1 | Server ID start index | + +### Virtual Server Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `virtualserver_unique_identifier` | string | - | Server UID | +| `virtualserver_name` | string | "Another TeaSpeak server..." | Server name | +| `virtualserver_welcomemessage` | string | "Welcome on another..." | Welcome message | +| `virtualserver_maxclients` | uint | 120 | Max clients | +| `virtualserver_password` | string | empty | Server password | +| `virtualserver_port` | uint | 9987 | Voice port | +| `virtualserver_host` | string | `0.0.0.0,::` | Bind address | +| `virtualserver_codec_encryption_mode` | uint | 0 | Encryption mode | +| `virtualserver_hostmessage` | string | "Welcome" | Host message | +| `virtualserver_hostbanner_url` | string | empty | Banner URL | +| `virtualserver_hostbanner_gfx_url` | string | empty | Banner image URL | +| `virtualserver_hostbanner_gfx_interval` | uint | 0 | Banner rotation interval | +| `virtualserver_complain_autoban_count` | uint | 5 | Auto-ban threshold | +| `virtualserver_complain_autoban_time` | uint | 5 | Auto-ban time | +| `virtualserver_complain_remove_time` | uint | 5 | Complain expiry | +| `virtualserver_priority_speaker_dimm_modificator` | float | -18 | Priority speaker volume reduction | +| `virtualserver_antiflood_points_tick_reduce` | uint | 25 | Anti-flood point reduction | +| `virtualserver_antiflood_points_needed_command_block` | uint | 150 | Command block threshold | +| `virtualserver_antiflood_points_needed_ip_block` | uint | 300 | IP block threshold | +| `virtualserver_needed_identity_security_level` | uint | 8 | Required security level | +| `virtualserver_channel_temp_delete_delay_default` | uint | 60 | Temp channel delete delay | +| `virtualserver_max_channels` | uint | 1000 | Max channels | +| `virtualserver_web_host` | string | `0.0.0.0` | Web client host | +| `virtualserver_web_port` | uint | 0 | Web client port | +| `virtualserver_default_client_description` | string | empty | Default client description | +| `virtualserver_default_channel_description` | string | empty | Default channel description | +| `virtualserver_default_channel_topic` | string | empty | Default channel topic | +| `virtualserver_music_bot_limit` | int | -1 | Music bot limit | +| `virtualserver_country_code` | string | XX | Server country code | +| `virtualserver_reserved_slots` | uint | 0 | Reserved slots | + +### Client Properties (Key) + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `client_unique_identifier` | string | - | Client UID | +| `client_nickname` | string | - | Nickname | +| `client_version` | string | "unknown" | Client version | +| `client_platform` | string | "unknown" | Client platform | +| `client_input_muted` | bool | 0 | Input muted | +| `client_output_muted` | bool | 0 | Output muted | +| `client_is_recording` | bool | 0 | Recording flag | +| `client_database_id` | uint | 0 | Database ID | +| `client_away` | bool | 0 | Away status | +| `client_away_message` | string | empty | Away message | +| `client_type` | uint | 0 | 0=normal, 1=query | +| `client_type_exact` | uint | 0 | Exact type | +| `client_talk_power` | uint | 0 | Talk power | +| `client_is_talker` | bool | 0 | Talker flag | +| `client_is_priority_speaker` | bool | 0 | Priority speaker | +| `client_is_channel_commander` | bool | 0 | Channel commander | +| `client_badges` | string | empty | Client badges | +| `client_total_online_time` | uint | 0 | Total online time | +| `client_month_online_time` | uint | 0 | Monthly online time | +| `client_meta_data` | string | empty | Metadata | +| `client_description` | string | empty | Description | +| `client_country` | string | "TS" | Country code | +| `client_teaforo_id` | uint | 0 | TeaForum ID | +| `client_teaforo_name` | string | empty | TeaForum name | +| `client_owner` | uint | 0 | Owner (for music bots) | +| `client_bot_type` | uint | 0 | Bot type | +| `player_state` | uint | 0 | Music player state | +| `player_volume` | float | 1 | Music player volume | +| `client_playlist_id` | uint | 0 | Assigned playlist | + +--- + +## Feature Support Commands + +### listfeaturesupport + +The server exposes feature support via `listfeaturesupport`: + +| Feature Name | Version | Description | +|--------------|---------|-------------| +| `error-bulks` | 1 | Bulked command responses | +| `advanced-channel-chat` | 1 | Cross-channel persistent chat | +| `log-query` | 1 | Instance log querying | +| `sidebar-mode` | 1 | Channel sidebar modes | + +### Bulked Command Responses + +Supported commands for individual error results: +- `servergroupaddperm`, `servergroupdelperm`, `servergroupautoaddperm`, `servergroupautodelperm` +- `channeladdperm`, `channeldelperm` +- `clientaddperm`, `clientdelperm` +- `channelclientaddperm`, `channelclientdelperm` +- `channelgroupaddperm`, `channelgroupdelperm` +- `playlistaddperm`, `playlistdelperm`, `playlistclientaddperm`, `playlistclientdelperm` +- `ftdeletefile`, `ftgetfileinfo` + +--- + +## Additional Command Extensions + +### Extended Command Parameters + +| Command | Extra Parameters | +|---------|-----------------| +| `channellist` / `channelinfo` | `created_by`, `created_at` | +| `clientdblist -details` / `clientdbfind -details` / `clientdbinfo` | `client_badges`, `client_version`, `client_platform`, `client_hwid` | +| `notifyplugincmd` / `notifyconnectioninforequest` | `invokerid` | +| `sendtextmessage` | `cid` (target channel) | +| `tokenadd` | `token` (custom value) | +| `banclient` | Accepts database ID | + +### New Commands + +| Command | Description | +|---------|-------------| +| `propertylist` | List all properties | +| `listfeaturesupport` | List supported features | +| `logquery` | Query server log | +| `logadd` | Add log entry | +| `permoverview` | Permission overview | +| `ftrenamefile` | Rename file | +| `ftlist` | List file transfers | +| `ftstop` | Stop file transfer | +| `conversationhistory` | Chat history | +| `conversationfetch` | Fetch conversation | +| `conversationmessagedelete` | Delete chat message | +| `conversationsetsubscription` | Set chat subscription | +| `tokenactionlist` | List token actions | +| `tokenedit` | Edit token | + +### Removed Commands + +| Command | Replacement | +|---------|-------------| +| `logview` | `logquery` | +| `musicbotqueuelist` | Playlist system | +| `musicbotqueueadd` | Playlist system | +| `musicbotqueuereorder` | Playlist system | +| `musicbotqueueremove` | Playlist system | + +--- + +## Version History Highlights + +### Major Versions + +| Version | Key Changes | +|---------|-------------| +| **1.5.6** | Latest known version, IP2Location update, config reload fix | +| **1.5.5** | Video viewer tracking, native client counting | +| **1.5.4** | Channel admin fix, bulked commands, query group improvements | +| **1.5.2** | WebRTC STUN enabled by default | +| **1.5.1** | Token system redesign, web list removal | +| **1.5.0** | **Video broadcasting**, OPUS-only, WebRTC improvements, sidebar modes | +| **1.4.22** | Conversation modes (none/public/private) | +| **1.4.21** | File transfer crash fix, logging properties | +| **1.4.20** | Web client whisper support, echo tests | +| **1.4.19** | Raw command support for web client, whisper API | +| **1.4.18** | Database improvements, compressed snapshots, snapshot deploy improvements | +| **1.4.17** | YT-DL improvements, file transfer changes | +| **1.4.16** | Server logging system, `logadd`/`logquery` commands | +| **1.4.15** | File transfer restructure, bulked responses, `ftrenamefile` | +| **1.4.14** | Permission checking rework, bulk operations, query newline change | +| **1.4.13** | Statistics improvements, packet loss calculation, RTO adjustment | +| **1.4.12** | Connection statistics, UDP packet loss, RTO RFC 6298 | +| **1.4.11** | WebRTC thread pool, automated rlimit check | +| **1.4.10** | License renewal system, music bot fixes | +| **1.4.8** | Playlist client commands, skip/negate fix | +| **1.4.7** | Packet handling restructure (voice separation) | +| **1.4.6** | Command API rework, permission system overhaul | +| **1.4.5** | ARM support, join flood protection | +| **1.4.4** | Config reload, default certificates | +| **1.4.3** | libnice bundled, music bot slot counting | +| **1.4.1** | Music bot properties, country code, IP2Location | +| **1.4.0** | Server snapshots, conversation system, new permissions | +| **1.3.26b** | Critical packet ordering fix | +| **1.3.22b** | Permission system performance improvements | +| **1.3b** | Music bot overhaul, playlist system introduction | + +--- + +## References + +- **TeaSpeak Server Issues**: https://github.com/TeaSpeak/TeaSpeak/issues +- **TeaWeb Issues**: https://github.com/TeaSpeak/TeaWeb/issues (archived) +- **TeaMusic Issues**: https://github.com/TeaSpeak/TeaMusic/issues +- **Archived Website**: https://web.archive.org/web/2024/https://teaspeak.de/ +- **Forum** (archived): https://forum.teaspeak.de/ +- **Docker Hub**: https://hub.docker.com/r/teaspeak/web diff --git a/docs/references/yatqa-offline-reference.md b/docs/references/yatqa-offline-reference.md new file mode 100644 index 0000000..b8aa47f --- /dev/null +++ b/docs/references/yatqa-offline-reference.md @@ -0,0 +1,746 @@ +# YaTQA Offline Reference — TeamSpeak 3 Protocol Documentation + +**Source:** https://yat.qa/ressourcen/ (German pages) +**Author:** Janni "Яedeemer" K. +**Fetched:** 2026-06-11 +**Purpose:** Offline reference for Chanora development — protocol details, error codes, undocumented features + +> **Note:** The German pages contain significantly more detail than the English pages. This document captures ALL German-only content. + +--- + +## Table of Contents + +1. [Definitions and Algorithms](#1-definitions-and-algorithms) +2. [Server Query Comments](#2-server-query-comments) +3. [Server Query Notify](#3-server-query-notify) +4. [Variable Parameters](#4-variable-parameters) +5. [Voice Client Anti-Flood](#5-voice-client-anti-flood) +6. [Security Level (Hashcash)](#6-security-level-hashcash) +7. [Snapshots](#7-snapshots) +8. [Other Protocols](#8-other-protocols) +9. [Server Error Codes](#9-server-error-codes) +10. [Permission IDs](#10-permission-ids) +11. [Client Versions](#11-client-versions) +12. [Badges](#12-badges) + +--- + +## 1. Definitions and Algorithms + +### 1.1 Codecs + +**Codec bitrates (b_Raw in bytes/s):** + +| Codec \ Quality | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | +|---|---|---|---|---|---|---|---|---|---|---|---| +| Speex Narrowband (8kHz) | 300 | 500 | 750 | 1000 | 1400 | 1900 | 2300 | 3100 | | | | +| Speex Wideband (16kHz) | 500 | 750 | 1000 | 1250 | 1600 | 2100 | 2600 | 3000 | 3500 | 4300 | 5300 | +| Speex Ultra-wideband (32kHz) | 550 | 950 | 1200 | 1450 | 1850 | 2350 | 2800 | 3200 | 3700 | 4500 | 5500 | +| CELT Mono (48kHz) | | | | | 4000 | 5000 | 6000 | 8000 | 12000 | | | +| Opus Voice | 550 | 1050 | 1550 | 2050 | 2600 | 3100 | 3600 | 4100 | 4650 | 5150 | 5650 | +| Opus Music | 900 | 1800 | 2700 | 3600 | 4500 | 5400 | 6300 | 7200 | 8100 | 9000 | 9900 | + +**Key formulas:** +- `b_Official = floor(b_Raw + 45 byte / t)` +- `d = b_Raw * t + 45 byte ≤ d_Max` +- `d_Max ≈ 527 ± 1 byte` (MTU) +- `t_Max(Opus) = 20 ms` +- `t_Max(Speex/CELT) = floor((527±1 - 45) / (b_Raw * 50)) * 20 ms` + +**MTU explanation:** 528 bytes (TS-MTU) + 40 bytes (IPv6 header) + 8 bytes (UDP header) = 576 bytes (old modem/ISDN MTU). + +**Opus is VBR** — bitrate varies ±250 bytes/s at quality 6. Max deviation needed to reach d_Max is ~144% (never happens in practice). + +### 1.2 Permission System + +**Permission tiers (evaluated top to bottom, lowest wins):** + +| Tier | Level | Description | +|---|---|---| +| 0 | Server Groups | Highest value wins (unless Negate flag) | +| 1 | Client (Server level) | Client-specific server permissions | +| 2 | Channel | Skipped if Skip flag set | +| 3 | Channel Group | Skipped if Skip flag set | +| 4 | Client (Channel level) | Client-specific channel permissions | + +**Skip flag:** Skips channel and channel group permissions. Determined by: +1. If client permission set → use its skip flag +2. If no client permission → use effective server group's skip flag +3. If groups with Negate flag → only Negate groups count +4. If multiple groups remain → lowest ID wins + +**Negate flag:** If ANY server group has Negate flag set, only groups WITH Negate flag count. Lowest ID among Negate groups wins. Even if non-Negate groups have lower IDs. + +**Grant permission:** Tells how much `i_client_permission_modify_power` needed to change a permission. Grant permission name = replace first letter of original permission with `i_needed_permission_modify_power`. + +**b_client_skip_channelgroup_permissions:** If set in first two tiers, ALL channel group AND channel permissions are ignored. + +### 1.3 Query Connection + +**Timeout behavior by version:** + +| Versions | Timeout | Paragraph | Space+Enter | Command+Enter | +|---|---|---|---|---| +| – 3.2.0 | 10 min | yes | yes | yes | +| 3.3.0-beta1 – beta2 | 5 min | no | no | no | +| 3.3.0-beta3 – 3.3.1-steadyclock | 5 min | no | no* | yes | +| 3.3.1 – | 5 min | no | yes | yes | + +*Sending just a command keeps client on server forever (exploitable). + +**Character encoding:** TeamSpeak claims UTF-8 but actually uses UCS-2 (BMP only). Mobile apps use CESU-8. Server 3.2.0 adds partial SIP support (emoji ranges). + +**Line terminator:** `0x0A 0x0D` (Windows format, reversed). +**Max line length:** 9203 bytes (excluding line terminator). Not limited for 12 permission add/remove commands and `serversnapshotdeploy`. + +### 1.4 Icons + +- Max dimensions: 16×16 +- Filename = CRC32 of icon data (same algorithm as PNG/ZIP) +- Cannot be animated + +**Data types for icon IDs vary by context:** + +| Context | Parameter | Read | Write | +|---|---|---|---| +| *permlist, *addpermsid | permsid=i_icon_id value= | signed | signed | +| clientlist -icon, clientinfo | client_icon_id= | signed | via clientaddperm only | +| serverinfo, serveredit | virtualserver_icon_id= | signed | unsigned | +| channellist -icon, channelinfo | channel_icon_id | signed | unsigned | + +### 1.5 Avatars + +- Max dimensions: 300×300 +- Avatar flag = MD5 hash (not a boolean) +- Stored in channel ID 0 +- Filename derived from Global ID (not from avatar flag) +- Algorithm: Base64-decode the Global ID → 20 bytes → display with `[a-p]` instead of `[0-9a-f]` + +**Example calculation:** +- UID: `yGRWD2BOWPC6xSROXoi7U8NAljI=` +- Base64 decode → 20 bytes → hex: `C86456...` → filename: `migefg...` + +### 1.6 Snapshots + +- File starts with SHA1 hash of remaining UTF-8 data (excluding trailing newline) +- Internally runs normal Query commands when deploying +- If `serveradmin` is added to a server group, snapshot may fail on newer servers + +### 1.7 Client Cache + +- Subfolder names = Base64-encoded Server UID (double-encoded to avoid `/` in filenames) +- Avatars in `cache/clients/`, Icons in `cache/icons/` +- Private chat partners in `chats/clients/` (also Base64-encoded UIDs) + +### 1.8 BBCode + +- Max stack size: 20 +- 10 tags can be active simultaneously +- Self-closing tag `[hr]` doesn't count toward stack but can't be used at 20 + +**Inline elements:** `[b]`, `[i]`, `[u]`, `[color=X]`, `[url=URL]Text[/url]`, `[url]URL[/url]` + +**Block elements** (channel descriptions only): `[hr]`, `[size=X]`, `[img]URL[/img]`, `[left]`, `[center]`, `[right]`, `[list][*]Text[/list]` + +**Internal links:** +- `client://{ClientID}/{ClientUID}~{Name}` +- `channelid://{ChannelID}` (0 = server) +- `ts3file://{Serveraddress}?port={Port}&serverUID={UID}&channel={ChannelID}&path={Path}&filename={Filename}&isDir={0|1}&size={Bytes}&fileDateTime={UnixTimestamp}` +- `ts3image://{Filename}?channel={ChannelID}&path={Path}` + +**External links:** +- `ts3server://{Serveraddress}?port={Port}&nickname={Nickname}&password={Password}&channel={ChannelName}&cid={ChannelID}&channelpassword={ChannelPassword}&token={Token}&addbookmark={BookmarkName}` + +**Colors:** W3C color names + `#123456` + `#123` + `transparent` + +**Font sizes (since client 3.0.3):** Measured in points (pt). Legacy HTML sizes `[size=+X]` don't work — `+` prefix resets to default. + +--- + +## 2. Server Query Comments + +### 2.1 General + +- `login` failure logs you out if already logged in +- `use` with non-existent server returns "server not running" error +- `use` does NOT auto-start stopped servers — must use `-virtual` flag +- `return_code` parameter available on every command + +### 2.2 Key Command Issues + +**serveredit:** `virtualserver_ask_for_privilegekey` setting gives error 1538 (invalid parameter). + +**serversnapshotdeploy:** +- With `use` → overwrites selected server; without → creates new server +- Returns `sid` and `virtualserver_port` when creating new server +- Port not preserved from snapshot when creating new +- `-mapping` flag must come before snapshot data + +**servernotifyregister:** +- Undocumented parameter `event=tokenused` +- Invalid `event` values require another parameter, then fail with parameter error +- `id=0` stands for all channels (gives duplicate events) + +**sendtextmessage:** `targetmode=2` (channel) and `targetmode=3` (server) don't require `target` parameter. + +**clientlist:** Undocumented `-badges` switch exists. + +**clientedit:** Only `client_description` and `client_is_talker` can be modified. + +**clientdblist:** `duration` is entry count (max 200), not a time duration. `-1` = maximum. + +**clientdbfind:** +- Uses SQL `LIKE` matching: `%` = wildcard, `_` = single char +- Backslashes must be doubled +- Undocumented `-details` switch returns: unique_identifier, nickname, lastconnected, totalconnections, lastip +- Limited to 50 results + +**clientdbedit:** Only `client_description` can be changed. + +**clientgetnamefromuid:** Also returns `cldbid` — better than `clientgetdbidfromuid`. + +**clientkick:** Clients to kick must come LAST in parameter list. QueryManual example is wrong. + +**clientpoke:** Cannot poke multiple clients simultaneously (despite QueryManual claiming otherwise). + +**privilegekeyadd:** `tokencustomset` is a self-parameterized string (spaces between params). Individual idents/values must be escaped before the entire string is escaped. QueryManual example is wrong. + +### 2.3 Undocumented Commands + +**plugincmd:** Parameters: `name`, `data`, `targetmode` (0-3), `target`. Only works on virtual servers. No longer allowed from Query clients. + +**dummy_connectionlost:** Same as `logout` but doesn't fail if not logged in. If on a server, kicks you (connection lost). You remain invisible on instance. + +**verifyserverpassword / verifychannelpassword:** Both return "not on a server" if not connected, or "command doesn't exist" if connected. Both non-functional. + +**channelcreateprivate:** Returns error 2 (not implemented). + +**cmd_custom_unknown_command:** Returns error 256 (command not found) — intentional. + +--- + +## 3. Server Query Notify + +### 3.1 Subscription Behavior + +- Subscriptions disappear on logout, re-login, or server switch +- Must subscribe individually (no array parameter) +- Can only have ONE channel subscription at a time +- `id=0` = all channels (gives duplicate events) +- Existing subscriptions persist even if permissions revoked + +### 3.2 Events + +#### notifycliententerview (server + channel) +Fields: cfid, ctid, reasonid, clid, client_unique_identifier, client_nickname, client_input_muted, client_output_muted, client_outputonly_muted, client_input_hardware, client_output_hardware, client_meta_data, client_is_recording, client_database_id, client_channel_group_id, client_servergroups, client_away, client_away_message, client_type, client_flag_avatar, client_talk_power, client_talk_request, client_talk_request_msg, client_description, client_is_talker, client_is_priority_speaker, client_unread_messages, client_nickname_phonetic, client_needed_serverquery_view_power, client_icon_id, client_is_channel_commander, client_country, client_channel_group_inherited_channel_id, client_badges + +#### notifyclientleftview (server + channel) +Fields: cfid, ctid, reasonid, invokerid, invokername, invokeruid, reasonmsg, bantime, clid + +#### notifyserveredited (server) +Always reasonid=10. Reports new values for: name, codec_encryption_mode, default_server_group, default_channel_group, hostbanner_*, priority_speaker_dimm_modificator, hostbutton_*, name_phonetic, icon_id, hostbanner_mode, channel_temp_delete_delay_default + +#### notifychannelchanged, notifychannelmoved, notifychanneledited, notifychannelcreated, notifychanneldeleted (channel) + +#### notifyclientmoved (channel) +Fields: ctid, reasonid (0=self, 1=moved), invokerid, invokername, invokeruid, clid + +#### notifytextmessage (textserver, textchannel, textprivate) +Fields: targetmode (1=private, 2=channel, 3=server), msg, target (only for private), invokerid, invokername, invokeruid + +#### notifytokenused (tokenused — undocumented) +Fields: clid, cldbid, cluid, token, tokencustomset, token1 (group), token2 (0 for server token) + +### 3.3 Reason IDs + +| ID | Meaning | +|---|---| +| 0 | Self channel change or server join | +| 1 | User or channel moved | +| 3 | Timeout | +| 4 | Channel kick | +| 5 | Server kick | +| 6 | Ban | +| 8 | Voluntary server leave | +| 10 | Server or channel edited | +| 11 | Server shutdown | + +--- + +## 4. Variable Parameters + +### 4.1 Client Variables + +**Key variables and their availability:** + +| Variable | clientlist | clientinfo | notify | clientupdate | clientedit | clientdblist | clientdbinfo | +|---|---|---|---|---|---|---|---| +| cid | ✓ | ✓ | ✓(ctid) | | | | | +| clid | ✓ | ✓ | N/A | | | | | +| client_unique_identifier | ✓(uid) | ✓ | ✓ | ✗ | | ✓ | ✓ | +| client_nickname | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| client_input_muted | ✓(voice) | ✓ | ✓ | ✓(limited) | ✗ | | | +| client_output_muted | ✓(voice) | ✓ | ✓ | ✓(limited) | ✗ | | | +| client_database_id | ✓ | ✓ | ✓ | ✗ | | ✓(cldbid) | ✓ | +| client_servergroups | ✓(groups) | ✓ | ✓ | ✗ | | | | +| client_away | ✓(away) | ✓ | ✓ | ✓ | ✗ | | | +| client_type | ✓ | ✓ | ✓ | ✗ | | | | +| client_flag_avatar | ✓ | ✓ | ✓(modified) | ✗ | ✗ | ✓(limited) | | +| client_description | ✓ | ✓ | ✓ | ✓ | ✓ | ✓(limited) | ✓(limited) | +| client_icon_id | ✓(icon) | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | +| client_channel_group_id | ✓(groups) | ✓ | ✓ | ✗ | ✗ | | | +| client_channel_group_inherited_channel_id | ✓(groups) | ✓ | ✓ | | | | | +| client_base64HashClientUID | ✓ | ✓(limited) | | | | | | + +**Notes:** +- `clientupdate` with `client_input_hardware=0` has 0 flood points (tab switch) +- `client_flag_avatar` is MD5 hash, not a boolean +- `client_badges` format: `overwolf=0:badges=GUID1=GUID2=...` + +### 4.2 Channel Variables + +**Key variables:** + +| Variable | channellist | channelinfo | notify(created/edited/moved) | channeledit | channelcreate | +|---|---|---|---|---|---| +| cid | ✓ | ✓ | ✓ | N/A | | +| pid (parent) | ✓ | ✓ | ✓(cpid) | ✓(cpid) | ✓(cpid) | +| channel_name | ✓ | ✓ | ✓ | ✓ | ✓ | +| channel_codec | ✓(voice) | ✓ | ✓ | ✓ | ✓ | +| channel_codec_quality | ✓(voice) | ✓ | ✓ | ✓ | ✓ | +| channel_maxclients | ✓(limits) | ✓ | ✓ | ✓ | ✓ | +| channel_order | ✓ | ✓ | ✓ | ✓(order) | ✓(order) | +| channel_flag_password | ✓(flags) | ✓ | ✓ | ✓ | ✗ | +| channel_icon_id | ✓(icon) | ✓ | ✓ | ✓(limited) | ✗ | +| channel_needed_talk_power | ✓(voice) | ✓ | ✓ | ✓ | ✓ | +| channel_flag_private | ✓ | ✗ | | | | +| seconds_empty | ✓(secondsempty) | ✓ | ✗ | | | +| total_clients | ✓ | ✗ | ✗ | | | + +**Notes:** +- `channel_flag_temporary` doesn't exist at all +- `channel_icon_id` changes via `channeledit` are semi-permanent (lost on restart) +- `channel_password` returns Base64(SHA1(Base64(SHA1(plaintext)) + virtualserver_keypair)) for non-Query clients + +### 4.3 Server Variables + +**All variables available in serverinfo. Key differences:** + +| Variable | serverlist | serverinfo | serverrequestconnectioninfo | serveredit | notifyserveredited | +|---|---|---|---|---|---| +| virtualserver_name | ✓ | ✓ | | ✓ | ✓ | +| virtualserver_maxclients | ✓(limited) | ✓ | | ✓ | | +| virtualserver_port | ✓ | ✓ | | ✓ | | +| virtualserver_autostart | ✓ | ✓ | | ✓ | | +| virtualserver_icon_id | ✓ | ✓ | | ✓ | ✓ | +| virtualserver_total_packetloss_total | ✓ | ✓ | ✓(limited) | | | +| virtualserver_total_ping | ✓ | ✓ | ✓(limited) | | | + +--- + +## 5. Voice Client Anti-Flood + +### 5.1 General Rules + +- Client starts with 0 points +- Every 0.5 seconds ("tick"): `virtualserver_antiflood_points_tick_reduce` points deducted (min 1) +- If `b_client_ignore_antiflood` → no points accumulated (but existing points still drain) +- Connection = 80 points (respects `b_client_ignore_antiflood`) +- `b_client_ignore_bans` bypasses IP block (but not anti-flood) +- Threshold: `virtualserver_antiflood_points_needed_command_block` blocks at EQUALITY + +### 5.2 Flood Points Per Action + +**High-cost actions (25 points):** +- `banadd`, `banclient`, `complainadd`, `complaindelall`, `complainlist` +- `channelcreate`, `channeldelete`, `channelmove`, `channeledit` +- `clientmove` (10), `clientkick`, `clientpoke`, `clientedit` +- `servergroupaddclient`, `servergroupdelclient`, `setclientchannelgroup` +- `clientdbdelete`, `clientdbedit`, `clientdbfind` (50!) +- `messageadd`, `messagelist`, `textmessagesend` (15) +- `logview` (50!) + +**Medium-cost actions (5-15 points):** +- Most permission operations: 5 points +- Most group operations: 5 points +- File operations: 5 points (except `ftinitupload`/`ftinitdownload` = 0) +- `channelsubscribe`: 158 points! + +**Zero-cost actions:** +- `clientdisconnect`, `clientgetvariables`, `clientinit`, `clientinitiv` +- `setwhisperlist`, `ftgetfilelist`, `ftinitupload`, `ftinitdownload` +- `clientmute`/`clientunmute` (0 with specific conditions) +- Internal client operations + +### 5.3 Connection Flow + +1. `clientinitiv` +2. `clientinit` +3. Set default channel (10 points) +4. Set badges (15 points) +5. `permissionlist` (5 points, if not cached) +6. `clientgetvariables` (0 points) +7. Subscribe channels (15-20 points) + +--- + +## 6. Security Level (Hashcash) + +### 6.1 How It Works + +- Hashcash variant using SHA1 +- Input: Public Key + unsigned 64-bit number (as string) +- Security level = number of leading zeros in 160-bit binary SHA1 hash +- Byte order: Big Endian, Bit order: Little Endian + +### 6.2 Growth Rate + +- Average 2^k hashes needed to reach level k from level 0 +- Doubles for each additional level + +**Time estimates (2009, modern CPUs ~4x faster):** +- Level 0-23: seconds +- Level 23-29: minutes +- Level 29-34: hours +- Level 35-39: days +- Level 40-43: months +- Level 44+: years + +### 6.3 Optimization + +- TeamSpeak uses single-threaded SHA1 (~1 MH/s on i5) +- Hashdog tool: multi-threaded, ~5 MH/s per core (~20-30x faster than TS) +- GPU (Hashcat): ~8.5 GH/s = 850,000% faster than TeamSpeak +- Level 33 on GTX 1080: ~1 second + +--- + +## 7. Snapshots + +### 7.1 What's Included + +- Virtual server settings (except port) including keypair +- Channels +- Client database +- Permissions for local groups (both types), clients (both types), and channels +- Group assignments + +### 7.2 What's NOT Included + +- Server port (auto-assigned on deploy) +- Files +- Bans +- Complaints +- Offline messages (but unread count preserved) + +### 7.3 Format + +``` +hash=Base64(SHA1(remaining_data))|snapshot_data +``` + +**Sections:** +1. `virtualserver_*` settings +2. `end_virtualserver|begin_channels` → channel list (tree order) +3. `end_channels|begin_clients` → client database (creation order) +4. `end_clients|begin_permissions|server_groups` → server group permissions +5. `end_groups|iid=0` → server group memberships (by cldbid, then sgid) +6. `end_relations|channel_groups` → channel group permissions +7. `end_groups|` → channel group memberships +8. `end_relations|client_flat` → client permissions (server level) +9. `end_flat|channel_flat` → channel permissions +10. `end_flat|channel_client_flat` → client-channel permissions +11. `end_flat|end_permissions` + +--- + +## 8. Other Protocols + +### 8.1 Protobuf Format + +**Two key data types:** + +**BigNum (Varint):** +``` +if x < 128: write byte x +else: write (x mod 128 OR 128), recurse with x >> 7 +``` + +**Binary data with length prefix:** BigNum length + raw data + +**File format:** Pairs of (BigNum identifier, data) until EOF. +- Identifier AND 7 = data type (0=BigNum, 1=64-bit, 2=binary, 5=32-bit) +- Identifier SHR 3 = field number + +### 8.2 Update Protocol + +- Current: Downloads `ts3-client-2` from `versions.teamspeak.com` (Protobuf format) +- Contains: server version (3.0.10, outdated), stable/beta/alpha client versions +- Updater images: gzip compressed (despite `.compress` extension) + +### 8.3 File Transfer + +- Send key received from `ftinitupload`/`ftinitdownload` to server IP:port +- No escaping, nothing before/after +- Upload: send key then data +- Download: receive data from server + +### 8.4 TSDNS + +- Input → lowercase → UTF-8/CESU-8 → append `0x0A 0x0D 0x0D 0x0D 0x0A` → TCP to port 41144 +- Returns IP or `404` +- `$PORT` = keep user's port + +### 8.5 DNS Resolution Order + +1. **SRV TS3:** `_ts3._udp.INPUT` — port overrides user input +2. **SRV TSDNS:** `_tsdns._tcp.DOMAIN` +3. **TSDNS:** Port 41144 +4. **DNS:** AAAA, A records (CNAME implicit) + +**First complete resolution wins. No fallback on connection failure.** + +### 8.6 Blacklist (v1) + +- UDP to `blacklist.teamspeak.com:17385` +- Send: `ip4:RESOLVED_IP` +- Response: `x,13371337133` where x = 0 (blacklisted), 1 (OK), 2 (greylisted) +- No response → connect anyway + +### 8.7 Blacklist2 (v2, since 3.1.6) + +- HTTPS POST to `blacklist2.teamspeak.com/check` +- Content-Type: `application/x-ts3blacklist` +- Protobuf-encoded `BlacklistInfoRequest` with: ip_address, domain_name, virtual_server_id, public_license_id, port, timestamp, valid_token_present, slots_ok +- Response: 8 bytes Protobuf with status_ip, status_domain, status_virtual_server_id, status_public_license_id (1=INVALID, 2=BLACKLISTED, 3=GREYLISTED, 4=NOT_LISTED) + +**IPv6 canonicalization bug (3.1.6-3.1.7):** Missing blocks filled with `3030` instead of `0`. Fixed in 3.1.8-beta1. + +### 8.8 Weblist (Server) + +- UDP to `weblist.teamspeak.com:2010` +- Packet format: 1 byte version (always 1), 2 bytes sequence number, 1 byte type (1=key request, 2=data), payload +- Update cycle: request key → send data (key + port + slots + clients + flags + name) +- Server updates every 10 minutes, retries at 1.3s and 2s intervals + +### 8.9 Badges + +- Stored as GUIDs on server +- Binary list from `badges-content.teamspeak.com/list` (Protobuf format) +- Cached in `cache/badges` +- Refreshed every 24 hours + +**Protobuf structure:** +1. BigNum: revision number +2. BigNum: Unix timestamp +3. For each badge: GUID, name, URL base, description, timestamp, unknown field (1-3) + +--- + +## 9. Server Error Codes + +**Complete error code list (from English page):** + +| Hex | Dec | Message | +|---|---|---| +| 0x0000 | 0 | ok | +| 0x0001 | 1 | undefined error | +| 0x0002 | 2 | not implemented | +| 0x0100 | 256 | command not found | +| 0x0101 | 257 | unable to bind network port | +| 0x0200 | 512 | invalid clientID | +| 0x0201 | 513 | nickname is already in use | +| 0x0203 | 515 | max clients protocol limit reached | +| 0x0204 | 516 | invalid client type | +| 0x0205 | 517 | already subscribed | +| 0x0206 | 518 | not logged in | +| 0x0207 | 519 | could not validate client identity | +| 0x0208 | 520 | invalid loginname or password | +| 0x0209 | 521 | too many clones already connected | +| 0x020a | 522 | client version outdated | +| 0x020b | 523 | client is online | +| 0x020c | 524 | client is flooding | +| 0x020d | 525 | client is modified | +| 0x020e | 526 | can not verify client at this moment | +| 0x020f | 527 | client is not permitted to log in | +| 0x0210 | 528 | client is not subscribed to the channel | +| 0x0300 | 768 | invalid channelID | +| 0x0301 | 769 | max channels protocol limit reached | +| 0x0302 | 770 | already member of channel | +| 0x0303 | 771 | channel name is already in use | +| 0x0304 | 772 | channel not empty | +| 0x0305 | 773 | can not delete default channel | +| 0x0306 | 774 | default channel requires permanent | +| 0x0307 | 775 | invalid channel flags | +| 0x0308 | 776 | permanent channel can not be child of non permanent channel | +| 0x0309 | 777 | channel maxclient reached | +| 0x030a | 778 | channel maxfamily reached | +| 0x030b | 779 | invalid channel order | +| 0x030c | 780 | channel does not support filetransfers | +| 0x030d | 781 | invalid channel password | +| 0x030e | 782 | channel is private channel | +| 0x030f | 783 | invalid security hash supplied by client | +| 0x0400 | 1024 | invalid serverID | +| 0x0401 | 1025 | server is running | +| 0x0402 | 1026 | server is shutting down | +| 0x0403 | 1027 | server maxclient reached | +| 0x0404 | 1028 | invalid server password | +| 0x0405 | 1029 | deployment active | +| 0x0406 | 1030 | unable to stop own server | +| 0x0407 | 1031 | server is virtual | +| 0x0408 | 1032 | server wrong machineID | +| 0x0409 | 1033 | server is not running | +| 0x040a | 1034 | server is booting up | +| 0x040b | 1035 | server got an invalid status | +| 0x040c | 1036 | server modal quit | +| 0x040d | 1037 | server version is too old for command | +| 0x0410 | 1040 | server blacklisted | +| 0x0500 | 1280 | database error | +| 0x0501 | 1281 | database empty result set | +| 0x0502 | 1282 | database duplicate entry | +| 0x0503 | 1283 | database no modifications | +| 0x0504 | 1284 | database invalid constraint | +| 0x0505 | 1285 | database reinvoke command | +| 0x0600 | 1536 | invalid quote | +| 0x0601 | 1537 | invalid parameter count | +| 0x0602 | 1538 | invalid parameter | +| 0x0603 | 1539 | parameter not found | +| 0x0604 | 1540 | convert error | +| 0x0605 | 1541 | invalid parameter size | +| 0x0606 | 1542 | missing required parameter | +| 0x0607 | 1543 | invalid checksum | +| 0x0700 | 1792 | virtual server got a critical error | +| 0x0701 | 1793 | connection lost | +| 0x0702 | 1794 | not connected | +| 0x0703 | 1795 | no cached connection info | +| 0x0704 | 1796 | currently not possible | +| 0x0705 | 1797 | failed connection initialization | +| 0x0706 | 1798 | could not resolve hostname | +| 0x0707 | 1799 | invalid server connection handler ID | +| 0x0708 | 1800 | could not initialize Input Manager | +| 0x0709 | 1801 | client library not initialized | +| 0x070a | 1802 | server library not initialized | +| 0x070b | 1803 | too many whisper targets | +| 0x070c | 1804 | no whisper targets found | +| 0x0800 | 2048 | invalid file name | +| 0x0801 | 2049 | invalid file permissions | +| 0x0802 | 2050 | file already exists | +| 0x0803 | 2051 | file not found | +| 0x0804 | 2052 | file input/output error | +| 0x0805 | 2053 | invalid file transfer ID | +| 0x0806 | 2054 | invalid file path | +| 0x0807 | 2055 | no files available | +| 0x0808 | 2056 | overwrite excludes resume | +| 0x0809 | 2057 | invalid file size | +| 0x080a | 2058 | file already in use | +| 0x080b | 2059 | could not open file transfer connection | +| 0x080c | 2060 | no space left on device | +| 0x080d | 2061 | file exceeds file system's maximum file size | +| 0x080e | 2062 | file transfer connection timeout | +| 0x080f | 2063 | lost file transfer connection | +| 0x0810 | 2064 | file exceeds supplied file size | +| 0x0811 | 2065 | file transfer complete | +| 0x0812 | 2066 | file transfer canceled | +| 0x0813 | 2067 | file transfer interrupted | +| 0x0814 | 2068 | file transfer server quota exceeded | +| 0x0815 | 2069 | file transfer client quota exceeded | +| 0x0816 | 2070 | file transfer reset | +| 0x0817 | 2071 | file transfer limit reached | +| 0x0900 | 2304 | preprocessor disabled | +| 0x0901 | 2305 | internal preprocessor | +| 0x0902 | 2306 | internal encoder | +| 0x0903 | 2307 | internal playback | +| 0x0904 | 2308 | no capture device available | +| 0x0905 | 2309 | no playback device available | +| 0x0906 | 2310 | could not open capture device | +| 0x0907 | 2311 | could not open playback device | +| 0x090f | 2319 | device still in use | +| 0x0910 | 2320 | device already registered | +| 0x0911 | 2321 | device not registered/known | +| 0x0912 | 2322 | unsupported frequency | +| 0x0913 | 2323 | invalid channel count | +| 0x0a00 | 2560 | invalid group ID | +| 0x0a01 | 2561 | duplicate entry | +| 0x0a02 | 2562 | invalid permission ID | +| 0x0a03 | 2563 | empty result set | +| 0x0a04 | 2564 | access to default group is forbidden | +| 0x0a05 | 2565 | invalid size | +| 0x0a06 | 2566 | invalid value | +| 0x0a07 | 2567 | group is not empty | +| 0x0a08 | 2568 | insufficient client permissions | +| 0x0a09 | 2569 | insufficient group modify power | +| 0x0a0a | 2570 | insufficient permission modify power | +| 0x0a0b | 2571 | template group is currently used | +| 0x0a0c | 2572 | permission error | +| 0x0b00 | 2816 | virtualserver limit reached | +| 0x0b01 | 2817 | max slot limit reached | +| 0x0b02 | 2818 | license file not found | +| 0x0b03 | 2819 | license date not ok | +| 0x0b04 | 2820 | unable to connect to accounting server | +| 0x0b05 | 2821 | unknown accounting error | +| 0x0b06 | 2822 | accounting server error | +| 0x0b07 | 2823 | instance limit reached | +| 0x0b08 | 2824 | instance check error | +| 0x0b09 | 2825 | license file invalid | +| 0x0b0a | 2826 | virtualserver is running elsewhere | +| 0x0b0b | 2827 | virtualserver running in same instance already | +| 0x0b0c | 2828 | virtualserver already started | +| 0x0b0d | 2829 | virtualserver not started | +| 0x0c00 | 3072 | invalid message id | +| 0x0d00 | 3328 | invalid ban id | +| 0x0d01 | 3329 | connection failed, you are banned | +| 0x0d02 | 3330 | rename failed, new name is banned | +| 0x0d03 | 3331 | flood ban | +| 0x0e00 | 3584 | unable to initialize tts | +| 0x0f00 | 3840 | invalid privilege key | +| 0x1000 | 4096 | VoIP pjsua error | +| 0x1100 | 4352 | provisioning invalid password | +| 0x1101 | 4353 | provisioning invalid request | +| 0x1102 | 4354 | no (more) slots available | +| 0x1103 | 4355 | pool missing | +| 0x1104 | 4356 | pool unknown | +| 0x1105 | 4357 | unknown ip location | +| 0x1106 | 4358 | internal error (tries exceeded) | +| 0x1107 | 4359 | too many slots requested | +| 0x1108 | 4360 | too many reserved | +| 0x1109 | 4361 | could not connect to provisioning server | +| 0x1110 | 4368 | authentication server not connected | +| 0x1111 | 4369 | authentication data too large | +| 0x1112 | 4370 | already initialized | +| 0x1113 | 4371 | not initialized | +| 0x1114 | 4372 | already connecting | +| 0x1115 | 4373 | already connected | +| 0x1116 | 4374 | not connected | +| 0x1117 | 4375 | io_error | +| 0x1118 | 4376 | invalid timeout | +| 0x1119 | 4377 | ts3server not found | +| 0x111A | 4378 | unknown permissionID | + +--- + +## 10. Permission IDs + +**Source:** https://yat.qa/resources/permission-ids/ (English) + +> See ReSpeak/tsdeclarations/Permissions.csv for the complete machine-readable list. + +--- + +## 11. Client Versions + +**Source:** https://yat.qa/resources/client-versions/ (English) + +> See ReSpeak/tsdeclarations/Versions.csv for the complete machine-readable list with version hashes. + +--- + +## 12. Badges + +**Source:** https://yat.qa/ressourcen/abzeichen-badges/ (German) + +> See ReSpeak/tsdeclarations/Badges.csv for the complete machine-readable list. + +--- + +*Fetched and compiled on 2026-06-11* diff --git a/docs/verification/test-environment-requirements.md b/docs/verification/test-environment-requirements.md new file mode 100644 index 0000000..8dd96f7 --- /dev/null +++ b/docs/verification/test-environment-requirements.md @@ -0,0 +1,243 @@ +# Automated Test Environment Requirements + +**Date:** 2026-06-11 +**Purpose:** Define what's needed for a fully automated test system + +--- + +## 1. Current Test Infrastructure + +### What's Automated + +| Area | Status | +|---|---| +| Rust unit/integration tests | ✅ CI on Ubuntu | +| Rust static analysis (clippy) | ✅ Advisory | +| Flutter analyze + test | ✅ CI on Ubuntu | +| Supply-chain checks | ✅ CI | +| License inventories | ✅ CI | +| Audio benchmarks | ⚠️ Advisory only | +| iOS unsigned build | ✅ CI on macOS | + +### What's Missing + +| Gap | Impact | +|---|---| +| Android CI build or test | Android verification blocked | +| iOS device/simulator test | Audio session untested | +| Windows CI | PTT and audio untested | +| macOS CI | Native audio untested | +| Linux CI (non-Ubuntu) | Portal behavior untested | +| Audio quality metrics | No POLQA/PESQ/ViSQOL | +| Network condition simulation | No latency/packet loss testing | +| Integration test with real server | E2E excluded from CI | +| Performance regression gates | Benchmarks advisory only | + +--- + +## 2. Platform Requirements + +### iOS / iPadOS + +| Requirement | Details | +|---|---| +| Minimum OS | iOS 16+ (CoreML Silero VAD) | +| Hardware | Physical iPhone (A12+), physical iPad | +| Simulator | UI/audio session mock testing | +| Platform features | AVAudioSession, CoreML VAD, haptics, push-to-talk | + +### Android + +| Requirement | Details | +|---|---| +| Minimum SDK | API 28 (Android 9) | +| Hardware | Physical device (arm64), emulator for CI | +| Platform features | Oboe audio, AudioManager, permissions, foreground service | + +### macOS + +| Requirement | Details | +|---|---| +| Minimum OS | macOS 13+ (CoreML Silero VAD) | +| Hardware | Apple Silicon Mac (primary), Intel Mac (compatibility) | +| Platform features | CoreAudio VoiceProcessingIO, Event Tap PTT, permissions | + +### Windows + +| Requirement | Details | +|---|---| +| Minimum OS | Windows 10+ | +| Hardware | Windows PC with audio hardware | +| Platform features | cpal audio, Raw Input PTT, Credential Manager | + +### Linux + +| Requirement | Details | +|---|---| +| Environment | GNOME on Wayland | +| Hardware | Linux PC with audio hardware | +| Platform features | cpal capture, SDL2 playback, D-Bus GlobalShortcuts | + +--- + +## 3. Physical Devices Needed + +| Device | Purpose | Est. Cost | +|---|---|---| +| iPhone 14+ (A15+) | iOS audio, CoreML VAD, PTT | $600-800 | +| iPad (A12+) | iPadOS layout, audio session | $350-500 | +| Android phone (arm64) | Android audio, Oboe | $200-400 | +| Android tablet | Layout testing | $200-300 | +| Apple Silicon Mac | macOS build/test, iOS Simulator | (dev machine) | +| Intel Mac | macOS x86_64 compatibility | $500-800 (used) | +| Windows PC | Windows PTT, audio | $500-800 | +| Linux PC | GNOME/Wayland, PipeWire | $500-800 | +| USB headset | Audio device switching | $30-60 | +| Bluetooth earbuds | Bluetooth audio route | $50-150 | +| **Total** | | **$2,400-4,200** | + +--- + +## 4. Audio Testing Tools + +| Tool | Purpose | Cost | +|---|---|---| +| **ViSQOL** (Google, open-source) | Speech quality metric | Free | +| **PESQ / POLQA** | ITU-T speech quality | $500-2000 (license) | +| **Virtual audio devices** | Software loopback for CI | Free (BlackHole, VB-Audio, snd-aloop) | +| **Opus test vectors** | Codec conformance | Free (IETF) | +| **Custom DSP analysis** | THD, SNR, frequency response | Build in-house | + +--- + +## 5. Network Simulation Tools + +| Tool | Purpose | Cost | +|---|---|---| +| **tc (traffic control)** | Linux latency/jitter/packet loss | Free | +| **Network Link Conditioner** | Apple's built-in network impairment | Free | +| **clumsy / NetLimiter** | Windows network impairment | Free / $30 | +| **comcast** | Cross-platform network impairment | Free | +| **Toxiproxy** | TCP proxy with configurable latency | Free | + +--- + +## 6. Test Automation Architecture + +### Test Layers + +``` +┌─────────────────────────────────────────────────────────────┐ +│ SYS.4 System Integration │ +│ Real devices, real servers, real networks, store builds │ +├─────────────────────────────────────────────────────────────┤ +│ SWE.6 Software Verification │ +│ MVP acceptance matrix, E2E flows, audio quality │ +├─────────────────────────────────────────────────────────────┤ +│ SWE.5 Software Integration │ +│ Flutter ↔ Bridge ↔ Rust ↔ Protocol, platform channels │ +├─────────────────────────────────────────────────────────────┤ +│ SWE.4 Unit Tests │ +│ Rust crate tests, Flutter widget/service tests, mocks │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Recommended Test Matrix + +| Test Type | Runner | Frequency | Blocking? | +|---|---|---|---| +| Rust `cargo test` | Ubuntu CI | Every PR | Yes | +| Rust `cargo clippy` | Ubuntu CI | Every PR | Advisory | +| Flutter `analyze` + `test` | Ubuntu CI | Every PR | Yes | +| Supply-chain | Ubuntu CI | Every PR | Yes | +| iOS unsigned build | macOS CI | Every PR | Yes | +| Android build (multi-ABI) | Ubuntu CI + NDK | Every PR | Yes | +| Windows build + smoke | Windows runner | Every PR | Yes | +| macOS build + smoke | macOS runner | Every PR | Yes | +| Audio benchmarks | Ubuntu CI | Every PR | Advisory | +| E2E (live server) | Dedicated runner | Nightly | No | +| Audio quality (loopback) | Device runners | Weekly | Advisory | +| Network condition tests | Linux + tc | Weekly | Advisory | + +--- + +## 7. Cloud Testing Services + +| Service | Use Case | Est. Monthly Cost | +|---|---|---| +| Firebase Test Lab | Android device matrix | $0-150 (free tier) | +| BrowserStack App Live | Real iOS + Android devices | $200-400 | +| AWS Device Farm | Automated device testing | $0.17/device-minute | +| GitHub Actions | Current CI baseline | $0-100 | +| MacStadium | macOS CI for signed builds | $80-150 | + +--- + +## 8. Cost Estimates + +### Hardware (One-Time) + +| Item | Cost | +|---|---| +| iPhone 14+ | $700 | +| iPad | $400 | +| Android phone | $300 | +| Windows PC | $600 | +| Linux PC | $600 | +| Audio peripherals | $100 | +| **Total hardware** | **$2,700** | + +### Cloud Services (Monthly) + +| Service | Cost | +|---|---| +| GitHub Actions (public) | $0 | +| GitHub Actions (private) | $0-40 | +| MacStadium macOS runner | $80-150 | +| Firebase Test Lab | $0-150 | +| **Total monthly** | **$80-740** | + +### Maintenance Effort + +| Area | Effort | +|---|---| +| CI workflow maintenance | 2-4 hrs/week | +| Test fixture updates | 1-2 hrs/week | +| Device OS updates | 2-4 hrs/month | +| Benchmark reviews | 1-2 hrs/month | +| **Total maintenance** | **~15-25 hrs/month** | + +--- + +## 9. Implementation Roadmap + +### Phase 1: Foundation (Weeks 1-4) + +- [ ] Add Android build job to CI (NDK + cargo-ndk + multi-ABI) +- [ ] Add Windows build job to CI (windows-latest runner) +- [ ] Add macOS build + smoke job to CI +- [ ] Add Linux multi-distro build matrix (Docker) +- [ ] Enable `cargo clippy` as blocking check +- [ ] Add `cargo llvm-cov` coverage reporting + +### Phase 2: Device Integration (Weeks 5-8) + +- [ ] Acquire physical test devices +- [ ] Set up self-hosted runners for device-connected tests +- [ ] Implement audio loopback test harness +- [ ] Add Flutter integration tests with platform channels +- [ ] Set up Firebase Test Lab for Android device matrix +- [ ] Implement network condition test suite (tc-based) + +### Phase 3: Full Automation (Weeks 9-12) + +- [ ] Nightly E2E test against controlled TeamSpeak server +- [ ] Weekly audio quality regression suite on physical devices +- [ ] Automated Android multi-device testing (Firebase) +- [ ] Benchmark regression gates +- [ ] iOS TestFlight build + device smoke automation +- [ ] Windows/macOS signed build + smoke automation + +--- + +*Generated by test environment research agents on 2026-06-11*