o_sfu/config/
codec_preferences.rs1use anyhow::{Result, anyhow, ensure};
2use o_sfu_core::prelude::{AudioCodecPreference, CodecPreferences, VideoCodecPreference};
3
4use super::env::Env;
5
6pub(super) fn load_codec_preferences(env: &Env<'_>) -> Result<CodecPreferences> {
7 let audio = match env.var::<String>("CODEC_AUDIO_PREFERENCE").optional()? {
8 Some(value) => parse_codec_list(&value, "CODEC_AUDIO_PREFERENCE", audio_codec_preference)?,
9 None => Vec::new(),
10 };
11 let video = match env.var::<String>("CODEC_VIDEO_PREFERENCE").optional()? {
12 Some(value) => parse_codec_list(&value, "CODEC_VIDEO_PREFERENCE", video_codec_preference)?,
13 None => Vec::new(),
14 };
15 Ok(CodecPreferences::default()
16 .with_audio_order(&audio)
17 .with_video_order(&video))
18}
19
20fn parse_codec_list<T>(
21 value: &str,
22 env_key: &str,
23 parse_codec: impl Fn(&str) -> Option<T>,
24) -> Result<Vec<T>>
25where
26 T: Copy + PartialEq,
27{
28 let mut codecs = Vec::new();
29 for raw_codec in value.split(',') {
30 let codec_name = raw_codec.trim();
31 ensure!(
32 !codec_name.is_empty(),
33 "{env_key} cannot contain empty entries"
34 );
35 let codec = parse_codec(codec_name)
36 .ok_or_else(|| anyhow!("{env_key} contains unsupported codec `{codec_name}`"))?;
37 ensure!(
38 !codecs.contains(&codec),
39 "{env_key} cannot contain duplicate codec `{codec_name}`"
40 );
41 codecs.push(codec);
42 }
43 ensure!(!codecs.is_empty(), "{env_key} cannot be empty");
44 Ok(codecs)
45}
46
47fn audio_codec_preference(codec_name: &str) -> Option<AudioCodecPreference> {
48 if codec_name.eq_ignore_ascii_case(AudioCodecPreference::Opus.wire_name()) {
49 Some(AudioCodecPreference::Opus)
50 } else if codec_name.eq_ignore_ascii_case(AudioCodecPreference::Pcmu.wire_name()) {
51 Some(AudioCodecPreference::Pcmu)
52 } else if codec_name.eq_ignore_ascii_case(AudioCodecPreference::Pcma.wire_name()) {
53 Some(AudioCodecPreference::Pcma)
54 } else {
55 None
56 }
57}
58
59fn video_codec_preference(codec_name: &str) -> Option<VideoCodecPreference> {
60 if codec_name.eq_ignore_ascii_case(VideoCodecPreference::Vp8.wire_name()) {
61 Some(VideoCodecPreference::Vp8)
62 } else if codec_name.eq_ignore_ascii_case(VideoCodecPreference::H264.wire_name()) {
63 Some(VideoCodecPreference::H264)
64 } else if codec_name.eq_ignore_ascii_case(VideoCodecPreference::H265.wire_name()) {
65 Some(VideoCodecPreference::H265)
66 } else if codec_name.eq_ignore_ascii_case(VideoCodecPreference::Vp9.wire_name()) {
67 Some(VideoCodecPreference::Vp9)
68 } else if codec_name.eq_ignore_ascii_case(VideoCodecPreference::Av1.wire_name()) {
69 Some(VideoCodecPreference::Av1)
70 } else {
71 None
72 }
73}
74
75#[cfg(test)]
76#[path = "TESTS/codec_preferences.rs"]
77mod tests;