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::SongBrief;
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: SongBrief) {
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<SongBrief>) {
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<SongBrief> {
599 self.queue.current_song().cloned()
600 }
601
602 #[instrument(skip(self))]
603 fn get_next_song(&mut self) -> Option<SongBrief> {
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: &SongBrief) -> 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::{
829 db::schemas::song::Song,
830 test_utils::{arb_song_case, create_song_metadata, init_test_database},
831 };
832 use pretty_assertions::assert_eq;
833 use rstest::rstest;
834
835 use crate::test_utils::init;
836
837 use super::{super::*, audio_kernel, audio_kernel_sender, get_state, sound};
838
839 #[rstest]
840 fn test_audio_kernel_play_pause(
841 mut audio_kernel: AudioKernel,
842 sound: impl Source<Item = f32> + Send + 'static,
843 ) {
844 init();
845 audio_kernel.player.append(sound);
846 audio_kernel.play();
847 assert!(!audio_kernel.player.is_paused());
848 audio_kernel.pause();
849 assert!(audio_kernel.player.is_paused());
850 }
851
852 #[rstest]
853 fn test_audio_kernel_toggle_playback(
854 mut audio_kernel: AudioKernel,
855 sound: impl Source<Item = f32> + Send + 'static,
856 ) {
857 init();
858 audio_kernel.player.append(sound);
859 audio_kernel.play();
860 assert!(!audio_kernel.player.is_paused());
861 audio_kernel.toggle_playback();
862 assert!(audio_kernel.player.is_paused());
863 audio_kernel.toggle_playback();
864 assert!(!audio_kernel.player.is_paused());
865 }
866
867 #[rstest]
868 #[timeout(Duration::from_secs(10))] #[tokio::test]
870 async fn test_play_pause_toggle_restart(
871 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
872 ) {
873 init();
874 let db = init_test_database().await.unwrap();
875 let tempdir = tempfile::tempdir().unwrap();
876
877 let song = Song::try_load_into_db(
878 &db,
879 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
880 )
881 .await
882 .unwrap();
883
884 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
885 OneOrMany::One(song.into()),
886 )));
887
888 let state = get_state(sender.clone()).await;
889 assert_eq!(state.queue_position, Some(0));
890 assert_eq!(state.status, Status::Playing);
891
892 sender.send(AudioCommand::Pause);
893 let state = get_state(sender.clone()).await;
894 assert_eq!(state.status, Status::Paused);
895
896 sender.send(AudioCommand::Play);
897 let state = get_state(sender.clone()).await;
898 assert_eq!(state.status, Status::Playing);
899
900 sender.send(AudioCommand::RestartSong);
901 let state = get_state(sender.clone()).await;
902 assert_eq!(state.status, Status::Playing); sender.send(AudioCommand::TogglePlayback);
905 let state = get_state(sender.clone()).await;
906 assert_eq!(state.status, Status::Paused);
907
908 sender.send(AudioCommand::RestartSong);
909 let state = get_state(sender.clone()).await;
910 assert_eq!(state.status, Status::Paused); sender.send(AudioCommand::Exit);
913 }
914
915 #[rstest]
916 fn test_audio_kernel_stop(mut audio_kernel: AudioKernel) {
917 init();
918 audio_kernel.player.append(sound());
919 audio_kernel.play();
920 assert!(!audio_kernel.player.is_paused());
921 audio_kernel.stop();
922 assert!(audio_kernel.player.is_paused());
923 assert_eq!(audio_kernel.player.get_pos(), Duration::from_secs(0));
924 assert_eq!(audio_kernel.status, Status::Stopped);
925 }
926
927 #[rstest]
928 #[timeout(Duration::from_secs(10))] #[tokio::test]
930 async fn test_audio_kernel_skip_forward(mut audio_kernel: AudioKernel) {
931 init();
932 let db = init_test_database().await.unwrap();
933 let tempdir = tempfile::tempdir().unwrap();
934
935 let state = audio_kernel.state();
936 assert_eq!(state.queue_position, None);
937 assert!(state.paused());
938 assert_eq!(state.status, Status::Stopped);
939
940 audio_kernel.queue_control(QueueCommand::AddToQueue(OneOrMany::Many(vec![
941 Song::try_load_into_db(
942 &db,
943 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
944 )
945 .await
946 .unwrap()
947 .into(),
948 Song::try_load_into_db(
949 &db,
950 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
951 )
952 .await
953 .unwrap()
954 .into(),
955 Song::try_load_into_db(
956 &db,
957 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
958 )
959 .await
960 .unwrap()
961 .into(),
962 ])));
963
964 let state = audio_kernel.state();
966 assert_eq!(state.queue_position, Some(0));
967 assert!(!state.paused());
968 assert_eq!(state.status, Status::Playing);
969
970 audio_kernel.queue_control(QueueCommand::SkipForward(1));
971
972 let state = audio_kernel.state();
974 assert_eq!(state.queue_position, Some(1));
975 assert!(!state.paused());
976 assert_eq!(state.status, Status::Playing);
977
978 audio_kernel.queue_control(QueueCommand::SkipForward(1));
979
980 let state = audio_kernel.state();
982 assert_eq!(state.queue_position, Some(2));
983 assert!(!state.paused());
984 assert_eq!(state.status, Status::Playing);
985
986 audio_kernel.queue_control(QueueCommand::SkipForward(1));
987
988 let state = audio_kernel.state();
991 assert_eq!(state.queue_position, None);
992 assert!(state.paused());
993 assert_eq!(state.status, Status::Stopped);
994 }
995
996 #[rstest]
997 #[timeout(Duration::from_secs(6))] #[tokio::test]
999 async fn test_audio_kernel_skip_forward_sender(
1000 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1001 ) {
1002 init();
1004
1005 let db = init_test_database().await.unwrap();
1006 let tempdir = tempfile::tempdir().unwrap();
1007
1008 let state = get_state(sender.clone()).await;
1009 assert_eq!(state.queue_position, None);
1010 assert!(state.paused());
1011 assert_eq!(state.status, Status::Stopped);
1012
1013 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1014 OneOrMany::Many(vec![
1015 Song::try_load_into_db(
1016 &db,
1017 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1018 )
1019 .await
1020 .unwrap()
1021 .into(),
1022 Song::try_load_into_db(
1023 &db,
1024 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1025 )
1026 .await
1027 .unwrap()
1028 .into(),
1029 Song::try_load_into_db(
1030 &db,
1031 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1032 )
1033 .await
1034 .unwrap()
1035 .into(),
1036 ]),
1037 )));
1038 let state = get_state(sender.clone()).await;
1040 assert_eq!(state.queue_position, Some(0));
1041 assert!(!state.paused());
1042 assert_eq!(state.status, Status::Playing);
1043
1044 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1045 let state = get_state(sender.clone()).await;
1047 assert_eq!(state.queue_position, Some(1));
1048 assert!(!state.paused());
1049 assert_eq!(state.status, Status::Playing);
1050
1051 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1052 let state = get_state(sender.clone()).await;
1054 assert_eq!(state.queue_position, Some(2));
1055 assert!(!state.paused());
1056 assert_eq!(state.status, Status::Playing);
1057
1058 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1059 let state = get_state(sender.clone()).await;
1061 assert_eq!(state.queue_position, None);
1062 assert!(state.paused());
1063 assert_eq!(state.status, Status::Stopped);
1064
1065 sender.send(AudioCommand::Exit);
1066 }
1067
1068 #[rstest]
1069 #[timeout(Duration::from_secs(6))] #[tokio::test]
1071 async fn test_remove_range_from_queue(
1072 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1073 ) {
1074 init();
1075 let db = init_test_database().await.unwrap();
1076 let tempdir = tempfile::tempdir().unwrap();
1077 let song1 = Song::try_load_into_db(
1078 &db,
1079 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1080 )
1081 .await
1082 .unwrap();
1083 let song2 = Song::try_load_into_db(
1084 &db,
1085 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1086 )
1087 .await
1088 .unwrap();
1089
1090 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1092 OneOrMany::Many(vec![song1.clone().into(), song2.clone().into()]),
1093 )));
1094 let state = get_state(sender.clone()).await;
1095 assert_eq!(state.queue_position, Some(0));
1096 assert!(!state.paused());
1097 assert_eq!(state.status, Status::Playing);
1098
1099 sender.send(AudioCommand::Pause);
1101
1102 sender.send(AudioCommand::Queue(QueueCommand::RemoveRange(0..1)));
1104 let state = get_state(sender.clone()).await;
1105 assert_eq!(state.queue_position, Some(0));
1106 assert!(state.paused());
1107 assert_eq!(state.status, Status::Stopped);
1108 assert_eq!(state.queue.len(), 1);
1109 assert_eq!(state.queue[0], song2.clone().into());
1110
1111 sender.send(AudioCommand::Play);
1113
1114 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1116 OneOrMany::One(song1.clone().into()),
1117 )));
1118 let state = get_state(sender.clone()).await;
1119 assert_eq!(state.queue_position, Some(0));
1120 assert!(!state.paused());
1121 assert_eq!(state.status, Status::Playing);
1122 assert_eq!(state.queue.len(), 2);
1123 assert_eq!(state.queue[0], song2.clone().into());
1124 assert_eq!(state.queue[1], song1.into());
1125
1126 sender.send(AudioCommand::Queue(QueueCommand::RemoveRange(1..2)));
1128 let state = get_state(sender.clone()).await;
1129 assert_eq!(state.queue_position, Some(0));
1130 assert!(!state.paused());
1131 assert_eq!(state.status, Status::Playing);
1132 assert_eq!(state.queue.len(), 1);
1133 assert_eq!(state.queue[0], song2.into());
1134
1135 sender.send(AudioCommand::Exit);
1136 }
1137
1138 #[rstest]
1139 #[timeout(Duration::from_secs(10))] #[tokio::test]
1141 async fn test_audio_kernel_skip_backward(
1142 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1143 ) {
1144 init();
1145 let db = init_test_database().await.unwrap();
1146 let tempdir = tempfile::tempdir().unwrap();
1147
1148 let state = get_state(sender.clone()).await;
1149 assert_eq!(state.queue_position, None);
1150 assert!(state.paused());
1151 assert_eq!(state.status, Status::Stopped);
1152
1153 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1154 OneOrMany::Many(vec![
1155 Song::try_load_into_db(
1156 &db,
1157 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1158 )
1159 .await
1160 .unwrap()
1161 .into(),
1162 Song::try_load_into_db(
1163 &db,
1164 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1165 )
1166 .await
1167 .unwrap()
1168 .into(),
1169 Song::try_load_into_db(
1170 &db,
1171 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1172 )
1173 .await
1174 .unwrap()
1175 .into(),
1176 ]),
1177 )));
1178
1179 let state = get_state(sender.clone()).await;
1181 assert_eq!(state.queue_position, Some(0));
1182 assert!(!state.paused());
1183 assert_eq!(state.status, Status::Playing);
1184
1185 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(2)));
1186
1187 let state = get_state(sender.clone()).await;
1189 assert_eq!(state.queue_position, Some(2));
1190 assert!(!state.paused());
1191 assert_eq!(state.status, Status::Playing);
1192
1193 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1194
1195 let state = get_state(sender.clone()).await;
1197 assert_eq!(state.queue_position, Some(1));
1198 assert!(!state.paused());
1199 assert_eq!(state.status, Status::Playing);
1200
1201 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1202
1203 let state = get_state(sender.clone()).await;
1205 assert_eq!(state.queue_position, Some(0));
1206 assert!(!state.paused());
1207
1208 sender.send(AudioCommand::Queue(QueueCommand::SkipBackward(1)));
1209
1210 let state = get_state(sender.clone()).await;
1212 assert_eq!(state.queue_position, None);
1213 assert!(state.paused());
1214 assert_eq!(state.status, Status::Stopped);
1215
1216 sender.send(AudioCommand::Exit);
1217 }
1218
1219 #[rstest]
1220 #[timeout(Duration::from_secs(10))] #[tokio::test]
1222 async fn test_audio_kernel_set_position(
1223 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1224 ) {
1225 init();
1226 let db = init_test_database().await.unwrap();
1227 let tempdir = tempfile::tempdir().unwrap();
1228
1229 let state = get_state(sender.clone()).await;
1230 assert_eq!(state.queue_position, None);
1231 assert!(state.paused());
1232 assert_eq!(state.status, Status::Stopped);
1233
1234 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1235 OneOrMany::Many(vec![
1236 Song::try_load_into_db(
1237 &db,
1238 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1239 )
1240 .await
1241 .unwrap()
1242 .into(),
1243 Song::try_load_into_db(
1244 &db,
1245 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1246 )
1247 .await
1248 .unwrap()
1249 .into(),
1250 Song::try_load_into_db(
1251 &db,
1252 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1253 )
1254 .await
1255 .unwrap()
1256 .into(),
1257 ]),
1258 )));
1259 let state = get_state(sender.clone()).await;
1261 assert_eq!(state.queue_position, Some(0));
1262 assert!(!state.paused());
1263 assert_eq!(state.status, Status::Playing);
1264
1265 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(1)));
1266 let state = get_state(sender.clone()).await;
1268 assert_eq!(state.queue_position, Some(1));
1269 assert!(!state.paused());
1270 assert_eq!(state.status, Status::Playing);
1271
1272 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(2)));
1273 let state = get_state(sender.clone()).await;
1275 assert_eq!(state.queue_position, Some(2));
1276 assert!(!state.paused());
1277 assert_eq!(state.status, Status::Playing);
1278
1279 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(0)));
1280 let state = get_state(sender.clone()).await;
1282 assert_eq!(state.queue_position, Some(0));
1283 assert!(!state.paused());
1284 assert_eq!(state.status, Status::Playing);
1285
1286 sender.send(AudioCommand::Queue(QueueCommand::SetPosition(3)));
1287 let state = get_state(sender.clone()).await;
1289 assert_eq!(state.queue_position, Some(2));
1290 assert!(!state.paused());
1291 assert_eq!(state.status, Status::Playing);
1292
1293 sender.send(AudioCommand::Exit);
1294 }
1295
1296 #[rstest]
1297 #[timeout(Duration::from_secs(6))] #[tokio::test]
1299 async fn test_audio_kernel_clear(
1300 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1301 ) {
1302 init();
1303 let db = init_test_database().await.unwrap();
1304 let tempdir = tempfile::tempdir().unwrap();
1305
1306 let state = get_state(sender.clone()).await;
1307 assert_eq!(state.queue_position, None);
1308 assert!(state.paused());
1309 assert_eq!(state.status, Status::Stopped);
1310
1311 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1312 OneOrMany::Many(vec![
1313 Song::try_load_into_db(
1314 &db,
1315 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1316 )
1317 .await
1318 .unwrap()
1319 .into(),
1320 Song::try_load_into_db(
1321 &db,
1322 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1323 )
1324 .await
1325 .unwrap()
1326 .into(),
1327 Song::try_load_into_db(
1328 &db,
1329 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1330 )
1331 .await
1332 .unwrap()
1333 .into(),
1334 ]),
1335 )));
1336 let state = get_state(sender.clone()).await;
1338 assert_eq!(state.queue_position, Some(0));
1339 assert_eq!(state.queue.len(), 3);
1340 assert!(!state.paused());
1341 assert_eq!(state.status, Status::Playing);
1342
1343 sender.send(AudioCommand::ClearPlayer);
1344 let state = get_state(sender.clone()).await;
1346 assert_eq!(state.queue_position, Some(0));
1347 assert_eq!(state.queue.len(), 3);
1348 assert!(state.paused());
1349 assert_eq!(state.status, Status::Stopped);
1350
1351 sender.send(AudioCommand::Queue(QueueCommand::Clear));
1352 let state = get_state(sender.clone()).await;
1354 assert_eq!(state.queue_position, None);
1355 assert_eq!(state.queue.len(), 0);
1356 assert!(state.paused());
1357 assert_eq!(state.status, Status::Stopped);
1358
1359 sender.send(AudioCommand::Exit);
1360 }
1361
1362 #[rstest]
1363 #[timeout(Duration::from_secs(6))] #[tokio::test]
1365 async fn test_audio_kernel_shuffle(
1366 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1367 ) {
1368 init();
1369 let db = init_test_database().await.unwrap();
1370 let tempdir = tempfile::tempdir().unwrap();
1371
1372 let state = get_state(sender.clone()).await;
1373 assert_eq!(state.queue_position, None);
1374 assert!(state.paused());
1375 assert_eq!(state.status, Status::Stopped);
1376
1377 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1378 OneOrMany::Many(vec![
1379 Song::try_load_into_db(
1380 &db,
1381 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1382 )
1383 .await
1384 .unwrap()
1385 .into(),
1386 Song::try_load_into_db(
1387 &db,
1388 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1389 )
1390 .await
1391 .unwrap()
1392 .into(),
1393 Song::try_load_into_db(
1394 &db,
1395 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1396 )
1397 .await
1398 .unwrap()
1399 .into(),
1400 ]),
1401 )));
1402 let state = get_state(sender.clone()).await;
1404 assert_eq!(state.queue_position, Some(0));
1405 assert_eq!(state.queue.len(), 3);
1406 assert!(!state.paused());
1407 assert_eq!(state.status, Status::Playing);
1408
1409 sender.send(AudioCommand::Queue(QueueCommand::SkipForward(1)));
1411 let state = get_state(sender.clone()).await;
1412 assert_eq!(state.queue_position, Some(1));
1413 assert_eq!(state.queue.len(), 3);
1414 assert!(!state.paused());
1415 assert_eq!(state.status, Status::Playing);
1416
1417 sender.send(AudioCommand::Queue(QueueCommand::Shuffle));
1419 let state = get_state(sender.clone()).await;
1421 assert_eq!(state.queue_position, Some(0));
1422 assert_eq!(state.queue.len(), 3);
1423 assert!(!state.paused());
1424 assert_eq!(state.status, Status::Playing);
1425
1426 sender.send(AudioCommand::Exit);
1427 }
1428
1429 #[rstest]
1430 #[timeout(Duration::from_secs(5))] #[tokio::test]
1432 async fn test_volume_commands(#[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>) {
1433 init();
1434
1435 let state = get_state(sender.clone()).await;
1436 assert!(
1437 f32::EPSILON > (state.volume - 1.0).abs(),
1438 "{} != 1.0",
1439 state.volume
1440 );
1441 assert!(!state.muted);
1442
1443 sender.send(AudioCommand::Volume(VolumeCommand::Up(0.1)));
1444 let state = get_state(sender.clone()).await;
1445 assert!(
1446 f32::EPSILON > (state.volume - 1.1).abs(),
1447 "{} != 1.1",
1448 state.volume
1449 );
1450 assert!(!state.muted);
1451
1452 sender.send(AudioCommand::Volume(VolumeCommand::Down(0.1)));
1453 let state = get_state(sender.clone()).await;
1454 assert!(
1455 f32::EPSILON > (state.volume - 1.0).abs(),
1456 "{} != 1.0",
1457 state.volume
1458 );
1459 assert!(!state.muted);
1460
1461 sender.send(AudioCommand::Volume(VolumeCommand::Set(0.5)));
1462 let state = get_state(sender.clone()).await;
1463 assert!(
1464 f32::EPSILON > (state.volume - 0.5).abs(),
1465 "{} != 0.5",
1466 state.volume
1467 );
1468 assert!(!state.muted);
1469
1470 sender.send(AudioCommand::Volume(VolumeCommand::Mute));
1471 let state = get_state(sender.clone()).await;
1472 assert!(
1473 f32::EPSILON > (state.volume - 0.5).abs(),
1474 "{} != 0.5",
1475 state.volume
1476 ); assert!(state.muted);
1478
1479 sender.send(AudioCommand::Volume(VolumeCommand::Unmute));
1480 let state = get_state(sender.clone()).await;
1481 assert!(
1482 f32::EPSILON > (state.volume - 0.5).abs(),
1483 "{} != 0.5",
1484 state.volume
1485 );
1486 assert!(!state.muted);
1487
1488 sender.send(AudioCommand::Volume(VolumeCommand::ToggleMute));
1489 let state = get_state(sender.clone()).await;
1490 assert!(
1491 f32::EPSILON > (state.volume - 0.5).abs(),
1492 "{} != 0.5",
1493 state.volume
1494 );
1495 assert!(state.muted);
1496
1497 sender.send(AudioCommand::Volume(VolumeCommand::ToggleMute));
1498 let state = get_state(sender.clone()).await;
1499 assert!(
1500 f32::EPSILON > (state.volume - 0.5).abs(),
1501 "{} != 0.5",
1502 state.volume
1503 );
1504 assert!(!state.muted);
1505
1506 sender.send(AudioCommand::Exit);
1507 }
1508
1509 #[rstest]
1510 #[timeout(Duration::from_secs(5))] #[tokio::test]
1512 async fn test_volume_out_of_bounds(
1513 #[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>,
1514 ) {
1515 init();
1516
1517 sender.send(AudioCommand::Volume(VolumeCommand::Up(MAX_VOLUME + 0.5)));
1519 let state = get_state(sender.clone()).await;
1520 assert!(
1521 f32::EPSILON > (state.volume - MAX_VOLUME).abs(),
1522 "{} != {}",
1523 state.volume,
1524 MAX_VOLUME
1525 );
1526 assert!(!state.muted);
1527 sender.send(AudioCommand::Volume(VolumeCommand::Down(
1528 MAX_VOLUME + 0.5 - MIN_VOLUME,
1529 )));
1530 let state = get_state(sender.clone()).await;
1531 assert!(
1532 f32::EPSILON > (state.volume - MIN_VOLUME).abs(),
1533 "{} != {}",
1534 state.volume,
1535 MIN_VOLUME
1536 );
1537 assert!(!state.muted);
1538
1539 sender.send(AudioCommand::Volume(VolumeCommand::Set(MAX_VOLUME + 0.5)));
1541 let state = get_state(sender.clone()).await;
1542 assert!(
1543 f32::EPSILON > (state.volume - MAX_VOLUME).abs(),
1544 "{} != {}",
1545 state.volume,
1546 MAX_VOLUME
1547 );
1548 assert!(!state.muted);
1549 sender.send(AudioCommand::Volume(VolumeCommand::Set(MIN_VOLUME - 0.5)));
1550 let state = get_state(sender.clone()).await;
1551 assert!(
1552 f32::EPSILON > (state.volume - MIN_VOLUME).abs(),
1553 "{} != {}",
1554 state.volume,
1555 MIN_VOLUME
1556 );
1557 assert!(!state.muted);
1558
1559 sender.send(AudioCommand::Exit);
1560 }
1561
1562 #[rstest]
1563 #[timeout(Duration::from_secs(9))] #[tokio::test]
1565 async fn test_seek_commands(#[from(audio_kernel_sender)] sender: Arc<AudioKernelSender>) {
1566 init();
1567 let db = init_test_database().await.unwrap();
1568 let tempdir = tempfile::tempdir().unwrap();
1569
1570 let song = Song::try_load_into_db(
1571 &db,
1572 create_song_metadata(&tempdir, arb_song_case()()).unwrap(),
1573 )
1574 .await
1575 .unwrap();
1576
1577 sender.send(AudioCommand::Queue(QueueCommand::AddToQueue(
1580 OneOrMany::One(song.clone().into()),
1581 )));
1582 sender.send(AudioCommand::Stop);
1583 sender.send(AudioCommand::Seek(
1584 SeekType::Absolute,
1585 Duration::from_secs(0),
1586 ));
1587 let state: StateAudio = get_state(sender.clone()).await;
1588 assert_eq!(state.queue_position, Some(0));
1589 assert_eq!(state.status, Status::Stopped);
1590 assert_eq!(
1591 state.runtime.unwrap().duration,
1592 Duration::from_secs(10) + Duration::from_millis(188)
1593 );
1594 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(0));
1595
1596 sender.send(AudioCommand::Seek(
1598 SeekType::RelativeForwards,
1599 Duration::from_secs(2),
1600 ));
1601 let state = get_state(sender.clone()).await;
1602 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(2));
1603 assert_eq!(state.current_song, Some(song.clone().into()));
1604 assert_eq!(state.status, Status::Paused);
1605
1606 sender.send(AudioCommand::Seek(
1608 SeekType::RelativeBackwards,
1609 Duration::from_secs(1),
1610 ));
1611 let state = get_state(sender.clone()).await;
1612 assert_eq!(state.runtime.unwrap().seek_position, Duration::from_secs(1));
1613 assert_eq!(state.current_song, Some(song.clone().into()));
1614 assert_eq!(state.status, Status::Paused);
1615
1616 sender.send(AudioCommand::Seek(
1618 SeekType::Absolute,
1619 Duration::from_secs(10),
1620 ));
1621 let state = get_state(sender.clone()).await;
1622 assert_eq!(
1623 state.runtime.unwrap().seek_position,
1624 Duration::from_secs(10)
1625 );
1626 assert_eq!(state.current_song, Some(song.clone().into()));
1627 assert_eq!(state.status, Status::Paused);
1628
1629 sender.send(AudioCommand::Play);
1631 tokio::time::sleep(Duration::from_millis(500)).await;
1632 let state = get_state(sender.clone()).await;
1633 assert_eq!(state.queue_position, None);
1634 assert_eq!(state.status, Status::Stopped);
1635
1636 sender.send(AudioCommand::Exit);
1637 }
1638 }
1639}