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 {
40 let (tx, mut rx) = mpsc::channel::<AudioCommand>(16);
41
42 tokio::spawn(async move {
43 println!("hey im the audio thread nya meow meow >:3");
44 let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
45 .expect("audio: failed to initialize stream handle");
46 let mixer = stream_handle.mixer();
47 let mut current_sink: Option<rodio::Sink> = None;
48
49 while let Some(message) = rx.recv().await {
50 match message {
51 AudioCommand::Play(pathbuf) => {
52 if let Some(sink) = current_sink.take() {
53 sink.stop();
54 }
55
56 let file =
57 std::fs::File::open(&pathbuf).expect("audio: failed to open file");
58 let sink = rodio::play(mixer, BufReader::new(file))
59 .expect("audio: failed to start playback");
60 sink.set_volume(1.0);
61 current_sink = Some(sink);
62 }
63 AudioCommand::Stop => {
64 if let Some(sink) = current_sink.take() {
65 sink.stop();
66 }
67 }
68 }
69 }
70 });
71
72 Self { channel: tx }
73 }
74
75 pub async fn play_audio(
77 &mut self,
78 path: &Path,
79 _interrupt_current_playback: bool,
80 ) -> anyhow::Result<()> {
81 self.channel
83 .send(AudioCommand::Play(path.to_path_buf()))
84 .await?;
85 Ok(())
86 }
87}
88
89impl Default for Audio {
91 fn default() -> Self {
93 Self::new()
94 }
95}