Rename stream `Format` types to `Config`

This implements the changes described at #370.

This commit implements only the `null` and `alsa` backends - the rest
will be implemented in follow-up commits.

Closes #370.
This commit is contained in:
mitchmindtree 2020-01-27 21:28:07 +01:00
parent ae910e3fe5
commit 9c781bd381
10 changed files with 287 additions and 272 deletions

View File

@ -8,23 +8,23 @@ fn main() -> Result<(), anyhow::Error> {
let device = host
.default_output_device()
.expect("failed to find a default output device");
let format = device.default_output_format()?;
let config = device.default_output_config()?;
match format.data_type {
cpal::SampleFormat::F32 => run::<f32>(&device, &format.shape())?,
cpal::SampleFormat::I16 => run::<i16>(&device, &format.shape())?,
cpal::SampleFormat::U16 => run::<u16>(&device, &format.shape())?,
match config.sample_format {
cpal::SampleFormat::F32 => run::<f32>(&device, &config.into())?,
cpal::SampleFormat::I16 => run::<i16>(&device, &config.into())?,
cpal::SampleFormat::U16 => run::<u16>(&device, &config.into())?,
}
Ok(())
}
fn run<T>(device: &cpal::Device, shape: &cpal::Shape) -> Result<(), anyhow::Error>
fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error>
where
T: cpal::Sample,
{
let sample_rate = shape.sample_rate.0 as f32;
let channels = shape.channels as usize;
let sample_rate = config.sample_rate.0 as f32;
let channels = config.channels as usize;
// Produce a sinusoid of maximum amplitude.
let mut sample_clock = 0f32;
@ -36,7 +36,7 @@ where
let err_fn = |err| eprintln!("an error occurred on stream: {}", err);
let stream = device.build_output_stream(
shape,
config,
move |data: &mut [T]| write_data(data, channels, &mut next_value),
err_fn,
)?;

View File

@ -21,48 +21,48 @@ fn main() -> Result<(), anyhow::Error> {
for (device_index, device) in devices.enumerate() {
println!(" {}. \"{}\"", device_index + 1, device.name()?);
// Input formats
if let Ok(fmt) = device.default_input_format() {
println!(" Default input stream format:\n {:?}", fmt);
// Input configs
if let Ok(fmt) = device.default_input_config() {
println!(" Default input stream config:\n {:?}", fmt);
}
let mut input_formats = match device.supported_input_formats() {
let mut input_configs = match device.supported_input_configs() {
Ok(f) => f.peekable(),
Err(e) => {
println!("Error: {:?}", e);
continue;
}
};
if input_formats.peek().is_some() {
println!(" All supported input stream formats:");
for (format_index, format) in input_formats.enumerate() {
if input_configs.peek().is_some() {
println!(" All supported input stream configs:");
for (config_index, config) in input_configs.enumerate() {
println!(
" {}.{}. {:?}",
device_index + 1,
format_index + 1,
format
config_index + 1,
config
);
}
}
// Output formats
if let Ok(fmt) = device.default_output_format() {
println!(" Default output stream format:\n {:?}", fmt);
// Output configs
if let Ok(fmt) = device.default_output_config() {
println!(" Default output stream config:\n {:?}", fmt);
}
let mut output_formats = match device.supported_output_formats() {
let mut output_configs = match device.supported_output_configs() {
Ok(f) => f.peekable(),
Err(e) => {
println!("Error: {:?}", e);
continue;
}
};
if output_formats.peek().is_some() {
println!(" All supported output stream formats:");
for (format_index, format) in output_formats.enumerate() {
if output_configs.peek().is_some() {
println!(" All supported output stream configs:");
for (config_index, config) in output_configs.enumerate() {
println!(
" {}.{}. {:?}",
device_index + 1,
format_index + 1,
format
config_index + 1,
config
);
}
}

View File

@ -1,7 +1,7 @@
//! Feeds back the input stream directly into the output stream.
//!
//! Assumes that the input and output devices can use the same stream format and that they support
//! the f32 sample format.
//! Assumes that the input and output devices can use the same stream configuration and that they
//! support the f32 sample format.
//!
//! Uses a delay of `LATENCY_MS` milliseconds in case the default input and output streams are not
//! precisely synchronised.
@ -28,12 +28,12 @@ fn main() -> Result<(), anyhow::Error> {
println!("Using default input device: \"{}\"", input_device.name()?);
println!("Using default output device: \"{}\"", output_device.name()?);
// We'll try and use the same format between streams to keep it simple
let shape = input_device.default_input_format()?.shape();
// We'll try and use the same configuration between streams to keep it simple.
let config: cpal::StreamConfig = input_device.default_input_config()?.into();
// Create a delay in case the input and output devices aren't synced.
let latency_frames = (LATENCY_MS / 1_000.0) * shape.sample_rate.0 as f32;
let latency_samples = latency_frames as usize * shape.channels as usize;
let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32;
let latency_samples = latency_frames as usize * config.channels as usize;
// The buffer to share samples
let ring = RingBuffer::new(latency_samples * 2);
@ -80,10 +80,10 @@ fn main() -> Result<(), anyhow::Error> {
// Build streams.
println!(
"Attempting to build both streams with f32 samples and `{:?}`.",
shape
config
);
let input_stream = input_device.build_input_stream(&shape, input_data_fn, err_fn)?;
let output_stream = output_device.build_output_stream(&shape, output_data_fn, err_fn)?;
let input_stream = input_device.build_input_stream(&config, input_data_fn, err_fn)?;
let output_stream = output_device.build_output_stream(&config, output_data_fn, err_fn)?;
println!("Successfully built streams.");
// Play the streams.

View File

@ -1,4 +1,4 @@
//! Records a WAV file (roughly 3 seconds long) using the default input device and format.
//! Records a WAV file (roughly 3 seconds long) using the default input device and config.
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
@ -15,18 +15,18 @@ fn main() -> Result<(), anyhow::Error> {
// Use the default host for working with audio devices.
let host = cpal::default_host();
// Setup the default input device and stream with the default input format.
// Setup the default input device and stream with the default input config.
let device = host
.default_input_device()
.expect("Failed to get default input device");
println!("Default input device: {}", device.name()?);
let format = device
.default_input_format()
.expect("Failed to get default input format");
println!("Default input format: {:?}", format);
let config = device
.default_input_config()
.expect("Failed to get default input config");
println!("Default input config: {:?}", config);
// The WAV file we're recording to.
const PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.wav");
let spec = wav_spec_from_format(&format);
let spec = wav_spec_from_config(&config);
let writer = hound::WavWriter::create(PATH, spec)?;
let writer = Arc::new(Mutex::new(Some(writer)));
@ -40,19 +40,19 @@ fn main() -> Result<(), anyhow::Error> {
eprintln!("an error occurred on stream: {}", err);
};
let stream = match format.data_type {
let stream = match config.sample_format {
cpal::SampleFormat::F32 => device.build_input_stream(
&format.shape(),
&config.into(),
move |data| write_input_data::<f32, f32>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::I16 => device.build_input_stream(
&format.shape(),
&config.into(),
move |data| write_input_data::<i16, i16>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::U16 => device.build_input_stream(
&format.shape(),
&config.into(),
move |data| write_input_data::<u16, i16>(data, &writer_2),
err_fn,
)?,
@ -76,12 +76,12 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat {
}
}
fn wav_spec_from_format(format: &cpal::Format) -> hound::WavSpec {
fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec {
hound::WavSpec {
channels: format.channels as _,
sample_rate: format.sample_rate.0 as _,
bits_per_sample: (format.data_type.sample_size() * 8) as _,
sample_format: sample_format(format.data_type),
channels: config.channels as _,
sample_rate: config.sample_rate.0 as _,
bits_per_sample: (config.sample_format.sample_size() * 8) as _,
sample_format: sample_format(config.sample_format),
}
}

View File

@ -47,7 +47,7 @@ pub enum DeviceNameError {
/// Error that can happen when enumerating the list of supported formats.
#[derive(Debug, Error)]
pub enum SupportedFormatsError {
pub enum SupportedStreamConfigsError {
/// The device no longer exists. This can happen if the device is disconnected while the
/// program is running.
#[error("The requested device is no longer available. For example, it has been unplugged.")]
@ -67,7 +67,7 @@ pub enum SupportedFormatsError {
/// May occur when attempting to request the default input or output stream format from a `Device`.
#[derive(Debug, Error)]
pub enum DefaultFormatError {
pub enum DefaultStreamConfigError {
/// The device no longer exists. This can happen if the device is disconnected while the
/// program is running.
#[error("The requested device is no longer available. For example, it has been unplugged.")]

View File

@ -2,9 +2,9 @@ extern crate alsa_sys as alsa;
extern crate libc;
use crate::{
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultFormatError,
DeviceNameError, DevicesError, Format, PauseStreamError, PlayStreamError, SampleFormat,
SampleRate, StreamError, SupportedFormat, SupportedFormatsError,
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
@ -14,8 +14,8 @@ use traits::{DeviceTrait, HostTrait, StreamTrait};
pub use self::enumerate::{default_input_device, default_output_device, Devices};
pub type SupportedInputFormats = VecIntoIter<SupportedFormat>;
pub type SupportedOutputFormats = VecIntoIter<SupportedFormat>;
pub type SupportedInputConfigs = VecIntoIter<SupportedStreamConfigRange>;
pub type SupportedOutputConfigs = VecIntoIter<SupportedStreamConfigRange>;
mod enumerate;
@ -52,37 +52,37 @@ impl HostTrait for Host {
}
impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats;
type SupportedInputConfigs = SupportedInputConfigs;
type SupportedOutputConfigs = SupportedOutputConfigs;
type Stream = Stream;
fn name(&self) -> Result<String, DeviceNameError> {
Device::name(self)
}
fn supported_input_formats(
fn supported_input_configs(
&self,
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
Device::supported_input_formats(self)
) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
Device::supported_input_configs(self)
}
fn supported_output_formats(
fn supported_output_configs(
&self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
Device::supported_output_formats(self)
) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
Device::supported_output_configs(self)
}
fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
Device::default_input_format(self)
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_input_config(self)
}
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
Device::default_output_format(self)
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_output_config(self)
}
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
conf: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -90,14 +90,14 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_stream_inner(format, alsa::SND_PCM_STREAM_CAPTURE)?;
let stream_inner = self.build_stream_inner(conf, alsa::SND_PCM_STREAM_CAPTURE)?;
let stream = Stream::new_input(Arc::new(stream_inner), data_callback, error_callback);
Ok(stream)
}
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
conf: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -105,7 +105,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_stream_inner(format, alsa::SND_PCM_STREAM_PLAYBACK)?;
let stream_inner = self.build_stream_inner(conf, alsa::SND_PCM_STREAM_PLAYBACK)?;
let stream = Stream::new_output(Arc::new(stream_inner), data_callback, error_callback);
Ok(stream)
}
@ -161,7 +161,7 @@ pub struct Device(String);
impl Device {
fn build_stream_inner(
&self,
format: &Format,
conf: &SupportedStreamConfig,
stream_type: alsa::snd_pcm_stream_t,
) -> Result<StreamInner, BuildStreamError> {
let name = ffi::CString::new(self.0.clone()).expect("unable to clone device");
@ -185,13 +185,13 @@ impl Device {
};
let can_pause = unsafe {
let hw_params = HwParams::alloc();
set_hw_params_from_format(handle, &hw_params, format)
set_hw_params_from_format(handle, &hw_params, conf)
.map_err(|description| BackendSpecificError { description })?;
alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1
};
let (buffer_len, period_len) = unsafe {
set_sw_params_from_format(handle, format)
set_sw_params_from_format(handle, conf)
.map_err(|description| BackendSpecificError { description })?
};
@ -213,9 +213,9 @@ impl Device {
let stream_inner = StreamInner {
channel: handle,
sample_format: format.data_type,
sample_format: conf.sample_format,
num_descriptors,
num_channels: format.channels as u16,
num_channels: conf.channels as u16,
buffer_len,
period_len,
can_pause,
@ -235,10 +235,10 @@ impl Device {
Ok(self.0.clone())
}
unsafe fn supported_formats(
unsafe fn supported_configs(
&self,
stream_t: alsa::snd_pcm_stream_t,
) -> Result<VecIntoIter<SupportedFormat>, SupportedFormatsError> {
) -> Result<VecIntoIter<SupportedStreamConfigRange>, SupportedStreamConfigsError> {
let mut handle = ptr::null_mut();
let device_name = match ffi::CString::new(&self.0[..]) {
Ok(name) => name,
@ -256,8 +256,8 @@ impl Device {
alsa::SND_PCM_NONBLOCK,
) {
-2 |
-16 /* determined empirically */ => return Err(SupportedFormatsError::DeviceNotAvailable),
-22 => return Err(SupportedFormatsError::InvalidArgument),
-16 /* determined empirically */ => return Err(SupportedStreamConfigsError::DeviceNotAvailable),
-22 => return Err(SupportedStreamConfigsError::InvalidArgument),
e => if let Err(description) = check_errors(e) {
let err = BackendSpecificError { description };
return Err(err.into())
@ -402,14 +402,14 @@ impl Device {
let mut output = Vec::with_capacity(
supported_formats.len() * supported_channels.len() * sample_rates.len(),
);
for &data_type in supported_formats.iter() {
for &sample_format in supported_formats.iter() {
for channels in supported_channels.iter() {
for &(min_rate, max_rate) in sample_rates.iter() {
output.push(SupportedFormat {
output.push(SupportedStreamConfigRange {
channels: channels.clone(),
min_sample_rate: SampleRate(min_rate as u32),
max_sample_rate: SampleRate(max_rate as u32),
data_type: data_type,
sample_format: sample_format,
});
}
}
@ -420,31 +420,35 @@ impl Device {
Ok(output.into_iter())
}
fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
unsafe { self.supported_formats(alsa::SND_PCM_STREAM_CAPTURE) }
fn supported_input_configs(
&self,
) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
unsafe { self.supported_configs(alsa::SND_PCM_STREAM_CAPTURE) }
}
fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> {
unsafe { self.supported_formats(alsa::SND_PCM_STREAM_PLAYBACK) }
fn supported_output_configs(
&self,
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
unsafe { self.supported_configs(alsa::SND_PCM_STREAM_PLAYBACK) }
}
// ALSA does not offer default stream formats, so instead we compare all supported formats by
// the `SupportedFormat::cmp_default_heuristics` order and select the greatest.
fn default_format(
// the `SupportedStreamConfigRange::cmp_default_heuristics` order and select the greatest.
fn default_config(
&self,
stream_t: alsa::snd_pcm_stream_t,
) -> Result<Format, DefaultFormatError> {
) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
let mut formats: Vec<_> = unsafe {
match self.supported_formats(stream_t) {
Err(SupportedFormatsError::DeviceNotAvailable) => {
return Err(DefaultFormatError::DeviceNotAvailable);
match self.supported_configs(stream_t) {
Err(SupportedStreamConfigsError::DeviceNotAvailable) => {
return Err(DefaultStreamConfigError::DeviceNotAvailable);
}
Err(SupportedFormatsError::InvalidArgument) => {
Err(SupportedStreamConfigsError::InvalidArgument) => {
// this happens sometimes when querying for input and output capabilities but
// the device supports only one
return Err(DefaultFormatError::StreamTypeNotSupported);
return Err(DefaultStreamConfigError::StreamTypeNotSupported);
}
Err(SupportedFormatsError::BackendSpecific { err }) => {
Err(SupportedStreamConfigsError::BackendSpecific { err }) => {
return Err(err.into());
}
Ok(fmts) => fmts.collect(),
@ -464,16 +468,16 @@ impl Device {
}
Ok(format)
}
None => Err(DefaultFormatError::StreamTypeNotSupported),
None => Err(DefaultStreamConfigError::StreamTypeNotSupported),
}
}
fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
self.default_format(alsa::SND_PCM_STREAM_CAPTURE)
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
self.default_config(alsa::SND_PCM_STREAM_CAPTURE)
}
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
self.default_format(alsa::SND_PCM_STREAM_PLAYBACK)
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
self.default_config(alsa::SND_PCM_STREAM_PLAYBACK)
}
}
@ -900,7 +904,7 @@ fn get_available_samples(stream: &StreamInner) -> Result<usize, BackendSpecificE
unsafe fn set_hw_params_from_format(
pcm_handle: *mut alsa::snd_pcm_t,
hw_params: &HwParams,
format: &Format,
format: &SupportedStreamConfig,
) -> Result<(), String> {
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_any(pcm_handle, hw_params.0)) {
return Err(format!("errors on pcm handle: {}", e));
@ -913,14 +917,14 @@ unsafe fn set_hw_params_from_format(
return Err(format!("handle not acessible: {}", e));
}
let data_type = if cfg!(target_endian = "big") {
match format.data_type {
let sample_format = if cfg!(target_endian = "big") {
match format.sample_format {
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_BE,
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_BE,
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_BE,
}
} else {
match format.data_type {
match format.sample_format {
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_LE,
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_LE,
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_LE,
@ -930,7 +934,7 @@ unsafe fn set_hw_params_from_format(
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(
pcm_handle,
hw_params.0,
data_type,
sample_format,
)) {
return Err(format!("format could not be set: {}", e));
}
@ -969,7 +973,7 @@ unsafe fn set_hw_params_from_format(
unsafe fn set_sw_params_from_format(
pcm_handle: *mut alsa::snd_pcm_t,
format: &Format,
format: &SupportedStreamConfig,
) -> Result<(usize, usize), String> {
let mut sw_params = ptr::null_mut(); // TODO: RAII
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)) {

View File

@ -1,6 +1,7 @@
use crate::{
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
PauseStreamError, PlayStreamError, StreamError, SupportedFormat, SupportedFormatsError,
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig,
SupportedStreamConfigRange, SupportedStreamConfigsError,
};
use traits::{DeviceTrait, HostTrait, StreamTrait};
@ -15,8 +16,8 @@ pub struct Host;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Stream;
pub struct SupportedInputFormats;
pub struct SupportedOutputFormats;
pub struct SupportedInputConfigs;
pub struct SupportedOutputConfigs;
impl Host {
#[allow(dead_code)]
@ -32,8 +33,8 @@ impl Devices {
}
impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats;
type SupportedInputConfigs = SupportedInputConfigs;
type SupportedOutputConfigs = SupportedOutputConfigs;
type Stream = Stream;
#[inline]
@ -42,28 +43,32 @@ impl DeviceTrait for Device {
}
#[inline]
fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
fn supported_input_configs(
&self,
) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
unimplemented!()
}
#[inline]
fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> {
fn supported_output_configs(
&self,
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
unimplemented!()
}
#[inline]
fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
unimplemented!()
}
#[inline]
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
unimplemented!()
}
fn build_input_stream_raw<D, E>(
&self,
_format: &Format,
_format: &SupportedStreamConfig,
_data_callback: D,
_error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -77,7 +82,7 @@ impl DeviceTrait for Device {
/// Create an output stream.
fn build_output_stream_raw<D, E>(
&self,
_format: &Format,
_format: &SupportedStreamConfig,
_data_callback: D,
_error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -129,20 +134,20 @@ impl Iterator for Devices {
}
}
impl Iterator for SupportedInputFormats {
type Item = SupportedFormat;
impl Iterator for SupportedInputConfigs {
type Item = SupportedStreamConfigRange;
#[inline]
fn next(&mut self) -> Option<SupportedFormat> {
fn next(&mut self) -> Option<SupportedStreamConfigRange> {
None
}
}
impl Iterator for SupportedOutputFormats {
type Item = SupportedFormat;
impl Iterator for SupportedOutputConfigs {
type Item = SupportedStreamConfigRange;
#[inline]
fn next(&mut self) -> Option<SupportedFormat> {
fn next(&mut self) -> Option<SupportedStreamConfigRange> {
None
}
}

View File

@ -31,24 +31,25 @@
//! let device = host.default_output_device().expect("no output device available");
//! ```
//!
//! Before we can create a stream, we must decide what the format of the audio samples is going to
//! be. You can query all the supported formats with the `supported_input_formats()` and
//! `supported_output_formats()` methods. These produce a list of `SupportedFormat` structs which
//! can later be turned into actual `Format` structs. If you don't want to query the list of
//! formats, you can also build your own `Format` manually, but doing so could lead to an error
//! when building the stream if the format is not supported by the device.
//! Before we can create a stream, we must decide what the configuration of the audio stream is
//! going to be. You can query all the supported configurations with the
//! `supported_input_configs()` and `supported_output_configs()` methods. These produce a list of
//! `SupportedStreamConfigRange` structs which can later be turned into actual
//! `SupportedStreamConfig` structs. If you don't want to query the list of configs, you can also
//! build your own `StreamConfig` manually, but doing so could lead to an error when building the
//! stream if the config is not supported by the device.
//!
//! > **Note**: the `supported_formats()` method could return an error for example if the device
//! > has been disconnected.
//! > **Note**: the `supported_input/output_configs()` methods could return an error for example if
//! > the device has been disconnected.
//!
//! ```no_run
//! use cpal::traits::{DeviceTrait, HostTrait};
//! # let host = cpal::default_host();
//! # let device = host.default_output_device().unwrap();
//! let mut supported_formats_range = device.supported_output_formats()
//! .expect("error while querying formats");
//! let format = supported_formats_range.next()
//! .expect("no supported format?!")
//! let mut supported_configs_range = device.supported_output_configs()
//! .expect("error while querying configs");
//! let supported_config = supported_configs_range.next()
//! .expect("no supported config?!")
//! .with_max_sample_rate();
//! ```
//!
@ -59,9 +60,9 @@
//! use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
//! # let host = cpal::default_host();
//! # let device = host.default_output_device().unwrap();
//! # let shape = device.default_output_format().unwrap().shape();
//! # let config = device.default_output_config().unwrap().into();
//! let stream = device.build_output_stream(
//! &shape,
//! &config,
//! move |data: &mut [f32]| {
//! // react to stream events and read or write stream data here.
//! },
@ -91,13 +92,14 @@
//! use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
//! # let host = cpal::default_host();
//! # let device = host.default_output_device().unwrap();
//! # let format = device.default_output_format().unwrap();
//! # let supported_config = device.default_output_config().unwrap();
//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
//! let shape = format.shape();
//! let stream = match format.data_type {
//! SampleFormat::F32 => device.build_output_stream(&shape, write_silence::<f32>, err_fn),
//! SampleFormat::I16 => device.build_output_stream(&shape, write_silence::<i16>, err_fn),
//! SampleFormat::U16 => device.build_output_stream(&shape, write_silence::<u16>, err_fn),
//! let sample_format = supported_config.sample_format;
//! let config = supported_config.into();
//! let stream = match sample_format {
//! SampleFormat::F32 => device.build_output_stream(&config, write_silence::<f32>, err_fn),
//! SampleFormat::I16 => device.build_output_stream(&config, write_silence::<i16>, err_fn),
//! SampleFormat::U16 => device.build_output_stream(&config, write_silence::<u16>, err_fn),
//! }.unwrap();
//!
//! fn write_silence<T: Sample>(data: &mut [T]) {
@ -114,10 +116,11 @@
//! # use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
//! # let host = cpal::default_host();
//! # let device = host.default_output_device().unwrap();
//! # let format = device.default_output_format().unwrap();
//! # let supported_config = device.default_output_config().unwrap();
//! # let config = supported_config.into();
//! # let data_fn = move |_data: &mut cpal::Data| {};
//! # let err_fn = move |_err| {};
//! # let stream = device.build_output_stream_raw(&format, data_fn, err_fn).unwrap();
//! # let stream = device.build_output_stream_raw(&config, data_fn, err_fn).unwrap();
//! stream.play().unwrap();
//! ```
//!
@ -128,10 +131,11 @@
//! # use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
//! # let host = cpal::default_host();
//! # let device = host.default_output_device().unwrap();
//! # let format = device.default_output_format().unwrap();
//! # let supported_config = device.default_output_config().unwrap();
//! # let config = supported_config.into();
//! # let data_fn = move |_data: &mut cpal::Data| {};
//! # let err_fn = move |_err| {};
//! # let stream = device.build_output_stream_raw(&format, data_fn, err_fn).unwrap();
//! # let stream = device.build_output_stream_raw(&config, data_fn, err_fn).unwrap();
//! stream.pause().unwrap();
//! ```
@ -149,7 +153,7 @@ extern crate thiserror;
pub use error::*;
pub use platform::{
available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream,
SupportedInputFormats, SupportedOutputFormats, ALL_HOSTS,
SupportedInputConfigs, SupportedOutputConfigs, ALL_HOSTS,
};
pub use samples_formats::{Sample, SampleFormat};
@ -172,56 +176,35 @@ pub type ChannelCount = u16;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SampleRate(pub u32);
/// The format of an input or output audio stream.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Format {
pub channels: ChannelCount,
pub sample_rate: SampleRate,
pub data_type: SampleFormat,
}
impl Format {
/// Construct a format having a particular `shape` and `data_type`.
pub fn with_shape(shape: &Shape, data_type: SampleFormat) -> Self {
Self {
channels: shape.channels,
sample_rate: shape.sample_rate,
data_type,
}
}
/// Extract aspects of the format independent of the data type.
pub fn shape(&self) -> Shape {
self.clone().into()
}
}
/// The properties of an input or output audio stream excluding its data type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Shape {
/// The set of parameters used to describe how to open a stream.
///
/// The sample format is omitted in favour of using a sample type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StreamConfig {
pub channels: ChannelCount,
pub sample_rate: SampleRate,
}
impl From<Format> for Shape {
fn from(x: Format) -> Self {
Self {
channels: x.channels,
sample_rate: x.sample_rate,
}
}
}
/// Describes a range of supported stream formats.
/// Describes a range of supported stream configurations, retrieved via the
/// `Device::supported_input/output_configs` method.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SupportedFormat {
pub struct SupportedStreamConfigRange {
pub channels: ChannelCount,
/// Minimum value for the samples rate of the supported formats.
pub min_sample_rate: SampleRate,
/// Maximum value for the samples rate of the supported formats.
pub max_sample_rate: SampleRate,
/// Type of data expected by the device.
pub data_type: SampleFormat,
pub sample_format: SampleFormat,
}
/// Describes a single supported stream configuration, retrieved via either a
/// `SupportedStreamConfigRange` instance or one of the `Device::default_input/output_config` methods.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SupportedStreamConfig {
pub channels: ChannelCount,
pub sample_rate: SampleRate,
pub sample_format: SampleFormat,
}
/// A buffer of dynamically typed audio data, passed to raw stream callbacks.
@ -235,6 +218,17 @@ pub struct Data {
sample_format: SampleFormat,
}
impl SupportedStreamConfig {
/// Construct a `SupportedStreamConfig` from an existing `StreamConfig`.
pub fn from_config(conf: &StreamConfig, fmt: SampleFormat) -> Self {
Self {
channels: conf.channels,
sample_rate: conf.sample_rate,
sample_format: fmt,
}
}
}
impl Data {
// Internal constructor for host implementations to use.
//
@ -328,25 +322,25 @@ impl Data {
}
}
impl SupportedFormat {
/// Turns this `SupportedFormat` into a `Format` corresponding to the maximum samples rate.
impl SupportedStreamConfigRange {
/// Turns this `SupportedStreamConfigRange` into a `SupportedStreamConfig` corresponding to the maximum samples rate.
#[inline]
pub fn with_max_sample_rate(self) -> Format {
Format {
pub fn with_max_sample_rate(self) -> SupportedStreamConfig {
SupportedStreamConfig {
channels: self.channels,
sample_rate: self.max_sample_rate,
data_type: self.data_type,
sample_format: self.sample_format,
}
}
/// A comparison function which compares two `SupportedFormat`s in terms of their priority of
/// A comparison function which compares two `SupportedStreamConfigRange`s in terms of their priority of
/// use as a default stream format.
///
/// Some backends do not provide a default stream format for their audio devices. In these
/// cases, CPAL attempts to decide on a reasonable default format for the user. To do this we
/// use the "greatest" of all supported stream formats when compared with this method.
///
/// Formats are prioritised by the following heuristics:
/// SupportedStreamConfigs are prioritised by the following heuristics:
///
/// **Channels**:
///
@ -382,17 +376,17 @@ impl SupportedFormat {
return cmp_channels;
}
let cmp_f32 = (self.data_type == F32).cmp(&(other.data_type == F32));
let cmp_f32 = (self.sample_format == F32).cmp(&(other.sample_format == F32));
if cmp_f32 != Equal {
return cmp_f32;
}
let cmp_i16 = (self.data_type == I16).cmp(&(other.data_type == I16));
let cmp_i16 = (self.sample_format == I16).cmp(&(other.sample_format == I16));
if cmp_i16 != Equal {
return cmp_i16;
}
let cmp_u16 = (self.data_type == U16).cmp(&(other.data_type == U16));
let cmp_u16 = (self.sample_format == U16).cmp(&(other.sample_format == U16));
if cmp_u16 != Equal {
return cmp_u16;
}
@ -410,14 +404,25 @@ impl SupportedFormat {
}
}
impl From<Format> for SupportedFormat {
impl From<SupportedStreamConfig> for StreamConfig {
fn from(conf: SupportedStreamConfig) -> Self {
let channels = conf.channels;
let sample_rate = conf.sample_rate;
StreamConfig {
channels,
sample_rate,
}
}
}
impl From<SupportedStreamConfig> for SupportedStreamConfigRange {
#[inline]
fn from(format: Format) -> SupportedFormat {
SupportedFormat {
fn from(format: SupportedStreamConfig) -> SupportedStreamConfigRange {
SupportedStreamConfigRange {
channels: format.channels,
min_sample_rate: format.sample_rate,
max_sample_rate: format.sample_rate,
data_type: format.data_type,
sample_format: format.sample_format,
}
}
}

View File

@ -27,8 +27,8 @@ pub use self::platform_impl::*;
// }
// ```
//
// And so on for Device, Devices, EventLoop, Host, StreamId, SupportedInputFormats,
// SupportedOutputFormats and all their necessary trait implementations.
// And so on for Device, Devices, EventLoop, Host, StreamId, SupportedInputConfigs,
// SupportedOutputConfigs and all their necessary trait implementations.
// ```
macro_rules! impl_platform_host {
($($HostVariant:ident $host_mod:ident $host_name:literal),*) => {
@ -67,13 +67,13 @@ macro_rules! impl_platform_host {
// TODO: Confirm this and add more specific detail and references.
pub struct Stream(StreamInner, crate::platform::NotSendSyncAcrossAllPlatforms);
/// The **SupportedInputFormats** iterator associated with the platform's dynamically
/// The **SupportedInputConfigs** iterator associated with the platform's dynamically
/// dispatched **Host** type.
pub struct SupportedInputFormats(SupportedInputFormatsInner);
pub struct SupportedInputConfigs(SupportedInputConfigsInner);
/// The **SupportedOutputFormats** iterator associated with the platform's dynamically
/// The **SupportedOutputConfigs** iterator associated with the platform's dynamically
/// dispatched **Host** type.
pub struct SupportedOutputFormats(SupportedOutputFormatsInner);
pub struct SupportedOutputConfigs(SupportedOutputConfigsInner);
/// Unique identifier for available hosts on the platform.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
@ -107,15 +107,15 @@ macro_rules! impl_platform_host {
)*
}
enum SupportedInputFormatsInner {
enum SupportedInputConfigsInner {
$(
$HostVariant(crate::host::$host_mod::SupportedInputFormats),
$HostVariant(crate::host::$host_mod::SupportedInputConfigs),
)*
}
enum SupportedOutputFormatsInner {
enum SupportedOutputConfigsInner {
$(
$HostVariant(crate::host::$host_mod::SupportedOutputFormats),
$HostVariant(crate::host::$host_mod::SupportedOutputConfigs),
)*
}
@ -162,13 +162,13 @@ macro_rules! impl_platform_host {
}
}
impl Iterator for SupportedInputFormats {
type Item = crate::SupportedFormat;
impl Iterator for SupportedInputConfigs {
type Item = crate::SupportedStreamConfigRange;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
$(
SupportedInputFormatsInner::$HostVariant(ref mut s) => s.next(),
SupportedInputConfigsInner::$HostVariant(ref mut s) => s.next(),
)*
}
}
@ -176,19 +176,19 @@ macro_rules! impl_platform_host {
fn size_hint(&self) -> (usize, Option<usize>) {
match self.0 {
$(
SupportedInputFormatsInner::$HostVariant(ref d) => d.size_hint(),
SupportedInputConfigsInner::$HostVariant(ref d) => d.size_hint(),
)*
}
}
}
impl Iterator for SupportedOutputFormats {
type Item = crate::SupportedFormat;
impl Iterator for SupportedOutputConfigs {
type Item = crate::SupportedStreamConfigRange;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
$(
SupportedOutputFormatsInner::$HostVariant(ref mut s) => s.next(),
SupportedOutputConfigsInner::$HostVariant(ref mut s) => s.next(),
)*
}
}
@ -196,15 +196,15 @@ macro_rules! impl_platform_host {
fn size_hint(&self) -> (usize, Option<usize>) {
match self.0 {
$(
SupportedOutputFormatsInner::$HostVariant(ref d) => d.size_hint(),
SupportedOutputConfigsInner::$HostVariant(ref d) => d.size_hint(),
)*
}
}
}
impl crate::traits::DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats;
type SupportedInputConfigs = SupportedInputConfigs;
type SupportedOutputConfigs = SupportedOutputConfigs;
type Stream = Stream;
fn name(&self) -> Result<String, crate::DeviceNameError> {
@ -215,49 +215,49 @@ macro_rules! impl_platform_host {
}
}
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, crate::SupportedFormatsError> {
fn supported_input_configs(&self) -> Result<Self::SupportedInputConfigs, crate::SupportedStreamConfigsError> {
match self.0 {
$(
DeviceInner::$HostVariant(ref d) => {
d.supported_input_formats()
.map(SupportedInputFormatsInner::$HostVariant)
.map(SupportedInputFormats)
d.supported_input_configs()
.map(SupportedInputConfigsInner::$HostVariant)
.map(SupportedInputConfigs)
}
)*
}
}
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, crate::SupportedFormatsError> {
fn supported_output_configs(&self) -> Result<Self::SupportedOutputConfigs, crate::SupportedStreamConfigsError> {
match self.0 {
$(
DeviceInner::$HostVariant(ref d) => {
d.supported_output_formats()
.map(SupportedOutputFormatsInner::$HostVariant)
.map(SupportedOutputFormats)
d.supported_output_configs()
.map(SupportedOutputConfigsInner::$HostVariant)
.map(SupportedOutputConfigs)
}
)*
}
}
fn default_input_format(&self) -> Result<crate::Format, crate::DefaultFormatError> {
fn default_input_config(&self) -> Result<crate::SupportedStreamConfig, crate::DefaultStreamConfigError> {
match self.0 {
$(
DeviceInner::$HostVariant(ref d) => d.default_input_format(),
DeviceInner::$HostVariant(ref d) => d.default_input_config(),
)*
}
}
fn default_output_format(&self) -> Result<crate::Format, crate::DefaultFormatError> {
fn default_output_config(&self) -> Result<crate::SupportedStreamConfig, crate::DefaultStreamConfigError> {
match self.0 {
$(
DeviceInner::$HostVariant(ref d) => d.default_output_format(),
DeviceInner::$HostVariant(ref d) => d.default_output_config(),
)*
}
}
fn build_input_stream_raw<D, E>(
&self,
format: &crate::Format,
format: &crate::SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, crate::BuildStreamError>
@ -276,7 +276,7 @@ macro_rules! impl_platform_host {
fn build_output_stream_raw<D, E>(
&self,
format: &crate::Format,
format: &crate::SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, crate::BuildStreamError>
@ -436,8 +436,8 @@ macro_rules! impl_platform_host {
mod platform_impl {
pub use crate::host::alsa::{
Device as AlsaDevice, Devices as AlsaDevices, Host as AlsaHost, Stream as AlsaStream,
SupportedInputFormats as AlsaSupportedInputFormats,
SupportedOutputFormats as AlsaSupportedOutputFormats,
SupportedInputConfigs as AlsaSupportedInputConfigs,
SupportedOutputConfigs as AlsaSupportedOutputConfigs,
};
impl_platform_host!(Alsa alsa "ALSA");
@ -454,8 +454,8 @@ mod platform_impl {
mod platform_impl {
pub use crate::host::coreaudio::{
Device as CoreAudioDevice, Devices as CoreAudioDevices, Host as CoreAudioHost,
Stream as CoreAudioStream, SupportedInputFormats as CoreAudioSupportedInputFormats,
SupportedOutputFormats as CoreAudioSupportedOutputFormats,
Stream as CoreAudioStream, SupportedInputConfigs as CoreAudioSupportedInputConfigs,
SupportedOutputConfigs as CoreAudioSupportedOutputConfigs,
};
impl_platform_host!(CoreAudio coreaudio "CoreAudio");
@ -472,8 +472,8 @@ mod platform_impl {
mod platform_impl {
pub use crate::host::emscripten::{
Device as EmscriptenDevice, Devices as EmscriptenDevices, Host as EmscriptenHost,
Stream as EmscriptenStream, SupportedInputFormats as EmscriptenSupportedInputFormats,
SupportedOutputFormats as EmscriptenSupportedOutputFormats,
Stream as EmscriptenStream, SupportedInputConfigs as EmscriptenSupportedInputConfigs,
SupportedOutputConfigs as EmscriptenSupportedOutputConfigs,
};
impl_platform_host!(Emscripten emscripten "Emscripten");
@ -491,13 +491,13 @@ mod platform_impl {
#[cfg(feature = "asio")]
pub use crate::host::asio::{
Device as AsioDevice, Devices as AsioDevices, Host as AsioHost, Stream as AsioStream,
SupportedInputFormats as AsioSupportedInputFormats,
SupportedOutputFormats as AsioSupportedOutputFormats,
SupportedInputConfigs as AsioSupportedInputConfigs,
SupportedOutputConfigs as AsioSupportedOutputConfigs,
};
pub use crate::host::wasapi::{
Device as WasapiDevice, Devices as WasapiDevices, Host as WasapiHost,
Stream as WasapiStream, SupportedInputFormats as WasapiSupportedInputFormats,
SupportedOutputFormats as WasapiSupportedOutputFormats,
Stream as WasapiStream, SupportedInputConfigs as WasapiSupportedInputConfigs,
SupportedOutputConfigs as WasapiSupportedOutputConfigs,
};
#[cfg(feature = "asio")]
@ -526,8 +526,8 @@ mod platform_impl {
mod platform_impl {
pub use crate::host::null::{
Device as NullDevice, Devices as NullDevices, EventLoop as NullEventLoop, Host as NullHost,
StreamId as NullStreamId, SupportedInputFormats as NullSupportedInputFormats,
SupportedOutputFormats as NullSupportedOutputFormats,
StreamId as NullStreamId, SupportedInputConfigs as NullSupportedInputConfigs,
SupportedOutputConfigs as NullSupportedOutputConfigs,
};
impl_platform_host!(Null null "Null");

View File

@ -1,9 +1,9 @@
//! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs.
use {
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
InputDevices, OutputDevices, PauseStreamError, PlayStreamError, Sample, Shape, StreamError,
SupportedFormat, SupportedFormatsError,
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, InputDevices,
OutputDevices, PauseStreamError, PlayStreamError, Sample, StreamConfig, StreamError,
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
};
/// A **Host** provides access to the available audio devices on the system.
@ -56,7 +56,7 @@ pub trait HostTrait {
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
fn supports_input<D: DeviceTrait>(device: &D) -> bool {
device
.supported_input_formats()
.supported_input_configs()
.map(|mut iter| iter.next().is_some())
.unwrap_or(false)
}
@ -70,7 +70,7 @@ pub trait HostTrait {
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
fn supports_output<D: DeviceTrait>(device: &D) -> bool {
device
.supported_output_formats()
.supported_output_configs()
.map(|mut iter| iter.next().is_some())
.unwrap_or(false)
}
@ -84,9 +84,9 @@ pub trait HostTrait {
/// methods that involve a device return a `Result` allowing the user to handle this case.
pub trait DeviceTrait {
/// The iterator type yielding supported input stream formats.
type SupportedInputFormats: Iterator<Item = SupportedFormat>;
type SupportedInputConfigs: Iterator<Item = SupportedStreamConfigRange>;
/// The iterator type yielding supported output stream formats.
type SupportedOutputFormats: Iterator<Item = SupportedFormat>;
type SupportedOutputConfigs: Iterator<Item = SupportedStreamConfigRange>;
/// The stream type created by `build_input_stream_raw` and `build_output_stream_raw`.
type Stream: StreamTrait;
@ -96,26 +96,27 @@ pub trait DeviceTrait {
/// An iterator yielding formats that are supported by the backend.
///
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
fn supported_input_formats(&self)
-> Result<Self::SupportedInputFormats, SupportedFormatsError>;
fn supported_input_configs(
&self,
) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError>;
/// An iterator yielding output stream formats that are supported by the device.
///
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
fn supported_output_formats(
fn supported_output_configs(
&self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError>;
) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError>;
/// The default input stream format for the device.
fn default_input_format(&self) -> Result<Format, DefaultFormatError>;
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
/// The default output stream format for the device.
fn default_output_format(&self) -> Result<Format, DefaultFormatError>;
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
/// Create an input stream.
fn build_input_stream<T, D, E>(
&self,
shape: &Shape,
config: &StreamConfig,
mut data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -125,7 +126,7 @@ pub trait DeviceTrait {
E: FnMut(StreamError) + Send + 'static,
{
self.build_input_stream_raw(
&Format::with_shape(shape, T::FORMAT),
&SupportedStreamConfig::from_config(config, T::FORMAT),
move |data| {
data_callback(
data.as_slice()
@ -139,7 +140,7 @@ pub trait DeviceTrait {
/// Create an output stream.
fn build_output_stream<T, D, E>(
&self,
shape: &Shape,
config: &StreamConfig,
mut data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -149,7 +150,7 @@ pub trait DeviceTrait {
E: FnMut(StreamError) + Send + 'static,
{
self.build_output_stream_raw(
&Format::with_shape(shape, T::FORMAT),
&SupportedStreamConfig::from_config(config, T::FORMAT),
move |data| {
data_callback(
data.as_slice_mut()
@ -163,7 +164,7 @@ pub trait DeviceTrait {
/// Create a dynamically typed input stream.
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
format: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -174,7 +175,7 @@ pub trait DeviceTrait {
/// Create a dynamically typed output stream.
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
format: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>