Update to v7
This commit is contained in:
parent
ca6d629006
commit
6ecbda1550
|
@ -34,8 +34,10 @@ impl WebSocketEvent for VoiceStateUpdate {}
|
||||||
/// Received to indicate which voice endpoint, token and guild_id to use;
|
/// Received to indicate which voice endpoint, token and guild_id to use;
|
||||||
pub struct VoiceServerUpdate {
|
pub struct VoiceServerUpdate {
|
||||||
pub token: String,
|
pub token: String,
|
||||||
/// Can be None in dm calls
|
/// The guild this voice server update is for
|
||||||
pub guild_id: Option<Snowflake>,
|
pub guild_id: Option<Snowflake>,
|
||||||
|
/// The private channel this voice server update is for
|
||||||
|
pub channel_id: Option<Snowflake>,
|
||||||
pub endpoint: Option<String>,
|
pub endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::types::{Snowflake, WebSocketEvent};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)]
|
||||||
|
/// Sent when another user connects to the voice server.
|
||||||
|
///
|
||||||
|
/// Contains the user id and "flags".
|
||||||
|
///
|
||||||
|
/// Not documented anywhere, if you know what this is, please reach out
|
||||||
|
///
|
||||||
|
/// {"op":18,"d":{"user_id":"1234567890","flags":2}}
|
||||||
|
pub struct VoiceClientConnectFlags {
|
||||||
|
pub user_id: Snowflake,
|
||||||
|
// Likely some sort of bitflags
|
||||||
|
pub flags: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for VoiceClientConnectFlags {}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)]
|
||||||
|
/// Sent when another user connects to the voice server.
|
||||||
|
///
|
||||||
|
/// Contains the user id and "platform".
|
||||||
|
///
|
||||||
|
/// Not documented anywhere, if you know what this is, please reach out
|
||||||
|
///
|
||||||
|
/// {"op":20,"d":{"user_id":"1234567890","platform":0}}
|
||||||
|
pub struct VoiceClientConnectPlatform {
|
||||||
|
pub user_id: Snowflake,
|
||||||
|
// Likely an enum
|
||||||
|
pub platform: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for VoiceClientConnectPlatform {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
use crate::types::{Snowflake, WebSocketEvent};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)]
|
||||||
|
/// Sent when another user disconnects from the voice server.
|
||||||
|
///
|
||||||
|
/// When received, the SSRC of the user should be discarded.
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#other-client-disconnection>
|
||||||
|
pub struct VoiceClientDisconnection {
|
||||||
|
pub user_id: Snowflake,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for VoiceClientDisconnection {}
|
|
@ -5,7 +5,14 @@ use serde::{Deserialize, Serialize};
|
||||||
/// Contains info on how often the client should send heartbeats to the server;
|
/// Contains info on how often the client should send heartbeats to the server;
|
||||||
///
|
///
|
||||||
/// Differs from the normal hello data in that discord sends heartbeat interval as a float.
|
/// Differs from the normal hello data in that discord sends heartbeat interval as a float.
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#heartbeating>
|
||||||
pub struct VoiceHelloData {
|
pub struct VoiceHelloData {
|
||||||
|
/// The voice gateway version.
|
||||||
|
///
|
||||||
|
/// Note: no idea why this is sent, we already specify the version when establishing a connection.
|
||||||
|
#[serde(rename = "v")]
|
||||||
|
pub version: u8,
|
||||||
/// How often a client should send heartbeats, in milliseconds
|
/// How often a client should send heartbeats, in milliseconds
|
||||||
pub heartbeat_interval: f64,
|
pub heartbeat_interval: f64,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,16 @@ use serde::{Deserialize, Serialize};
|
||||||
///
|
///
|
||||||
/// Contains info to begin a webrtc connection;
|
/// Contains info to begin a webrtc connection;
|
||||||
///
|
///
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload>
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#identify-structure>
|
||||||
pub struct VoiceIdentify {
|
pub struct VoiceIdentify {
|
||||||
/// Not needed when in a dm call
|
/// The ID of the guild or the private channel being connected to
|
||||||
pub server_id: Option<Snowflake>,
|
pub server_id: Snowflake,
|
||||||
pub user_id: Snowflake,
|
pub user_id: Snowflake,
|
||||||
pub session_id: String,
|
pub session_id: String,
|
||||||
pub token: String,
|
pub token: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// Undocumented field, but is also in discord client comms
|
|
||||||
pub video: Option<bool>,
|
pub video: Option<bool>,
|
||||||
|
// TODO: Add video streams
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebSocketEvent for VoiceIdentify {}
|
impl WebSocketEvent for VoiceIdentify {}
|
||||||
|
|
|
@ -2,19 +2,25 @@ use super::WebSocketEvent;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{value::RawValue, Value};
|
use serde_json::{value::RawValue, Value};
|
||||||
|
|
||||||
|
pub use client_connect::*;
|
||||||
|
pub use client_disconnect::*;
|
||||||
pub use hello::*;
|
pub use hello::*;
|
||||||
pub use identify::*;
|
pub use identify::*;
|
||||||
pub use ready::*;
|
pub use ready::*;
|
||||||
pub use select_protocol::*;
|
pub use select_protocol::*;
|
||||||
pub use session_description::*;
|
pub use session_description::*;
|
||||||
pub use speaking::*;
|
pub use speaking::*;
|
||||||
|
pub use voice_backend_version::*;
|
||||||
|
|
||||||
|
mod client_connect;
|
||||||
|
mod client_disconnect;
|
||||||
mod hello;
|
mod hello;
|
||||||
mod identify;
|
mod identify;
|
||||||
mod ready;
|
mod ready;
|
||||||
mod select_protocol;
|
mod select_protocol;
|
||||||
mod session_description;
|
mod session_description;
|
||||||
mod speaking;
|
mod speaking;
|
||||||
|
mod voice_backend_version;
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Clone)]
|
#[derive(Debug, Default, Serialize, Clone)]
|
||||||
/// The payload used for sending events to the webrtc gateway.
|
/// The payload used for sending events to the webrtc gateway.
|
||||||
|
@ -48,22 +54,41 @@ pub struct VoiceGatewayReceivePayload<'a> {
|
||||||
impl<'a> WebSocketEvent for VoiceGatewayReceivePayload<'a> {}
|
impl<'a> WebSocketEvent for VoiceGatewayReceivePayload<'a> {}
|
||||||
|
|
||||||
/// The modes of encryption available in webrtc connections;
|
/// The modes of encryption available in webrtc connections;
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-encryption-modes>
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#encryption-mode> and <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-encryption-modes>
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WebrtcEncryptionMode {
|
pub enum VoiceEncryptionMode {
|
||||||
#[default]
|
#[default]
|
||||||
// Documented
|
// Officially Documented
|
||||||
Xsalsa20Poly1305,
|
Xsalsa20Poly1305,
|
||||||
Xsalsa20Poly1305Suffix,
|
Xsalsa20Poly1305Suffix,
|
||||||
Xsalsa20Poly1305Lite,
|
Xsalsa20Poly1305Lite,
|
||||||
// Undocumented
|
// Officially Undocumented
|
||||||
Xsalsa20Poly1305LiteRtpsize,
|
Xsalsa20Poly1305LiteRtpsize,
|
||||||
AeadAes256Gcm,
|
AeadAes256Gcm,
|
||||||
AeadAes256GcmRtpsize,
|
AeadAes256GcmRtpsize,
|
||||||
AeadXchacha20Poly1305Rtpsize,
|
AeadXchacha20Poly1305Rtpsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The possible audio codecs to use
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum AudioCodec {
|
||||||
|
#[default]
|
||||||
|
Opus,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible video codecs to use
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
pub enum VideoCodec {
|
||||||
|
#[default]
|
||||||
|
VP8,
|
||||||
|
VP9,
|
||||||
|
H264,
|
||||||
|
}
|
||||||
|
|
||||||
// The various voice opcodes
|
// The various voice opcodes
|
||||||
pub const VOICE_IDENTIFY: u8 = 0;
|
pub const VOICE_IDENTIFY: u8 = 0;
|
||||||
pub const VOICE_SELECT_PROTOCOL: u8 = 1;
|
pub const VOICE_SELECT_PROTOCOL: u8 = 1;
|
||||||
|
@ -77,7 +102,12 @@ pub const VOICE_HELLO: u8 = 8;
|
||||||
pub const VOICE_RESUMED: u8 = 9;
|
pub const VOICE_RESUMED: u8 = 9;
|
||||||
/// See <https://discord-userdoccers.vercel.app/topics/opcodes-and-status-codes#voice-opcodes>
|
/// See <https://discord-userdoccers.vercel.app/topics/opcodes-and-status-codes#voice-opcodes>
|
||||||
pub const VOICE_VIDEO: u8 = 12;
|
pub const VOICE_VIDEO: u8 = 12;
|
||||||
pub const VOICE_CLIENT_DISCONENCT: u8 = 13;
|
pub const VOICE_CLIENT_DISCONNECT: u8 = 13;
|
||||||
|
pub const VOICE_SESSION_UPDATE: u8 = 14;
|
||||||
/// See <https://discord-userdoccers.vercel.app/topics/opcodes-and-status-codes#voice-opcodes>
|
/// See <https://discord-userdoccers.vercel.app/topics/opcodes-and-status-codes#voice-opcodes>
|
||||||
/// Sent with empty data from the client, the server responds with the voice backend version;
|
/// Sent with empty data from the client, the server responds with the voice backend version;
|
||||||
pub const VOICE_BACKEND_VERSION: u8 = 16;
|
pub const VOICE_BACKEND_VERSION: u8 = 16;
|
||||||
|
|
||||||
|
// These two get simultaenously fired when a user joins, one has flags and one has a platform
|
||||||
|
pub const VOICE_CLIENT_CONNECT_FLAGS: u8 = 18;
|
||||||
|
pub const VOICE_CLIENT_CONNECT_PLATFORM: u8 = 20;
|
||||||
|
|
|
@ -3,21 +3,24 @@ use std::net::Ipv4Addr;
|
||||||
use crate::types::WebSocketEvent;
|
use crate::types::WebSocketEvent;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::WebrtcEncryptionMode;
|
use super::VoiceEncryptionMode;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||||
/// The ready event for the webrtc stream;
|
/// The ready event for the webrtc stream;
|
||||||
///
|
///
|
||||||
/// Used to give info after the identify event;
|
/// Used to give info after the identify event;
|
||||||
///
|
///
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-ready-payload>
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#ready-structure>
|
||||||
pub struct VoiceReady {
|
pub struct VoiceReady {
|
||||||
/// See <https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpStreamStats/ssrc>
|
/// See <https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpStreamStats/ssrc>
|
||||||
pub ssrc: i32,
|
pub ssrc: i32,
|
||||||
pub ip: Ipv4Addr,
|
pub ip: Ipv4Addr,
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
/// The available encryption modes for the webrtc connection
|
/// The available encryption modes for the webrtc connection
|
||||||
pub modes: Vec<WebrtcEncryptionMode>,
|
pub modes: Vec<VoiceEncryptionMode>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub experiments: Vec<String>,
|
||||||
|
// TODO: Add video streams
|
||||||
// Heartbeat interval is also sent, but is "an erroneous field and should be ignored. The correct heartbeat_interval value comes from the Hello payload."
|
// Heartbeat interval is also sent, but is "an erroneous field and should be ignored. The correct heartbeat_interval value comes from the Hello payload."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +31,7 @@ impl Default for VoiceReady {
|
||||||
ip: Ipv4Addr::UNSPECIFIED,
|
ip: Ipv4Addr::UNSPECIFIED,
|
||||||
port: 0,
|
port: 0,
|
||||||
modes: Vec::new(),
|
modes: Vec::new(),
|
||||||
|
experiments: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,58 @@ use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::WebrtcEncryptionMode;
|
use super::VoiceEncryptionMode;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||||
/// An event sent by the client to the webrtc server, detailing what protocol, address and encryption to use;
|
/// An event sent by the client to the webrtc server, detailing what protocol, address and encryption to use;
|
||||||
///
|
///
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-example-select-protocol-payload>
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#select-protocol-structure>
|
||||||
pub struct SelectProtocol {
|
pub struct SelectProtocol {
|
||||||
/// The protocol to use. The only option detailed in discord docs is "udp"
|
/// The protocol to use. The only option chorus supports is [VoiceProtocol::Udp].
|
||||||
pub protocol: String,
|
pub protocol: VoiceProtocol,
|
||||||
pub data: SelectProtocolData,
|
pub data: SelectProtocolData,
|
||||||
|
/// The UUID4 RTC connection ID, used for analytics.
|
||||||
|
///
|
||||||
|
/// Note: Not recommended to set this
|
||||||
|
pub rtc_connection_id: Option<String>,
|
||||||
|
// TODO: Add codecs, what is a codec object
|
||||||
|
/// The possible experiments we want to enable
|
||||||
|
#[serde(rename = "experiments")]
|
||||||
|
pub enabled_experiments: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible protocol for sending a receiving voice data.
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#select-protocol-structure>
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum VoiceProtocol {
|
||||||
|
#[default]
|
||||||
|
/// Sending data via UDP, documented and the only protocol chorus supports.
|
||||||
|
Udp,
|
||||||
|
// Possible value, yet NOT RECOMMENED, AS CHORUS DOES NOT SUPPORT WEBRTC
|
||||||
|
//Webrtc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
/// The data field of the SelectProtocol Event
|
/// The data field of the SelectProtocol Event
|
||||||
///
|
///
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-example-select-protocol-payload>
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#protocol-data-structure>
|
||||||
pub struct SelectProtocolData {
|
pub struct SelectProtocolData {
|
||||||
/// Our external ip
|
/// Our external ip
|
||||||
pub address: Ipv4Addr,
|
pub address: Ipv4Addr,
|
||||||
/// Our external udp port
|
/// Our external udp port
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
/// The mode of encryption to use
|
/// The mode of encryption to use
|
||||||
pub mode: WebrtcEncryptionMode,
|
pub mode: VoiceEncryptionMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SelectProtocolData {
|
||||||
|
fn default() -> Self {
|
||||||
|
SelectProtocolData {
|
||||||
|
address: Ipv4Addr::UNSPECIFIED,
|
||||||
|
port: 0,
|
||||||
|
mode: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,39 @@
|
||||||
use super::WebrtcEncryptionMode;
|
use super::{AudioCodec, VideoCodec, VoiceEncryptionMode};
|
||||||
use crate::types::WebSocketEvent;
|
use crate::types::WebSocketEvent;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||||
/// Event that describes our encryption mode and secret key for encryption
|
/// Event that describes our encryption mode and secret key for encryption
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#session-description-structure>
|
||||||
pub struct SessionDescription {
|
pub struct SessionDescription {
|
||||||
/// The encryption mode we're using in webrtc
|
pub audio_codec: AudioCodec,
|
||||||
pub mode: WebrtcEncryptionMode,
|
pub video_codec: VideoCodec,
|
||||||
|
pub media_session_id: String,
|
||||||
|
/// The encryption mode to use
|
||||||
|
#[serde(rename = "mode")]
|
||||||
|
pub encryption_mode: VoiceEncryptionMode,
|
||||||
/// The secret key we'll use for encryption
|
/// The secret key we'll use for encryption
|
||||||
pub secret_key: [u8; 32],
|
pub secret_key: [u8; 32],
|
||||||
|
/// The keyframe interval in milliseconds
|
||||||
|
pub keyframe_interval: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebSocketEvent for SessionDescription {}
|
impl WebSocketEvent for SessionDescription {}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||||
|
/// Event that might be sent to update session parameters
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#session-update-structure>
|
||||||
|
pub struct SessionUpdate {
|
||||||
|
#[serde(rename = "audio_codec")]
|
||||||
|
pub new_audio_codec: Option<AudioCodec>,
|
||||||
|
|
||||||
|
#[serde(rename = "video_codec")]
|
||||||
|
pub new_video_codec: Option<VideoCodec>,
|
||||||
|
|
||||||
|
#[serde(rename = "media_session_id")]
|
||||||
|
pub new_media_session_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for SessionUpdate {}
|
||||||
|
|
|
@ -1,20 +1,28 @@
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::types::{Snowflake, WebSocketEvent};
|
||||||
|
|
||||||
/// Event that tells the server we are speaking;
|
/// Event that tells the server we are speaking;
|
||||||
///
|
///
|
||||||
/// Essentially, what allows us to send udp data and lights up the green circle around your avatar.
|
/// Essentially, what allows us to send udp data and lights up the green circle around your avatar.
|
||||||
///
|
///
|
||||||
/// See <https://discord.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload>
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#speaking-structure>
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||||
pub struct Speaking {
|
pub struct Speaking {
|
||||||
/// Data about the audio we're transmitting, its type
|
/// Data about the audio we're transmitting, its type
|
||||||
pub speaking: SpeakingBitflags,
|
pub speaking: SpeakingBitflags,
|
||||||
/// Assuming delay in milliseconds for the audio, should be 0 most of the time
|
|
||||||
pub delay: u64,
|
|
||||||
pub ssrc: i32,
|
pub ssrc: i32,
|
||||||
|
/// The user id of the speaking user, only sent by the server
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub user_id: Option<Snowflake>,
|
||||||
|
/// Delay in milliseconds, not sent by the server
|
||||||
|
#[serde(default)]
|
||||||
|
pub delay: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for Speaking {}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Bitflags of speaking types;
|
/// Bitflags of speaking types;
|
||||||
///
|
///
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
use crate::types::WebSocketEvent;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
|
||||||
|
/// Received from the server to describe the backend version.
|
||||||
|
///
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#voice-backend-version>
|
||||||
|
pub struct VoiceBackendVersion {
|
||||||
|
/// The voice backend's version
|
||||||
|
#[serde(rename = "voice")]
|
||||||
|
pub voice_version: String,
|
||||||
|
/// The WebRTC worker's version
|
||||||
|
#[serde(rename = "rtc_worker")]
|
||||||
|
pub rtc_worker_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketEvent for VoiceBackendVersion {}
|
96
src/voice.rs
96
src/voice.rs
|
@ -19,9 +19,10 @@ use crate::errors::VoiceGatewayError;
|
||||||
use crate::gateway::{GatewayEvent, HEARTBEAT_ACK_TIMEOUT};
|
use crate::gateway::{GatewayEvent, HEARTBEAT_ACK_TIMEOUT};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
self, SelectProtocol, Speaking, VoiceGatewayReceivePayload, VoiceGatewaySendPayload,
|
self, SelectProtocol, Speaking, VoiceGatewayReceivePayload, VoiceGatewaySendPayload,
|
||||||
VoiceIdentify, WebSocketEvent, VOICE_BACKEND_VERSION, VOICE_HEARTBEAT, VOICE_HEARTBEAT_ACK,
|
VoiceIdentify, WebSocketEvent, VOICE_BACKEND_VERSION, VOICE_CLIENT_CONNECT_FLAGS,
|
||||||
|
VOICE_CLIENT_CONNECT_PLATFORM, VOICE_CLIENT_DISCONNECT, VOICE_HEARTBEAT, VOICE_HEARTBEAT_ACK,
|
||||||
VOICE_HELLO, VOICE_IDENTIFY, VOICE_READY, VOICE_RESUME, VOICE_SELECT_PROTOCOL,
|
VOICE_HELLO, VOICE_IDENTIFY, VOICE_READY, VOICE_RESUME, VOICE_SELECT_PROTOCOL,
|
||||||
VOICE_SESSION_DESCRIPTION, VOICE_SPEAKING,
|
VOICE_SESSION_DESCRIPTION, VOICE_SESSION_UPDATE, VOICE_SPEAKING,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::voice_events::VoiceEvents;
|
use self::voice_events::VoiceEvents;
|
||||||
|
@ -199,7 +200,7 @@ impl VoiceGateway {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub async fn new(websocket_url: String) -> Result<VoiceGatewayHandle, VoiceGatewayError> {
|
pub async fn new(websocket_url: String) -> Result<VoiceGatewayHandle, VoiceGatewayError> {
|
||||||
// Append the needed things to the websocket url
|
// Append the needed things to the websocket url
|
||||||
let processed_url = format!("wss://{}/?v=4", websocket_url);
|
let processed_url = format!("wss://{}/?v=7", websocket_url);
|
||||||
trace!("Created voice socket url: {}", processed_url.clone());
|
trace!("Created voice socket url: {}", processed_url.clone());
|
||||||
|
|
||||||
let (websocket_stream, _) = match connect_async_tls_with_config(
|
let (websocket_stream, _) = match connect_async_tls_with_config(
|
||||||
|
@ -357,6 +358,19 @@ impl VoiceGateway {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VOICE_BACKEND_VERSION => {
|
||||||
|
trace!("VGW: Received Backend Version");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.backend_version;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!(
|
||||||
|
"Failed to parse VOICE_BACKEND_VERSION ({})",
|
||||||
|
result.err().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
VOICE_SESSION_DESCRIPTION => {
|
VOICE_SESSION_DESCRIPTION => {
|
||||||
trace!("VGW: Received Session Description");
|
trace!("VGW: Received Session Description");
|
||||||
|
|
||||||
|
@ -364,12 +378,75 @@ impl VoiceGateway {
|
||||||
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
warn!(
|
warn!(
|
||||||
"Failed to parse VOICE_SELECT_PROTOCOL ({})",
|
"Failed to parse VOICE_SESSION_DESCRIPTION ({})",
|
||||||
result.err().unwrap()
|
result.err().unwrap()
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VOICE_SESSION_UPDATE => {
|
||||||
|
trace!("VGW: Received Session Update");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.session_update;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!(
|
||||||
|
"Failed to parse VOICE_SESSION_UPDATE ({})",
|
||||||
|
result.err().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOICE_SPEAKING => {
|
||||||
|
trace!("VGW: Received Speaking");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.speaking;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!("Failed to parse VOICE_SPEAKING ({})", result.err().unwrap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOICE_CLIENT_DISCONNECT => {
|
||||||
|
trace!("VGW: Received Client Disconnect");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.client_disconnect;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!(
|
||||||
|
"Failed to parse VOICE_CLIENT_DISCONNECT ({})",
|
||||||
|
result.err().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOICE_CLIENT_CONNECT_FLAGS => {
|
||||||
|
trace!("VGW: Received Client Connect Flags");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.client_connect_flags;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!(
|
||||||
|
"Failed to parse VOICE_CLIENT_CONNECT_FLAGS ({})",
|
||||||
|
result.err().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOICE_CLIENT_CONNECT_PLATFORM => {
|
||||||
|
trace!("VGW: Received Client Connect Platform");
|
||||||
|
|
||||||
|
let event = &mut self.events.lock().await.client_connect_platform;
|
||||||
|
let result = VoiceGateway::handle_event(gateway_payload.data.get(), event).await;
|
||||||
|
if result.is_err() {
|
||||||
|
warn!(
|
||||||
|
"Failed to parse VOICE_CLIENT_CONNECT_PLATFORM ({})",
|
||||||
|
result.err().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We received a heartbeat from the server
|
// We received a heartbeat from the server
|
||||||
// "Discord may send the app a Heartbeat (opcode 1) event, in which case the app should send a Heartbeat event immediately."
|
// "Discord may send the app a Heartbeat (opcode 1) event, in which case the app should send a Heartbeat event immediately."
|
||||||
VOICE_HEARTBEAT => {
|
VOICE_HEARTBEAT => {
|
||||||
|
@ -563,14 +640,23 @@ struct VoiceHeartbeatThreadCommunication {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod voice_events {
|
pub mod voice_events {
|
||||||
use crate::types::{SessionDescription, VoiceReady};
|
use crate::types::{
|
||||||
|
SessionDescription, SessionUpdate, VoiceBackendVersion, VoiceClientConnectFlags,
|
||||||
|
VoiceClientConnectPlatform, VoiceClientDisconnection, VoiceReady,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct VoiceEvents {
|
pub struct VoiceEvents {
|
||||||
pub voice_ready: GatewayEvent<VoiceReady>,
|
pub voice_ready: GatewayEvent<VoiceReady>,
|
||||||
|
pub backend_version: GatewayEvent<VoiceBackendVersion>,
|
||||||
pub session_description: GatewayEvent<SessionDescription>,
|
pub session_description: GatewayEvent<SessionDescription>,
|
||||||
|
pub session_update: GatewayEvent<SessionUpdate>,
|
||||||
|
pub speaking: GatewayEvent<Speaking>,
|
||||||
|
pub client_disconnect: GatewayEvent<VoiceClientDisconnection>,
|
||||||
|
pub client_connect_flags: GatewayEvent<VoiceClientConnectFlags>,
|
||||||
|
pub client_connect_platform: GatewayEvent<VoiceClientConnectPlatform>,
|
||||||
pub error: GatewayEvent<VoiceGatewayError>,
|
pub error: GatewayEvent<VoiceGatewayError>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue