From bcf962c447db7cf979d5555cf5d6f57b5af812c3 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 16 Apr 2020 14:50:36 +0200 Subject: [PATCH] Add a `CallbackInfo` argument to the stream data callback I began on an implementation of the timestamp API described in #363 but quickly realised that it might be best to land the API for providing extra information to the user's callback first. This PR adds two new types: `InputCallbackInfo` and `OutputCallbackInfo`. These types are delivered to the user's data callback as a new, second argument. While these types are currently empty, the intention is for these types to provide information relevant to the current request for or delivery of data. This includes: - Timestamp information #363. - Flags related to the state of the stream (e.g buffer underflow/overflow). In order to maintain flexibility to avoid breaking things, I figure we can keep the fields of these types private and provide methods for retrieving this info. @Ralith, @ishitatsuyuki does this seem OK to you? --- examples/beep.rs | 4 +++- examples/feedback.rs | 4 ++-- examples/record_wav.rs | 6 +++--- src/host/alsa/mod.rs | 28 +++++++++++++++------------- src/host/asio/mod.rs | 8 ++++---- src/host/asio/stream.rs | 23 ++++++++++------------- src/host/coreaudio/mod.rs | 20 +++++++++++--------- src/host/emscripten/mod.rs | 14 ++++++++------ src/host/null/mod.rs | 9 +++++---- src/host/wasapi/device.rs | 9 +++++---- src/host/wasapi/stream.rs | 21 ++++++++++++--------- src/lib.rs | 16 ++++++++++++---- src/platform/mod.rs | 4 ++-- src/traits.rs | 21 ++++++++++++--------- 14 files changed, 104 insertions(+), 83 deletions(-) diff --git a/examples/beep.rs b/examples/beep.rs index 60ec8aa..dec1fdf 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -37,7 +37,9 @@ where let stream = device.build_output_stream( config, - move |data: &mut [T]| write_data(data, channels, &mut next_value), + move |data: &mut [T], _: &cpal::OutputCallbackInfo| { + write_data(data, channels, &mut next_value) + }, err_fn, )?; stream.play()?; diff --git a/examples/feedback.rs b/examples/feedback.rs index 2601136..e44f2d0 100644 --- a/examples/feedback.rs +++ b/examples/feedback.rs @@ -46,7 +46,7 @@ fn main() -> Result<(), anyhow::Error> { producer.push(0.0).unwrap(); } - let input_data_fn = move |data: &[f32]| { + let input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| { let mut output_fell_behind = false; for &sample in data { if producer.push(sample).is_err() { @@ -58,7 +58,7 @@ fn main() -> Result<(), anyhow::Error> { } }; - let output_data_fn = move |data: &mut [f32]| { + let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { let mut input_fell_behind = None; for sample in data { *sample = match consumer.pop() { diff --git a/examples/record_wav.rs b/examples/record_wav.rs index fcee828..ac6d237 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -43,17 +43,17 @@ fn main() -> Result<(), anyhow::Error> { let stream = match config.sample_format() { cpal::SampleFormat::F32 => device.build_input_stream( &config.into(), - move |data| write_input_data::(data, &writer_2), + move |data, _: &_| write_input_data::(data, &writer_2), err_fn, )?, cpal::SampleFormat::I16 => device.build_input_stream( &config.into(), - move |data| write_input_data::(data, &writer_2), + move |data, _: &_| write_input_data::(data, &writer_2), err_fn, )?, cpal::SampleFormat::U16 => device.build_input_stream( &config.into(), - move |data| write_input_data::(data, &writer_2), + move |data, _: &_| write_input_data::(data, &writer_2), err_fn, )?, }; diff --git a/src/host/alsa/mod.rs b/src/host/alsa/mod.rs index c094bf1..b66079c 100644 --- a/src/host/alsa/mod.rs +++ b/src/host/alsa/mod.rs @@ -4,9 +4,9 @@ extern crate libc; use self::alsa::poll::Descriptors; use crate::{ BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, - DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate, - StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, - SupportedStreamConfigsError, + DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, + PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedStreamConfig, + SupportedStreamConfigRange, SupportedStreamConfigsError, }; use std::cmp; use std::sync::Arc; @@ -90,7 +90,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_inner = @@ -107,7 +107,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_inner = @@ -464,7 +464,7 @@ struct StreamWorkerContext { fn input_stream_worker( rx: TriggerReceiver, stream: &StreamInner, - data_callback: &mut (dyn FnMut(&Data) + Send + 'static), + data_callback: &mut (dyn FnMut(&Data, &InputCallbackInfo) + Send + 'static), error_callback: &mut (dyn FnMut(StreamError) + Send + 'static), ) { let mut ctxt = StreamWorkerContext::default(); @@ -499,7 +499,7 @@ fn input_stream_worker( fn output_stream_worker( rx: TriggerReceiver, stream: &StreamInner, - data_callback: &mut (dyn FnMut(&mut Data) + Send + 'static), + data_callback: &mut (dyn FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static), error_callback: &mut (dyn FnMut(StreamError) + Send + 'static), ) { let mut ctxt = StreamWorkerContext::default(); @@ -636,14 +636,15 @@ fn poll_descriptors_and_prepare_buffer( fn process_input( stream: &StreamInner, buffer: &mut [u8], - data_callback: &mut (dyn FnMut(&Data) + Send + 'static), + data_callback: &mut (dyn FnMut(&Data, &InputCallbackInfo) + Send + 'static), ) -> Result<(), BackendSpecificError> { stream.channel.io().readi(buffer)?; let sample_format = stream.sample_format; let data = buffer.as_mut_ptr() as *mut (); let len = buffer.len() / sample_format.sample_size(); let data = unsafe { Data::from_parts(data, len, sample_format) }; - data_callback(&data); + let info = crate::InputCallbackInfo {}; + data_callback(&data, &info); Ok(()) } @@ -655,7 +656,7 @@ fn process_output( stream: &StreamInner, buffer: &mut [u8], available_frames: usize, - data_callback: &mut (dyn FnMut(&mut Data) + Send + 'static), + data_callback: &mut (dyn FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static), error_callback: &mut dyn FnMut(StreamError), ) { { @@ -664,7 +665,8 @@ fn process_output( let data = buffer.as_mut_ptr() as *mut (); let len = buffer.len() / sample_format.sample_size(); let mut data = unsafe { Data::from_parts(data, len, sample_format) }; - data_callback(&mut data); + let info = crate::OutputCallbackInfo {}; + data_callback(&mut data, &info); } loop { match stream.channel.io().writei(buffer) { @@ -700,7 +702,7 @@ impl Stream { mut error_callback: E, ) -> Stream where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let (tx, rx) = trigger(); @@ -722,7 +724,7 @@ impl Stream { mut error_callback: E, ) -> Stream where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let (tx, rx) = trigger(); diff --git a/src/host/asio/mod.rs b/src/host/asio/mod.rs index a885db6..ae99c3e 100644 --- a/src/host/asio/mod.rs +++ b/src/host/asio/mod.rs @@ -3,8 +3,8 @@ extern crate parking_lot; use crate::{ BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, - PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, - SupportedStreamConfig, SupportedStreamConfigsError, + InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat, + StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigsError, }; use traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -90,7 +90,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback) @@ -104,7 +104,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback) diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index 33f7974..0c1345b 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -4,19 +4,14 @@ extern crate num_traits; use self::num_traits::PrimInt; use super::parking_lot::Mutex; use super::Device; +use crate::{ + BackendSpecificError, BuildStreamError, Data, InputCallbackInfo, OutputCallbackInfo, + PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig, StreamError, + SupportedStreamConfig, +}; use std; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use BackendSpecificError; -use BuildStreamError; -use Data; -use PauseStreamError; -use PlayStreamError; -use Sample; -use SampleFormat; -use StreamConfig; -use StreamError; -use SupportedStreamConfig; /// Sample types whose constant silent value is known. trait Silence { @@ -66,7 +61,7 @@ impl Device { _error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_type = self.driver.input_data_type().map_err(build_stream_err)?; @@ -133,7 +128,8 @@ impl Device { let data = interleaved.as_mut_ptr() as *mut (); let len = interleaved.len(); let data = Data::from_parts(data, len, B::FORMAT); - callback(&data); + let info = InputCallbackInfo {}; + callback(&data, &info); } match (&stream_type, sample_format) { @@ -233,7 +229,7 @@ impl Device { _error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_type = self.driver.output_data_type().map_err(build_stream_err)?; @@ -315,6 +311,7 @@ impl Device { let data = interleaved.as_mut_ptr() as *mut (); let len = interleaved.len(); let mut data = Data::from_parts(data, len, A::FORMAT); + let info = OutputCallbackInfo {}; callback(&mut data); // 2. Silence ASIO channels if necessary. diff --git a/src/host/coreaudio/mod.rs b/src/host/coreaudio/mod.rs index e3a699f..10173af 100644 --- a/src/host/coreaudio/mod.rs +++ b/src/host/coreaudio/mod.rs @@ -21,9 +21,9 @@ use self::coreaudio::sys::{ use crate::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::{ BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, - DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate, - StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, - SupportedStreamConfigsError, + DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, + PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedStreamConfig, + SupportedStreamConfigRange, SupportedStreamConfigsError, }; use std::cell::RefCell; use std::ffi::CStr; @@ -111,7 +111,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback) @@ -125,7 +125,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback) @@ -486,7 +486,7 @@ impl Device { _error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { // The scope and element for working with a device's input stream. @@ -653,7 +653,8 @@ impl Device { let data = data as *mut (); let len = (data_byte_size as usize / bytes_per_channel) as usize; let data = Data::from_parts(data, len, sample_format); - data_callback(&data); + let info = InputCallbackInfo {}; + data_callback(&data, &info); Ok(()) })?; @@ -674,7 +675,7 @@ impl Device { _error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let mut audio_unit = audio_unit_from_device(self, false)?; @@ -704,7 +705,8 @@ impl Device { let data = data as *mut (); let len = (data_byte_size as usize / bytes_per_channel) as usize; let mut data = Data::from_parts(data, len, sample_format); - data_callback(&mut data); + let info = OutputCallbackInfo {}; + data_callback(&mut data, &info); Ok(()) })?; diff --git a/src/host/emscripten/mod.rs b/src/host/emscripten/mod.rs index 999746c..fba0a04 100644 --- a/src/host/emscripten/mod.rs +++ b/src/host/emscripten/mod.rs @@ -9,8 +9,9 @@ use stdweb::Reference; use crate::{ BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, - PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, - SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, + InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat, + StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, + SupportedStreamConfigsError, }; use traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -160,7 +161,7 @@ impl DeviceTrait for Device { _error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { unimplemented!() @@ -174,7 +175,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { assert_eq!( @@ -224,7 +225,7 @@ impl StreamTrait for Stream { // and to the `callback` parameter that was passed to `run`. fn audio_callback_fn(user_data_ptr: *mut c_void) where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { unsafe { @@ -241,7 +242,8 @@ where let data = temporary_buffer.as_mut_ptr() as *mut (); let sample_format = SampleFormat::F32; let mut data = Data::from_parts(data, len, sample_format); - data_cb(&mut data); + let info = OutputCallbackInfo {}; + data_cb(&mut data, &info); } // TODO: directly use a TypedArray once this is supported by stdweb diff --git a/src/host/null/mod.rs b/src/host/null/mod.rs index 1424ca8..dc83b39 100644 --- a/src/host/null/mod.rs +++ b/src/host/null/mod.rs @@ -1,7 +1,8 @@ use crate::{ BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, - PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, - SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, + InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat, + StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, + SupportedStreamConfigsError, }; use traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -74,7 +75,7 @@ impl DeviceTrait for Device { _error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { unimplemented!() @@ -89,7 +90,7 @@ impl DeviceTrait for Device { _error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { unimplemented!() diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index f1e1e1b..1106bb7 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -1,7 +1,8 @@ use crate::{ BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, - SampleFormat, SampleRate, StreamConfig, SupportedStreamConfig, SupportedStreamConfigRange, - SupportedStreamConfigsError, COMMON_SAMPLE_RATES, + InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig, + SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, + COMMON_SAMPLE_RATES, }; use std; use std::ffi::OsString; @@ -104,7 +105,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_inner = self.build_input_stream_raw_inner(config, sample_format)?; @@ -123,7 +124,7 @@ impl DeviceTrait for Device { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let stream_inner = self.build_output_stream_raw_inner(config, sample_format)?; diff --git a/src/host/wasapi/stream.rs b/src/host/wasapi/stream.rs index 8d996d3..5719cbc 100644 --- a/src/host/wasapi/stream.rs +++ b/src/host/wasapi/stream.rs @@ -8,7 +8,8 @@ use super::winapi::um::winbase; use super::winapi::um::winnt; use crate::traits::StreamTrait; use crate::{ - BackendSpecificError, Data, PauseStreamError, PlayStreamError, SampleFormat, StreamError, + BackendSpecificError, Data, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, + PlayStreamError, SampleFormat, StreamError, }; use std::mem; use std::ptr; @@ -83,7 +84,7 @@ impl Stream { mut error_callback: E, ) -> Stream where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let pending_scheduled_event = @@ -112,7 +113,7 @@ impl Stream { mut error_callback: E, ) -> Stream where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { let pending_scheduled_event = @@ -277,7 +278,7 @@ fn stream_error_from_hresult(hresult: winnt::HRESULT) -> Result<(), StreamError> fn run_input( mut run_ctxt: RunContext, - data_callback: &mut dyn FnMut(&Data), + data_callback: &mut dyn FnMut(&Data, &InputCallbackInfo), error_callback: &mut dyn FnMut(StreamError), ) { loop { @@ -304,7 +305,7 @@ fn run_input( fn run_output( mut run_ctxt: RunContext, - data_callback: &mut dyn FnMut(&mut Data), + data_callback: &mut dyn FnMut(&mut Data, &OutputCallbackInfo), error_callback: &mut dyn FnMut(StreamError), ) { loop { @@ -370,7 +371,7 @@ fn process_commands_and_await_signal( fn process_input( stream: &StreamInner, capture_client: *mut audioclient::IAudioCaptureClient, - data_callback: &mut dyn FnMut(&Data), + data_callback: &mut dyn FnMut(&Data, &InputCallbackInfo), error_callback: &mut dyn FnMut(StreamError), ) -> ControlFlow { let mut frames_available = 0; @@ -409,7 +410,8 @@ fn process_input( let len = frames_available as usize * stream.bytes_per_frame as usize / stream.sample_format.sample_size(); let data = Data::from_parts(data, len, stream.sample_format); - data_callback(&data); + let info = InputCallbackInfo {}; + data_callback(&data, &info); // Release the buffer. let hresult = (*capture_client).ReleaseBuffer(frames_available); @@ -425,7 +427,7 @@ fn process_input( fn process_output( stream: &StreamInner, render_client: *mut audioclient::IAudioRenderClient, - data_callback: &mut dyn FnMut(&mut Data), + data_callback: &mut dyn FnMut(&mut Data, &OutputCallbackInfo), error_callback: &mut dyn FnMut(StreamError), ) -> ControlFlow { // The number of frames available for writing. @@ -453,7 +455,8 @@ fn process_output( let len = frames_available as usize * stream.bytes_per_frame as usize / stream.sample_format.sample_size(); let mut data = Data::from_parts(data, len, stream.sample_format); - data_callback(&mut data); + let info = OutputCallbackInfo {}; + data_callback(&mut data, &info); let hresult = (*render_client).ReleaseBuffer(frames_available as u32, 0); if let Err(err) = stream_error_from_hresult(hresult) { diff --git a/src/lib.rs b/src/lib.rs index da10a9f..31a6b45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ //! # let config = device.default_output_config().unwrap().into(); //! let stream = device.build_output_stream( //! &config, -//! move |data: &mut [f32]| { +//! move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { //! // react to stream events and read or write stream data here. //! }, //! move |err| { @@ -102,7 +102,7 @@ //! SampleFormat::U16 => device.build_output_stream(&config, write_silence::, err_fn), //! }.unwrap(); //! -//! fn write_silence(data: &mut [T]) { +//! fn write_silence(data: &mut [T], _: &cpal::OutputCallbackInfo) { //! for sample in data.iter_mut() { //! *sample = Sample::from(&0.0); //! } @@ -119,7 +119,7 @@ //! # let supported_config = device.default_output_config().unwrap(); //! # let sample_format = supported_config.sample_format(); //! # let config = supported_config.into(); -//! # let data_fn = move |_data: &mut cpal::Data| {}; +//! # let data_fn = move |_data: &mut cpal::Data, _: &cpal::OutputCallbackInfo| {}; //! # let err_fn = move |_err| {}; //! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap(); //! stream.play().unwrap(); @@ -135,7 +135,7 @@ //! # let supported_config = device.default_output_config().unwrap(); //! # let sample_format = supported_config.sample_format(); //! # let config = supported_config.into(); -//! # let data_fn = move |_data: &mut cpal::Data| {}; +//! # let data_fn = move |_data: &mut cpal::Data, _: &cpal::OutputCallbackInfo| {}; //! # let err_fn = move |_err| {}; //! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap(); //! stream.pause().unwrap(); @@ -220,6 +220,14 @@ pub struct Data { sample_format: SampleFormat, } +/// Information relevant to a single call to the user's output stream data callback. +#[derive(Debug, Clone, PartialEq)] +pub struct OutputCallbackInfo {} + +/// Information relevant to a single call to the user's input stream data callback. +#[derive(Debug, Clone, PartialEq)] +pub struct InputCallbackInfo {} + impl SupportedStreamConfig { pub fn channels(&self) -> ChannelCount { self.channels diff --git a/src/platform/mod.rs b/src/platform/mod.rs index cd5f529..3c6db74 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -263,7 +263,7 @@ macro_rules! impl_platform_host { error_callback: E, ) -> Result where - D: FnMut(&crate::Data) + Send + 'static, + D: FnMut(&crate::Data, &crate::InputCallbackInfo) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static, { match self.0 { @@ -289,7 +289,7 @@ macro_rules! impl_platform_host { error_callback: E, ) -> Result where - D: FnMut(&mut crate::Data) + Send + 'static, + D: FnMut(&mut crate::Data, &crate::OutputCallbackInfo) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static, { match self.0 { diff --git a/src/traits.rs b/src/traits.rs index ef94aa7..51228ee 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,9 +1,10 @@ //! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs. use { - BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, InputDevices, - OutputDevices, PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig, - StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, + BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, + InputCallbackInfo, InputDevices, OutputCallbackInfo, OutputDevices, PauseStreamError, + PlayStreamError, Sample, SampleFormat, StreamConfig, StreamError, SupportedStreamConfig, + SupportedStreamConfigRange, SupportedStreamConfigsError, }; /// A **Host** provides access to the available audio devices on the system. @@ -122,16 +123,17 @@ pub trait DeviceTrait { ) -> Result where T: Sample, - D: FnMut(&[T]) + Send + 'static, + D: FnMut(&[T], &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { self.build_input_stream_raw( config, T::FORMAT, - move |data| { + move |data, info| { data_callback( data.as_slice() .expect("host supplied incorrect sample type"), + info, ) }, error_callback, @@ -147,16 +149,17 @@ pub trait DeviceTrait { ) -> Result where T: Sample, - D: FnMut(&mut [T]) + Send + 'static, + D: FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { self.build_output_stream_raw( config, T::FORMAT, - move |data| { + move |data, info| { data_callback( data.as_slice_mut() .expect("host supplied incorrect sample type"), + info, ) }, error_callback, @@ -172,7 +175,7 @@ pub trait DeviceTrait { error_callback: E, ) -> Result where - D: FnMut(&Data) + Send + 'static, + D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static; /// Create a dynamically typed output stream. @@ -184,7 +187,7 @@ pub trait DeviceTrait { error_callback: E, ) -> Result where - D: FnMut(&mut Data) + Send + 'static, + D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static; }