From 6b6830ab57f60c0bfaec8c6f099c09689a95b5ad Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Mon, 24 Jun 2019 22:38:48 +0200 Subject: [PATCH] Implement `Host` API for emscripten backend --- src/host/emscripten/mod.rs | 136 +++++++++++++++++++++++++++++++++---- src/host/mod.rs | 6 +- 2 files changed, 125 insertions(+), 17 deletions(-) diff --git a/src/host/emscripten/mod.rs b/src/host/emscripten/mod.rs index 78ffa96..18b621f 100644 --- a/src/host/emscripten/mod.rs +++ b/src/host/emscripten/mod.rs @@ -10,17 +10,125 @@ use stdweb::web::set_timeout; use BuildStreamError; use DefaultFormatError; +use Device as DeviceTrait; use DeviceNameError; use DevicesError; +use EventLoop as EventLoopTrait; use Format; +use Host as HostTrait; use PauseStreamError; use PlayStreamError; use SupportedFormatsError; use StreamData; use StreamDataResult; +use StreamId as StreamIdTrait; use SupportedFormat; use UnknownTypeOutputBuffer; +/// The default emscripten host type. +#[derive(Debug)] +pub struct Host; + +impl Host { + pub fn new() -> Result { + Ok(Host) + } +} + +impl HostTrait for Host { + type Devices = Devices; + type Device = Device; + type EventLoop = EventLoop; + + fn is_available() -> bool { + // Assume ALSA is always available on linux/freebsd. + true + } + + fn devices(&self) -> Result { + Devices::new() + } + + fn default_input_device(&self) -> Option { + default_input_device() + } + + fn default_output_device(&self) -> Option { + default_output_device() + } + + fn event_loop(&self) -> Self::EventLoop { + EventLoop::new() + } +} + +impl DeviceTrait for Device { + type SupportedInputFormats = SupportedInputFormats; + type SupportedOutputFormats = SupportedOutputFormats; + + fn name(&self) -> Result { + Device::name(self) + } + + fn supported_input_formats(&self) -> Result { + Device::supported_input_formats(self) + } + + fn supported_output_formats(&self) -> Result { + Device::supported_output_formats(self) + } + + fn default_input_format(&self) -> Result { + Device::default_input_format(self) + } + + fn default_output_format(&self) -> Result { + Device::default_output_format(self) + } +} + +impl EventLoopTrait for EventLoop { + type Device = Device; + type StreamId = StreamId; + + fn build_input_stream( + &self, + device: &Self::Device, + format: &Format, + ) -> Result { + EventLoop::build_input_stream(self, device, format) + } + + fn build_output_stream( + &self, + device: &Self::Device, + format: &Format, + ) -> Result { + EventLoop::build_output_stream(self, device, format) + } + + fn play_stream(&self, stream: Self::StreamId) -> Result<(), PlayStreamError> { + EventLoop::play_stream(self, stream) + } + + fn pause_stream(&self, stream: Self::StreamId) -> Result<(), PauseStreamError> { + EventLoop::pause_stream(self, stream) + } + + fn destroy_stream(&self, stream: Self::StreamId) { + EventLoop::destroy_stream(self, stream) + } + + fn run(&self, callback: F) -> ! + where + F: FnMut(Self::StreamId, StreamDataResult) + Send, + { + EventLoop::run(self, callback) + } +} + +impl StreamIdTrait for StreamId {} + // The emscripten backend works by having a global variable named `_cpal_audio_contexts`, which // is an array of `AudioContext` objects. A stream ID corresponds to an entry in this array. // @@ -44,7 +152,7 @@ impl EventLoop { } #[inline] - pub fn run(&self, callback: F) -> ! + fn run(&self, callback: F) -> ! where F: FnMut(StreamId, StreamDataResult), { // The `run` function uses `set_timeout` to invoke a Rust callback repeatidely. The job @@ -124,12 +232,12 @@ impl EventLoop { } #[inline] - pub fn build_input_stream(&self, _: &Device, _format: &Format) -> Result { + fn build_input_stream(&self, _: &Device, _format: &Format) -> Result { unimplemented!(); } #[inline] - pub fn build_output_stream(&self, _: &Device, _format: &Format) -> Result { + fn build_output_stream(&self, _: &Device, _format: &Format) -> Result { let stream = js!(return new AudioContext()).into_reference().unwrap(); let mut streams = self.streams.lock().unwrap(); @@ -146,12 +254,12 @@ impl EventLoop { } #[inline] - pub fn destroy_stream(&self, stream_id: StreamId) { + fn destroy_stream(&self, stream_id: StreamId) { self.streams.lock().unwrap()[stream_id.0] = None; } #[inline] - pub fn play_stream(&self, stream_id: StreamId) -> Result<(), PlayStreamError> { + fn play_stream(&self, stream_id: StreamId) -> Result<(), PlayStreamError> { let streams = self.streams.lock().unwrap(); let stream = streams .get(stream_id.0) @@ -162,7 +270,7 @@ impl EventLoop { } #[inline] - pub fn pause_stream(&self, stream_id: StreamId) -> Result<(), PauseStreamError> { + fn pause_stream(&self, stream_id: StreamId) -> Result<(), PauseStreamError> { let streams = self.streams.lock().unwrap(); let stream = streams .get(stream_id.0) @@ -193,7 +301,7 @@ fn is_webaudio_available() -> bool { pub struct Devices(bool); impl Devices { - pub fn new() -> Result { + fn new() -> Result { Ok(Self::default()) } } @@ -218,12 +326,12 @@ impl Iterator for Devices { } #[inline] -pub fn default_input_device() -> Option { +fn default_input_device() -> Option { unimplemented!(); } #[inline] -pub fn default_output_device() -> Option { +fn default_output_device() -> Option { if is_webaudio_available() { Some(Device) } else { @@ -236,17 +344,17 @@ pub struct Device; impl Device { #[inline] - pub fn name(&self) -> Result { + fn name(&self) -> Result { Ok("Default Device".to_owned()) } #[inline] - pub fn supported_input_formats(&self) -> Result { + fn supported_input_formats(&self) -> Result { unimplemented!(); } #[inline] - pub fn supported_output_formats(&self) -> Result { + fn supported_output_formats(&self) -> Result { // TODO: right now cpal's API doesn't allow flexibility here // "44100" and "2" (channels) have also been hard-coded in the rest of the code ; if // this ever becomes more flexible, don't forget to change that @@ -264,11 +372,11 @@ impl Device { ) } - pub fn default_input_format(&self) -> Result { + fn default_input_format(&self) -> Result { unimplemented!(); } - pub fn default_output_format(&self) -> Result { + fn default_output_format(&self) -> Result { // TODO: because it is hard coded, see supported_output_formats. Ok( Format { diff --git a/src/host/mod.rs b/src/host/mod.rs index 1821453..7862815 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -1,10 +1,10 @@ #[cfg(any(target_os = "linux", target_os = "freebsd"))] pub(crate) mod alsa; #[cfg(any(target_os = "macos", target_os = "ios"))] -mod coreaudio; +pub(crate) mod coreaudio; //mod dynamic; #[cfg(target_os = "emscripten")] -mod emscripten; -mod null; +pub(crate) mod emscripten; +pub(crate) mod null; #[cfg(windows)] pub(crate) mod wasapi;