voice-bridge
Verbindet Gruppen in Simple Voice Chat mit Voice-Channels in TeamSpeak und Discord („Crosstalk“). Jede Seite hört die beiden anderen: Discord und TeamSpeak bekommen je einen gemischten Stream, im Spiel kommt jeder externe Sprecher einzeln an (Lautstärke-Kategorie „Discord/TeamSpeak“).
| Modul | Läuft als | Inhalt |
|---|---|---|
plugin |
plugins/voice-bridge.jar auf Paper |
legt die Gruppen an, schickt/spielt Audio, Hinweis beim Beitritt |
bridge |
eigener Dienst (voice-bridge.jar) |
Discord-Bots (JDA + JDave), TeamSpeak-Clients (ts3j), Mischer (Concentus) |
protocol |
in beiden | UDP-Nachrichten Plugin ↔ Bridge (Standard: 127.0.0.1:24470) |
third_party/ts3j ist ein Git-Submodul (git submodule update --init), JitPack hat keinen aktuellen Build.
Bauen
./gradlew build
- Plugin:
plugin/build/libs/voice-bridge.jar - Bridge:
bridge/build/libs/voice-bridge.jar(Fat-Jar), starten mitjava --enable-native-access=ALL-UNNAMED -jar voice-bridge.jar config.yml
Verhalten
- Ein Raum ist aktiv, sobald auf mindestens zwei Seiten jemand ist.
- Bots verbinden sich nur, wenn der Raum aktiv ist und auf ihrer Seite jemand sitzt; danach bleiben
sie
lingerSeconds(Standard 15) verbunden. - TeamSpeak: eine ServerQuery über SSH (Port 10022) sieht alle Clients und Channels und belegt keinen
Slot. Raum-Clients verbinden sich nur bei Bedarf. Fehlende Channels legt die Query unter
parentChannelan. - Rechte: Servergruppe „Bridge“ (Kopie von „Normal“) plus
b_channel_create_permanent,b_channel_create_child,b_channel_create_modify_with_codec_opusvoice,b_client_ignore_antiflood,i_client_talk_power75. Darin: die Identität des Query-Logins und alle Raum-Identitäten. Kein Serveradmin nötig. - Discord: ein Bot pro Raum (ein Bot kann pro Server nur in einem Voice-Channel sein). Fehlende
Channels legt der Bot in
categoryan. Einladen mithttps://discord.com/oauth2/authorize?client_id=APP_ID&scope=bot&permissions=70255632(Kanäle sehen, verbinden, sprechen, Kanäle verwalten, Nickname ändern).
Config
Vorlage: bridge/config.example.yml. Die echte config.yml enthält Bot-Tokens und gehört nicht ins Repo.
teamspeakChannel und discordChannel pro Raum dürfen ein Name oder eine ID sein. Einen Namen löst die
Bridge beim Start auf (oder legt den Channel an) und schreibt die ID in die config.yml zurück, nur diese
Zeile, mit dem alten Namen als Kommentar. Die Datei muss dafür für den Dienst beschreibbar sein.
Stolpersteine
- glibc ≥ 2.38: Die
libdave.soaus JDave (und Discords eigene Builds) brauchen glibc 2.38 und GLIBCXX_3.4.32. Auf Debian 13 kein Problem, auf Ubuntu 22.04 lädt sie nicht („Cannot open library … dave….so“). Lokal hilft ein Debian-13-Loader: glibc und libstdc++ aus den trixie-Paketen entpacken undld-linux-x86-64.so.2 --library-path <libs>:$JAVA_HOME/lib:$JAVA_HOME/lib/server $JAVA_HOME/bin/java …starten. - TeamSpeak 6 (mhsl.eu): verlangt Security-Level 15, Nicknames höchstens 30 Zeichen.
Schnelle Reconnects lösen den Flood-Schutz aus (IP-Bann), deshalb Backoff beim Verbinden.
Den Bot-Identitäten am besten
b_client_ignore_antifloodgeben. - TeamSpeak-Query-Flood: Die Query sperrt die IP schon nach wenigen schnellen Befehlen (Instanz-Bann,
nicht in der Bann-Liste des Servers, läuft nach einigen Minuten ab). Die Bridge hält mindestens 1 s Abstand;
sauberer ist es, ihre IP in
query_ip_allowlist.txtdes TS-Servers einzutragen. - UIDs: ts3j rechnet die UID einer Identität anders als der TS6-Server. Eigene Clients erkennt die Bridge deshalb an ihrer Client-ID, nicht an der UID.
- Discord: Die ersten Pakete nach dem Beitritt schlagen beim Entschlüsseln fehl („Decrypt failed“), bis DAVE die Schlüssel ausgehandelt hat. Das ist normal.
- Mit
-Dvoicebridge.ts3debug=trueloggt ts3j das TeamSpeak-Protokoll (Fehlercodes vom Server).