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: 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 Ok(codecs)
44}
45
46fn audio_codec_preference(codec_name: &str) -> Option<AudioCodecPreference> {
47 CodecPreferences::DEFAULT_AUDIO
48 .into_iter()
49 .find(|codec| codec_name.eq_ignore_ascii_case(codec.wire_name()))
50}
51
52fn video_codec_preference(codec_name: &str) -> Option<VideoCodecPreference> {
53 CodecPreferences::DEFAULT_VIDEO
54 .into_iter()
55 .find(|codec| codec_name.eq_ignore_ascii_case(codec.wire_name()))
56}
57
58#[cfg(test)]
59#[path = "TESTS/codec_preferences.rs"]
60mod tests;