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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
41pub struct Config {
42 #[cfg(any(feature = "mpris", doc))]
46 pub identity: String,
47 #[cfg(any(feature = "mpris", doc))]
58 pub bus_name_suffix: String,
59 pub allow_rate_modification: bool,
64 #[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
173pub 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
187pub(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
501static 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}