Голос
Голосовые боты, включая Lavalink и @discordjs/voice, работают без изменений кода. GameVox дословно реализует протокол голосового шлюза Discord, а затем передаёт поток AEAD-RTP в собственный WebRTC SFU как синтетический участник.
Совместимые библиотеки
- Lavalink v3 + v4 (Java; JVM-боты, работающие с ним через JDA / discord4j и т. д.)
- @discordjs/voice (Node)
- discord.py с голосовыми дополнениями (
PyNaCl) - JDA с аудиомодулем
- discord4j
- Eris с необязательными голосовыми зависимостями
Эндпоинты
По регионам: бот подключается к тому региону, который укажет событие VOICE_SERVER_UPDATE.
compatible-voice-gateway-us.gamevox.comcompatible-voice-gateway-eu.gamevox.comcompatible-voice-gateway-ap.gamevox.com
Основной шлюз указывает нужный регион в зависимости от расположения SFU канала. Библиотека бота читает endpoint из события и подключается туда, ручная маршрутизация не нужна.
Порядок подключения
- Бот отправляет
op:4 Update Voice Stateв основной шлюз (gateway.gamevox.com) сchannel_id. - Основной шлюз отправляет
VOICE_STATE_UPDATE+VOICE_SERVER_UPDATEс эндпоинтом и токеном для этой сессии. - Бот открывает WSS к
wss://{endpoint}/?v=8и отправляетop:0 Identifyс{server_id, user_id, session_id, token}. - Голосовой шлюз отвечает
op:2 Readyсssrc,ip,portи поддерживаемыми режимами шифрования. - Бот выполняет обнаружение IP по UDP (74-байтовый пакет типа
0x0001→ эхо-ответ типа0x0002). - Бот отправляет
op:1 Select Protocolс выбранным режимом шифрования. - Голосовой шлюз отвечает
op:4 Session Descriptionс 32-байтовымsecret_key. - Бот передаёт Opus по RTP, зашифрованный AEAD в согласованном режиме.
Режимы шифрования
Поддерживаются два режима AEAD-RTPSize, как в Discord:
aead_aes256_gcm_rtpsize: предпочтительный. AES-256-GCM с nonce, получаемым из 4-байтового счётчика, добавленного к зашифрованному payload.aead_xchacha20_poly1305_rtpsize: запасной для библиотек без AES-NI.
Старые режимы (xsalsa20_poly1305, _lite, _suffix) не предлагаются: Discord отказался от них в 2024 году, и основные библиотеки уже перешли на новые. Если библиотека вашего бота привязана к старому режиму, обновите её.
Заметки о Lavalink
Lavalink берёт endpoint прямо из VOICE_SERVER_UPDATE и сам подключается по UDP. Пока эндпоинт доступен (а он доступен), Lavalink не знает, что общается не с Discord.
Проверенные версии: Lavalink v3.7.x и v4.0.x. Если вы столкнулись с проблемой конкретной версии, сообщите о ней в портале разработчиков, чтобы мы добавили вашу версию в CI.
Бюджет задержки
Целевая задержка, добавляемая мостом: менее 5 мс от входящего UDP до выхода из SFU. При задержке больше 5 мс музыка звучит неправильно (плывёт тайминг атак нот, дрожат хай-хэты). Мост пропускает Opus без перекодирования, поэтому основные затраты это расшифровка и переупаковка.
События речи
op:5 Speaking работает в обе стороны и совпадает с Discord. Голосовой шлюз сопоставляет SSRC входящих говорящих людей с их ID пользователей и отправляет op:5 с {ssrc, user_id}, чтобы бот мог их связать.
Корректная остановка
Отправка op:4 Update Voice State с channel_id: null в основной шлюз завершает сессию. Голосовой шлюз закрывает UDP-сокет и удаляет синтетического участника SFU; слушатели сразу перестают получать звук.
Пока не поддерживается
- DAVE / E2EE: режим сквозного шифрования голоса для отдельных каналов в Discord. Сроков пока нет.
- Саундборд: боты не могут воспроизводить звуки саундборда.
- Stage-каналы: принимаются протоколом, но без отдельной обработки слушателей и выступающих.