Merge pull request #395 from mitchmindtree/callback_info

Add a `CallbackInfo` argument to the stream data callback
This commit is contained in:
mitchmindtree 2020-04-27 14:32:37 +02:00 committed by GitHub
commit f032557fb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 123 additions and 109 deletions

View File

@ -4,11 +4,11 @@ on: [push, pull_request]
jobs: jobs:
clippy-test: clippy-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Update apt
run: sudo apt update
- name: Install alsa - name: Install alsa
run: sudo apt-get install libasound2-dev run: sudo apt-get install libasound2-dev
- name: Install stable - name: Install stable
@ -27,7 +27,7 @@ jobs:
rustfmt-check: rustfmt-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Install stable - name: Install stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -42,16 +42,14 @@ jobs:
args: --all -- --check args: --all -- --check
cargo-publish: cargo-publish:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' if: github.event_name == 'push' && github.ref == 'refs/heads/master'
env: env:
CRATESIO_TOKEN: ${{ secrets.CRATESIO_TOKEN }} CRATESIO_TOKEN: ${{ secrets.CRATESIO_TOKEN }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Update apt
run: sudo apt update
- name: Install alsa - name: Install alsa
run: sudo apt-get install libasound2-dev run: sudo apt-get install libasound2-dev
- name: Run cargo publish for cpal - name: Run cargo publish for cpal
@ -68,11 +66,11 @@ jobs:
[ $empty -eq 1 ] || grep -q "is already uploaded" < $CPAL_TMP [ $empty -eq 1 ] || grep -q "is already uploaded" < $CPAL_TMP
ubuntu-test: ubuntu-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Update apt
run: sudo apt update
- name: Install alsa - name: Install alsa
run: sudo apt-get install libasound2-dev run: sudo apt-get install libasound2-dev
- name: Install stable - name: Install stable
@ -93,15 +91,12 @@ jobs:
args: --all --all-features --verbose args: --all --all-features --verbose
asmjs-wasm32-test: asmjs-wasm32-test:
strategy: strategy:
matrix: matrix:
target: [asmjs-unknown-emscripten, wasm32-unknown-emscripten] target: [asmjs-unknown-emscripten, wasm32-unknown-emscripten]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Install emscripten - name: Install emscripten
run: sudo apt-get install emscripten run: sudo apt-get install emscripten
- name: Install stable - name: Install stable
@ -114,15 +109,12 @@ jobs:
run: cargo build --example beep --target ${{ matrix.target }} run: cargo build --example beep --target ${{ matrix.target }}
windows-test: windows-test:
strategy: strategy:
matrix: matrix:
version: [x86_64, i686] version: [x86_64, i686]
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Install ASIO SDK - name: Install ASIO SDK
env: env:
LINK: https://www.steinberg.net/asiosdk LINK: https://www.steinberg.net/asiosdk
@ -150,9 +142,8 @@ jobs:
macos-test: macos-test:
runs-on: macOS-latest runs-on: macOS-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Install llvm and clang - name: Install llvm and clang
run: brew install llvm run: brew install llvm
- name: Install stable - name: Install stable

View File

@ -17,6 +17,8 @@
- Added `build_input/output_stream_raw` methods allowing for dynamically - Added `build_input/output_stream_raw` methods allowing for dynamically
handling sample format type. handling sample format type.
- Added support for DragonFly platform. - Added support for DragonFly platform.
- Add `InputCallbackInfo` and `OutputCallbackInfo` types and update expected
user data callback function signature to provide these.
# Version 0.11.0 (2019-12-11) # Version 0.11.0 (2019-12-11)
@ -48,7 +50,7 @@
- Better buffer handling - Better buffer handling
- Fix logic error in frame/sample size - Fix logic error in frame/sample size
- Added error handling for unknown ALSA device errors - Added error handling for unknown ALSA device errors
- Fix resuming a paused stream on Windows (wasapi). - Fix resuming a paused stream on Windows (wasapi).
- Implement `default_output_format` for emscripten backend. - Implement `default_output_format` for emscripten backend.

View File

@ -37,7 +37,9 @@ where
let stream = device.build_output_stream( let stream = device.build_output_stream(
config, 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, err_fn,
)?; )?;
stream.play()?; stream.play()?;

View File

@ -46,7 +46,7 @@ fn main() -> Result<(), anyhow::Error> {
producer.push(0.0).unwrap(); 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; let mut output_fell_behind = false;
for &sample in data { for &sample in data {
if producer.push(sample).is_err() { 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; let mut input_fell_behind = None;
for sample in data { for sample in data {
*sample = match consumer.pop() { *sample = match consumer.pop() {

View File

@ -43,17 +43,17 @@ fn main() -> Result<(), anyhow::Error> {
let stream = match config.sample_format() { let stream = match config.sample_format() {
cpal::SampleFormat::F32 => device.build_input_stream( cpal::SampleFormat::F32 => device.build_input_stream(
&config.into(), &config.into(),
move |data| write_input_data::<f32, f32>(data, &writer_2), move |data, _: &_| write_input_data::<f32, f32>(data, &writer_2),
err_fn, err_fn,
)?, )?,
cpal::SampleFormat::I16 => device.build_input_stream( cpal::SampleFormat::I16 => device.build_input_stream(
&config.into(), &config.into(),
move |data| write_input_data::<i16, i16>(data, &writer_2), move |data, _: &_| write_input_data::<i16, i16>(data, &writer_2),
err_fn, err_fn,
)?, )?,
cpal::SampleFormat::U16 => device.build_input_stream( cpal::SampleFormat::U16 => device.build_input_stream(
&config.into(), &config.into(),
move |data| write_input_data::<u16, i16>(data, &writer_2), move |data, _: &_| write_input_data::<u16, i16>(data, &writer_2),
err_fn, err_fn,
)?, )?,
}; };

View File

@ -4,9 +4,9 @@ extern crate libc;
use self::alsa::poll::Descriptors; use self::alsa::poll::Descriptors;
use crate::{ use crate::{
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedStreamConfig,
SupportedStreamConfigsError, SupportedStreamConfigRange, SupportedStreamConfigsError,
}; };
use std::sync::Arc; use std::sync::Arc;
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
@ -90,7 +90,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = let stream_inner =
@ -107,7 +107,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = let stream_inner =
@ -464,7 +464,7 @@ struct StreamWorkerContext {
fn input_stream_worker( fn input_stream_worker(
rx: TriggerReceiver, rx: TriggerReceiver,
stream: &StreamInner, 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), error_callback: &mut (dyn FnMut(StreamError) + Send + 'static),
) { ) {
let mut ctxt = StreamWorkerContext::default(); let mut ctxt = StreamWorkerContext::default();
@ -499,7 +499,7 @@ fn input_stream_worker(
fn output_stream_worker( fn output_stream_worker(
rx: TriggerReceiver, rx: TriggerReceiver,
stream: &StreamInner, 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), error_callback: &mut (dyn FnMut(StreamError) + Send + 'static),
) { ) {
let mut ctxt = StreamWorkerContext::default(); let mut ctxt = StreamWorkerContext::default();
@ -636,14 +636,15 @@ fn poll_descriptors_and_prepare_buffer(
fn process_input( fn process_input(
stream: &StreamInner, stream: &StreamInner,
buffer: &mut [u8], buffer: &mut [u8],
data_callback: &mut (dyn FnMut(&Data) + Send + 'static), data_callback: &mut (dyn FnMut(&Data, &InputCallbackInfo) + Send + 'static),
) -> Result<(), BackendSpecificError> { ) -> Result<(), BackendSpecificError> {
stream.channel.io().readi(buffer)?; stream.channel.io().readi(buffer)?;
let sample_format = stream.sample_format; let sample_format = stream.sample_format;
let data = buffer.as_mut_ptr() as *mut (); let data = buffer.as_mut_ptr() as *mut ();
let len = buffer.len() / sample_format.sample_size(); let len = buffer.len() / sample_format.sample_size();
let data = unsafe { Data::from_parts(data, len, sample_format) }; let data = unsafe { Data::from_parts(data, len, sample_format) };
data_callback(&data); let info = crate::InputCallbackInfo {};
data_callback(&data, &info);
Ok(()) Ok(())
} }
@ -655,7 +656,7 @@ fn process_output(
stream: &StreamInner, stream: &StreamInner,
buffer: &mut [u8], buffer: &mut [u8],
available_frames: usize, 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), error_callback: &mut dyn FnMut(StreamError),
) { ) {
{ {
@ -664,7 +665,8 @@ fn process_output(
let data = buffer.as_mut_ptr() as *mut (); let data = buffer.as_mut_ptr() as *mut ();
let len = buffer.len() / sample_format.sample_size(); let len = buffer.len() / sample_format.sample_size();
let mut data = unsafe { Data::from_parts(data, len, sample_format) }; 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 { loop {
match stream.channel.io().writei(buffer) { match stream.channel.io().writei(buffer) {
@ -700,7 +702,7 @@ impl Stream {
mut error_callback: E, mut error_callback: E,
) -> Stream ) -> Stream
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let (tx, rx) = trigger(); let (tx, rx) = trigger();
@ -722,7 +724,7 @@ impl Stream {
mut error_callback: E, mut error_callback: E,
) -> Stream ) -> Stream
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let (tx, rx) = trigger(); let (tx, rx) = trigger();

View File

@ -3,8 +3,8 @@ extern crate parking_lot;
use crate::{ use crate::{
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat,
SupportedStreamConfig, SupportedStreamConfigsError, StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigsError,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; use traits::{DeviceTrait, HostTrait, StreamTrait};
@ -90,7 +90,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback) Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback)
@ -104,7 +104,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback) Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback)

View File

@ -4,19 +4,14 @@ extern crate num_traits;
use self::num_traits::PrimInt; use self::num_traits::PrimInt;
use super::parking_lot::Mutex; use super::parking_lot::Mutex;
use super::Device; use super::Device;
use crate::{
BackendSpecificError, BuildStreamError, Data, InputCallbackInfo, OutputCallbackInfo,
PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig, StreamError,
SupportedStreamConfig,
};
use std; use std;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; 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. /// Sample types whose constant silent value is known.
trait Silence { trait Silence {
@ -66,7 +61,7 @@ impl Device {
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_type = self.driver.input_data_type().map_err(build_stream_err)?; let stream_type = self.driver.input_data_type().map_err(build_stream_err)?;
@ -116,7 +111,7 @@ impl Device {
) where ) where
A: AsioSample, A: AsioSample,
B: Sample, B: Sample,
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
F: Fn(A) -> A, F: Fn(A) -> A,
{ {
// 1. Write the ASIO channels to the CPAL buffer. // 1. Write the ASIO channels to the CPAL buffer.
@ -133,7 +128,8 @@ impl Device {
let data = interleaved.as_mut_ptr() as *mut (); let data = interleaved.as_mut_ptr() as *mut ();
let len = interleaved.len(); let len = interleaved.len();
let data = Data::from_parts(data, len, B::FORMAT); let data = Data::from_parts(data, len, B::FORMAT);
callback(&data); let info = InputCallbackInfo {};
callback(&data, &info);
} }
match (&stream_type, sample_format) { match (&stream_type, sample_format) {
@ -233,7 +229,7 @@ impl Device {
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_type = self.driver.output_data_type().map_err(build_stream_err)?; let stream_type = self.driver.output_data_type().map_err(build_stream_err)?;
@ -307,7 +303,7 @@ impl Device {
) where ) where
A: Sample, A: Sample,
B: AsioSample, B: AsioSample,
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
F: Fn(B) -> B, F: Fn(B) -> B,
{ {
// 1. Render interleaved buffer from callback. // 1. Render interleaved buffer from callback.
@ -315,7 +311,8 @@ impl Device {
let data = interleaved.as_mut_ptr() as *mut (); let data = interleaved.as_mut_ptr() as *mut ();
let len = interleaved.len(); let len = interleaved.len();
let mut data = Data::from_parts(data, len, A::FORMAT); let mut data = Data::from_parts(data, len, A::FORMAT);
callback(&mut data); let info = OutputCallbackInfo {};
callback(&mut data, &info);
// 2. Silence ASIO channels if necessary. // 2. Silence ASIO channels if necessary.
let n_channels = interleaved.len() / asio_stream.buffer_size as usize; let n_channels = interleaved.len() / asio_stream.buffer_size as usize;

View File

@ -21,9 +21,9 @@ use self::coreaudio::sys::{
use crate::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
use crate::{ use crate::{
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange, PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedStreamConfig,
SupportedStreamConfigsError, SupportedStreamConfigRange, SupportedStreamConfigsError,
}; };
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::CStr; use std::ffi::CStr;
@ -111,7 +111,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback) Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback)
@ -125,7 +125,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback) Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback)
@ -486,7 +486,7 @@ impl Device {
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
// The scope and element for working with a device's input stream. // The scope and element for working with a device's input stream.
@ -653,7 +653,8 @@ impl Device {
let data = data as *mut (); let data = data as *mut ();
let len = (data_byte_size as usize / bytes_per_channel) as usize; let len = (data_byte_size as usize / bytes_per_channel) as usize;
let data = Data::from_parts(data, len, sample_format); let data = Data::from_parts(data, len, sample_format);
data_callback(&data); let info = InputCallbackInfo {};
data_callback(&data, &info);
Ok(()) Ok(())
})?; })?;
@ -674,7 +675,7 @@ impl Device {
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let mut audio_unit = audio_unit_from_device(self, false)?; let mut audio_unit = audio_unit_from_device(self, false)?;
@ -704,7 +705,8 @@ impl Device {
let data = data as *mut (); let data = data as *mut ();
let len = (data_byte_size as usize / bytes_per_channel) as usize; let len = (data_byte_size as usize / bytes_per_channel) as usize;
let mut data = Data::from_parts(data, len, sample_format); let mut data = Data::from_parts(data, len, sample_format);
data_callback(&mut data); let info = OutputCallbackInfo {};
data_callback(&mut data, &info);
Ok(()) Ok(())
})?; })?;

View File

@ -9,8 +9,9 @@ use stdweb::Reference;
use crate::{ use crate::{
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat,
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
SupportedStreamConfigsError,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; use traits::{DeviceTrait, HostTrait, StreamTrait};
@ -160,7 +161,7 @@ impl DeviceTrait for Device {
_error_callback: E, _error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
unimplemented!() unimplemented!()
@ -174,7 +175,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
assert_eq!( assert_eq!(
@ -224,7 +225,7 @@ impl StreamTrait for Stream {
// and to the `callback` parameter that was passed to `run`. // and to the `callback` parameter that was passed to `run`.
fn audio_callback_fn<D, E>(user_data_ptr: *mut c_void) fn audio_callback_fn<D, E>(user_data_ptr: *mut c_void)
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
unsafe { unsafe {
@ -241,7 +242,8 @@ where
let data = temporary_buffer.as_mut_ptr() as *mut (); let data = temporary_buffer.as_mut_ptr() as *mut ();
let sample_format = SampleFormat::F32; let sample_format = SampleFormat::F32;
let mut data = Data::from_parts(data, len, sample_format); 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<f32> once this is supported by stdweb // TODO: directly use a TypedArray<f32> once this is supported by stdweb

View File

@ -1,7 +1,8 @@
use crate::{ use crate::{
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat,
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
SupportedStreamConfigsError,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; use traits::{DeviceTrait, HostTrait, StreamTrait};
@ -74,7 +75,7 @@ impl DeviceTrait for Device {
_error_callback: E, _error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
unimplemented!() unimplemented!()
@ -89,7 +90,7 @@ impl DeviceTrait for Device {
_error_callback: E, _error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
unimplemented!() unimplemented!()

View File

@ -1,7 +1,8 @@
use crate::{ use crate::{
BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
SampleFormat, SampleRate, StreamConfig, SupportedStreamConfig, SupportedStreamConfigRange, InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig,
SupportedStreamConfigsError, COMMON_SAMPLE_RATES, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
COMMON_SAMPLE_RATES,
}; };
use std; use std;
use std::ffi::OsString; use std::ffi::OsString;
@ -104,7 +105,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_input_stream_raw_inner(config, sample_format)?; let stream_inner = self.build_input_stream_raw_inner(config, sample_format)?;
@ -123,7 +124,7 @@ impl DeviceTrait for Device {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_output_stream_raw_inner(config, sample_format)?; let stream_inner = self.build_output_stream_raw_inner(config, sample_format)?;

View File

@ -8,7 +8,8 @@ use super::winapi::um::winbase;
use super::winapi::um::winnt; use super::winapi::um::winnt;
use crate::traits::StreamTrait; use crate::traits::StreamTrait;
use crate::{ use crate::{
BackendSpecificError, Data, PauseStreamError, PlayStreamError, SampleFormat, StreamError, BackendSpecificError, Data, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
PlayStreamError, SampleFormat, StreamError,
}; };
use std::mem; use std::mem;
use std::ptr; use std::ptr;
@ -83,7 +84,7 @@ impl Stream {
mut error_callback: E, mut error_callback: E,
) -> Stream ) -> Stream
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let pending_scheduled_event = let pending_scheduled_event =
@ -112,7 +113,7 @@ impl Stream {
mut error_callback: E, mut error_callback: E,
) -> Stream ) -> Stream
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let pending_scheduled_event = let pending_scheduled_event =
@ -277,7 +278,7 @@ fn stream_error_from_hresult(hresult: winnt::HRESULT) -> Result<(), StreamError>
fn run_input( fn run_input(
mut run_ctxt: RunContext, mut run_ctxt: RunContext,
data_callback: &mut dyn FnMut(&Data), data_callback: &mut dyn FnMut(&Data, &InputCallbackInfo),
error_callback: &mut dyn FnMut(StreamError), error_callback: &mut dyn FnMut(StreamError),
) { ) {
loop { loop {
@ -304,7 +305,7 @@ fn run_input(
fn run_output( fn run_output(
mut run_ctxt: RunContext, 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), error_callback: &mut dyn FnMut(StreamError),
) { ) {
loop { loop {
@ -370,7 +371,7 @@ fn process_commands_and_await_signal(
fn process_input( fn process_input(
stream: &StreamInner, stream: &StreamInner,
capture_client: *mut audioclient::IAudioCaptureClient, capture_client: *mut audioclient::IAudioCaptureClient,
data_callback: &mut dyn FnMut(&Data), data_callback: &mut dyn FnMut(&Data, &InputCallbackInfo),
error_callback: &mut dyn FnMut(StreamError), error_callback: &mut dyn FnMut(StreamError),
) -> ControlFlow { ) -> ControlFlow {
let mut frames_available = 0; let mut frames_available = 0;
@ -409,7 +410,8 @@ fn process_input(
let len = frames_available as usize * stream.bytes_per_frame as usize let len = frames_available as usize * stream.bytes_per_frame as usize
/ stream.sample_format.sample_size(); / stream.sample_format.sample_size();
let data = Data::from_parts(data, len, stream.sample_format); let data = Data::from_parts(data, len, stream.sample_format);
data_callback(&data); let info = InputCallbackInfo {};
data_callback(&data, &info);
// Release the buffer. // Release the buffer.
let hresult = (*capture_client).ReleaseBuffer(frames_available); let hresult = (*capture_client).ReleaseBuffer(frames_available);
@ -425,7 +427,7 @@ fn process_input(
fn process_output( fn process_output(
stream: &StreamInner, stream: &StreamInner,
render_client: *mut audioclient::IAudioRenderClient, 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), error_callback: &mut dyn FnMut(StreamError),
) -> ControlFlow { ) -> ControlFlow {
// The number of frames available for writing. // 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 let len = frames_available as usize * stream.bytes_per_frame as usize
/ stream.sample_format.sample_size(); / stream.sample_format.sample_size();
let mut data = Data::from_parts(data, len, stream.sample_format); 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); let hresult = (*render_client).ReleaseBuffer(frames_available as u32, 0);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {

View File

@ -63,7 +63,7 @@
//! # let config = device.default_output_config().unwrap().into(); //! # let config = device.default_output_config().unwrap().into();
//! let stream = device.build_output_stream( //! let stream = device.build_output_stream(
//! &config, //! &config,
//! move |data: &mut [f32]| { //! move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
//! // react to stream events and read or write stream data here. //! // react to stream events and read or write stream data here.
//! }, //! },
//! move |err| { //! move |err| {
@ -102,7 +102,7 @@
//! SampleFormat::U16 => device.build_output_stream(&config, write_silence::<u16>, err_fn), //! SampleFormat::U16 => device.build_output_stream(&config, write_silence::<u16>, err_fn),
//! }.unwrap(); //! }.unwrap();
//! //!
//! fn write_silence<T: Sample>(data: &mut [T]) { //! fn write_silence<T: Sample>(data: &mut [T], _: &cpal::OutputCallbackInfo) {
//! for sample in data.iter_mut() { //! for sample in data.iter_mut() {
//! *sample = Sample::from(&0.0); //! *sample = Sample::from(&0.0);
//! } //! }
@ -119,7 +119,7 @@
//! # let supported_config = device.default_output_config().unwrap(); //! # let supported_config = device.default_output_config().unwrap();
//! # let sample_format = supported_config.sample_format(); //! # let sample_format = supported_config.sample_format();
//! # let config = supported_config.into(); //! # 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 err_fn = move |_err| {};
//! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap(); //! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap();
//! stream.play().unwrap(); //! stream.play().unwrap();
@ -135,7 +135,7 @@
//! # let supported_config = device.default_output_config().unwrap(); //! # let supported_config = device.default_output_config().unwrap();
//! # let sample_format = supported_config.sample_format(); //! # let sample_format = supported_config.sample_format();
//! # let config = supported_config.into(); //! # 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 err_fn = move |_err| {};
//! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap(); //! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn).unwrap();
//! stream.pause().unwrap(); //! stream.pause().unwrap();
@ -220,6 +220,14 @@ pub struct Data {
sample_format: SampleFormat, 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 { impl SupportedStreamConfig {
pub fn channels(&self) -> ChannelCount { pub fn channels(&self) -> ChannelCount {
self.channels self.channels

View File

@ -263,7 +263,7 @@ macro_rules! impl_platform_host {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, crate::BuildStreamError> ) -> Result<Self::Stream, crate::BuildStreamError>
where where
D: FnMut(&crate::Data) + Send + 'static, D: FnMut(&crate::Data, &crate::InputCallbackInfo) + Send + 'static,
E: FnMut(crate::StreamError) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static,
{ {
match self.0 { match self.0 {
@ -289,7 +289,7 @@ macro_rules! impl_platform_host {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, crate::BuildStreamError> ) -> Result<Self::Stream, crate::BuildStreamError>
where where
D: FnMut(&mut crate::Data) + Send + 'static, D: FnMut(&mut crate::Data, &crate::OutputCallbackInfo) + Send + 'static,
E: FnMut(crate::StreamError) + Send + 'static, E: FnMut(crate::StreamError) + Send + 'static,
{ {
match self.0 { match self.0 {

View File

@ -1,9 +1,10 @@
//! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs. //! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs.
use { use {
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, InputDevices, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
OutputDevices, PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig, InputCallbackInfo, InputDevices, OutputCallbackInfo, OutputDevices, PauseStreamError,
StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, PlayStreamError, Sample, SampleFormat, StreamConfig, StreamError, SupportedStreamConfig,
SupportedStreamConfigRange, SupportedStreamConfigsError,
}; };
/// A **Host** provides access to the available audio devices on the system. /// A **Host** provides access to the available audio devices on the system.
@ -122,16 +123,17 @@ pub trait DeviceTrait {
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
T: Sample, T: Sample,
D: FnMut(&[T]) + Send + 'static, D: FnMut(&[T], &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
self.build_input_stream_raw( self.build_input_stream_raw(
config, config,
T::FORMAT, T::FORMAT,
move |data| { move |data, info| {
data_callback( data_callback(
data.as_slice() data.as_slice()
.expect("host supplied incorrect sample type"), .expect("host supplied incorrect sample type"),
info,
) )
}, },
error_callback, error_callback,
@ -147,16 +149,17 @@ pub trait DeviceTrait {
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
T: Sample, T: Sample,
D: FnMut(&mut [T]) + Send + 'static, D: FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
self.build_output_stream_raw( self.build_output_stream_raw(
config, config,
T::FORMAT, T::FORMAT,
move |data| { move |data, info| {
data_callback( data_callback(
data.as_slice_mut() data.as_slice_mut()
.expect("host supplied incorrect sample type"), .expect("host supplied incorrect sample type"),
info,
) )
}, },
error_callback, error_callback,
@ -172,7 +175,7 @@ pub trait DeviceTrait {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static; E: FnMut(StreamError) + Send + 'static;
/// Create a dynamically typed output stream. /// Create a dynamically typed output stream.
@ -184,7 +187,7 @@ pub trait DeviceTrait {
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(StreamError) + Send + 'static; E: FnMut(StreamError) + Send + 'static;
} }