1use std::{
10 io::BufReader,
11 path::{Path, PathBuf},
12};
13
14use tokio::sync::mpsc::{self, Sender};
15
16#[derive(Debug, Clone)]
18pub struct Audio {
19 pub channel: Sender<AudioCommand>,
21}
22
23#[derive(Debug, Clone)]
25pub enum AudioCommand {
26 Play(PathBuf),
28 Stop,
30}
31
32impl Audio {
33 pub fn new() -> Audio {
35 let (tx, mut rx) = mpsc::channel::<AudioCommand>(16);
36
37 tokio::spawn(async move {
38 println!("hey im the audio thread nya meow meow >:3");
39 let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
40 .expect("audio: failed to initialize stream handle");
41 let mixer = stream_handle.mixer();
42 let mut current_sink: Option<rodio::Sink> = None;
43
44 while let Some(message) = rx.recv().await {
45 match message {
46 AudioCommand::Play(pathbuf) => {
47 if let Some(sink) = current_sink.take() {
48 sink.stop();
49 }
50
51 let file =
52 std::fs::File::open(&pathbuf).expect("audio: failed to open file");
53 let sink = rodio::play(mixer, BufReader::new(file))
54 .expect("audio: failed to start playback");
55 sink.set_volume(1.0);
56 current_sink = Some(sink);
57 }
58 AudioCommand::Stop => {
59 if let Some(sink) = current_sink.take() {
60 sink.stop();
61 }
62 }
63 }
64 }
65 });
66
67 Self { channel: tx }
68 }
69
70 pub async fn play_audio(
72 &mut self,
73 path: &Path,
74 _interrupt_current_playback: bool,
75 ) -> anyhow::Result<()> {
76 self.channel
78 .send(AudioCommand::Play(path.to_path_buf()))
79 .await?;
80 Ok(())
81 }
82}
83
84impl Default for Audio {
86 fn default() -> Self {
88 Self::new()
89 }
90}