proteus_lib/playback/player/
mod.rs1mod controls;
12mod effects;
13mod runtime;
14mod settings;
15
16use rodio::Sink;
17use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
18use std::sync::{Arc, Mutex};
19
20use crate::container::prot::{PathsTrack, Prot};
21use crate::diagnostics::reporter::Reporter;
22use crate::dsp::effects::convolution_reverb::ImpulseResponseSpec;
23use crate::playback::output_meter::OutputMeter;
24use crate::{
25 container::info::Info,
26 dsp::effects::AudioEffect,
27 playback::engine::{
28 DspChainMetrics, InlineEffectsUpdate, InlineTrackMixUpdate, PlaybackBufferSettings,
29 },
30};
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum PlayerState {
38 Init,
39 Resuming,
40 Playing,
41 Pausing,
42 Paused,
43 Stopping,
44 Stopped,
45 Finished,
46}
47
48#[derive(Debug, Clone, Copy)]
53pub struct ReverbSettingsSnapshot {
54 pub enabled: bool,
55 pub dry_wet: f32,
56}
57
58const OUTPUT_METER_REFRESH_HZ: f32 = 30.0;
59const OUTPUT_STREAM_OPEN_RETRIES: usize = 20;
60const OUTPUT_STREAM_OPEN_RETRY_MS: u64 = 100;
61
62#[derive(Clone)]
67pub struct Player {
68 pub info: Info,
69 pub finished_tracks: Arc<Mutex<Vec<i32>>>,
70 pub ts: Arc<Mutex<f64>>,
71 state: Arc<Mutex<PlayerState>>,
72 abort: Arc<AtomicBool>,
73 playback_thread_exists: Arc<AtomicBool>,
74 playback_id: Arc<AtomicU64>,
75 duration: Arc<Mutex<f64>>,
76 prot: Arc<Mutex<Prot>>,
77 audio_heard: Arc<AtomicBool>,
78 volume: Arc<Mutex<f32>>,
79 sink: Arc<Mutex<Sink>>,
80 reporter: Option<Arc<Mutex<Reporter>>>,
81 buffer_settings: Arc<Mutex<PlaybackBufferSettings>>,
82 effects: Arc<Mutex<Vec<AudioEffect>>>,
83 inline_effects_update: Arc<Mutex<Option<InlineEffectsUpdate>>>,
84 inline_track_mix_updates: Arc<Mutex<Vec<InlineTrackMixUpdate>>>,
85 dsp_metrics: Arc<Mutex<DspChainMetrics>>,
86 effects_reset: Arc<AtomicU64>,
87 output_meter: Arc<Mutex<OutputMeter>>,
88 buffering_done: Arc<AtomicBool>,
89 last_chunk_ms: Arc<AtomicU64>,
90 last_time_update_ms: Arc<AtomicU64>,
91 next_resume_fade_ms: Arc<Mutex<Option<f32>>>,
92 impulse_response_override: Option<ImpulseResponseSpec>,
93 impulse_response_tail_override: Option<f32>,
94}
95
96impl Player {
97 pub fn new(file_path: &String) -> Self {
103 Self::new_from_path_or_paths(Some(file_path), None)
104 }
105
106 pub fn new_from_file_paths(file_paths: Vec<PathsTrack>) -> Self {
112 Self::new_from_path_or_paths(None, Some(file_paths))
113 }
114
115 pub fn new_from_file_paths_legacy(file_paths: Vec<Vec<String>>) -> Self {
122 Self::new_from_path_or_paths(
123 None,
124 Some(
125 file_paths
126 .into_iter()
127 .map(PathsTrack::new_from_file_paths)
128 .collect(),
129 ),
130 )
131 }
132
133 pub fn new_from_path_or_paths(path: Option<&String>, paths: Option<Vec<PathsTrack>>) -> Self {
143 let (prot, info) = match path {
144 Some(path) => {
145 let prot = Arc::new(Mutex::new(Prot::new(path)));
146 let info = Info::new(path.clone());
147 (prot, info)
148 }
149 None => {
150 let prot = Arc::new(Mutex::new(Prot::new_from_file_paths(paths.unwrap())));
151 let locked_prot = prot.lock().unwrap();
152 let info = Info::new_from_file_paths(locked_prot.get_file_paths_dictionary());
153 drop(locked_prot);
154 (prot, info)
155 }
156 };
157
158 let (sink, _queue) = Sink::new();
159 let sink: Arc<Mutex<Sink>> = Arc::new(Mutex::new(sink));
160
161 let channels = info.channels as usize;
162 let sample_rate = info.sample_rate;
163 let effects = {
164 let prot_locked = prot.lock().unwrap();
165 match prot_locked.get_effects() {
166 Some(effects) => Arc::new(Mutex::new(effects)),
167 None => Arc::new(Mutex::new(vec![])),
168 }
169 };
170
171 let mut this = Self {
172 info,
173 finished_tracks: Arc::new(Mutex::new(Vec::new())),
174 state: Arc::new(Mutex::new(PlayerState::Stopped)),
175 abort: Arc::new(AtomicBool::new(false)),
176 ts: Arc::new(Mutex::new(0.0)),
177 playback_thread_exists: Arc::new(AtomicBool::new(true)),
178 playback_id: Arc::new(AtomicU64::new(0)),
179 duration: Arc::new(Mutex::new(0.0)),
180 audio_heard: Arc::new(AtomicBool::new(false)),
181 volume: Arc::new(Mutex::new(0.8)),
182 sink,
183 prot,
184 reporter: None,
185 buffer_settings: Arc::new(Mutex::new(PlaybackBufferSettings::new(20.0))),
186 effects,
187 inline_effects_update: Arc::new(Mutex::new(None)),
188 inline_track_mix_updates: Arc::new(Mutex::new(Vec::new())),
189 dsp_metrics: Arc::new(Mutex::new(DspChainMetrics::default())),
190 effects_reset: Arc::new(AtomicU64::new(0)),
191 output_meter: Arc::new(Mutex::new(OutputMeter::new(
192 channels,
193 sample_rate,
194 OUTPUT_METER_REFRESH_HZ,
195 ))),
196 buffering_done: Arc::new(AtomicBool::new(false)),
197 last_chunk_ms: Arc::new(AtomicU64::new(0)),
198 last_time_update_ms: Arc::new(AtomicU64::new(0)),
199 next_resume_fade_ms: Arc::new(Mutex::new(None)),
200 impulse_response_override: None,
201 impulse_response_tail_override: None,
202 };
203
204 this.initialize_thread(None);
205
206 this
207 }
208}
209
210impl Drop for Player {
211 fn drop(&mut self) {
212 if Arc::strong_count(&self.state) != 1 {
215 return;
216 }
217
218 if let Some(reporter) = self.reporter.take() {
219 reporter.lock().unwrap().stop();
220 }
221
222 if self
223 .playback_thread_exists
224 .load(std::sync::atomic::Ordering::SeqCst)
225 {
226 self.kill_current();
227 } else {
228 self.abort.store(true, Ordering::SeqCst);
229 }
230
231 {
232 let sink = self.sink.lock().unwrap();
233 sink.stop();
234 sink.clear();
235 }
236
237 {
238 let mut finished_tracks = self.finished_tracks.lock().unwrap();
239 finished_tracks.clear();
240 finished_tracks.shrink_to_fit();
241 }
242
243 {
244 let mut effects = self.effects.lock().unwrap();
245 effects.clear();
246 effects.shrink_to_fit();
247 }
248
249 {
250 let mut inline_effects_update = self.inline_effects_update.lock().unwrap();
251 *inline_effects_update = None;
252 }
253
254 {
255 let mut inline_track_mix_updates = self.inline_track_mix_updates.lock().unwrap();
256 inline_track_mix_updates.clear();
257 inline_track_mix_updates.shrink_to_fit();
258 }
259
260 {
261 let mut dsp_metrics = self.dsp_metrics.lock().unwrap();
262 *dsp_metrics = DspChainMetrics::default();
263 }
264
265 {
266 let mut output_meter = self.output_meter.lock().unwrap();
267 output_meter.reset();
268 }
269
270 *self.duration.lock().unwrap() = 0.0;
271 *self.ts.lock().unwrap() = 0.0;
272 *self.next_resume_fade_ms.lock().unwrap() = None;
273 self.buffering_done.store(false, Ordering::Relaxed);
274 self.last_chunk_ms.store(0, Ordering::Relaxed);
275 self.last_time_update_ms.store(0, Ordering::Relaxed);
276 self.audio_heard.store(false, Ordering::Relaxed);
277 self.impulse_response_override = None;
278 self.impulse_response_tail_override = None;
279 }
280}