discord_stream_rs/
utils.rs1use thiserror::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum StreamType {
7 Guild,
8 Call,
9}
10
11impl std::fmt::Display for StreamType {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 match self {
14 StreamType::Guild => write!(f, "guild"),
15 StreamType::Call => write!(f, "call"),
16 }
17 }
18}
19
20#[derive(Debug, Clone)]
21pub struct StreamKey {
22 pub kind: StreamType,
23 pub guild_id: Option<String>,
24 pub channel_id: String,
25 pub user_id: String,
26}
27
28#[derive(Debug, Error)]
29pub enum StreamKeyError {
30 #[error("invalid stream key type: {0}")]
31 InvalidType(String),
32 #[error("stream key too short: {0}")]
33 TooShort(String),
34}
35
36pub fn parse_stream_key(key: &str) -> Result<StreamKey, StreamKeyError> {
39 let mut parts: Vec<&str> = key.splitn(5, ':').collect();
40 let kind_str = parts.remove(0);
41 let kind = match kind_str {
42 "guild" => StreamType::Guild,
43 "call" => StreamType::Call,
44 other => return Err(StreamKeyError::InvalidType(other.to_owned())),
45 };
46
47 match kind {
48 StreamType::Guild => {
49 if parts.len() < 3 {
50 return Err(StreamKeyError::TooShort(key.to_owned()));
51 }
52 Ok(StreamKey {
53 kind,
54 guild_id: Some(parts[0].to_owned()),
55 channel_id: parts[1].to_owned(),
56 user_id: parts[2].to_owned(),
57 })
58 }
59 StreamType::Call => {
60 if parts.len() < 2 {
61 return Err(StreamKeyError::TooShort(key.to_owned()));
62 }
63 Ok(StreamKey {
64 kind,
65 guild_id: None,
66 channel_id: parts[0].to_owned(),
67 user_id: parts[1].to_owned(),
68 })
69 }
70 }
71}
72
73pub fn generate_stream_key(
75 kind: StreamType,
76 guild_id: Option<&str>,
77 channel_id: &str,
78 user_id: &str,
79) -> String {
80 match kind {
81 StreamType::Guild => {
82 format!(
83 "guild:{}:{}:{}",
84 guild_id.unwrap_or(""),
85 channel_id,
86 user_id
87 )
88 }
89 StreamType::Call => {
90 format!("call:{}:{}", channel_id, user_id)
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum VideoCodec {
101 H264,
102 H265,
103 Vp8,
104 Vp9,
105 Av1,
106}
107
108impl std::fmt::Display for VideoCodec {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 match self {
111 VideoCodec::H264 => write!(f, "H264"),
112 VideoCodec::H265 => write!(f, "H265"),
113 VideoCodec::Vp8 => write!(f, "VP8"),
114 VideoCodec::Vp9 => write!(f, "VP9"),
115 VideoCodec::Av1 => write!(f, "AV1"),
116 }
117 }
118}
119
120#[derive(Debug, Error)]
121#[error("unknown codec: {0}")]
122pub struct UnknownCodecError(pub String);
123
124pub fn normalize_video_codec(s: &str) -> Result<VideoCodec, UnknownCodecError> {
127 let upper = s.to_uppercase();
128 if upper.contains("264") || upper.contains("AVC") {
129 return Ok(VideoCodec::H264);
130 }
131 if upper.contains("265") || upper.contains("HEVC") {
132 return Ok(VideoCodec::H265);
133 }
134 if upper.contains("VP8") {
135 return Ok(VideoCodec::Vp8);
136 }
137 if upper.contains("VP9") {
138 return Ok(VideoCodec::Vp9);
139 }
140 if upper.contains("AV1") {
141 return Ok(VideoCodec::Av1);
142 }
143 Err(UnknownCodecError(s.to_owned()))
144}
145
146pub const ENCRYPTION_AES256: &str = "aead_aes256_gcm_rtpsize";
151pub const ENCRYPTION_XCHACHA20: &str = "aead_xchacha20_poly1305_rtpsize";
152
153pub const STREAMS_SIMULCAST_RID: &str = "100";
155pub const STREAMS_SIMULCAST_QUALITY: u8 = 100;
156
157pub const MAX_INT16: u32 = 1 << 16;
158pub const MAX_INT32: u64 = 1 << 32;