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