Change callback interface so that it takes a dedicated error callback
This commit is contained in:
parent
c97d1dd3fa
commit
3cce3e43d9
|
@ -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()?;
|
||||
|
||||
|
|
|
@ -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.");
|
||||
|
||||
|
|
|
@ -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()?;
|
||||
|
||||
|
|
|
@ -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<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError> 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<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError> 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<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError> 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<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError> 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<F>(inner: Arc<StreamInner>, mut callback: F) -> Stream where F: FnMut(StreamDataResult) + Send + 'static {
|
||||
fn new<D, E>(inner: Arc<StreamInner>, 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),
|
||||
|
|
|
@ -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<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
|
||||
where F: FnMut(StreamDataResult) + Send + 'static {
|
||||
fn build_input_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError>
|
||||
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Create an output stream.
|
||||
fn build_output_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
|
||||
where F: FnMut(StreamDataResult) + Send + 'static{
|
||||
fn build_output_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError>
|
||||
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StreamData<'a>, 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
|
||||
|
|
|
@ -250,22 +250,22 @@ macro_rules! impl_platform_host {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_input_stream<F>(&self, format: &crate::Format, callback: F) -> Result<Self::Stream, crate::BuildStreamError>
|
||||
where F: FnMut(crate::StreamDataResult) + Send + 'static {
|
||||
fn build_input_stream<D, E>(&self, format: &crate::Format, data_callback: D, error_callback: E) -> Result<Self::Stream, crate::BuildStreamError>
|
||||
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<F>(&self, format: &crate::Format, callback: F) -> Result<Self::Stream, crate::BuildStreamError>
|
||||
where F: FnMut(crate::StreamDataResult) + Send + 'static {
|
||||
fn build_output_stream<D, E>(&self, format: &crate::Format, data_callback: D, error_callback: E) -> Result<Self::Stream, crate::BuildStreamError>
|
||||
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),
|
||||
)*
|
||||
|
|
|
@ -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<Format, DefaultFormatError>;
|
||||
|
||||
/// Create an input stream.
|
||||
fn build_input_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
|
||||
where F: FnMut(StreamDataResult) + Send + 'static;
|
||||
fn build_input_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError>
|
||||
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static;
|
||||
|
||||
/// Create an output stream.
|
||||
fn build_output_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
|
||||
where F: FnMut(StreamDataResult) + Send + 'static;
|
||||
fn build_output_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError>
|
||||
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static;
|
||||
}
|
||||
|
||||
/// A stream created from `Device`, with methods to control playback.
|
||||
|
|
Loading…
Reference in New Issue