음성
음성 봇은 — Lavalink와 @discordjs/voice를 포함해 — 코드 변경 없이 동작합니다. GameVox는 Discord의 음성 게이트웨이 프로토콜을 그대로 구사한 다음, AEAD-RTP 스트림을 합성 피어로서 기본 WebRTC SFU에 연결합니다.
호환 라이브러리
- Lavalink v3 + v4(Java. JDA / discord4j 등으로 앞단에 두는 JVM 봇)
- @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를 읽어 그곳에 연결하기만 하면 되며, 수동 라우팅은 필요 없습니다.
연결 절차
- 봇이 메인 게이트웨이(
gateway.gamevox.com)에channel_id를 담아op:4 Update Voice State를 보냅니다. - 메인 게이트웨이가 엔드포인트와 세션별 토큰을 담아
VOICE_STATE_UPDATE와VOICE_SERVER_UPDATE를 전달합니다. - 봇이
wss://{endpoint}/?v=8로 WSS를 열고,{server_id, user_id, session_id, token}을 담아op:0 Identify를 보냅니다. - 음성 게이트웨이가
ssrc,ip,port와 지원하는 암호화 모드를 담아op:2 Ready로 응답합니다. - 봇이 UDP IP 디스커버리를 수행합니다(74바이트 type
0x0001패킷 → type0x0002로 응답). - 봇이 선택한 암호화 모드를 담아
op:1 Select Protocol을 보냅니다. - 음성 게이트웨이가 32바이트
secret_key를 담아op:4 Session Description으로 응답합니다. - 봇이 합의한 모드로 AEAD 암호화한 Opus를 RTP로 전송합니다.
암호화 모드
Discord와 같이 두 가지 AEAD-RTPSize 모드를 지원합니다.
aead_aes256_gcm_rtpsize— 권장. 암호화된 페이로드 뒤에 붙인 4바이트 카운터에서 nonce를 유도하는 AES-256-GCM입니다.aead_xchacha20_poly1305_rtpsize— AES-NI가 없는 라이브러리를 위한 대체입니다.
예전 모드(xsalsa20_poly1305, _lite, _suffix)는 제공하지 않습니다. Discord가 2024년에 폐기했고 주요 라이브러리도 옮겨 갔습니다. 라이브러리가 옛 모드에 고정되어 있다면 업데이트하세요.
Lavalink 참고
Lavalink는 VOICE_SERVER_UPDATE에서 endpoint를 바로 읽고 스스로 UDP를 엽니다. 엔드포인트에 도달할 수만 있다면(도달합니다) Lavalink는 상대가 Discord가 아니라는 사실을 알지 못합니다.
테스트한 버전: Lavalink v3.7.x와 v4.0.x. 특정 버전에서 문제가 생기면 개발자 포털로 알려 주세요. CI에서 해당 버전을 고정해 검증하겠습니다.
지연 예산
브리지가 더하는 지연의 목표는 수신 UDP부터 SFU 송출까지 5 ms 미만입니다. 5 ms를 넘으면 음악이 어색하게 들립니다(음의 시작이 어긋나고 하이햇에 지터가 생깁니다). 브리지는 Opus를 그대로 통과시키고 트랜스코딩하지 않으므로, 핵심 비용은 복호화와 재패킷화입니다.
발화 이벤트
op:5 Speaking은 양방향이며 Discord와 같습니다. 음성 게이트웨이는 들어오는 사람 화자의 SSRC를 사용자 ID에 매핑하고, 봇이 연결 지을 수 있도록 {ssrc, user_id}를 담은 op:5를 전달합니다.
깔끔하게 종료하기
메인 게이트웨이에 channel_id: null로 op:4 Update Voice State를 보내면 세션이 정리됩니다. 음성 게이트웨이가 UDP 소켓을 닫고 합성 SFU 피어를 제거하므로, 듣고 있던 사람들은 즉시 오디오를 받지 않게 됩니다.
아직 지원하지 않는 것
- DAVE / E2EE — Discord의 채널별 종단 간 암호화 음성 모드. 아직 일정은 없습니다.
- 사운드보드 — 봇은 사운드보드 소리를 재생할 수 없습니다.
- 스테이지 채널 — 와이어에서는 받아들이지만, 청중과 발언자를 구분해 처리하지는 않습니다.