1use std::{
2 collections::HashMap,
3 fs,
4 io::{BufReader, Cursor},
5 path::{Path, PathBuf},
6 thread,
7};
8
9use anyhow::bail;
10use tokio::sync::mpsc::{self, Sender};
11
12#[derive(Debug, Clone)]
13pub struct Audio {
14 pub channel: Sender<AudioCommand>,
15 pub cached_audio: HashMap<String, Box<Cursor<Vec<u8>>>>,
16}
17
18#[derive(Debug, Clone)]
19pub enum AudioCommand {
20 Play(PathBuf),
21 Stop,
22}
23
24impl Audio {
25 pub fn new() -> Audio {
26 let (tx, mut rx) = mpsc::channel::<AudioCommand>(1);
27
28 tokio::spawn(async move {
29 println!("hey im the audio thread");
30 let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
31 .expect("audio: failed to initialize stream handle");
32 let mixer = stream_handle.mixer().clone();
33
34 let mut current_sink: Option<rodio::Sink> = None;
35
36 while let Some(message) = rx.recv().await {
37 println!("{:?}", message);
38 if let AudioCommand::Play(pathbuf) = message {
39 if let Some(sink) = current_sink.take() {
40 sink.stop();
41 }
42
43 let file = std::fs::File::open(pathbuf.to_string_lossy().to_string()).unwrap();
44 println!("{:?}", file.metadata());
45 let sink = rodio::play(&mixer, BufReader::new(file)).unwrap();
46 sink.set_volume(1.0);
47 current_sink = Some(sink);
48 }
49 thread::sleep(std::time::Duration::from_millis(100));
50 }
51 });
52
53 Self {
54 channel: tx,
55 cached_audio: HashMap::new(),
56 }
57 }
58
59 pub fn load_asset(&mut self, path: &Path) -> anyhow::Result<()> {
60 if self
61 .cached_audio
62 .contains_key(&path.to_string_lossy().to_string())
63 {
64 bail!("resource already cached")
65 }
66
67 let data: Vec<u8> = fs::read(path)?;
68 self.cached_audio.insert(
69 path.to_string_lossy().to_string(),
70 Box::new(Cursor::new(data)),
71 );
72 Ok(())
73 }
74
75 pub async fn play_audio(
76 &mut self,
77 path: &Path,
78 _interrupt_current_playback: bool,
79 ) -> anyhow::Result<()> {
80 if !self
81 .cached_audio
82 .contains_key(&path.to_string_lossy().to_string())
83 {
84 println!("caching");
87 self.load_asset(path)?;
88 }
89 self.channel
90 .send(AudioCommand::Play(path.to_path_buf()))
91 .await?;
92 Ok(())
104 }
105}
106
107impl Default for Audio {
108 fn default() -> Self {
109 Self::new()
110 }
111}