snapcast_server/encoder/
mod.rs1#[cfg(feature = "f32lz4")]
4pub mod f32lz4;
5#[cfg(feature = "flac")]
6pub mod flac;
7#[cfg(feature = "opus")]
8pub mod opus;
9pub mod pcm;
10#[cfg(feature = "vorbis")]
11pub mod vorbis;
12
13use anyhow::Result;
14use snapcast_proto::SampleFormat;
15
16use crate::AudioData;
17
18pub(crate) struct EncodedChunk {
20 pub data: Vec<u8>,
22}
23
24pub(crate) trait Encoder: Send {
29 fn name(&self) -> &str;
31
32 fn header(&self) -> &[u8];
34
35 fn encode(&mut self, input: &AudioData) -> Result<EncodedChunk>;
37}
38
39#[derive(Debug, Clone)]
41pub(crate) struct EncoderConfig {
42 pub codec: String,
44 pub format: SampleFormat,
46 pub options: String,
48 #[cfg(feature = "encryption")]
50 pub encryption_psk: Option<String>,
51}
52
53pub(crate) fn create(config: &EncoderConfig) -> Result<Box<dyn Encoder>> {
55 #[allow(unused_variables)]
56 let EncoderConfig {
57 codec,
58 format,
59 options,
60 ..
61 } = config;
62 let format = *format;
63 match codec.as_str() {
64 "pcm" => Ok(Box::new(pcm::PcmEncoder::new(format))),
65 #[cfg(feature = "flac")]
66 "flac" => Ok(Box::new(flac::FlacEncoder::new(format, options)?)),
67 #[cfg(feature = "opus")]
68 "opus" => Ok(Box::new(opus::OpusEncoder::new(format, options)?)),
69 #[cfg(feature = "vorbis")]
70 "ogg" => Ok(Box::new(vorbis::VorbisEncoder::new(format, options)?)),
71 #[cfg(feature = "f32lz4")]
72 "f32lz4" => {
73 let enc = f32lz4::F32Lz4Encoder::new(format);
74 #[cfg(feature = "encryption")]
75 let enc = if let Some(ref key) = config.encryption_psk {
76 enc.with_encryption(key)
77 } else {
78 enc
79 };
80 Ok(Box::new(enc))
81 }
82 other => anyhow::bail!("unsupported codec: {other} (check enabled features)"),
83 }
84}
85
86pub(crate) fn f32_to_pcm(samples: &[f32], bits: u16) -> Vec<u8> {
89 match bits {
90 16 => {
91 let mut buf = Vec::with_capacity(samples.len() * 2);
92 for &s in samples {
93 let i = (s.clamp(-1.0, 1.0) * i16::MAX as f32) as i16;
94 buf.extend_from_slice(&i.to_le_bytes());
95 }
96 buf
97 }
98 24 => {
99 let mut buf = Vec::with_capacity(samples.len() * 3);
100 for &s in samples {
101 let i = (s.clamp(-1.0, 1.0) * 8_388_607.0) as i32;
102 let bytes = i.to_le_bytes();
103 buf.extend_from_slice(&bytes[..3]);
104 }
105 buf
106 }
107 32 => {
108 let mut buf = Vec::with_capacity(samples.len() * 4);
109 for &s in samples {
110 let i = (s.clamp(-1.0, 1.0) * i32::MAX as f32) as i32;
111 buf.extend_from_slice(&i.to_le_bytes());
112 }
113 buf
114 }
115 _ => f32_to_pcm(samples, 16),
116 }
117}
118
119#[cfg(feature = "f32lz4")]
122pub(crate) fn pcm_to_f32(pcm: &[u8], bits: u16) -> Vec<f32> {
123 match bits {
124 16 => pcm
125 .chunks_exact(2)
126 .map(|c| i16::from_le_bytes([c[0], c[1]]) as f32 / i16::MAX as f32)
127 .collect(),
128 24 => pcm
129 .chunks_exact(3)
130 .map(|c| {
131 let i =
132 i32::from_le_bytes([c[0], c[1], c[2], if c[2] & 0x80 != 0 { 0xFF } else { 0 }]);
133 i as f32 / 8_388_607.0
134 })
135 .collect(),
136 32 => pcm
137 .chunks_exact(4)
138 .map(|c| i32::from_le_bytes([c[0], c[1], c[2], c[3]]) as f32 / i32::MAX as f32)
139 .collect(),
140 _ => pcm_to_f32(pcm, 16),
141 }
142}