Skip to main content

selene_daemon/player/
opened_decoder.rs

1use std::{collections::VecDeque, num::NonZero, time::SystemTime};
2
3use audioadapter_buffers::direct::InterleavedSlice;
4use rubato::{Fft, FixedSync, Resampler, ResamplerConstructionError};
5use selene_core::{
6    library::loudnorm::LoudnormAnalysis, symphonia_helpers::raw_decoder::RawDecoder,
7};
8
9use symphonia::core::{
10    audio::{Audio, AudioBuffer},
11    errors::{Error as SymphoniaError, SeekErrorKind},
12    formats::{SeekMode, SeekTo},
13    units::{Time, TimeBase},
14};
15
16use crate::{player::PlayerError, playlist::PlayingTrack};
17
18pub struct OpenedDecoder {
19    pub decoded_from: PlayingTrack,
20    pub started_at: Option<SystemTime>,
21    gain: f64,
22
23    inner: RawDecoder,
24
25    resampler: Fft<f32>,
26    resample_buffer: VecDeque<f32>,
27
28    pub current_frame: usize,
29    pub decoded_frames: usize,
30
31    pub at_eof: bool,
32    pub sent_scrobble: bool,
33}
34
35impl OpenedDecoder {
36    #[must_use]
37    /// Returns the current time within the track
38    pub fn time(&self) -> f64 {
39        let sample_rate = f64::from(self.inner.stream.codec_params.sample_rate);
40        self.current_frame as f64 / sample_rate
41    }
42
43    #[must_use]
44    /// Returns the amount of 'time' that has been decoded total, regardless of seeking
45    pub fn decoded_time(&self) -> f64 {
46        let sample_rate = f64::from(self.inner.stream.codec_params.sample_rate);
47        self.decoded_frames as f64 / sample_rate
48    }
49
50    #[must_use]
51    pub fn start_time(&self) -> Option<u64> {
52        let time = self
53            .started_at?
54            .duration_since(SystemTime::UNIX_EPOCH)
55            .expect("Time went backwards")
56            .as_secs();
57
58        Some(time)
59    }
60
61    pub(crate) fn started(&mut self) -> bool {
62        if self.started_at.is_none() {
63            self.started_at = Some(SystemTime::now());
64            return true;
65        }
66
67        false
68    }
69
70    pub fn decode_next_packet(&mut self) -> Result<VecDeque<f32>, PlayerError> {
71        let channel_count = self.resampler.nbr_channels();
72
73        loop {
74            let next_frame_size = self.resampler.input_frames_next();
75            let chunk_size = next_frame_size * channel_count;
76
77            if self.resample_buffer.len() >= chunk_size {
78                let mut resampled = resample(
79                    &mut self.resampler,
80                    &self.resample_buffer.make_contiguous()[..chunk_size],
81                    channel_count,
82                    next_frame_size,
83                );
84
85                drop(self.resample_buffer.drain(..chunk_size));
86
87                for sample in &mut resampled {
88                    *sample *= self.gain as f32;
89                }
90                return Ok(resampled.into());
91            }
92
93            let Some(packet) = self.inner.decode_next_packet()? else {
94                let mut samples = std::mem::take(&mut self.resample_buffer);
95                samples.resize(chunk_size, 0.0);
96
97                let mut resampled = resample(
98                    &mut self.resampler,
99                    samples.make_contiguous(),
100                    channel_count,
101                    next_frame_size,
102                );
103
104                self.at_eof = true;
105
106                for sample in &mut resampled {
107                    *sample *= self.gain as f32;
108                }
109                return Ok(resampled.into());
110            };
111
112            let mut audio_buffer = AudioBuffer::<f32>::new(packet.spec().clone(), packet.frames());
113            audio_buffer.render_silence(Some(packet.frames()));
114            packet.copy_to(&mut audio_buffer);
115
116            self.current_frame += packet.frames();
117            self.decoded_frames += packet.frames();
118
119            self.resample_buffer.extend(audio_buffer.iter_interleaved());
120        }
121    }
122
123    pub fn seek(&mut self, seconds: f64, increment: bool) -> Result<f64, SymphoniaError> {
124        let seconds = if increment {
125            (self.time() + seconds).max(0.0)
126        } else {
127            seconds
128        }
129        .max(0.0);
130
131        let timestamp = Time::try_from_secs_f64(seconds).unwrap();
132
133        let seeked_to = match self.inner.format_reader.seek(
134            SeekMode::Accurate,
135            SeekTo::Time {
136                time: timestamp,
137                track_id: Some(self.inner.stream.id),
138            },
139        ) {
140            Ok(seeked_to) => seeked_to,
141            Err(SymphoniaError::SeekError(SeekErrorKind::OutOfRange)) => {
142                self.at_eof = true;
143                return Ok(self.inner.stream.duration());
144            }
145            Err(other) => return Err(other),
146        };
147
148        self.inner.decoder.reset();
149        self.at_eof = false;
150
151        let time_base = self
152            .inner
153            .stream
154            .time_base
155            .map(|(n, d)| TimeBase {
156                numer: NonZero::new(n).unwrap(),
157                denom: NonZero::new(d).unwrap(),
158            })
159            .unwrap();
160
161        let raw_time = time_base.calc_time(seeked_to.actual_ts).unwrap();
162        let time = raw_time.as_secs_f64();
163
164        let sample_rate = self.inner.stream.codec_params.sample_rate;
165        self.current_frame = (time * f64::from(sample_rate)) as usize;
166
167        Ok(time)
168    }
169}
170
171impl OpenedDecoder {
172    pub fn new(playable: PlayingTrack, output_sample_rate: usize) -> Result<Self, PlayerError> {
173        let container = playable.source.container();
174
175        let inner = RawDecoder::from_container(container, 64 * 1024)?;
176
177        let resampler = new_resampler(
178            inner.stream.codec_params.sample_rate as usize,
179            output_sample_rate,
180            inner.stream.codec_params.channels,
181        )?;
182
183        let resample_buffer =
184            VecDeque::with_capacity(resampler.input_frames_max() * resampler.nbr_channels());
185
186        let gain = playable
187            .source
188            .loudnorm_analysis()
189            .map_or(1.0, LoudnormAnalysis::calculated_gain);
190
191        Ok(OpenedDecoder {
192            inner,
193            gain,
194            current_frame: 0,
195            decoded_frames: 0,
196            started_at: None,
197            decoded_from: playable,
198            resampler,
199            resample_buffer,
200            at_eof: false,
201            sent_scrobble: false,
202        })
203    }
204}
205
206fn new_resampler(
207    input_sample_rate: usize,
208    output_sample_rate: usize,
209    channel_count: usize,
210) -> Result<Fft<f32>, ResamplerConstructionError> {
211    Fft::new(
212        input_sample_rate,
213        output_sample_rate,
214        1024,
215        1,
216        channel_count,
217        FixedSync::Both,
218    )
219}
220
221fn resample(
222    resampler: &mut Fft<f32>,
223    samples: &[f32],
224    channel_count: usize,
225    frame_size: usize,
226) -> Vec<f32> {
227    let buffer_in = InterleavedSlice::new(samples, channel_count, frame_size)
228        .expect("Sampler buffer contained less capacity then expected");
229
230    resampler
231        .process(&buffer_in, 0, None)
232        .expect("Resampler expects input and output to have the same number of channels")
233        .take_data()
234}