rodio/decoder/
flac.rs

1use std::cmp::Ordering;
2use std::io::{Read, Seek, SeekFrom};
3use std::mem;
4use std::time::Duration;
5
6use crate::source::SeekError;
7use crate::Source;
8
9use claxon::FlacReader;
10
11/// Decoder for the Flac format.
12pub struct FlacDecoder<R>
13where
14    R: Read + Seek,
15{
16    reader: FlacReader<R>,
17    current_block: Vec<i32>,
18    current_block_channel_len: usize,
19    current_block_off: usize,
20    bits_per_sample: u32,
21    sample_rate: u32,
22    channels: u16,
23    samples: Option<u64>,
24}
25
26impl<R> FlacDecoder<R>
27where
28    R: Read + Seek,
29{
30    /// Attempts to decode the data as Flac.
31    pub fn new(mut data: R) -> Result<FlacDecoder<R>, R> {
32        if !is_flac(data.by_ref()) {
33            return Err(data);
34        }
35
36        let reader = FlacReader::new(data).unwrap();
37        let spec = reader.streaminfo();
38
39        Ok(FlacDecoder {
40            reader,
41            current_block: Vec::with_capacity(
42                spec.max_block_size as usize * spec.channels as usize,
43            ),
44            current_block_channel_len: 1,
45            current_block_off: 0,
46            bits_per_sample: spec.bits_per_sample,
47            sample_rate: spec.sample_rate,
48            channels: spec.channels as u16,
49            samples: spec.samples,
50        })
51    }
52    pub fn into_inner(self) -> R {
53        self.reader.into_inner()
54    }
55}
56
57impl<R> Source for FlacDecoder<R>
58where
59    R: Read + Seek,
60{
61    #[inline]
62    fn current_frame_len(&self) -> Option<usize> {
63        None
64    }
65
66    #[inline]
67    fn channels(&self) -> u16 {
68        self.channels
69    }
70
71    #[inline]
72    fn sample_rate(&self) -> u32 {
73        self.sample_rate
74    }
75
76    #[inline]
77    fn total_duration(&self) -> Option<Duration> {
78        // `samples` in FLAC means "inter-channel samples" aka frames
79        // so we do not divide by `self.channels` here.
80        self.samples
81            .map(|s| Duration::from_micros(s * 1_000_000 / self.sample_rate as u64))
82    }
83
84    #[inline]
85    fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
86        Err(SeekError::NotSupported {
87            underlying_source: std::any::type_name::<Self>(),
88        })
89    }
90}
91
92impl<R> Iterator for FlacDecoder<R>
93where
94    R: Read + Seek,
95{
96    type Item = i16;
97
98    #[inline]
99    fn next(&mut self) -> Option<i16> {
100        loop {
101            if self.current_block_off < self.current_block.len() {
102                // Read from current block.
103                let real_offset = (self.current_block_off % self.channels as usize)
104                    * self.current_block_channel_len
105                    + self.current_block_off / self.channels as usize;
106                let raw_val = self.current_block[real_offset];
107                self.current_block_off += 1;
108                let real_val = match self.bits_per_sample.cmp(&16) {
109                    Ordering::Less => (raw_val << (16 - self.bits_per_sample)) as i16,
110                    Ordering::Equal => raw_val as i16,
111                    Ordering::Greater => (raw_val >> (self.bits_per_sample - 16)) as i16,
112                };
113                return Some(real_val);
114            }
115
116            // Load the next block.
117            self.current_block_off = 0;
118            let buffer = mem::take(&mut self.current_block);
119            match self.reader.blocks().read_next_or_eof(buffer) {
120                Ok(Some(block)) => {
121                    self.current_block_channel_len = (block.len() / block.channels()) as usize;
122                    self.current_block = block.into_buffer();
123                }
124                _ => return None,
125            }
126        }
127    }
128}
129
130/// Returns true if the stream contains Flac data, then resets it to where it was.
131fn is_flac<R>(mut data: R) -> bool
132where
133    R: Read + Seek,
134{
135    let stream_pos = data.stream_position().unwrap();
136
137    if FlacReader::new(data.by_ref()).is_err() {
138        data.seek(SeekFrom::Start(stream_pos)).unwrap();
139        return false;
140    }
141
142    data.seek(SeekFrom::Start(stream_pos)).unwrap();
143    true
144}