1#![allow(clippy::module_name_repetitions)]
2
3#[cfg(feature = "mock_playback")]
4use std::sync::atomic::AtomicBool;
5use std::{
6 fs::File,
7 io::BufReader,
8 ops::Range,
9 sync::{
10 Arc,
11 mpsc::{Receiver, Sender},
12 },
13 time::Duration,
14};
15
16use log::{debug, error};
17use rodio::{
18 Decoder, Source,
19 source::{EmptyCallback, SeekError},
20};
21use tracing::instrument;
22
23use crate::{
24 errors::LibraryError,
25 format_duration,
26 state::{Percent, SeekType, StateAudio, StateRuntime, Status},
27 udp::StateChange,
28};
29use mecomp_storage::db::schemas::song::Song;
30use one_or_many::OneOrMany;
31
32pub mod commands;
33pub mod queue;
34
35use commands::{AudioCommand, QueueCommand, VolumeCommand};
36use queue::Queue;
37
38const MIN_VOLUME: f32 = 0.0;
40const MAX_VOLUME: f32 = 10.0;
42
43#[derive(Debug, Clone)]
44pub struct AudioKernelSender {
45 tx: Sender<(AudioCommand, tracing::Span)>,
46}
47
48impl AudioKernelSender {
49 #[must_use]
60 #[inline]
61 pub fn start(event_tx: Sender<StateChange>) -> Arc<Self> {
62 let (command_tx, command_rx) = std::sync::mpsc::channel();
63 let tx_clone = command_tx.clone();
64 std::thread::Builder::new()
65 .name(String::from("Audio Kernel"))
66 .spawn(move || {
67 let kernel = AudioKernel::new(tx_clone, event_tx);
68 kernel.init(command_rx);
69 })
70 .unwrap();
71 Arc::new(Self::new(command_tx))
72 }
73
74 #[must_use]
75 #[inline]
76 pub(crate) const fn new(tx: Sender<(AudioCommand, tracing::Span)>) -> Self {
77 Self { tx }
78 }
79
80 #[instrument(skip(self))]
91 pub fn send(&self, command: AudioCommand) {
92 let ctx =
93 tracing::info_span!("Sending Audio Command to Kernel", command = ?command).or_current();
94
95 if let Err(e) = self.tx.send((command, ctx)) {
96 error!("Failed to send command to audio kernel: {e}");
97 panic!("Failed to send command to audio kernel: {e}");
98 }
99 }
100
101 #[instrument(skip(self))]
109 pub fn try_send(
110 &self,
111 command: AudioCommand,
112 ) -> Result<(), std::sync::mpsc::SendError<(AudioCommand, tracing::Span)>> {
113 let ctx =
114 tracing::info_span!("Sending Audio Command to Kernel", command = ?command).or_current();
115
116 self.tx.send((command, ctx))
117 }
118}
119
120impl Drop for AudioKernelSender {
121 #[allow(clippy::missing_inline_in_public_items)]
122 fn drop(&mut self) {
123 let _ = self.try_send(AudioCommand::Exit);
126 }
127}
128
129pub(crate) struct AudioKernel {
137 #[cfg(not(feature = "mock_playback"))]
139 _music_output: (rodio::OutputStream, rodio::OutputStreamHandle),
140 #[cfg(feature = "mock_playback")]
141 queue_rx_stop: Arc<AtomicBool>,
142 player: rodio::Sink,
146 queue: Queue,
148 volume: f32,
151 muted: bool,
153 status: Status,
155 command_tx: Sender<(AudioCommand, tracing::Span)>,
158 event_tx: Sender<StateChange>,
160}
161
162#[cfg(feature = "mock_playback")]
163impl Drop for AudioKernel {
164 fn drop(&mut self) {
165 self.queue_rx_stop
166 .store(true, std::sync::atomic::Ordering::Relaxed);
167 }
168}
169
170impl AudioKernel {
171 #[must_use]
177 #[cfg(not(feature = "mock_playback"))]
178 pub fn new(
179 command_tx: Sender<(AudioCommand, tracing::Span)>,
180 event_tx: Sender<StateChange>,
181 ) -> Self {
182 let (stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
183
184 let sink = rodio::Sink::try_new(&stream_handle).unwrap();
185 sink.pause();
186
187 Self {
188 _music_output: (stream, stream_handle),
189 player: sink.into(),
190 queue: Queue::new(),
191 volume: 1.0,
192 muted: false,
193 status: Status::Stopped,
194 command_tx,
195 event_tx,
196 }
197 }
198
199 #[must_use]
207 #[cfg(feature = "mock_playback")]
208 pub fn new(
209 command_tx: Sender<(AudioCommand, tracing::Span)>,
210 event_tx: Sender<StateChange>,
211 ) -> Self {
212 const QUEUE_POLLING_INTERVAL: Duration = Duration::from_micros(22);
215
216 let (sink, mut queue_rx) = rodio::Sink::new_idle();
217
218 let queue_stop = Arc::new(AtomicBool::new(false));
219 let queue_stop_clone = queue_stop.clone();
220
221 std::thread::spawn(move || {
222 loop {
224 if queue_stop_clone.load(std::sync::atomic::Ordering::Relaxed) {
225 break;
226 }
227 queue_rx.next();
228 std::thread::sleep(QUEUE_POLLING_INTERVAL);
229 }
230 });
231
232 sink.pause();
233
234 Self {
235 player: sink,
236 queue_rx_stop: queue_stop,
237 queue: Queue::new(),
238 volume: 1.0,
239 muted: false,
240 status: Status::Stopped,
241 command_tx,
242 event_tx,
243 }
244 }
245
246 pub fn init(mut self, command_rx: Receiver<(AudioCommand, tracing::Span)>) {
257 for (command, ctx) in command_rx {
258 let _guard = ctx.enter();
259
260 let prev_status = self.status;
261
262 match command {
263 AudioCommand::Play => self.play(),
264 AudioCommand::Pause => self.pause(),
265 AudioCommand::TogglePlayback => self.toggle_playback(),
266 AudioCommand::RestartSong => {
267 self.restart_song();
268 let _ = self
269 .event_tx
270 .send(StateChange::Seeked(Duration::from_secs(0)));
271 }
272 AudioCommand::ClearPlayer => self.clear_player(),
273 AudioCommand::Queue(command) => self.queue_control(command),
274 AudioCommand::Exit => break,
275 AudioCommand::ReportStatus(tx) => {
276 let state = self.state();
277
278 if let Err(e) = tx.send(state) {
279 error!(
284 "Audio Kernel failed to send state to the receiver, state receiver likely has been dropped. State: {e}"
285 );
286 break;
287 }
288 }
289 AudioCommand::Volume(command) => self.volume_control(command),
290 AudioCommand::Seek(seek, duration) => {
291 self.seek(seek, duration);
292 let _ = self
293 .event_tx
294 .send(StateChange::Seeked(self.get_time_played()));
295 }
296 AudioCommand::Stop if prev_status != Status::Stopped => {
297 self.stop();
298 let _ = self
299 .event_tx
300 .send(StateChange::Seeked(Duration::from_secs(0)));
301 }
302 AudioCommand::Stop => {}
303 }
304
305 let new_status = self.status;
306
307 if prev_status != new_status {
308 let _ = self.event_tx.send(StateChange::StatusChanged(new_status));
309 }
310 }
311 }
312
313 #[instrument(skip(self))]
314 fn play(&mut self) {
315 if self.player.empty() {
316 return;
317 }
318 self.player.play();
319 self.status = Status::Playing;
320 }
321
322 #[instrument(skip(self))]
323 fn pause(&mut self) {
324 self.player.pause();
325 self.status = Status::Paused;
326 }
327
328 #[instrument(skip(self))]
329 fn stop(&mut self) {
330 self.player.pause();
331 self.seek(SeekType::Absolute, Duration::from_secs(0));
332 self.status = Status::Stopped;
333 }
334
335 #[instrument(skip(self))]
336 fn toggle_playback(&mut self) {
337 if self.player.is_paused() {
338 self.play();
339 } else {
340 self.pause();
341 }
342 }
343
344 #[instrument(skip(self))]
345 fn restart_song(&mut self) {
346 let status = self.status;
347 self.clear_player();
348
349 if let Some(song) = self.queue.current_song() {
350 if let Err(e) = self.append_song_to_player(song) {
351 error!("Failed to append song to player: {e}");
352 }
353
354 match status {
355 Status::Stopped => {}
357 Status::Paused => self.pause(),
359 Status::Playing => self.play(),
361 }
362 }
363 }
364
365 #[instrument(skip(self))]
366 fn clear(&mut self) {
367 self.clear_player();
368 self.queue.clear();
369 }
370
371 #[instrument(skip(self))]
372 fn clear_player(&mut self) {
373 self.player.clear();
374 self.status = Status::Stopped;
375 }
376
377 #[instrument(skip(self))]
378 fn queue_control(&mut self, command: QueueCommand) {
379 let prev_song = self.queue.current_song().cloned();
380 match command {
381 QueueCommand::Clear => self.clear(),
382 QueueCommand::PlayNextSong => self.start_next_song(),
383 QueueCommand::SkipForward(n) => self.skip_forward(n),
384 QueueCommand::SkipBackward(n) => self.skip_backward(n),
385 QueueCommand::SetPosition(n) => self.set_position(n),
386 QueueCommand::Shuffle => self.queue.shuffle(),
387 QueueCommand::AddToQueue(song_box) => match *song_box {
388 OneOrMany::None => {}
389 OneOrMany::One(song) => self.add_song_to_queue(song),
390 OneOrMany::Many(songs) => self.add_songs_to_queue(songs),
391 },
392 QueueCommand::RemoveRange(range) => self.remove_range_from_queue(range),
393 QueueCommand::SetRepeatMode(mode) => {
394 self.queue.set_repeat_mode(mode);
395 let _ = self.event_tx.send(StateChange::RepeatModeChanged(mode));
396 }
397 }
398
399 let new_song = self.queue.current_song().cloned();
400
401 if prev_song != new_song {
402 let _ = self
403 .event_tx
404 .send(StateChange::TrackChanged(new_song.map(|s| s.id.into())));
405 }
406 }
407
408 #[instrument(skip(self))]
409 fn state(&self) -> StateAudio {
410 let queue_position = self.queue.current_index();
411 let current_song = self.queue.current_song().cloned();
412 let repeat_mode = self.queue.get_repeat_mode();
413 let runtime = current_song.as_ref().map(|song| {
414 let duration = song.runtime;
415 let seek_position = self.get_time_played();
416 let seek_percent =
417 Percent::new(seek_position.as_secs_f32() / duration.as_secs_f32() * 100.0);
418 StateRuntime {
419 seek_position,
420 seek_percent,
421 duration,
422 }
423 });
424 let status = self.status;
425 let status = if self.player.is_paused() {
426 debug_assert!(matches!(status, Status::Paused | Status::Stopped));
427 status
428 } else {
429 debug_assert_eq!(status, Status::Playing);
430 Status::Playing
431 };
432
433 let muted = self.muted;
434 let volume = self.volume;
435
436 let queued_songs = self.queue.queued_songs();
437
438 StateAudio {
439 queue: queued_songs,
440 queue_position,
441 current_song,
442 repeat_mode,
443 runtime,
444 status,
445 muted,
446 volume,
447 }
448 }
449
450 #[instrument(skip(self))]
451 fn start_next_song(&mut self) {
452 self.status = Status::Stopped;
453 self.player.pause();
457
458 let next_song = self.queue.next_song().cloned();
459 let repeat_mode = self.queue.get_repeat_mode();
460 let current_index = self.queue.current_index();
461
462 if let Some(song) = next_song {
463 if let Err(e) = self.append_song_to_player(&song) {
464 error!("Failed to append song to player: {e}");
465 }
466
467 if current_index.is_some() || repeat_mode.is_all() {
470 self.play();
471 }
472 }
473 }
474
475 #[instrument(skip(self))]
476 fn skip_forward(&mut self, n: usize) {
477 let status = self.status;
478 self.clear_player();
479
480 let next_song = self.queue.skip_forward(n).cloned();
481
482 if let Some(song) = next_song {
483 if let Err(e) = self.append_song_to_player(&song) {
484 error!("Failed to append song to player: {e}");
485 }
486
487 match status {
488 Status::Paused => self.pause(),
489 Status::Playing
492 if self.queue.get_repeat_mode().is_all()
493 || self.queue.current_index().is_some() =>
494 {
495 self.play();
496 }
497 _ => {}
498 }
499 }
500 }
501
502 #[instrument(skip(self))]
503 fn skip_backward(&mut self, n: usize) {
504 let status = self.status;
505 self.clear_player();
506
507 let next_song = self.queue.skip_backward(n).cloned();
508
509 if let Some(song) = next_song {
510 if let Err(e) = self.append_song_to_player(&song) {
511 error!("Failed to append song to player: {e}");
512 }
513 match status {
514 Status::Stopped => {}
515 Status::Paused => self.pause(),
516 Status::Playing => self.play(),
517 }
518 }
519 }
520
521 #[instrument(skip(self))]
522 fn set_position(&mut self, n: usize) {
523 let status = self.status;
524 self.clear_player();
525
526 self.queue.set_current_index(n);
527 let next_song = self.queue.current_song().cloned();
528
529 if let Some(song) = next_song {
530 if let Err(e) = self.append_song_to_player(&song) {
531 error!("Failed to append song to player: {e}");
532 }
533
534 match status {
535 Status::Stopped => {}
536 Status::Paused => self.pause(),
537 Status::Playing => self.play(),
538 }
539 }
540 }
541
542 #[instrument(skip(self))]
543 fn add_song_to_queue(&mut self, song: Song) {
544 self.queue.add_song(song);
545
546 if self.player.empty() {
548 let current_song = self.get_current_song();
549
550 if let Some(song) = current_song.or_else(|| self.get_next_song()) {
551 if let Err(e) = self.append_song_to_player(&song) {
552 error!("Failed to append song to player: {e}");
553 }
554 self.play();
555 }
556 }
557 }
558
559 #[instrument(skip(self))]
560 fn add_songs_to_queue(&mut self, songs: Vec<Song>) {
561 self.queue.add_songs(songs);
562
563 if self.player.empty() {
565 let current_song = self.get_current_song();
566
567 if let Some(song) = current_song.or_else(|| self.get_next_song()) {
568 if let Err(e) = self.append_song_to_player(&song) {
569 error!("Failed to append song to player: {e}");
570 }
571 self.play();
572 }
573 }
574 }
575
576 #[instrument(skip(self))]
577 fn remove_range_from_queue(&mut self, range: Range<usize>) {
578 let current_to_be_removed = self
580 .queue
581 .current_index()
582 .is_some_and(|current_index| range.contains(¤t_index));
583
584 self.queue.remove_range(range);
585
586 if current_to_be_removed {
588 self.clear_player();
589 if let Some(song) = self.get_current_song() {
590 if let Err(e) = self.append_song_to_player(&song) {
591 error!("Failed to append song to player: {e}");
592 }
593 }
594 }
595 }
596
597 #[instrument(skip(self))]
598 fn get_current_song(&self) -> Option<Song> {
599 self.queue.current_song().cloned()
600 }
601
602 #[instrument(skip(self))]
603 fn get_next_song(&mut self) -> Option<Song> {
604 self.queue.next_song().cloned()
605 }
606
607 fn get_time_played(&self) -> Duration {
608 self.player.get_pos()
609 }
610
611 #[instrument(skip(self, source))]
612 fn append_to_player<T>(&self, source: T)
613 where
614 T: Source<Item = f32> + Send + 'static,
615 {
616 self.player.append(source);
617
618 let command_tx = self.command_tx.clone();
620 self.player
621 .append(EmptyCallback::<f32>::new(Box::new(move || {
622 log::debug!("Song finished");
623 if let Err(e) = command_tx.send((
624 AudioCommand::Queue(QueueCommand::PlayNextSong),
625 tracing::Span::current(),
626 )) {
627 error!("Failed to send command to audio kernel: {e}");
628 } else {
629 log::debug!("Sent PlayNextSong command to audio kernel");
630 }
631 })));
632 }
633
634 #[instrument(skip(self))]
635 fn append_song_to_player(&self, song: &Song) -> Result<(), LibraryError> {
636 let source = Decoder::new(BufReader::new(File::open(&song.path)?))?.convert_samples();
637 self.append_to_player(source);
638
639 Ok(())
640 }
641
642 #[instrument(skip(self))]
643 fn volume_control(&mut self, command: VolumeCommand) {
644 match command {
645 VolumeCommand::Up(change) => {
646 let volume = self.volume;
647 let updated = (volume + change).clamp(MIN_VOLUME, MAX_VOLUME);
648 if (volume - updated).abs() > 0.0001 {
650 self.volume = updated;
651 let _ = self.event_tx.send(StateChange::VolumeChanged(self.volume));
652 }
653 }
654 VolumeCommand::Down(change) => {
655 let volume = self.volume;
656 let updated = (volume - change).clamp(MIN_VOLUME, MAX_VOLUME);
657 if (volume - updated).abs() > 0.0001 {
658 self.volume = updated;
659 let _ = self.event_tx.send(StateChange::VolumeChanged(self.volume));
660 }
661 }
662 VolumeCommand::Set(updated) => {
663 let volume = self.volume;
664 let updated = updated.clamp(MIN_VOLUME, MAX_VOLUME);
665 if (volume - updated).abs() > 0.0001 {
666 self.volume = updated;
667 let _ = self.event_tx.send(StateChange::VolumeChanged(self.volume));
668 }
669 }
670 VolumeCommand::Mute => {
671 self.muted = true;
672 let _ = self.event_tx.send(StateChange::Muted);
673 }
674 VolumeCommand::Unmute => {
675 self.muted = false;
676 let _ = self.event_tx.send(StateChange::Unmuted);
677 }
678 VolumeCommand::ToggleMute => {
679 self.muted = !self.muted;
680 if self.muted {
681 let _ = self.event_tx.send(StateChange::Muted);
682 } else {
683 let _ = self.event_tx.send(StateChange::Unmuted);
684 }
685 }
686 }
687
688 if self.muted {
689 self.player.set_volume(0.0);
690 } else {
691 self.player.set_volume(self.volume.to_owned());
692 }
693 }
694
695 #[instrument(skip(self))]
696 fn seek(&mut self, seek: SeekType, duration: Duration) {
697 let new_time = match seek {
699 SeekType::Absolute => duration,
700 SeekType::RelativeForwards => self.get_time_played().saturating_add(duration),
701 SeekType::RelativeBackwards => self.get_time_played().saturating_sub(duration),
702 };
703
704 match self.player.try_seek(new_time) {
708 Ok(()) => {
709 debug!("Seek to {} successful", format_duration(&new_time));
710 if new_time > Duration::from_secs(0) && self.status == Status::Stopped {
711 self.status = Status::Paused;
712 }
713 }
714 Err(SeekError::NotSupported { underlying_source }) => {
715 error!("Seek not supported by source: {underlying_source}");
716 }
717 Err(err) => {
718 error!("Seeking failed with error: {err}");
719 }
720 }
721 }
722}
723
724#[cfg(test)]
725mod tests {
726 use pretty_assertions::assert_eq;
727 use rstest::{fixture, rstest};
728
729 use crate::test_utils::init;
730
731 use super::*;
732 use std::sync::mpsc;
733 use std::time::Duration;
734
735 #[fixture]
736 fn audio_kernel() -> AudioKernel {
737 let (tx, _) = mpsc::channel();
739 let (event_tx, _) = mpsc::channel();
741 AudioKernel::new(tx, event_tx)
742 }
743
744 #[fixture]
745 fn audio_kernel_sender() -> Arc<AudioKernelSender> {
746 let (tx, _) = mpsc::channel();
748 AudioKernelSender::start(tx)
749 }
750
751 async fn get_state(sender: Arc<AudioKernelSender>) -> StateAudio {
752 let (tx, rx) = tokio::sync::oneshot::channel::<StateAudio>();
753 sender.send(AudioCommand::ReportStatus(tx));
754 rx.await.unwrap()
755 }
756
757 #[fixture]
758 fn sound() -> impl Source<Item = f32> + Send + 'static {
759 rodio::source::SineWave::new(440.0)
760 }
761
762 #[test]
763 fn test_audio_kernel_sender_send() {
764 let (tx, rx) = mpsc::channel();
765 let sender = AudioKernelSender::new(tx);
766 sender.send(AudioCommand::Play);
767 let (recv, _) = rx.recv().unwrap();
768 assert_eq!(recv, AudioCommand::Play);
769 }
770
771 #[test]
772 #[should_panic = "Failed to send command to audio kernel: sending on a closed channel"]
773 fn test_audio_kernel_send_closed_channel() {
774 let (tx, _) = mpsc::channel();
775 let sender = AudioKernelSender::new(tx);
776 sender.send(AudioCommand::Play);
777 }
778
779 #[test]
780 fn test_audio_kernel_try_send_closed_channel() {
781 let (tx, _) = mpsc::channel();
782 let sender = AudioKernelSender::new(tx);
783 assert!(sender.try_send(AudioCommand::Play).is_err());
784 }
785
786 #[rstest]
787 #[timeout(Duration::from_secs(3))] fn test_audio_player_kernel_spawn_and_exit(
789 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
790 ) {
791 init();
792
793 sender.send(AudioCommand::Exit);
794 }
795
796 #[rstest]
797 fn test_volume_control(mut audio_kernel: AudioKernel) {
798 audio_kernel.volume_control(VolumeCommand::Up(0.1));
799 let volume = audio_kernel.volume;
800 assert!(f32::EPSILON > (volume - 1.1).abs(), "{volume} != 1.1");
801
802 audio_kernel.volume_control(VolumeCommand::Down(0.1));
803 let volume = audio_kernel.volume;
804 assert!(f32::EPSILON > (volume - 1.0).abs(), "{volume} != 1.0");
805
806 audio_kernel.volume_control(VolumeCommand::Set(0.5));
807 let volume = audio_kernel.volume;
808 assert!(f32::EPSILON > (volume - 0.5).abs(), "{volume} != 0.5");
809
810 audio_kernel.volume_control(VolumeCommand::Mute);
811 assert_eq!(audio_kernel.muted, true);
812
813 audio_kernel.volume_control(VolumeCommand::Unmute);
814 assert_eq!(audio_kernel.muted, false);
815
816 audio_kernel.volume_control(VolumeCommand::ToggleMute);
817 assert_eq!(audio_kernel.muted, true);
818
819 audio_kernel.volume_control(VolumeCommand::ToggleMute);
820 assert_eq!(audio_kernel.muted, false);
821 }
822
823 mod playback_tests {
824 use mecomp_storage::test_utils::{arb_song_case, create_song_metadata, init_test_database};
829 use pretty_assertions::assert_eq;
830 use rstest::rstest;
831
832 use crate::test_utils::init;
833
834 use super::{super::*, audio_kernel, audio_kernel_sender, get_state, sound};
835
836 #[rstest]
837 fn test_audio_kernel_play_pause(
838 mut audio_kernel: AudioKernel,
839 sound: impl Source<Item = f32> + Send + 'static,
840 ) {
841 init();
842 audio_kernel.player.append(sound);
843 audio_kernel.play();
844 assert!(!audio_kernel.player.is_paused());
845 audio_kernel.pause();
846 assert!(audio_kernel.player.is_paused());
847 }
848
849 #[rstest]
850 fn test_audio_kernel_toggle_playback(
851 mut audio_kernel: AudioKernel,
852 sound: impl Source<Item = f32> + Send + 'static,
853 ) {
854 init();
855 audio_kernel.player.append(sound);
856 audio_kernel.play();
857 assert!(!audio_kernel.player.is_paused());
858 audio_kernel.toggle_playback();
859 assert!(audio_kernel.player.is_paused());
860 audio_kernel.toggle_playback();
861 assert!(!audio_kernel.player.is_paused());
862 }
863
864 #[rstest]
865 #[timeout(Duration::from_secs(10))] #[tokio::test]
867 async fn test_play_pause_toggle_restart(
868 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
869 ) {
870 init();
871 let db = init_test_database().await.unwrap();
872 let tempdir = tempfile::tempdir().unwrap();
873
874 let song = Song::try_load_into_db(
875 &db,
876 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
877 )
878 .await
879 .unwrap();
880
881 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
882 OneOrMany::One(song.clone()),
883 ))));
884
885 let state = get_state(sender.clone()).await;
886 assert_eq!(state.queue_position, Some(0));
887 assert_eq!(state.status, Status::Playing);
888
889 sender.send(AudioCommand::Pause);
890 let state = get_state(sender.clone()).await;
891 assert_eq!(state.status, Status::Paused);
892
893 sender.send(AudioCommand::Play);
894 let state = get_state(sender.clone()).await;
895 assert_eq!(state.status, Status::Playing);
896
897 sender.send(AudioCommand::RestartSong);
898 let state = get_state(sender.clone()).await;
899 assert_eq!(state.status, Status::Playing); sender.send(AudioCommand::TogglePlayback);
902 let state = get_state(sender.clone()).await;
903 assert_eq!(state.status, Status::Paused);
904
905 sender.send(AudioCommand::RestartSong);
906 let state = get_state(sender.clone()).await;
907 assert_eq!(state.status, Status::Paused); sender.send(AudioCommand::Exit);
910 }
911
912 #[rstest]
913 fn test_audio_kernel_stop(mut audio_kernel: AudioKernel) {
914 init();
915 audio_kernel.player.append(sound());
916 audio_kernel.play();
917 assert!(!audio_kernel.player.is_paused());
918 audio_kernel.stop();
919 assert!(audio_kernel.player.is_paused());
920 assert_eq!(audio_kernel.player.get_pos(), Duration::from_secs(0));
921 assert_eq!(audio_kernel.status, Status::Stopped);
922 }
923
924 #[rstest]
925 #[timeout(Duration::from_secs(10))] #[tokio::test]
927 async fn test_audio_kernel_skip_forward(mut audio_kernel: AudioKernel) {
928 init();
929 let db = init_test_database().await.unwrap();
930 let tempdir = tempfile::tempdir().unwrap();
931
932 let state = audio_kernel.state();
933 assert_eq!(state.queue_position, None);
934 assert!(state.paused());
935 assert_eq!(state.status, Status::Stopped);
936
937 audio_kernel.queue_control(QueueCommand::AddToQueue(Box::new(OneOrMany::Many(vec![
938 Song::try_load_into_db(
939 &db,
940 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
941 )
942 .await
943 .unwrap(),
944 Song::try_load_into_db(
945 &db,
946 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
947 )
948 .await
949 .unwrap(),
950 Song::try_load_into_db(
951 &db,
952 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
953 )
954 .await
955 .unwrap(),
956 ]))));
957
958 let state = audio_kernel.state();
960 assert_eq!(state.queue_position, Some(0));
961 assert!(!state.paused());
962 assert_eq!(state.status, Status::Playing);
963
964 audio_kernel.queue_control(QueueCommand::SkipForward(1));
965
966 let state = audio_kernel.state();
968 assert_eq!(state.queue_position, Some(1));
969 assert!(!state.paused());
970 assert_eq!(state.status, Status::Playing);
971
972 audio_kernel.queue_control(QueueCommand::SkipForward(1));
973
974 let state = audio_kernel.state();
976 assert_eq!(state.queue_position, Some(2));
977 assert!(!state.paused());
978 assert_eq!(state.status, Status::Playing);
979
980 audio_kernel.queue_control(QueueCommand::SkipForward(1));
981
982 let state = audio_kernel.state();
985 assert_eq!(state.queue_position, None);
986 assert!(state.paused());
987 assert_eq!(state.status, Status::Stopped);
988 }
989
990 #[rstest]
991 #[timeout(Duration::from_secs(6))] #[tokio::test]
993 async fn test_audio_kernel_skip_forward_sender(
994 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
995 ) {
996 init();
998
999 let db = init_test_database().await.unwrap();
1000 let tempdir = tempfile::tempdir().unwrap();
1001
1002 let state = get_state(sender.clone()).await;
1003 assert_eq!(state.queue_position, None);
1004 assert!(state.paused());
1005 assert_eq!(state.status, Status::Stopped);
1006
1007 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1008 OneOrMany::Many(vec![
1009 Song::try_load_into_db(
1010 &db,
1011 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1012 )
1013 .await
1014 .unwrap(),
1015 Song::try_load_into_db(
1016 &db,
1017 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1018 )
1019 .await
1020 .unwrap(),
1021 Song::try_load_into_db(
1022 &db,
1023 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1024 )
1025 .await
1026 .unwrap(),
1027 ]),
1028 ))));
1029 let state = get_state(sender.clone()).await;
1031 assert_eq!(state.queue_position, Some(0));
1032 assert!(!state.paused());
1033 assert_eq!(state.status, Status::Playing);
1034
1035 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1036 let state = get_state(sender.clone()).await;
1038 assert_eq!(state.queue_position, Some(1));
1039 assert!(!state.paused());
1040 assert_eq!(state.status, Status::Playing);
1041
1042 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1043 let state = get_state(sender.clone()).await;
1045 assert_eq!(state.queue_position, Some(2));
1046 assert!(!state.paused());
1047 assert_eq!(state.status, Status::Playing);
1048
1049 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1050 let state = get_state(sender.clone()).await;
1052 assert_eq!(state.queue_position, None);
1053 assert!(state.paused());
1054 assert_eq!(state.status, Status::Stopped);
1055
1056 sender.send(AudioCommand::Exit);
1057 }
1058
1059 #[rstest]
1060 #[timeout(Duration::from_secs(6))] #[tokio::test]
1062 async fn test_remove_range_from_queue(
1063 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1064 ) {
1065 init();
1066 let db = init_test_database().await.unwrap();
1067 let tempdir = tempfile::tempdir().unwrap();
1068 let song1 = Song::try_load_into_db(
1069 &db,
1070 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1071 )
1072 .await
1073 .unwrap();
1074 let song2 = Song::try_load_into_db(
1075 &db,
1076 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1077 )
1078 .await
1079 .unwrap();
1080
1081 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1083 OneOrMany::Many(vec![song1.clone(), song2.clone()]),
1084 ))));
1085 let state = get_state(sender.clone()).await;
1086 assert_eq!(state.queue_position, Some(0));
1087 assert!(!state.paused());
1088 assert_eq!(state.status, Status::Playing);
1089
1090 sender.send(AudioCommand::Pause);
1092
1093 sender.send(AudioCommand::Queue(QueueCommand::RemoveRange(0..1)));
1095 let state = get_state(sender.clone()).await;
1096 assert_eq!(state.queue_position, Some(0));
1097 assert!(state.paused());
1098 assert_eq!(state.status, Status::Stopped);
1099 assert_eq!(state.queue.len(), 1);
1100 assert_eq!(state.queue[0], song2);
1101
1102 sender.send(AudioCommand::Play);
1104
1105 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1107 OneOrMany::One(song1.clone()),
1108 ))));
1109 let state = get_state(sender.clone()).await;
1110 assert_eq!(state.queue_position, Some(0));
1111 assert!(!state.paused());
1112 assert_eq!(state.status, Status::Playing);
1113 assert_eq!(state.queue.len(), 2);
1114 assert_eq!(state.queue[0], song2);
1115 assert_eq!(state.queue[1], song1);
1116
1117 sender.send(AudioCommand::Queue(QueueCommand::RemoveRange(1..2)));
1119 let state = get_state(sender.clone()).await;
1120 assert_eq!(state.queue_position, Some(0));
1121 assert!(!state.paused());
1122 assert_eq!(state.status, Status::Playing);
1123 assert_eq!(state.queue.len(), 1);
1124 assert_eq!(state.queue[0], song2);
1125
1126 sender.send(AudioCommand::Exit);
1127 }
1128
1129 #[rstest]
1130 #[timeout(Duration::from_secs(10))] #[tokio::test]
1132 async fn test_audio_kernel_skip_backward(
1133 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1134 ) {
1135 init();
1136 let db = init_test_database().await.unwrap();
1137 let tempdir = tempfile::tempdir().unwrap();
1138
1139 let state = get_state(sender.clone()).await;
1140 assert_eq!(state.queue_position, None);
1141 assert!(state.paused());
1142 assert_eq!(state.status, Status::Stopped);
1143
1144 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1145 OneOrMany::Many(vec![
1146 Song::try_load_into_db(
1147 &db,
1148 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1149 )
1150 .await
1151 .unwrap(),
1152 Song::try_load_into_db(
1153 &db,
1154 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1155 )
1156 .await
1157 .unwrap(),
1158 Song::try_load_into_db(
1159 &db,
1160 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1161 )
1162 .await
1163 .unwrap(),
1164 ]),
1165 ))));
1166
1167 let state = get_state(sender.clone()).await;
1169 assert_eq!(state.queue_position, Some(0));
1170 assert!(!state.paused());
1171 assert_eq!(state.status, Status::Playing);
1172
1173 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(2)));
1174
1175 let state = get_state(sender.clone()).await;
1177 assert_eq!(state.queue_position, Some(2));
1178 assert!(!state.paused());
1179 assert_eq!(state.status, Status::Playing);
1180
1181 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1182
1183 let state = get_state(sender.clone()).await;
1185 assert_eq!(state.queue_position, Some(1));
1186 assert!(!state.paused());
1187 assert_eq!(state.status, Status::Playing);
1188
1189 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1190
1191 let state = get_state(sender.clone()).await;
1193 assert_eq!(state.queue_position, Some(0));
1194 assert!(!state.paused());
1195
1196 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1197
1198 let state = get_state(sender.clone()).await;
1200 assert_eq!(state.queue_position, None);
1201 assert!(state.paused());
1202 assert_eq!(state.status, Status::Stopped);
1203
1204 sender.send(AudioCommand::Exit);
1205 }
1206
1207 #[rstest]
1208 #[timeout(Duration::from_secs(10))] #[tokio::test]
1210 async fn test_audio_kernel_set_position(
1211 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1212 ) {
1213 init();
1214 let db = init_test_database().await.unwrap();
1215 let tempdir = tempfile::tempdir().unwrap();
1216
1217 let state = get_state(sender.clone()).await;
1218 assert_eq!(state.queue_position, None);
1219 assert!(state.paused());
1220 assert_eq!(state.status, Status::Stopped);
1221
1222 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1223 OneOrMany::Many(vec![
1224 Song::try_load_into_db(
1225 &db,
1226 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1227 )
1228 .await
1229 .unwrap(),
1230 Song::try_load_into_db(
1231 &db,
1232 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1233 )
1234 .await
1235 .unwrap(),
1236 Song::try_load_into_db(
1237 &db,
1238 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1239 )
1240 .await
1241 .unwrap(),
1242 ]),
1243 ))));
1244 let state = get_state(sender.clone()).await;
1246 assert_eq!(state.queue_position, Some(0));
1247 assert!(!state.paused());
1248 assert_eq!(state.status, Status::Playing);
1249
1250 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(1)));
1251 let state = get_state(sender.clone()).await;
1253 assert_eq!(state.queue_position, Some(1));
1254 assert!(!state.paused());
1255 assert_eq!(state.status, Status::Playing);
1256
1257 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(2)));
1258 let state = get_state(sender.clone()).await;
1260 assert_eq!(state.queue_position, Some(2));
1261 assert!(!state.paused());
1262 assert_eq!(state.status, Status::Playing);
1263
1264 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(0)));
1265 let state = get_state(sender.clone()).await;
1267 assert_eq!(state.queue_position, Some(0));
1268 assert!(!state.paused());
1269 assert_eq!(state.status, Status::Playing);
1270
1271 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(3)));
1272 let state = get_state(sender.clone()).await;
1274 assert_eq!(state.queue_position, Some(2));
1275 assert!(!state.paused());
1276 assert_eq!(state.status, Status::Playing);
1277
1278 sender.send(AudioCommand::Exit);
1279 }
1280
1281 #[rstest]
1282 #[timeout(Duration::from_secs(6))] #[tokio::test]
1284 async fn test_audio_kernel_clear(
1285 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1286 ) {
1287 init();
1288 let db = init_test_database().await.unwrap();
1289 let tempdir = tempfile::tempdir().unwrap();
1290
1291 let state = get_state(sender.clone()).await;
1292 assert_eq!(state.queue_position, None);
1293 assert!(state.paused());
1294 assert_eq!(state.status, Status::Stopped);
1295
1296 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1297 OneOrMany::Many(vec![
1298 Song::try_load_into_db(
1299 &db,
1300 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1301 )
1302 .await
1303 .unwrap(),
1304 Song::try_load_into_db(
1305 &db,
1306 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1307 )
1308 .await
1309 .unwrap(),
1310 Song::try_load_into_db(
1311 &db,
1312 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1313 )
1314 .await
1315 .unwrap(),
1316 ]),
1317 ))));
1318 let state = get_state(sender.clone()).await;
1320 assert_eq!(state.queue_position, Some(0));
1321 assert_eq!(state.queue.len(), 3);
1322 assert!(!state.paused());
1323 assert_eq!(state.status, Status::Playing);
1324
1325 sender.send(AudioCommand::ClearPlayer);
1326 let state = get_state(sender.clone()).await;
1328 assert_eq!(state.queue_position, Some(0));
1329 assert_eq!(state.queue.len(), 3);
1330 assert!(state.paused());
1331 assert_eq!(state.status, Status::Stopped);
1332
1333 sender.send(AudioCommand::Queue(QueueCommand::Clear));
1334 let state = get_state(sender.clone()).await;
1336 assert_eq!(state.queue_position, None);
1337 assert_eq!(state.queue.len(), 0);
1338 assert!(state.paused());
1339 assert_eq!(state.status, Status::Stopped);
1340
1341 sender.send(AudioCommand::Exit);
1342 }
1343
1344 #[rstest]
1345 #[timeout(Duration::from_secs(6))] #[tokio::test]
1347 async fn test_audio_kernel_shuffle(
1348 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1349 ) {
1350 init();
1351 let db = init_test_database().await.unwrap();
1352 let tempdir = tempfile::tempdir().unwrap();
1353
1354 let state = get_state(sender.clone()).await;
1355 assert_eq!(state.queue_position, None);
1356 assert!(state.paused());
1357 assert_eq!(state.status, Status::Stopped);
1358
1359 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1360 OneOrMany::Many(vec![
1361 Song::try_load_into_db(
1362 &db,
1363 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1364 )
1365 .await
1366 .unwrap(),
1367 Song::try_load_into_db(
1368 &db,
1369 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1370 )
1371 .await
1372 .unwrap(),
1373 Song::try_load_into_db(
1374 &db,
1375 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1376 )
1377 .await
1378 .unwrap(),
1379 ]),
1380 ))));
1381 let state = get_state(sender.clone()).await;
1383 assert_eq!(state.queue_position, Some(0));
1384 assert_eq!(state.queue.len(), 3);
1385 assert!(!state.paused());
1386 assert_eq!(state.status, Status::Playing);
1387
1388 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1390 let state = get_state(sender.clone()).await;
1391 assert_eq!(state.queue_position, Some(1));
1392 assert_eq!(state.queue.len(), 3);
1393 assert!(!state.paused());
1394 assert_eq!(state.status, Status::Playing);
1395
1396 sender.send(AudioCommand::Queue(QueueCommand::Shuffle));
1398 let state = get_state(sender.clone()).await;
1400 assert_eq!(state.queue_position, Some(0));
1401 assert_eq!(state.queue.len(), 3);
1402 assert!(!state.paused());
1403 assert_eq!(state.status, Status::Playing);
1404
1405 sender.send(AudioCommand::Exit);
1406 }
1407
1408 #[rstest]
1409 #[timeout(Duration::from_secs(5))] #[tokio::test]
1411 async fn test_volume_commands(#[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>) {
1412 init();
1413
1414 let state = get_state(sender.clone()).await;
1415 assert!(
1416 f32::EPSILON > (state.volume - 1.0).abs(),
1417 "{} != 1.0",
1418 state.volume
1419 );
1420 assert!(!state.muted);
1421
1422 sender.send(AudioCommand::Volume(VolumeCommand::Up(0.1)));
1423 let state = get_state(sender.clone()).await;
1424 assert!(
1425 f32::EPSILON > (state.volume - 1.1).abs(),
1426 "{} != 1.1",
1427 state.volume
1428 );
1429 assert!(!state.muted);
1430
1431 sender.send(AudioCommand::Volume(VolumeCommand::Down(0.1)));
1432 let state = get_state(sender.clone()).await;
1433 assert!(
1434 f32::EPSILON > (state.volume - 1.0).abs(),
1435 "{} != 1.0",
1436 state.volume
1437 );
1438 assert!(!state.muted);
1439
1440 sender.send(AudioCommand::Volume(VolumeCommand::Set(0.5)));
1441 let state = get_state(sender.clone()).await;
1442 assert!(
1443 f32::EPSILON > (state.volume - 0.5).abs(),
1444 "{} != 0.5",
1445 state.volume
1446 );
1447 assert!(!state.muted);
1448
1449 sender.send(AudioCommand::Volume(VolumeCommand::Mute));
1450 let state = get_state(sender.clone()).await;
1451 assert!(
1452 f32::EPSILON > (state.volume - 0.5).abs(),
1453 "{} != 0.5",
1454 state.volume
1455 ); assert!(state.muted);
1457
1458 sender.send(AudioCommand::Volume(VolumeCommand::Unmute));
1459 let state = get_state(sender.clone()).await;
1460 assert!(
1461 f32::EPSILON > (state.volume - 0.5).abs(),
1462 "{} != 0.5",
1463 state.volume
1464 );
1465 assert!(!state.muted);
1466
1467 sender.send(AudioCommand::Volume(VolumeCommand::ToggleMute));
1468 let state = get_state(sender.clone()).await;
1469 assert!(
1470 f32::EPSILON > (state.volume - 0.5).abs(),
1471 "{} != 0.5",
1472 state.volume
1473 );
1474 assert!(state.muted);
1475
1476 sender.send(AudioCommand::Volume(VolumeCommand::ToggleMute));
1477 let state = get_state(sender.clone()).await;
1478 assert!(
1479 f32::EPSILON > (state.volume - 0.5).abs(),
1480 "{} != 0.5",
1481 state.volume
1482 );
1483 assert!(!state.muted);
1484
1485 sender.send(AudioCommand::Exit);
1486 }
1487
1488 #[rstest]
1489 #[timeout(Duration::from_secs(5))] #[tokio::test]
1491 async fn test_volume_out_of_bounds(
1492 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1493 ) {
1494 init();
1495
1496 sender.send(AudioCommand::Volume(VolumeCommand::Up(MAX_VOLUME + 0.5)));
1498 let state = get_state(sender.clone()).await;
1499 assert!(
1500 f32::EPSILON > (state.volume - MAX_VOLUME).abs(),
1501 "{} != {}",
1502 state.volume,
1503 MAX_VOLUME
1504 );
1505 assert!(!state.muted);
1506 sender.send(AudioCommand::Volume(VolumeCommand::Down(
1507 MAX_VOLUME + 0.5 - MIN_VOLUME,
1508 )));
1509 let state = get_state(sender.clone()).await;
1510 assert!(
1511 f32::EPSILON > (state.volume - MIN_VOLUME).abs(),
1512 "{} != {}",
1513 state.volume,
1514 MIN_VOLUME
1515 );
1516 assert!(!state.muted);
1517
1518 sender.send(AudioCommand::Volume(VolumeCommand::Set(MAX_VOLUME + 0.5)));
1520 let state = get_state(sender.clone()).await;
1521 assert!(
1522 f32::EPSILON > (state.volume - MAX_VOLUME).abs(),
1523 "{} != {}",
1524 state.volume,
1525 MAX_VOLUME
1526 );
1527 assert!(!state.muted);
1528 sender.send(AudioCommand::Volume(VolumeCommand::Set(MIN_VOLUME - 0.5)));
1529 let state = get_state(sender.clone()).await;
1530 assert!(
1531 f32::EPSILON > (state.volume - MIN_VOLUME).abs(),
1532 "{} != {}",
1533 state.volume,
1534 MIN_VOLUME
1535 );
1536 assert!(!state.muted);
1537
1538 sender.send(AudioCommand::Exit);
1539 }
1540
1541 #[rstest]
1542 #[timeout(Duration::from_secs(9))] #[tokio::test]
1544 async fn test_seek_commands(#[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>) {
1545 init();
1546 let db = init_test_database().await.unwrap();
1547 let tempdir = tempfile::tempdir().unwrap();
1548
1549 let song = Song::try_load_into_db(
1550 &db,
1551 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1552 )
1553 .await
1554 .unwrap();
1555
1556 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(Box::new(
1559 OneOrMany::One(song.clone()),
1560 ))));
1561 sender.send(AudioCommand::Stop);
1562 sender.send(AudioCommand::Seek(
1563 SeekType::Absolute,
1564 Duration::from_secs(0),
1565 ));
1566 let state: StateAudio = get_state(sender.clone()).await;
1567 assert_eq!(state.queue_position, Some(0));
1568 assert_eq!(state.status, Status::Stopped);
1569 assert_eq!(
1570 state.runtime.unwrap().duration,
1571 Duration::from_secs(10) + Duration::from_millis(188)
1572 );
1573 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(0));
1574
1575 sender.send(AudioCommand::Seek(
1577 SeekType::RelativeForwards,
1578 Duration::from_secs(2),
1579 ));
1580 let state = get_state(sender.clone()).await;
1581 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(2));
1582 assert_eq!(state.current_song, Some(song.clone()));
1583 assert_eq!(state.status, Status::Paused);
1584
1585 sender.send(AudioCommand::Seek(
1587 SeekType::RelativeBackwards,
1588 Duration::from_secs(1),
1589 ));
1590 let state = get_state(sender.clone()).await;
1591 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(1));
1592 assert_eq!(state.current_song, Some(song.clone()));
1593 assert_eq!(state.status, Status::Paused);
1594
1595 sender.send(AudioCommand::Seek(
1597 SeekType::Absolute,
1598 Duration::from_secs(10),
1599 ));
1600 let state = get_state(sender.clone()).await;
1601 assert_eq!(
1602 state.runtime.unwrap().seek_position,
1603 Duration::from_secs(10)
1604 );
1605 assert_eq!(state.current_song, Some(song.clone()));
1606 assert_eq!(state.status, Status::Paused);
1607
1608 sender.send(AudioCommand::Play);
1610 tokio::time::sleep(Duration::from_millis(500)).await;
1611 let state = get_state(sender.clone()).await;
1612 assert_eq!(state.queue_position, None);
1613 assert_eq!(state.status, Status::Stopped);
1614
1615 sender.send(AudioCommand::Exit);
1616 }
1617 }
1618}