From 3cce3e43d9b7125b5ec7f8e0e4b638b79a292a36 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Mon, 15 Jul 2019 22:37:03 +0900 Subject: [PATCH] Change callback interface so that it takes a dedicated error callback --- examples/beep.rs | 12 +++--------- examples/feedback.rs | 23 ++++++----------------- examples/record_wav.rs | 12 +++--------- src/host/alsa/mod.rs | 36 ++++++++++++++++++++---------------- src/host/null/mod.rs | 11 ++++++----- src/lib.rs | 4 ---- src/platform/mod.rs | 12 ++++++------ src/traits.rs | 11 ++++++----- 8 files changed, 50 insertions(+), 71 deletions(-) diff --git a/examples/beep.rs b/examples/beep.rs index d2c570c..686230c 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -17,15 +17,7 @@ fn main() -> Result<(), anyhow::Error> { (sample_clock * 440.0 * 2.0 * 3.141592 / sample_rate).sin() }; - let stream = device.build_output_stream(&format, move |result| { - let data = match result { - Ok(data) => data, - Err(err) => { - eprintln!("an error occurred on stream: {}", err); - return; - } - }; - + let stream = device.build_output_stream(&format, move |data| { match data { cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::U16(mut buffer) } => { for sample in buffer.chunks_mut(channels as usize) { @@ -53,6 +45,8 @@ fn main() -> Result<(), anyhow::Error> { }, _ => (), } + }, move |err| { + eprintln!("an error occurred on stream: {}", err); })?; stream.play()?; diff --git a/examples/feedback.rs b/examples/feedback.rs index 11c1331..e6875b2 100644 --- a/examples/feedback.rs +++ b/examples/feedback.rs @@ -49,15 +49,7 @@ fn main() -> Result<(), anyhow::Error> { // Build streams. println!("Attempting to build both streams with `{:?}`.", format); - let input_stream = input_device.build_input_stream(&format, move |result| { - let data = match result { - Ok(data) => data, - Err(err) => { - eprintln!("an error occurred on input stream: {}", err); - return; - }, - }; - + let input_stream = input_device.build_input_stream(&format, move |data| { match data { cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::F32(buffer), @@ -74,15 +66,10 @@ fn main() -> Result<(), anyhow::Error> { }, _ => panic!("Expected input with f32 data"), } + }, move |err| { + eprintln!("an error occurred on input stream: {}", err); })?; - let output_stream = output_device.build_output_stream(&format, move |result| { - let data = match result { - Ok(data) => data, - Err(err) => { - eprintln!("an error occurred on output stream: {}", err); - return; - }, - }; + let output_stream = output_device.build_output_stream(&format, move |data| { match data { cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::F32(mut buffer), @@ -103,6 +90,8 @@ fn main() -> Result<(), anyhow::Error> { }, _ => panic!("Expected output with f32 data"), } + }, move |err| { + eprintln!("an error occurred on output stream: {}", err); })?; println!("Successfully built streams."); diff --git a/examples/record_wav.rs b/examples/record_wav.rs index d53f9b3..f69c8d0 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -32,15 +32,7 @@ fn main() -> Result<(), anyhow::Error> { // Run the input stream on a separate thread. let writer_2 = writer.clone(); - let stream = device.build_input_stream(&format, move |event| { - let data = match event { - Ok(data) => data, - Err(err) => { - eprintln!("an error occurred on stream: {}", err); - return; - }, - }; - + let stream = device.build_input_stream(&format, move |data| { // Otherwise write to the wav writer. match data { cpal::StreamData::Input { @@ -79,6 +71,8 @@ fn main() -> Result<(), anyhow::Error> { }, _ => (), } + }, move |err| { + eprintln!("an error occurred on stream: {}", err); })?; stream.play()?; diff --git a/src/host/alsa/mod.rs b/src/host/alsa/mod.rs index 72c3afe..4401ea9 100644 --- a/src/host/alsa/mod.rs +++ b/src/host/alsa/mod.rs @@ -18,7 +18,7 @@ use PlayStreamError; use SampleFormat; use SampleRate; use StreamData; -use StreamDataResult; +use StreamError; use SupportedFormat; use SupportedFormatsError; use traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -89,12 +89,12 @@ impl DeviceTrait for Device { Device::default_output_format(self) } - fn build_input_stream(&self, format: &Format, callback: F) -> Result where F: FnMut(StreamDataResult) + Send + 'static { - Ok(Stream::new(Arc::new(self.build_stream_inner(format, alsa::SND_PCM_STREAM_CAPTURE)?), callback)) + fn build_input_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { + Ok(Stream::new(Arc::new(self.build_stream_inner(format, alsa::SND_PCM_STREAM_CAPTURE)?), data_callback, error_callback)) } - fn build_output_stream(&self, format: &Format, callback: F) -> Result where F: FnMut(StreamDataResult) + Send + 'static { - Ok(Stream::new(Arc::new(self.build_stream_inner(format, alsa::SND_PCM_STREAM_PLAYBACK)?), callback)) + fn build_output_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { + Ok(Stream::new(Arc::new(self.build_stream_inner(format, alsa::SND_PCM_STREAM_PLAYBACK)?), data_callback, error_callback)) } } @@ -526,7 +526,10 @@ pub struct Stream { /// The inner body of the audio processing thread. Takes the polymorphic /// callback to avoid generating too much generic code. -fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn FnMut(StreamDataResult) + Send + 'static)) { +fn stream_worker(rx: TriggerReceiver, + stream: &StreamInner, + data_callback: &mut (dyn FnMut(StreamData) + Send + 'static), + error_callback: &mut (dyn FnMut(StreamError) + Send + 'static)) { let mut descriptors = Vec::new(); let mut buffer = Vec::new(); loop { @@ -559,11 +562,11 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn }; if res < 0 { let description = format!("`libc::poll()` failed: {}", io::Error::last_os_error()); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } else if res == 0 { let description = String::from("`libc::poll()` spuriously returned"); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } @@ -589,7 +592,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn Ok(n) => n, Err(err) => { let description = format!("Failed to query the number of available samples: {}", err); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } }; @@ -615,7 +618,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn }; if let Err(err) = check_errors(result as _) { let description = format!("`snd_pcm_readi` failed: {}", err); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } @@ -633,7 +636,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn let stream_data = StreamData::Input { buffer: input_buffer, }; - callback(Ok(stream_data)); + data_callback(stream_data); }, StreamType::Output => { { @@ -653,7 +656,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn let stream_data = StreamData::Output { buffer: output_buffer, }; - callback(Ok(stream_data)); + data_callback(stream_data); } loop { let result = unsafe { @@ -670,7 +673,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn unsafe { alsa::snd_pcm_recover(stream.channel, result as i32, 0) }; } else if let Err(err) = check_errors(result as _) { let description = format!("`snd_pcm_writei` failed: {}", err); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } else if result as usize != available_frames { let description = format!( @@ -679,7 +682,7 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn available_frames, result, ); - callback(Err(BackendSpecificError { description }.into())); + error_callback(BackendSpecificError { description }.into()); continue; } else { break; @@ -691,12 +694,13 @@ fn stream_worker(rx: TriggerReceiver, stream: &StreamInner, callback: &mut (dyn } impl Stream { - fn new(inner: Arc, mut callback: F) -> Stream where F: FnMut(StreamDataResult) + Send + 'static { + fn new(inner: Arc, mut data_callback: D, mut error_callback: E) -> Stream + where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { let (tx, rx) = trigger(); // Clone the handle for passing into worker thread. let stream = inner.clone(); let thread = thread::spawn(move || { - stream_worker(rx, &*stream, &mut callback); + stream_worker(rx, &*stream, &mut data_callback, &mut error_callback); }); Stream { thread: Some(thread), diff --git a/src/host/null/mod.rs b/src/host/null/mod.rs index 032f797..1683946 100644 --- a/src/host/null/mod.rs +++ b/src/host/null/mod.rs @@ -7,7 +7,8 @@ use DeviceNameError; use Format; use PauseStreamError; use PlayStreamError; -use StreamDataResult; +use StreamData; +use StreamError; use SupportedFormatsError; use SupportedFormat; use traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -76,14 +77,14 @@ impl DeviceTrait for Device { unimplemented!() } - fn build_input_stream(&self, format: &Format, callback: F) -> Result - where F: FnMut(StreamDataResult) + Send + 'static { + fn build_input_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { unimplemented!() } /// Create an output stream. - fn build_output_stream(&self, format: &Format, callback: F) -> Result - where F: FnMut(StreamDataResult) + Send + 'static{ + fn build_output_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static{ unimplemented!() } } diff --git a/src/lib.rs b/src/lib.rs index 61815e3..36f1ac8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,10 +206,6 @@ pub enum StreamData<'a> { }, } -/// Stream data passed to the `EventLoop::run` callback, or an error in the case that the device -/// was invalidated or some backend-specific error occurred. -pub type StreamDataResult<'a> = Result, StreamError>; - /// Represents a buffer containing audio data that may be read. /// /// This struct implements the `Deref` trait targeting `[T]`. Therefore this buffer can be read the diff --git a/src/platform/mod.rs b/src/platform/mod.rs index c85a8e6..c16c9dc 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -250,22 +250,22 @@ macro_rules! impl_platform_host { } } - fn build_input_stream(&self, format: &crate::Format, callback: F) -> Result - where F: FnMut(crate::StreamDataResult) + Send + 'static { + fn build_input_stream(&self, format: &crate::Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(crate::StreamData) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static { match self.0 { $( - DeviceInner::$HostVariant(ref d) => d.build_input_stream(format, callback) + DeviceInner::$HostVariant(ref d) => d.build_input_stream(format, data_callback, error_callback) .map(StreamInner::$HostVariant) .map(Stream), )* } } - fn build_output_stream(&self, format: &crate::Format, callback: F) -> Result - where F: FnMut(crate::StreamDataResult) + Send + 'static { + fn build_output_stream(&self, format: &crate::Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(crate::StreamData) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static { match self.0 { $( - DeviceInner::$HostVariant(ref d) => d.build_output_stream(format, callback) + DeviceInner::$HostVariant(ref d) => d.build_output_stream(format, data_callback, error_callback) .map(StreamInner::$HostVariant) .map(Stream), )* diff --git a/src/traits.rs b/src/traits.rs index f50bedc..d90d782 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -10,7 +10,8 @@ use { OutputDevices, PauseStreamError, PlayStreamError, - StreamDataResult, + StreamData, + StreamError, SupportedFormat, SupportedFormatsError, }; @@ -117,12 +118,12 @@ pub trait DeviceTrait { fn default_output_format(&self) -> Result; /// Create an input stream. - fn build_input_stream(&self, format: &Format, callback: F) -> Result - where F: FnMut(StreamDataResult) + Send + 'static; + fn build_input_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static; /// Create an output stream. - fn build_output_stream(&self, format: &Format, callback: F) -> Result - where F: FnMut(StreamDataResult) + Send + 'static; + fn build_output_stream(&self, format: &Format, data_callback: D, error_callback: E) -> Result + where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static; } /// A stream created from `Device`, with methods to control playback.