Skip to main content

chilen_daemon/playback/
mod.rs

1#[cfg(feature = "mpris")]
2mod mpris;
3mod state;
4#[cfg(test)]
5mod tests;
6
7use std::{
8    sync::{Arc, LazyLock, RwLock},
9    thread,
10    time::Duration,
11};
12
13#[cfg(feature = "shuffle")]
14use chilen_ipc::{
15    Event, Response,
16    playback::{
17        PlaybackCommand, PlaybackRate, PlaybackState, PlayerVolume, ShuffleState, SignedDuration,
18    },
19};
20use chilen_ipc::{
21    library::LibraryError,
22    playback::{LoopState, PlaybackError, PlaybackResponse},
23};
24use log::{debug, error, info, trace, warn};
25use rodio::Player;
26use serde::{Deserialize, Serialize};
27
28use crate::{
29    music_lib::{
30        state::{Track, get_library},
31        tracks_from_paths,
32    },
33    playback::state::{
34        PLAYER_STATE, PlayerState, background_save_state, restore_state_from_cache,
35        unwrap_state_mut, unwrap_state_ref,
36    },
37};
38
39/// Configuration options specific to the [`playback`](crate::playback) module.
40#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
41pub struct Config {
42    /// A friendly name to identify the media player to users (eg: “VLC media player”).
43    ///
44    /// This should usually match the name found in .desktop files.
45    #[cfg(any(feature = "mpris", doc))]
46    pub identity: String,
47    /// The bus name suffix to be used with MPRIS.
48    ///
49    /// The resulting bus name will be `org.mpris.MediaPlayer2.<bus_name_suffix>`, where
50    /// `<bus_name_suffix>` must be a unique identifier, such as one based on a UNIX process id.
51    /// For example, this could be:
52    ///
53    /// - `org.mpris.MediaPlayer2.vlc.instance7389`
54    ///
55    /// **Note:** According to the D-Bus specification, the unique identifier “must only contain
56    /// the ASCII characters \[A-Z\]\[a-z\]\[0-9\]_-” and “must not begin with a digit”.
57    #[cfg(any(feature = "mpris", doc))]
58    pub bus_name_suffix: String,
59    /// Whether to allow clients to modify the playback rate of the player.
60    ///
61    /// If set to true, the playback rate will be locked the value saved in cache the player state,
62    /// or set to the default value of `1.0` (regular speed) if the player state is not present.
63    pub allow_rate_modification: bool,
64    /// Whether the player's user interface can be brought to the front using any appropriate
65    /// mechanism available.
66    #[cfg(any(feature = "mpris", doc))]
67    pub can_raise: bool,
68}
69
70#[derive(Debug, Clone)]
71pub(crate) enum Command {
72    Play(Option<usize>),
73    Pause,
74    Stop,
75    TogglePlaying,
76    GetPlaybackState,
77    SetQueue(Vec<Track>),
78    AppendToQueue(Vec<Track>),
79    GetCurrentTrack,
80    Next,
81    Previous,
82    SetLoopState(LoopState),
83    GetLoopState,
84    SetRate(f64),
85    GetRate,
86    #[cfg(feature = "shuffle")]
87    SetShuffleState(ShuffleState),
88    GetShuffleState,
89    #[cfg(not(feature = "shuffle"))]
90    SetShuffleState,
91    SetPlayerPosition(Duration),
92    Seek(SignedDuration),
93    GetPlayerPosition,
94    SetPlayerVolume(PlayerVolume),
95    GetPlayerVolume,
96}
97
98impl TryFrom<PlaybackCommand> for Command {
99    type Error = LibraryError;
100    fn try_from(value: PlaybackCommand) -> Result<Self, Self::Error> {
101        match value {
102            PlaybackCommand::Play(maybe_index) => Ok(Self::Play(maybe_index)),
103            PlaybackCommand::Pause => Ok(Self::Pause),
104            PlaybackCommand::Stop => Ok(Self::Stop),
105            PlaybackCommand::TogglePlaying => Ok(Self::TogglePlaying),
106            PlaybackCommand::GetPlaybackState => Ok(Self::GetPlaybackState),
107            PlaybackCommand::SetQueue(track_paths) => {
108                let tracks = tracks_from_paths(&track_paths)?;
109                Ok(Self::SetQueue(tracks))
110            }
111            PlaybackCommand::AppendToQueue(track_paths) => {
112                let tracks = tracks_from_paths(&track_paths)?;
113                Ok(Self::AppendToQueue(tracks))
114            }
115            PlaybackCommand::SetPlaylist(playlist) => {
116                let lib = get_library()?;
117                let playlist = match lib.find_playlist(&playlist) {
118                    Some(playlist) => playlist,
119                    None => return Err(LibraryError::NoSuchPlaylist),
120                };
121                Ok(Self::SetQueue(
122                    playlist.tracks.iter().map(|t| t.as_ref().clone()).collect(),
123                ))
124            }
125            PlaybackCommand::AppendPlaylist(playlist) => {
126                let lib = get_library()?;
127                let playlist = match lib.find_playlist(&playlist) {
128                    Some(playlist) => playlist,
129                    None => return Err(LibraryError::NoSuchPlaylist),
130                };
131                Ok(Self::AppendToQueue(
132                    playlist.tracks.iter().map(|t| t.as_ref().clone()).collect(),
133                ))
134            }
135            PlaybackCommand::GetCurrentTrack => Ok(Self::GetCurrentTrack),
136            PlaybackCommand::Next => Ok(Self::Next),
137            PlaybackCommand::Previous => Ok(Self::Previous),
138            PlaybackCommand::SetLoopState(loop_state) => Ok(Self::SetLoopState(loop_state)),
139            PlaybackCommand::GetLoopState => Ok(Self::GetLoopState),
140            PlaybackCommand::SetRate(rate) => Ok(Self::SetRate(rate)),
141            PlaybackCommand::GetRate => Ok(Self::GetRate),
142            #[cfg(feature = "shuffle")]
143            PlaybackCommand::SetShuffleState(shuffle_state) => {
144                Ok(Self::SetShuffleState(shuffle_state))
145            }
146            #[cfg(not(feature = "shuffle"))]
147            PlaybackCommand::SetShuffleState(_) => Ok(Self::SetShuffleState),
148            PlaybackCommand::GetShuffleState => Ok(Self::GetShuffleState),
149            PlaybackCommand::SetPlayerPosition(position) => Ok(Self::SetPlayerPosition(position)),
150            PlaybackCommand::Seek(delta) => Ok(Self::Seek(delta)),
151            PlaybackCommand::GetPlayerPosition => Ok(Self::GetPlayerPosition),
152            PlaybackCommand::SetPlayerVolume(volume) => Ok(Self::SetPlayerVolume(volume)),
153            PlaybackCommand::GetPlayerVolume => Ok(Self::GetPlayerVolume),
154        }
155    }
156}
157
158static PLAYER_HANDLE: LazyLock<Arc<RwLock<Option<rodio::Player>>>> =
159    LazyLock::new(|| Arc::new(RwLock::new(None)));
160
161pub(crate) static CONFIG: LazyLock<Arc<RwLock<Option<Config>>>> =
162    LazyLock::new(|| Arc::new(RwLock::new(None)));
163
164pub(crate) fn unwrap_player(
165    maybe_player: Option<&rodio::Player>,
166) -> Result<&rodio::Player, PlaybackError> {
167    match maybe_player {
168        Some(player) => Ok(player),
169        None => Err(PlaybackError::StateNotInitialized),
170    }
171}
172
173/// Set whether the daemon should allow rate modification by clients.
174///
175/// Will fail with [`Error::ConfigNotInitialized`](super::Error::ConfigNotInitialized) if the daemon
176/// isn't running.
177pub fn set_allow_rate_modification(allow_rate_modification: bool) -> Result<(), super::Error> {
178    let mut conf_guard = CONFIG.write().unwrap();
179    let conf = match conf_guard.as_mut() {
180        Some(conf) => conf,
181        None => return Err(super::Error::ConfigNotInitialized),
182    };
183    conf.allow_rate_modification = allow_rate_modification;
184    Ok(())
185}
186
187/// Play the current track or a track at a specified index in the queue.
188pub(crate) fn play(index: Option<usize>) -> Result<(), PlaybackError> {
189    let player_guard = PLAYER_HANDLE.read().unwrap();
190    let player = unwrap_player(player_guard.as_ref())?;
191    let mut state_guard = PLAYER_STATE.write().unwrap();
192    let state = unwrap_state_mut(state_guard.as_mut())?;
193    if let Some(id) = index {
194        trace!("Playing a track at index {id}");
195        let track = match state.play_track(id) {
196            Some(track) => track,
197            None => {
198                error!("No track at index {id}");
199                return Err(PlaybackError::NoTrackAtIndex(id));
200            }
201        };
202        let source = match track.open_source() {
203            Ok(source) => source,
204            Err(e) => {
205                error!("Could not open audio source: {e}");
206                return Err(PlaybackError::SourceError);
207            }
208        };
209        player.stop();
210        player.append(source);
211        player.play();
212        state.set_playback_state(PlaybackState::Playing);
213        background_save_state(state.clone());
214        Ok(())
215    } else {
216        trace!("Playing the current media");
217        if !player.is_paused() && !player.empty() {
218            Err(PlaybackError::PlayerPlaying)
219        } else if player.empty() {
220            if let Some(track) = state.current() {
221                let source = match track.open_source() {
222                    Ok(source) => source,
223                    Err(e) => {
224                        error!("Could not open audio source: {e}");
225                        return Err(PlaybackError::SourceError);
226                    }
227                };
228                player.append(source);
229                state.set_playback_state(PlaybackState::Playing);
230                Ok(())
231            } else {
232                Err(PlaybackError::QueueEmpty)
233            }
234        } else {
235            player.play();
236            state.set_playback_state(PlaybackState::Playing);
237            Ok(())
238        }
239    }
240}
241
242pub(crate) fn pause() -> Result<(), PlaybackError> {
243    trace!("Pausing the current media");
244    let player_guard = PLAYER_HANDLE.read().unwrap();
245    let player = player_guard.as_ref().unwrap();
246    if player.is_paused() {
247        Err(PlaybackError::PlayerPaused)
248    } else {
249        player.pause();
250        let mut state_guard = PLAYER_STATE.write().unwrap();
251        let state = unwrap_state_mut(state_guard.as_mut())?;
252        state.set_playback_state(PlaybackState::Paused);
253        Ok(())
254    }
255}
256
257pub(crate) fn stop() -> Result<(), PlaybackError> {
258    trace!("Stopping the playback");
259    let player_guard = PLAYER_HANDLE.read().unwrap();
260    let player = player_guard.as_ref().unwrap();
261    if player.empty() {
262        Err(PlaybackError::PlayerStopped)
263    } else {
264        player.stop();
265        let mut state_guard = PLAYER_STATE.write().unwrap();
266        let state = unwrap_state_mut(state_guard.as_mut())?;
267        state.set_playback_state(PlaybackState::Stopped);
268        Ok(())
269    }
270}
271
272pub(crate) fn toggle_playing() -> Result<(), PlaybackError> {
273    trace!("Toggling playback state");
274    let state_guard = PLAYER_STATE.read().unwrap();
275    let state = unwrap_state_ref(state_guard.as_ref())?;
276    let playback_state = state.playback_state;
277    match playback_state {
278        PlaybackState::Paused => {
279            drop(state_guard);
280            play(None)
281        }
282        PlaybackState::Playing => {
283            drop(state_guard);
284            pause()
285        }
286        PlaybackState::Stopped => {
287            if state.current().is_some() {
288                let pos = state.position;
289                drop(state_guard);
290                play(Some(pos))
291            } else {
292                Err(PlaybackError::QueueEmpty)
293            }
294        }
295    }
296}
297
298pub(crate) fn get_playback_state() -> Result<PlaybackState, PlaybackError> {
299    let state_guard = PLAYER_STATE.read().unwrap();
300    let state = unwrap_state_ref(state_guard.as_ref())?;
301    Ok(state.playback_state)
302}
303
304pub(crate) fn set_queue(queue: Vec<Track>) -> Result<(), PlaybackError> {
305    trace!("Setting a new queue");
306    let mut state_guard = PLAYER_STATE.write().unwrap();
307    let state = unwrap_state_mut(state_guard.as_mut())?;
308    state.set_tracks(queue);
309    let player_guard = PLAYER_HANDLE.read().unwrap();
310    let player = unwrap_player(player_guard.as_ref())?;
311    player.stop();
312    if let Some(track) = state.current() {
313        let source = match track.open_source() {
314            Ok(source) => source,
315            Err(e) => {
316                error!("Could not open audio source: {e}");
317                return Err(PlaybackError::SourceError);
318            }
319        };
320        player.append(source);
321        player.pause();
322    }
323    background_save_state(state.clone());
324    Ok(())
325}
326
327pub(crate) fn append_to_queue(queue: &mut Vec<Track>) -> Result<(), PlaybackError> {
328    trace!("Appending tracks to queue");
329    let mut state_guard = PLAYER_STATE.write().unwrap();
330    let state = unwrap_state_mut(state_guard.as_mut())?;
331    state.append_tracks(queue);
332    background_save_state(state.clone());
333    Ok(())
334}
335
336pub(crate) fn get_current_track() -> Result<Option<Track>, PlaybackError> {
337    let state_guard = PLAYER_STATE.read().unwrap();
338    let state = unwrap_state_ref(state_guard.as_ref())?;
339    match state.current() {
340        Some(track) => Ok(Some(track.clone())),
341        None => Ok(None),
342    }
343}
344
345pub(crate) fn skip_next() -> Result<(), PlaybackError> {
346    trace!("Skipping to the next track");
347    let mut state_guard = PLAYER_STATE.write().unwrap();
348    let state = unwrap_state_mut(state_guard.as_mut())?;
349    if state.can_go_next() {
350        let track = state.next().unwrap();
351        let source = match track.open_source() {
352            Ok(source) => source,
353            Err(e) => {
354                error!("Could not open audio source: {e}");
355                return Err(PlaybackError::SourceError);
356            }
357        };
358        background_save_state(state.clone());
359        let player_guard = PLAYER_HANDLE.read().unwrap();
360        let player = unwrap_player(player_guard.as_ref())?;
361        state.set_player_position(Duration::default());
362        state.set_playback_state(PlaybackState::Playing);
363        player.clear();
364        player.append(source);
365        player.play();
366        Ok(())
367    } else if state.is_empty() {
368        info!("Cannot skip to the next track, queue is empty");
369        Err(PlaybackError::QueueEmpty)
370    } else {
371        info!("Cannot skip to the next track");
372        Err(PlaybackError::CannotGoNext)
373    }
374}
375
376pub(crate) fn skip_previous() -> Result<(), PlaybackError> {
377    trace!("Skipping to the previous track");
378    let mut state_guard = PLAYER_STATE.write().unwrap();
379    let state = unwrap_state_mut(state_guard.as_mut())?;
380    if state.can_go_previous() {
381        let track = state.previous().unwrap();
382        let source = match track.open_source() {
383            Ok(source) => source,
384            Err(e) => {
385                error!("Could not open audio source: {e}");
386                return Err(PlaybackError::SourceError);
387            }
388        };
389        background_save_state(state.clone());
390        let player_guard = PLAYER_HANDLE.read().unwrap();
391        let player = unwrap_player(player_guard.as_ref())?;
392        state.set_player_position(Duration::default());
393        state.set_playback_state(PlaybackState::Playing);
394        player.clear();
395        player.append(source);
396        player.play();
397        Ok(())
398    } else if state.is_empty() {
399        info!("Cannot go to the previous track, queue is empty");
400        Err(PlaybackError::QueueEmpty)
401    } else {
402        info!("Cannot go to the previous track");
403        Err(PlaybackError::CannotGoPrevious)
404    }
405}
406
407pub(crate) fn set_loop_state(loop_state: LoopState) -> Result<(), PlaybackError> {
408    trace!("Setting loop state to {loop_state:?}");
409    let mut state_guard = PLAYER_STATE.write().unwrap();
410    let state = unwrap_state_mut(state_guard.as_mut())?;
411    state.set_loop_state(loop_state);
412    background_save_state(state.clone());
413    Ok(())
414}
415
416pub(crate) fn get_loop_state() -> Result<LoopState, PlaybackError> {
417    let state_guard = PLAYER_STATE.read().unwrap();
418    let state = unwrap_state_ref(state_guard.as_ref())?;
419    Ok(state.loop_state)
420}
421
422pub(crate) fn set_rate(rate: f64) -> Result<(), PlaybackError> {
423    let conf = CONFIG.read().unwrap();
424    if !conf.as_ref().unwrap().allow_rate_modification {
425        return Err(PlaybackError::FixedRate);
426    }
427    let mut state_guard = PLAYER_STATE.write().unwrap();
428    let state = unwrap_state_mut(state_guard.as_mut())?;
429    if !state.playback_rate.is_in_range(rate) {
430        Err(PlaybackError::RateOutOfRange)
431    } else {
432        let player_guard = PLAYER_HANDLE.read().unwrap();
433        let player = unwrap_player(player_guard.as_ref())?;
434        player.set_speed(PlaybackRate::from(rate).get_value_f32());
435        state.set_rate(rate);
436        background_save_state(state.clone());
437        Ok(())
438    }
439}
440
441pub(crate) fn get_rate() -> Result<PlaybackRate, PlaybackError> {
442    let state_guard = PLAYER_STATE.read().unwrap();
443    let state = unwrap_state_ref(state_guard.as_ref())?;
444    Ok(state.playback_rate)
445}
446
447pub(crate) fn set_shuffle_state(shuffle_state: ShuffleState) -> Result<(), PlaybackError> {
448    #[cfg(feature = "shuffle")]
449    {
450        trace!("Setting shuffle state to {shuffle_state:?}");
451        let mut state_guard = PLAYER_STATE.write().unwrap();
452        let state = unwrap_state_mut(state_guard.as_mut())?;
453        state.set_shuffle_state(shuffle_state);
454        state.shuffle();
455        background_save_state(state.clone());
456        Ok(())
457    }
458    #[cfg(not(feature = "shuffle"))]
459    {
460        info!("The daemon was built without shuffle support");
461        return Err(PlaybackError::ShuffleNotSupported);
462    }
463}
464
465pub(crate) fn get_shuffle_state() -> Result<ShuffleState, PlaybackError> {
466    let state_guard = PLAYER_STATE.read().unwrap();
467    let state = unwrap_state_ref(state_guard.as_ref())?;
468    Ok(state.shuffle_state)
469}
470
471pub(crate) fn set_player_position(position: Duration) -> Result<(), PlaybackError> {
472    trace!("Setting player position to {:?}", position.as_secs());
473    let player_guard = PLAYER_HANDLE.read().unwrap();
474    let mut state_guard = PLAYER_STATE.write().unwrap();
475    let state = unwrap_state_mut(state_guard.as_mut())?;
476    if state.playback_state == PlaybackState::Stopped {
477        return Err(PlaybackError::PlayerStopped);
478    }
479    let player = match player_guard.as_ref() {
480        Some(player) => player,
481        None => {
482            warn!("Cannot set player position, player is not connected");
483            return Err(PlaybackError::PlayerNotConnected);
484        }
485    };
486    if player.empty() {
487        Err(PlaybackError::QueueEmpty)
488    } else if let Some(track) = state.current()
489        && position > track.duration
490    {
491        skip_next()
492    } else if let Err(e) = player.try_seek(position) {
493        error!("Could not set player position: {e}");
494        Err(PlaybackError::SeekNotSupported)
495    } else {
496        state.set_player_position(position);
497        Ok(())
498    }
499}
500
501/// When seeking, if the resulting position would result in a value less than this threshold, set
502/// the position to 0s.
503///
504/// Similarly, if the difference between the duration of the current track and the resulting
505/// position would be smaller than this value, skip to the next track.
506static SEEK_ROUND_THRESHOLD: LazyLock<Duration> = LazyLock::new(|| Duration::from_secs(1));
507
508pub(crate) fn seek(delta: SignedDuration) -> Result<(), PlaybackError> {
509    let player_guard = PLAYER_HANDLE.read().unwrap();
510    let player = match player_guard.as_ref() {
511        Some(player) => player,
512        None => {
513            warn!("Cannot seek, the player is not connected");
514            return Err(PlaybackError::PlayerNotConnected);
515        }
516    };
517    let mut state_guard = PLAYER_STATE.write().unwrap();
518    let state = unwrap_state_mut(state_guard.as_mut())?;
519    let pos = match delta {
520        SignedDuration::Positive(positive_dur) => {
521            if positive_dur == Duration::default() {
522                info!("Refusing to seek by 0s");
523                #[cfg(feature = "mpris")]
524                mpris::set_position(state.player_position);
525                return Err(PlaybackError::InvalidDuration);
526            }
527            let sum = match positive_dur.checked_add(player.get_pos()) {
528                Some(sum) => sum,
529                None => {
530                    error!("Overflow detected while seeking, aborting");
531                    return Err(PlaybackError::DurationOverflow);
532                }
533            };
534            if let Some(track) = state.current()
535                && sum > track.duration - *SEEK_ROUND_THRESHOLD
536            {
537                drop(state_guard);
538                return skip_next();
539            } else {
540                trace!("Seeking player by {positive_dur:?}");
541                sum
542            }
543        }
544        SignedDuration::Negative(negative_dur) => {
545            if negative_dur == Duration::default() {
546                info!("Refusing to seek by 0s");
547                return Err(PlaybackError::InvalidDuration);
548            }
549            trace!("Seeking player by -{negative_dur:?}");
550            let sub = match player.get_pos().checked_sub(negative_dur) {
551                Some(sub) => sub,
552                None => {
553                    error!("Overflow detected while seeking");
554                    return Err(PlaybackError::DurationOverflow);
555                }
556            };
557            if sub < *SEEK_ROUND_THRESHOLD {
558                Duration::default()
559            } else {
560                sub
561            }
562        }
563    };
564    if let Err(e) = player.try_seek(pos) {
565        error!("Could not set player position: {e}");
566        Err(PlaybackError::SeekNotSupported)
567    } else {
568        state.set_player_position(pos);
569        Ok(())
570    }
571}
572
573pub(crate) fn get_player_position() -> Result<Duration, PlaybackError> {
574    let state_guard = PLAYER_STATE.read().unwrap();
575    let state = unwrap_state_ref(state_guard.as_ref())?;
576    Ok(state.player_position)
577}
578
579pub(crate) fn set_player_volume(volume: PlayerVolume) -> Result<(), PlaybackError> {
580    trace!("Setting player volume to {:?}", volume);
581    let player_guard = PLAYER_HANDLE.read().unwrap();
582    let player = unwrap_player(player_guard.as_ref())?;
583    player.set_volume(volume.get());
584    let mut state_guard = PLAYER_STATE.write().unwrap();
585    let state = unwrap_state_mut(state_guard.as_mut())?;
586    state.set_player_volume(volume);
587    background_save_state(state.clone());
588    Ok(())
589}
590
591pub(crate) fn get_player_volume() -> Result<PlayerVolume, PlaybackError> {
592    let player_guard = PLAYER_HANDLE.read().unwrap();
593    let player = unwrap_player(player_guard.as_ref())?;
594    Ok(PlayerVolume::new(player.volume()))
595}
596
597pub(crate) fn get_initial_events() -> Result<Vec<Event>, PlaybackError> {
598    let state_guard = PLAYER_STATE.read().unwrap();
599    let state = unwrap_state_ref(state_guard.as_ref())?;
600    Ok(state.get_initial_events())
601}
602
603pub(crate) fn init(config: Config) {
604    trace!("Initializing the playback module");
605
606    trace!("Initializing config");
607    *CONFIG.write().unwrap() = Some(config.clone());
608
609    let state = match restore_state_from_cache() {
610        Ok(state) => {
611            debug!("Restored player state from cache");
612            state
613        }
614        Err(e) => {
615            error!("Could not restore player state from cache: {e}");
616            let state = PlayerState::default();
617            debug!("Creating a new state and attempting to save it in cache");
618            background_save_state(state.clone());
619            state
620        }
621    };
622    trace!("Player state ready!");
623
624    state.send_initial_events();
625
626    let handle = match rodio::DeviceSinkBuilder::open_default_sink() {
627        Ok(sink) => sink,
628        Err(e) => {
629            error!("Could not open the default sink, audio playback will not work! Error: {e}");
630            return;
631        }
632    };
633    let player = Player::connect_new(handle.mixer());
634    player.set_volume(state.player_volume.get());
635
636    *PLAYER_STATE.write().unwrap() = Some(state);
637    *PLAYER_HANDLE.write().unwrap() = Some(player);
638
639    let mut state_guard = PLAYER_STATE.write().unwrap();
640    let state = state_guard.as_mut().unwrap();
641    if let Some(track) = state.current()
642        && let Ok(source) = track.open_source()
643    {
644        let player_guard = PLAYER_HANDLE.read().unwrap();
645        let player = player_guard.as_ref().unwrap();
646        state.player_position = Duration::default();
647        player.append(source);
648        player.pause();
649        player.set_speed(state.playback_rate.get_value_f32());
650        drop(player_guard);
651    }
652    drop(state_guard);
653
654    #[cfg(feature = "mpris")]
655    mpris::launch_server(config);
656
657    let mut initial_iter = true;
658    let sleep_duration = Duration::from_millis(100);
659    loop {
660        thread::sleep(sleep_duration);
661        let mut state_guard = PLAYER_STATE.write().unwrap();
662        let state = state_guard.as_mut().unwrap();
663        let player_guard = PLAYER_HANDLE.read().unwrap();
664        let player = player_guard.as_ref().unwrap();
665        if !player.is_paused() && !player.empty() {
666            state.increment_player_position(sleep_duration);
667        } else if player.empty() {
668            state.set_player_position(Duration::default());
669            if !state.can_go_next() {
670                state.set_playback_state(PlaybackState::Stopped);
671                continue;
672            }
673            let track = state.next().unwrap();
674            let source = match track.open_source() {
675                Ok(source) => source,
676                Err(e) => {
677                    error!("Could not open audio source: {e}");
678                    continue;
679                }
680            };
681            player.append(source);
682            if initial_iter {
683                player.pause();
684                initial_iter = false;
685                state.set_playback_state(PlaybackState::Stopped);
686            } else {
687                state.set_playback_state(PlaybackState::Playing);
688            }
689        }
690        drop(state_guard);
691        drop(player_guard);
692    }
693}
694
695#[cfg(feature = "mpris")]
696pub(crate) fn can_play() -> Result<bool, PlaybackError> {
697    let state_guard = PLAYER_STATE.read().unwrap();
698    let state = unwrap_state_ref(state_guard.as_ref())?;
699    Ok(state.can_play())
700}
701
702#[cfg(feature = "mpris")]
703pub(crate) fn can_pause() -> Result<bool, PlaybackError> {
704    let state_guard = PLAYER_STATE.read().unwrap();
705    let state = unwrap_state_ref(state_guard.as_ref())?;
706    Ok(state.playback_state == PlaybackState::Playing)
707}
708
709#[cfg(feature = "mpris")]
710pub(crate) fn can_go_next() -> Result<bool, PlaybackError> {
711    let state_guard = PLAYER_STATE.read().unwrap();
712    let state = unwrap_state_ref(state_guard.as_ref())?;
713    Ok(state.can_go_next())
714}
715
716#[cfg(feature = "mpris")]
717pub(crate) fn can_go_previous() -> Result<bool, PlaybackError> {
718    let state_guard = PLAYER_STATE.read().unwrap();
719    let state = unwrap_state_ref(state_guard.as_ref())?;
720    Ok(state.can_go_previous())
721}
722
723pub(crate) fn run_command(cmd: Command) -> Result<Response, PlaybackError> {
724    match cmd {
725        Command::Play(pos) => play(pos)?,
726        Command::Pause => pause()?,
727        Command::Stop => stop()?,
728        Command::TogglePlaying => toggle_playing()?,
729        Command::GetPlaybackState => {
730            return Ok(Response::Playback(PlaybackResponse::PlaybackState(
731                get_playback_state()?,
732            )));
733        }
734        Command::SetQueue(queue) => set_queue(queue)?,
735        Command::AppendToQueue(mut queue) => append_to_queue(&mut queue)?,
736        Command::GetCurrentTrack => {
737            return Ok(Response::Playback(match get_current_track()? {
738                Some(track) => PlaybackResponse::Track(Some(Box::new(track.into()))),
739                None => PlaybackResponse::Track(None),
740            }));
741        }
742        Command::Next => skip_next()?,
743        Command::Previous => skip_previous()?,
744        Command::SetLoopState(loop_state) => set_loop_state(loop_state)?,
745        Command::GetLoopState => {
746            return Ok(Response::Playback(PlaybackResponse::LoopState(
747                get_loop_state()?,
748            )));
749        }
750        Command::SetRate(rate) => set_rate(rate)?,
751        Command::GetRate => {
752            return Ok(Response::Playback(PlaybackResponse::PlaybackRate(
753                get_rate()?,
754            )));
755        }
756        Command::SetShuffleState(shuffle_state) => set_shuffle_state(shuffle_state)?,
757        #[cfg(feature = "shuffle")]
758        Command::GetShuffleState => {
759            return Ok(Response::Playback(PlaybackResponse::ShuffleState(
760                get_shuffle_state()?,
761            )));
762        }
763        Command::SetPlayerPosition(position) => set_player_position(position)?,
764        Command::Seek(delta) => seek(delta)?,
765        Command::GetPlayerPosition => {
766            return Ok(Response::Playback(PlaybackResponse::PlayerPosition(
767                get_player_position()?,
768            )));
769        }
770        Command::SetPlayerVolume(volume) => set_player_volume(volume)?,
771        Command::GetPlayerVolume => {
772            return Ok(Response::Playback(PlaybackResponse::PlayerVolume(
773                get_player_volume()?,
774            )));
775        }
776    }
777
778    Ok(Response::Ok)
779}