commucat_media_types/
lib.rs

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}