Add new `StreamEvent` type - enables more flexible user callback API
This adds the following types: - `StreamEvent` - `CloseStreamCause` - `StreamError` These allow for notifying the user of the following events: - A stream has been played. - A stream has been paused. - A stream has been closed due to user destroying stream. - A stream has been closed due to an error.
This commit is contained in:
parent
9cc5df8805
commit
59c789fbcd
86
src/lib.rs
86
src/lib.rs
|
@ -70,8 +70,8 @@
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # let event_loop = cpal::EventLoop::new();
|
//! # let event_loop = cpal::EventLoop::new();
|
||||||
//! event_loop.run(move |_stream_id, _stream_data| {
|
//! event_loop.run(move |_stream_id, _stream_event| {
|
||||||
//! // read or write stream data here
|
//! // react to stream events and read or write stream data here
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -90,7 +90,16 @@
|
||||||
//! use cpal::{StreamData, UnknownTypeOutputBuffer};
|
//! use cpal::{StreamData, UnknownTypeOutputBuffer};
|
||||||
//!
|
//!
|
||||||
//! # let event_loop = cpal::EventLoop::new();
|
//! # let event_loop = cpal::EventLoop::new();
|
||||||
//! event_loop.run(move |_stream_id, mut stream_data| {
|
//! 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);
|
||||||
|
//! return;
|
||||||
|
//! }
|
||||||
|
//! _ => return,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
//! match stream_data {
|
//! match stream_data {
|
||||||
//! StreamData::Output { buffer: UnknownTypeOutputBuffer::U16(mut buffer) } => {
|
//! StreamData::Output { buffer: UnknownTypeOutputBuffer::U16(mut buffer) } => {
|
||||||
//! for elem in buffer.iter_mut() {
|
//! for elem in buffer.iter_mut() {
|
||||||
|
@ -206,6 +215,31 @@ 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 has received a **Play** command.
|
||||||
|
Play,
|
||||||
|
/// The stream has received a **Pause** command.
|
||||||
|
///
|
||||||
|
/// No **Data** events should occur until a subsequent **Play** command is received.
|
||||||
|
Pause,
|
||||||
|
/// 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),
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a buffer containing audio data that may be read.
|
/// 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
|
/// This struct implements the `Deref` trait targeting `[T]`. Therefore this buffer can be read the
|
||||||
|
@ -291,7 +325,7 @@ pub struct SupportedOutputFormats(cpal_impl::SupportedOutputFormats);
|
||||||
/// **Note:** If you notice a `BackendSpecificError` that you believe could be better handled in a
|
/// **Note:** If you notice a `BackendSpecificError` that you believe could be better handled in a
|
||||||
/// cross-platform manner, please create an issue or submit a pull request with a patch that adds
|
/// cross-platform manner, please create an issue or submit a pull request with a patch that adds
|
||||||
/// the necessary error variant to the appropriate error enum.
|
/// the necessary error variant to the appropriate error enum.
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Clone, Debug, Fail)]
|
||||||
#[fail(display = "A backend-specific error has occurred: {}", description)]
|
#[fail(display = "A backend-specific error has occurred: {}", description)]
|
||||||
pub struct BackendSpecificError {
|
pub struct BackendSpecificError {
|
||||||
pub description: String
|
pub description: String
|
||||||
|
@ -412,6 +446,24 @@ 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
|
||||||
|
/// program is running.
|
||||||
|
#[fail(display = "The requested device is no longer available. For example, it has been unplugged.")]
|
||||||
|
DeviceNotAvailable,
|
||||||
|
/// See the `BackendSpecificError` docs for more information about this error variant.
|
||||||
|
#[fail(display = "{}", err)]
|
||||||
|
BackendSpecific {
|
||||||
|
#[fail(cause)]
|
||||||
|
err: BackendSpecificError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator yielding all `Device`s currently available to the system.
|
/// An iterator yielding all `Device`s currently available to the system.
|
||||||
///
|
///
|
||||||
/// Can be empty if the system does not support audio in general.
|
/// Can be empty if the system does not support audio in general.
|
||||||
|
@ -591,7 +643,7 @@ impl EventLoop {
|
||||||
/// You can call the other methods of `EventLoop` without getting a deadlock.
|
/// You can call the other methods of `EventLoop` without getting a deadlock.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run<F>(&self, mut callback: F) -> !
|
pub fn run<F>(&self, mut callback: F) -> !
|
||||||
where F: FnMut(StreamId, StreamData) + Send
|
where F: FnMut(StreamId, StreamEvent) + Send
|
||||||
{
|
{
|
||||||
self.0.run(move |id, data| callback(StreamId(id), data))
|
self.0.run(move |id, data| callback(StreamId(id), data))
|
||||||
}
|
}
|
||||||
|
@ -789,6 +841,18 @@ impl Iterator for SupportedOutputFormats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<StreamError> for StreamCloseCause {
|
||||||
|
fn from(err: StreamError) -> Self {
|
||||||
|
StreamCloseCause::Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<StreamCloseCause> for StreamEvent<'a> {
|
||||||
|
fn from(cause: StreamCloseCause) -> Self {
|
||||||
|
StreamEvent::Close(cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<BackendSpecificError> for DevicesError {
|
impl From<BackendSpecificError> for DevicesError {
|
||||||
fn from(err: BackendSpecificError) -> Self {
|
fn from(err: BackendSpecificError) -> Self {
|
||||||
DevicesError::BackendSpecific { err }
|
DevicesError::BackendSpecific { err }
|
||||||
|
@ -831,6 +895,18 @@ impl From<BackendSpecificError> for PauseStreamError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BackendSpecificError> for StreamError {
|
||||||
|
fn from(err: BackendSpecificError) -> Self {
|
||||||
|
StreamError::BackendSpecific { err }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BackendSpecificError> 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
|
// 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.
|
// of commonly used rates. This is always the case for wasapi and is sometimes the case for alsa.
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue