1use serde::{Deserialize, Serialize};
2use std::convert::TryFrom;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum AudioCodec {
7 Opus,
8 RawPcm,
9}
10
11impl Default for AudioCodec {
12 fn default() -> Self {
13 Self::Opus
14 }
15}
16
17impl From<AudioCodec> for u8 {
18 fn from(value: AudioCodec) -> Self {
19 match value {
20 AudioCodec::Opus => 0,
21 AudioCodec::RawPcm => 1,
22 }
23 }
24}
25
26impl TryFrom<u8> for AudioCodec {
27 type Error = &'static str;
28
29 fn try_from(value: u8) -> Result<Self, Self::Error> {
30 match value {
31 0 => Ok(AudioCodec::Opus),
32 1 => Ok(AudioCodec::RawPcm),
33 _ => Err("unknown audio codec"),
34 }
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "snake_case")]
40pub enum VideoCodec {
41 RawI420,
42 Vp8,
43 Vp9,
44 H264Baseline,
45 H264Main,
46 H265Main,
47 Av1Main,
48}
49
50impl Default for VideoCodec {
51 fn default() -> Self {
52 Self::Vp8
53 }
54}
55
56impl From<VideoCodec> for u8 {
57 fn from(value: VideoCodec) -> Self {
58 match value {
59 VideoCodec::RawI420 => 0,
60 VideoCodec::Vp8 => 1,
61 VideoCodec::Vp9 => 2,
62 VideoCodec::H264Baseline => 3,
63 VideoCodec::H264Main => 4,
64 VideoCodec::H265Main => 5,
65 VideoCodec::Av1Main => 6,
66 }
67 }
68}
69
70impl TryFrom<u8> for VideoCodec {
71 type Error = &'static str;
72
73 fn try_from(value: u8) -> Result<Self, Self::Error> {
74 match value {
75 0 => Ok(VideoCodec::RawI420),
76 1 => Ok(VideoCodec::Vp8),
77 2 => Ok(VideoCodec::Vp9),
78 3 => Ok(VideoCodec::H264Baseline),
79 4 => Ok(VideoCodec::H264Main),
80 5 => Ok(VideoCodec::H265Main),
81 6 => Ok(VideoCodec::Av1Main),
82 _ => Err("unknown video codec"),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
88#[serde(rename_all = "snake_case")]
89pub enum MediaSourceMode {
90 #[default]
91 Encoded,
92 Raw,
93 Hybrid,
94}
95
96impl From<MediaSourceMode> for u8 {
97 fn from(value: MediaSourceMode) -> Self {
98 match value {
99 MediaSourceMode::Encoded => 0,
100 MediaSourceMode::Raw => 1,
101 MediaSourceMode::Hybrid => 2,
102 }
103 }
104}
105
106impl TryFrom<u8> for MediaSourceMode {
107 type Error = &'static str;
108
109 fn try_from(value: u8) -> Result<Self, Self::Error> {
110 match value {
111 0 => Ok(MediaSourceMode::Encoded),
112 1 => Ok(MediaSourceMode::Raw),
113 2 => Ok(MediaSourceMode::Hybrid),
114 _ => Err("unknown media source mode"),
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "snake_case")]
121pub enum HardwareAcceleration {
122 Cpu,
123 Nvidia,
124 Amd,
125 Intel,
126 Apple,
127}
128
129impl Default for HardwareAcceleration {
130 fn default() -> Self {
131 Self::Cpu
132 }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
136pub struct VideoResolution {
137 pub width: u16,
138 pub height: u16,
139}
140
141impl VideoResolution {
142 #[must_use]
143 pub const fn new(width: u16, height: u16) -> Self {
144 Self { width, height }
145 }
146}
147
148impl Default for VideoResolution {
149 fn default() -> Self {
150 Self {
151 width: 640,
152 height: 360,
153 }
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
158pub struct CodecPriority(pub u8);
159
160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub struct AudioCodecDescriptor {
162 pub codec: AudioCodec,
163 #[serde(default)]
164 pub bitrate: Option<u32>,
165 #[serde(default)]
166 pub sample_rate: Option<u32>,
167 #[serde(default)]
168 pub channels: Option<u8>,
169 #[serde(default)]
170 pub priority: CodecPriority,
171}
172
173impl Default for AudioCodecDescriptor {
174 fn default() -> Self {
175 Self {
176 codec: AudioCodec::Opus,
177 bitrate: Some(16_000),
178 sample_rate: Some(48_000),
179 channels: Some(1),
180 priority: CodecPriority(100),
181 }
182 }
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186pub struct VideoCodecDescriptor {
187 pub codec: VideoCodec,
188 #[serde(default)]
189 pub max_bitrate: Option<u32>,
190 #[serde(default)]
191 pub max_resolution: Option<VideoResolution>,
192 #[serde(default)]
193 pub frame_rate: Option<u8>,
194 #[serde(default)]
195 pub hardware: Vec<HardwareAcceleration>,
196 #[serde(default)]
197 pub priority: CodecPriority,
198 #[serde(default)]
199 pub supports_scalability: bool,
200}
201
202impl Default for VideoCodecDescriptor {
203 fn default() -> Self {
204 Self {
205 codec: VideoCodec::Vp8,
206 max_bitrate: Some(750_000),
207 max_resolution: Some(VideoResolution::new(640, 360)),
208 frame_rate: Some(24),
209 hardware: vec![HardwareAcceleration::Cpu],
210 priority: CodecPriority(100),
211 supports_scalability: true,
212 }
213 }
214}
215
216#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
217pub struct MediaCapabilities {
218 #[serde(default)]
219 pub audio: Vec<AudioCodecDescriptor>,
220 #[serde(default)]
221 pub video: Vec<VideoCodecDescriptor>,
222 #[serde(default)]
223 pub allow_raw_audio: bool,
224 #[serde(default)]
225 pub allow_raw_video: bool,
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn audio_codec_roundtrip() {
234 for value in [AudioCodec::Opus, AudioCodec::RawPcm] {
235 let encoded: u8 = value.into();
236 let decoded = AudioCodec::try_from(encoded).expect("audio codec");
237 assert_eq!(decoded, value);
238 }
239 }
240
241 #[test]
242 fn video_codec_roundtrip() {
243 for value in [
244 VideoCodec::RawI420,
245 VideoCodec::Vp8,
246 VideoCodec::Vp9,
247 VideoCodec::H264Baseline,
248 VideoCodec::H264Main,
249 VideoCodec::H265Main,
250 VideoCodec::Av1Main,
251 ] {
252 let encoded: u8 = value.into();
253 let decoded = VideoCodec::try_from(encoded).expect("video codec");
254 assert_eq!(decoded, value);
255 }
256 }
257
258 #[test]
259 fn media_source_mode_roundtrip() {
260 for value in [
261 MediaSourceMode::Encoded,
262 MediaSourceMode::Raw,
263 MediaSourceMode::Hybrid,
264 ] {
265 let encoded: u8 = value.into();
266 let decoded = MediaSourceMode::try_from(encoded).expect("source mode");
267 assert_eq!(decoded, value);
268 }
269 }
270}