snapcast_client/decoder/
flac.rs1use anyhow::{Result, bail};
7use snapcast_proto::SampleFormat;
8use snapcast_proto::message::codec_header::CodecHeader;
9use symphonia::core::audio::SampleBuffer;
10use symphonia::core::codecs::{CODEC_TYPE_FLAC, CodecParameters, DecoderOptions};
11use symphonia::core::formats::Packet;
12
13use crate::decoder::Decoder;
14use crate::stream::SampleEncoding;
15
16fn parse_streaminfo(payload: &[u8]) -> Result<(SampleFormat, CodecParameters)> {
21 if payload.len() < 42 {
22 bail!(
23 "FLAC header too small ({} bytes, need >= 42)",
24 payload.len()
25 );
26 }
27 if &payload[0..4] != b"fLaC" {
28 bail!("not a FLAC header (missing fLaC magic)");
29 }
30
31 let si = &payload[8..];
33
34 let b10 = si[10] as u32;
37 let b11 = si[11] as u32;
38 let b12 = si[12] as u32;
39
40 let sample_rate = (b10 << 12) | (b11 << 4) | (b12 >> 4);
41 let channels = ((b12 >> 1) & 0x07) + 1;
42 let bits_per_sample = (((b12 & 0x01) << 4) | (si[13] as u32 >> 4)) + 1;
43
44 let sf = SampleFormat::new(sample_rate, bits_per_sample as u16, channels as u16);
45
46 let mut params = CodecParameters::new();
47 params
48 .for_codec(CODEC_TYPE_FLAC)
49 .with_sample_rate(sample_rate)
50 .with_bits_per_sample(bits_per_sample)
51 .with_channels(
52 symphonia::core::audio::Channels::from_bits(((1u64 << channels) - 1) as u32)
53 .unwrap_or(symphonia::core::audio::Channels::FRONT_LEFT),
54 )
55 .with_extra_data(payload[8..42].to_vec().into_boxed_slice());
56
57 Ok((sf, params))
58}
59
60pub struct FlacDecoder {
62 decoder: Box<dyn symphonia::core::codecs::Decoder>,
63 sample_format: SampleFormat,
64 packet_id: u64,
65}
66
67impl FlacDecoder {
68 fn new_from_params(sf: SampleFormat, params: &CodecParameters) -> Result<Self> {
69 let decoder = symphonia::default::get_codecs()
70 .make(params, &DecoderOptions::default())
71 .map_err(|e| anyhow::anyhow!("failed to create FLAC decoder: {e}"))?;
72 let output_format = SampleFormat::new(sf.rate(), 32, sf.channels());
74 Ok(Self {
75 decoder,
76 sample_format: output_format,
77 packet_id: 0,
78 })
79 }
80}
81
82impl Decoder for FlacDecoder {
83 fn set_header(&mut self, header: &CodecHeader) -> Result<SampleFormat> {
84 tracing::trace!(
85 codec = "flac",
86 payload_len = header.payload.len(),
87 "set_header"
88 );
89 let (sf, params) = parse_streaminfo(&header.payload)?;
90 *self = Self::new_from_params(sf, ¶ms)?;
91 Ok(self.sample_format)
92 }
93
94 fn decode(&mut self, data: &mut Vec<u8>) -> Result<bool> {
95 if data.is_empty() {
96 return Ok(false);
97 }
98
99 tracing::trace!(
100 codec = "flac",
101 input_bytes = data.len(),
102 packet_id = self.packet_id,
103 "decode"
104 );
105
106 let packet = Packet::new_from_slice(0, self.packet_id, 0, data);
107 self.packet_id += 1;
108
109 let decoded = match self.decoder.decode(&packet) {
110 Ok(buf) => buf,
111 Err(e) => {
112 tracing::warn!(codec = "flac", error = %e, "decode failed");
113 return Ok(false);
114 }
115 };
116
117 let spec = *decoded.spec();
118 let frames = decoded.frames() as u64;
119
120 let mut sample_buf = SampleBuffer::<f32>::new(frames, spec);
121 sample_buf.copy_interleaved_ref(decoded);
122 let samples = sample_buf.samples();
123
124 let mut out = Vec::with_capacity(samples.len() * 4);
125 for &s in samples {
126 out.extend_from_slice(&s.to_le_bytes());
127 }
128
129 *data = out;
130 Ok(true)
131 }
132
133 fn output_encoding(&self) -> SampleEncoding {
134 SampleEncoding::Float32
135 }
136}
137
138pub fn create(header: &CodecHeader) -> Result<FlacDecoder> {
140 let (sf, params) = parse_streaminfo(&header.payload)?;
141 FlacDecoder::new_from_params(sf, ¶ms)
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 fn flac_header_44100_16_2() -> Vec<u8> {
151 let mut h = Vec::new();
152 h.extend_from_slice(b"fLaC");
153 h.push(0x80);
155 h.extend_from_slice(&[0x00, 0x00, 0x22]); h.extend_from_slice(&[0x00, 0x10]); h.extend_from_slice(&[0x10, 0x00]); h.extend_from_slice(&[0x00, 0x00, 0x00]); h.extend_from_slice(&[0x00, 0x00, 0x00]); h.push(0x0A);
171 h.push(0xC4);
172 h.push(0x42);
173 h.push(0xF0);
174
175 h.extend_from_slice(&[0; 20]);
177
178 assert_eq!(h.len(), 42);
179 h
180 }
181
182 #[test]
183 fn parse_streaminfo_44100_16_2() {
184 let payload = flac_header_44100_16_2();
185 let (sf, _params) = parse_streaminfo(&payload).unwrap();
186 assert_eq!(sf.rate(), 44100);
187 assert_eq!(sf.bits(), 16);
188 assert_eq!(sf.channels(), 2);
189 }
190
191 #[test]
192 fn parse_streaminfo_48000_24_2() {
193 let mut h = Vec::new();
194 h.extend_from_slice(b"fLaC");
195 h.push(0x80);
196 h.extend_from_slice(&[0x00, 0x00, 0x22]);
197 h.extend_from_slice(&[0x10, 0x00]); h.extend_from_slice(&[0x10, 0x00]); h.extend_from_slice(&[0; 6]); h.push(0x0B);
207 h.push(0xB8);
208 h.push(0x03);
209 h.push(0x70);
210 h.extend_from_slice(&[0; 20]);
211
212 let (sf, _) = parse_streaminfo(&h).unwrap();
213 assert_eq!(sf.rate(), 48000);
214 assert_eq!(sf.bits(), 24);
215 assert_eq!(sf.channels(), 2);
216 }
217
218 #[test]
219 fn parse_streaminfo_too_small() {
220 assert!(parse_streaminfo(&[0; 10]).is_err());
221 }
222
223 #[test]
224 fn parse_streaminfo_bad_magic() {
225 let mut h = vec![0u8; 42];
226 h[0..4].copy_from_slice(b"NOPE");
227 assert!(parse_streaminfo(&h).is_err());
228 }
229
230 #[test]
231 fn create_decoder_from_header() {
232 let header = CodecHeader {
233 codec: "flac".into(),
234 payload: flac_header_44100_16_2(),
235 };
236 let dec = create(&header);
237 if let Err(e) = &dec {
238 eprintln!("Error: {e:?}");
239 }
240 let dec = dec.unwrap();
241 assert_eq!(dec.sample_format.rate(), 44100);
242 }
243}