diff --git a/examples/beep.rs b/examples/beep.rs index c6b70e0..dc0edd2 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -17,14 +17,13 @@ fn main() -> Result<(), failure::Error> { (sample_clock * 440.0 * 2.0 * 3.141592 / sample_rate).sin() }; - event_loop.run(move |id, event| { - let data = match event { - cpal::StreamEvent::Data(data) => data, - cpal::StreamEvent::Close(cpal::StreamCloseCause::Error(err)) => { + event_loop.run(move |id, result| { + let data = match result { + Ok(data) => data, + Err(err) => { eprintln!("stream {:?} closed due to an error: {}", id, err); return; } - _ => return, }; match data { diff --git a/examples/feedback.rs b/examples/feedback.rs index 4c067dd..29aec5e 100644 --- a/examples/feedback.rs +++ b/examples/feedback.rs @@ -49,14 +49,13 @@ fn main() -> Result<(), failure::Error> { // Run the event loop on a separate thread. std::thread::spawn(move || { - event_loop.run(move |id, event| { - let data = match event { - cpal::StreamEvent::Data(data) => data, - cpal::StreamEvent::Close(cpal::StreamCloseCause::Error(err)) => { + event_loop.run(move |id, result| { + let data = match result { + Ok(data) => data, + Err(err) => { eprintln!("stream {:?} closed due to an error: {}", id, err); return; } - _ => return, }; match data { diff --git a/examples/record_wav.rs b/examples/record_wav.rs index 74c10aa..0b58e01 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -32,12 +32,11 @@ fn main() -> Result<(), failure::Error> { std::thread::spawn(move || { event_loop.run(move |id, event| { let data = match event { - cpal::StreamEvent::Data(data) => data, - cpal::StreamEvent::Close(cpal::StreamCloseCause::Error(err)) => { + Ok(data) => data, + Err(err) => { eprintln!("stream {:?} closed due to an error: {}", id, err); return; } - _ => return, }; // If we're done recording, return early. diff --git a/src/alsa/mod.rs b/src/alsa/mod.rs index b11b590..4d276cc 100644 --- a/src/alsa/mod.rs +++ b/src/alsa/mod.rs @@ -15,8 +15,8 @@ use SupportedFormatsError; use SampleFormat; use SampleRate; use StreamData; +use StreamDataResult; use StreamError; -use StreamEvent; use SupportedFormat; use UnknownTypeInputBuffer; use UnknownTypeOutputBuffer; @@ -461,12 +461,12 @@ impl EventLoop { #[inline] pub fn run(&self, mut callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + where F: FnMut(StreamId, StreamDataResult) { self.run_inner(&mut callback) } - fn run_inner(&self, callback: &mut dyn FnMut(StreamId, StreamEvent)) -> ! { + fn run_inner(&self, callback: &mut dyn FnMut(StreamId, StreamDataResult)) -> ! { unsafe { let mut run_context = self.run_context.lock().unwrap(); let run_context = &mut *run_context; @@ -487,8 +487,8 @@ impl EventLoop { Ok(false) => continue, Err(err) => { for stream in run_context.streams.iter() { - let event = StreamEvent::Close(err.clone().into()); - callback(stream.id, event); + let result = Err(err.clone().into()); + callback(stream.id, result); } run_context.streams.clear(); break 'stream_loop; @@ -578,8 +578,7 @@ impl EventLoop { let stream_data = StreamData::Input { buffer: input_buffer, }; - let event = StreamEvent::Data(stream_data); - callback(stream.id, event); + callback(stream.id, Ok(stream_data)); }, StreamType::Output => { { @@ -599,8 +598,7 @@ impl EventLoop { let stream_data = StreamData::Output { buffer: output_buffer, }; - let event = StreamEvent::Data(stream_data); - callback(stream.id, event); + callback(stream.id, Ok(stream_data)); } loop { let result = alsa::snd_pcm_writei( @@ -639,8 +637,7 @@ impl EventLoop { // Remove any streams that have errored and notify the user. for (stream_id, err) in streams_to_remove { run_context.streams.retain(|s| s.id != stream_id); - let event = StreamEvent::Close(err.into()); - callback(stream_id, event); + callback(stream_id, Err(err.into())); } } } diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 101dbcc..3cd3613 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -13,7 +13,7 @@ use SupportedFormatsError; use SampleFormat; use SampleRate; use StreamData; -use StreamEvent; +use StreamDataResult; use SupportedFormat; use UnknownTypeInputBuffer; use UnknownTypeOutputBuffer; @@ -332,7 +332,7 @@ enum UserCallback { // // It is essential for the safety of the program that this callback is removed before `run` // returns (not possible with the current CPAL API). - Active(&'static mut (FnMut(StreamId, StreamEvent) + Send)), + Active(&'static mut (FnMut(StreamId, StreamDataResult) + Send)), // A queue of events that have occurred but that have not yet been emitted to the user as we // don't yet have a callback to do so. Inactive, @@ -444,14 +444,14 @@ impl EventLoop { #[inline] pub fn run(&self, mut callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + Send + where F: FnMut(StreamId, StreamDataResult) + Send { { let mut guard = self.user_callback.lock().unwrap(); if let UserCallback::Active(_) = *guard { panic!("`EventLoop::run` was called when the event loop was already running"); } - let callback: &mut (FnMut(StreamId, StreamEvent) + Send) = &mut callback; + let callback: &mut (FnMut(StreamId, StreamDataResult) + Send) = &mut callback; *guard = UserCallback::Active(unsafe { mem::transmute(callback) }); } @@ -689,8 +689,7 @@ impl EventLoop { }; let unknown_type_buffer = UnknownTypeInputBuffer::$SampleFormat(::InputBuffer { buffer: data_slice }); let stream_data = StreamData::Input { buffer: unknown_type_buffer }; - let stream_event = StreamEvent::Data(stream_data); - callback(StreamId(stream_id), stream_event); + callback(StreamId(stream_id), Ok(stream_data)); }}; } @@ -766,8 +765,7 @@ impl EventLoop { }; let unknown_type_buffer = UnknownTypeOutputBuffer::$SampleFormat(::OutputBuffer { buffer: data_slice }); let stream_data = StreamData::Output { buffer: unknown_type_buffer }; - let stream_event = StreamEvent::Data(stream_data); - callback(StreamId(stream_id), stream_event); + callback(StreamId(stream_id), Ok(stream_data)); }}; } diff --git a/src/emscripten/mod.rs b/src/emscripten/mod.rs index 687f648..2ca7a93 100644 --- a/src/emscripten/mod.rs +++ b/src/emscripten/mod.rs @@ -17,7 +17,7 @@ use PauseStreamError; use PlayStreamError; use SupportedFormatsError; use StreamData; -use StreamEvent; +use StreamDataResult; use SupportedFormat; use UnknownTypeOutputBuffer; @@ -45,7 +45,7 @@ impl EventLoop { #[inline] pub fn run(&self, callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + Send, + where F: FnMut(StreamId, StreamDataResult) + Send, { // The `run` function uses `set_timeout` to invoke a Rust callback repeatidely. The job // of this callback is to fill the content of the audio buffers. @@ -54,7 +54,7 @@ impl EventLoop { // and to the `callback` parameter that was passed to `run`. fn callback_fn(user_data_ptr: *mut c_void) - where F: FnMut(StreamId, StreamEvent) + where F: FnMut(StreamId, StreamDataResult) { unsafe { let user_data_ptr2 = user_data_ptr as *mut (&EventLoop, F); @@ -73,8 +73,7 @@ impl EventLoop { { let buffer = UnknownTypeOutputBuffer::F32(::OutputBuffer { buffer: &mut temporary_buffer }); let data = StreamData::Output { buffer: buffer }; - let event = StreamEvent::Data(data); - user_cb(StreamId(stream_id), event); + user_cb(StreamId(stream_id), Ok(data)); // TODO: directly use a TypedArray once this is supported by stdweb } diff --git a/src/lib.rs b/src/lib.rs index 78a21d1..d496b32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,9 +92,9 @@ //! # let event_loop = cpal::EventLoop::new(); //! event_loop.run(move |stream_id, stream_event| { //! let stream_data = match stream_event { -//! cpal::StreamEvent::Data(data) => data, -//! cpal::StreamEvent::Close(cpal::StreamCloseCause::Error(err)) => { -//! eprintln!("stream {:?} closed due to an error: {}", stream_id, err); +//! Ok(data) => data, +//! Err(err) => { +//! eprintln!("an error occurred on stream {:?}: {}", stream_id, err); //! return; //! } //! _ => return, @@ -215,24 +215,9 @@ pub enum StreamData<'a> { }, } -/// Events that may be emitted to the user via the callback submitted to `EventLoop::run`. -pub enum StreamEvent<'a> { - /// Some data is ready to be processed. - Data(StreamData<'a>), - /// The stream was closed, either because the user destroyed it or because of an error. - /// - /// The stream event callback will not be called again after this event occurs. - Close(StreamCloseCause), -} - -/// The cause behind why a stream was closed. -#[derive(Debug)] -pub enum StreamCloseCause { - /// The stream was closed as the user called `destroy_stream`. - UserDestroyed, - /// The stream was closed due to an error occurring. - Error(StreamError), -} +/// 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. /// @@ -441,9 +426,6 @@ pub enum PauseStreamError { } /// Errors that might occur while a stream is running. -/// -/// These errors are delivered to the user callback via -/// `StreamEvent::Close(StreamCloseCause::Error(_))` #[derive(Debug, Fail)] pub enum StreamError { /// The device no longer exists. This can happen if the device is disconnected while the @@ -637,7 +619,7 @@ impl EventLoop { /// You can call the other methods of `EventLoop` without getting a deadlock. #[inline] pub fn run(&self, mut callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + Send + where F: FnMut(StreamId, StreamDataResult) + Send { self.0.run(move |id, data| callback(StreamId(id), data)) } @@ -835,18 +817,6 @@ impl Iterator for SupportedOutputFormats { } } -impl From for StreamCloseCause { - fn from(err: StreamError) -> Self { - StreamCloseCause::Error(err) - } -} - -impl<'a> From for StreamEvent<'a> { - fn from(cause: StreamCloseCause) -> Self { - StreamEvent::Close(cause) - } -} - impl From for DevicesError { fn from(err: BackendSpecificError) -> Self { DevicesError::BackendSpecific { err } @@ -895,12 +865,6 @@ impl From for StreamError { } } -impl From for StreamCloseCause { - fn from(err: BackendSpecificError) -> Self { - StreamCloseCause::Error(err.into()) - } -} - // If a backend does not provide an API for retrieving supported formats, we query it with a bunch // of commonly used rates. This is always the case for wasapi and is sometimes the case for alsa. // diff --git a/src/null/mod.rs b/src/null/mod.rs index f3238c8..ff5213a 100644 --- a/src/null/mod.rs +++ b/src/null/mod.rs @@ -9,8 +9,8 @@ use DeviceNameError; use Format; use PauseStreamError; use PlayStreamError; +use StreamDataResult; use SupportedFormatsError; -use StreamEvent; use SupportedFormat; pub struct EventLoop; @@ -23,7 +23,7 @@ impl EventLoop { #[inline] pub fn run(&self, _callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + where F: FnMut(StreamId, StreamDataResult) { loop { /* TODO: don't spin */ } } diff --git a/src/wasapi/stream.rs b/src/wasapi/stream.rs index 2ba2ac6..cad7b81 100644 --- a/src/wasapi/stream.rs +++ b/src/wasapi/stream.rs @@ -27,8 +27,8 @@ use PauseStreamError; use PlayStreamError; use SampleFormat; use StreamData; +use StreamDataResult; use StreamError; -use StreamEvent; use UnknownTypeOutputBuffer; use UnknownTypeInputBuffer; @@ -445,12 +445,12 @@ impl EventLoop { #[inline] pub fn run(&self, mut callback: F) -> ! - where F: FnMut(StreamId, StreamEvent) + where F: FnMut(StreamId, StreamDataResult) { self.run_inner(&mut callback); } - fn run_inner(&self, callback: &mut dyn FnMut(StreamId, StreamEvent)) -> ! { + fn run_inner(&self, callback: &mut dyn FnMut(StreamId, StreamDataResult)) -> ! { unsafe { // We keep `run_context` locked forever, which guarantees that two invocations of // `run()` cannot run simultaneously. @@ -472,8 +472,7 @@ impl EventLoop { Some(p) => { run_context.handles.remove(p + 1); run_context.streams.remove(p); - let event = StreamEvent::Close(err.into()); - callback(stream_id, event); + callback(stream_id, Err(err.into())); }, } } @@ -486,8 +485,7 @@ impl EventLoop { Ok(idx) => idx, Err(err) => { for stream in &run_context.streams { - let event = StreamEvent::Close(err.clone().into()); - callback(stream.id.clone(), event); + callback(stream.id.clone(), Err(err.clone().into())); } run_context.streams.clear(); run_context.handles.truncate(1); @@ -553,8 +551,7 @@ impl EventLoop { buffer: slice, }); let data = StreamData::Input { buffer: unknown_buffer }; - let event = StreamEvent::Data(data); - callback(stream.id.clone(), event); + callback(stream.id.clone(), Ok(data)); // Release the buffer. let hresult = (*capture_client).ReleaseBuffer(frames_available); if let Err(err) = stream_error_from_hresult(hresult) { @@ -596,8 +593,7 @@ impl EventLoop { buffer: slice }); let data = StreamData::Output { buffer: unknown_buffer }; - let event = StreamEvent::Data(data); - callback(stream.id.clone(), event); + callback(stream.id.clone(), Ok(data)); let hresult = (*render_client) .ReleaseBuffer(frames_available as u32, 0); if let Err(err) = stream_error_from_hresult(hresult) { @@ -739,7 +735,7 @@ fn format_to_waveformatextensible(format: &Format) -> Option { - let event = StreamEvent::Close(err.into()); - callback(stream_id, event); + callback(stream_id, Err(err.into())); run_context.handles.remove(p + 1); run_context.streams.remove(p); } @@ -794,8 +789,7 @@ fn process_commands( run_context.streams[p].playing = false; } Err(err) => { - let event = StreamEvent::Close(err.into()); - callback(stream_id, event); + callback(stream_id, Err(err.into())); run_context.handles.remove(p + 1); run_context.streams.remove(p); }