diff --git a/src/agents/audio_agent.rs b/src/agents/audio_agent.rs index e6d7cd8..4e3b54a 100644 --- a/src/agents/audio_agent.rs +++ b/src/agents/audio_agent.rs @@ -1,6 +1,6 @@ use js_sys::Uint8Array; use std::collections::HashSet; -use std::rc::Rc; +use std::sync::Arc; use wasm_bindgen::JsValue; use wasm_bindgen_futures::JsFuture; use web_sys::console; @@ -12,7 +12,7 @@ use yewtil::future::LinkFuture; const FILE_LOAD_CHUNK_SIZE: usize = 4096; -pub type AudioData = Rc; +pub type AudioData = Arc; #[derive(Debug)] pub struct AudioAgent { @@ -79,7 +79,7 @@ impl Agent for AudioAgent { } Msg::AudioDecoded(samples) => { let audio_buffer = web_sys::AudioBuffer::from(samples); - let audio_data = Rc::new(audio_buffer); + let audio_data = Arc::new(audio_buffer); for subscriber in self.subscribers.iter() { self.link.respond(*subscriber, Ok(audio_data.clone())); diff --git a/src/player.rs b/src/player.rs index a0a405e..d790a39 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,4 +1,4 @@ -use crate::agents::audio_agent::{self, AudioAgent}; +use crate::agents::audio_agent::{self, AudioAgent, AudioData}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{Device, SampleFormat, SampleRate, Stream, StreamConfig}; use yew::agent::Dispatcher; @@ -14,11 +14,13 @@ pub struct Player { link: ComponentLink, status: Status, stream: Option, - audio_agent: Dispatcher, + audio_agent: Box>, + audio_data: Option, } pub enum Msg { Play, + AudioAgentMessage(Result), } impl Component for Player { @@ -26,11 +28,14 @@ impl Component for Player { type Properties = (); fn create(_: Self::Properties, link: ComponentLink) -> Self { + let cb = link.callback(Msg::AudioAgentMessage); + Self { link, status: Status::Stopped, stream: None, - audio_agent: AudioAgent::dispatcher(), + audio_agent: AudioAgent::bridge(cb), + audio_data: None, } } @@ -39,6 +44,8 @@ impl Component for Player { fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { Msg::Play => self.handle_play_button_clicked(), + Msg::AudioAgentMessage(Ok(audio_data)) => self.handle_samples_loaded(audio_data), + Msg::AudioAgentMessage(Err(err)) => self.handle_samples_loaded_error(&err), } } @@ -56,30 +63,50 @@ impl Component for Player { } impl Player { - fn play(&mut self) { - let host = cpal::default_host(); - let device = host.default_output_device().unwrap(); - - // TODO: improve - let config = device - .supported_output_configs() - .unwrap() - .nth(1) - .unwrap() - .with_sample_rate(SampleRate(44100)); - - ConsoleService::log(&format!("Using output config: {:?}", config)); - - let stream = match config.sample_format() { - SampleFormat::F32 => Player::run::(&device, &config.into()), - SampleFormat::I16 => Player::run::(&device, &config.into()), - SampleFormat::U16 => Player::run::(&device, &config.into()), - }; - - self.stream = Some(stream); + fn handle_samples_loaded(&mut self, audio_data: AudioData) -> ShouldRender { + ConsoleService::log("Player: samples loaded"); + self.audio_data = Some(audio_data); + true } - fn run(device: &Device, config: &StreamConfig) -> Stream + fn handle_samples_loaded_error(&mut self, err: &str) -> ShouldRender { + ConsoleService::log(&format!("Player: error loading samples: {:?}", err)); + self.audio_data = None; + false + } + + fn play(&mut self) { + if let Some(audio_data) = &self.audio_data { + let host = cpal::default_host(); + let device = host.default_output_device().unwrap(); + + // TODO: improve + let config = device + .supported_output_configs() + .unwrap() + .nth(1) + .unwrap() + .with_sample_rate(SampleRate(44100)); + + ConsoleService::log(&format!("Using output config: {:?}", config)); + + let stream = match config.sample_format() { + SampleFormat::F32 => { + Player::run::(&device, &config.into(), audio_data.clone()) + } + SampleFormat::I16 => { + Player::run::(&device, &config.into(), audio_data.clone()) + } + SampleFormat::U16 => { + Player::run::(&device, &config.into(), audio_data.clone()) + } + }; + + self.stream = Some(stream); + } + } + + fn run(device: &Device, config: &StreamConfig, audio_data: AudioData) -> Stream where T: cpal::Sample, {