Skip to content

Commit

Permalink
Merge pull request RustAudio#4 from mitchmindtree/stream_config_pub
Browse files Browse the repository at this point in the history
Restrict the ways in which `SupportedStreamConfig/Range`s can be constructed
  • Loading branch information
mitchmindtree authored Feb 4, 2020
2 parents 07b66f5 + 7a6cb0b commit a2e6232
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 119 deletions.
2 changes: 1 addition & 1 deletion examples/beep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() -> Result<(), anyhow::Error> {
.expect("failed to find a default output device");
let config = device.default_output_config()?;

match config.sample_format {
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())?,
Expand Down
8 changes: 4 additions & 4 deletions examples/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ fn main() -> Result<(), anyhow::Error> {
println!(" {}. \"{}\"", device_index + 1, device.name()?);

// Input configs
if let Ok(fmt) = device.default_input_config() {
println!(" Default input stream config:\n {:?}", fmt);
if let Ok(conf) = device.default_input_config() {
println!(" Default input stream config:\n {:?}", conf);
}
let mut input_configs = match device.supported_input_configs() {
Ok(f) => f.peekable(),
Expand All @@ -45,8 +45,8 @@ fn main() -> Result<(), anyhow::Error> {
}

// Output configs
if let Ok(fmt) = device.default_output_config() {
println!(" Default output stream config:\n {:?}", fmt);
if let Ok(conf) = device.default_output_config() {
println!(" Default output stream config:\n {:?}", conf);
}
let mut output_configs = match device.supported_output_configs() {
Ok(f) => f.peekable(),
Expand Down
10 changes: 5 additions & 5 deletions examples/record_wav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() -> Result<(), anyhow::Error> {
eprintln!("an error occurred on stream: {}", err);
};

let stream = match config.sample_format {
let stream = match config.sample_format() {
cpal::SampleFormat::F32 => device.build_input_stream(
&config.into(),
move |data| write_input_data::<f32, f32>(data, &writer_2),
Expand Down Expand Up @@ -78,10 +78,10 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat {

fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec {
hound::WavSpec {
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),
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()),
}
}

Expand Down
39 changes: 23 additions & 16 deletions src/host/alsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ extern crate libc;
use crate::{
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
SupportedStreamConfigsError,
};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
Expand Down Expand Up @@ -82,30 +83,34 @@ impl DeviceTrait for Device {

fn build_input_stream_raw<D, E>(
&self,
conf: &SupportedStreamConfig,
conf: &StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_stream_inner(conf, alsa::SND_PCM_STREAM_CAPTURE)?;
let stream_inner =
self.build_stream_inner(conf, sample_format, 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,
conf: &SupportedStreamConfig,
conf: &StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_stream_inner(conf, alsa::SND_PCM_STREAM_PLAYBACK)?;
let stream_inner =
self.build_stream_inner(conf, sample_format, alsa::SND_PCM_STREAM_PLAYBACK)?;
let stream = Stream::new_output(Arc::new(stream_inner), data_callback, error_callback);
Ok(stream)
}
Expand Down Expand Up @@ -161,7 +166,8 @@ pub struct Device(String);
impl Device {
fn build_stream_inner(
&self,
conf: &SupportedStreamConfig,
conf: &StreamConfig,
sample_format: SampleFormat,
stream_type: alsa::snd_pcm_stream_t,
) -> Result<StreamInner, BuildStreamError> {
let name = ffi::CString::new(self.0.clone()).expect("unable to clone device");
Expand All @@ -185,7 +191,7 @@ impl Device {
};
let can_pause = unsafe {
let hw_params = HwParams::alloc();
set_hw_params_from_format(handle, &hw_params, conf)
set_hw_params_from_format(handle, &hw_params, conf, sample_format)
.map_err(|description| BackendSpecificError { description })?;

alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1
Expand Down Expand Up @@ -213,7 +219,7 @@ impl Device {

let stream_inner = StreamInner {
channel: handle,
sample_format: conf.sample_format,
sample_format,
num_descriptors,
num_channels: conf.channels as u16,
buffer_len,
Expand Down Expand Up @@ -904,7 +910,8 @@ 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: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
) -> 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));
Expand All @@ -918,13 +925,13 @@ unsafe fn set_hw_params_from_format(
}

let sample_format = if cfg!(target_endian = "big") {
match format.sample_format {
match 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.sample_format {
match 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,
Expand All @@ -941,15 +948,15 @@ unsafe fn set_hw_params_from_format(
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(
pcm_handle,
hw_params.0,
format.sample_rate.0 as libc::c_uint,
config.sample_rate.0 as libc::c_uint,
0,
)) {
return Err(format!("sample rate could not be set: {}", e));
}
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(
pcm_handle,
hw_params.0,
format.channels as libc::c_uint,
config.channels as libc::c_uint,
)) {
return Err(format!("channel count could not be set: {}", e));
}
Expand All @@ -973,7 +980,7 @@ unsafe fn set_hw_params_from_format(

unsafe fn set_sw_params_from_format(
pcm_handle: *mut alsa::snd_pcm_t,
format: &SupportedStreamConfig,
config: &StreamConfig,
) -> 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)) {
Expand Down Expand Up @@ -1009,8 +1016,8 @@ unsafe fn set_sw_params_from_format(
)) {
return Err(format!("snd_pcm_sw_params_set_avail_min failed: {}", e));
}
let buffer = buffer as usize * format.channels as usize;
let period = period as usize * format.channels as usize;
let buffer = buffer as usize * config.channels as usize;
let period = period as usize * config.channels as usize;
(buffer, period)
};

Expand Down
14 changes: 8 additions & 6 deletions src/host/asio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ extern crate parking_lot;

use crate::{
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig,
SupportedStreamConfigsError,
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError,
SupportedStreamConfig, SupportedStreamConfigsError,
};
use traits::{DeviceTrait, HostTrait, StreamTrait};

Expand Down Expand Up @@ -84,28 +84,30 @@ impl DeviceTrait for Device {

fn build_input_stream_raw<D, E>(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_input_stream_raw(self, config, data_callback, error_callback)
Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback)
}

fn build_output_stream_raw<D, E>(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_output_stream_raw(self, config, data_callback, error_callback)
Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback)
}
}

Expand Down
35 changes: 20 additions & 15 deletions src/host/asio/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use PauseStreamError;
use PlayStreamError;
use Sample;
use SampleFormat;
use StreamConfig;
use StreamError;
use SupportedStreamConfig;

Expand Down Expand Up @@ -59,7 +60,8 @@ impl Stream {
impl Device {
pub fn build_input_stream_raw<D, E>(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
mut data_callback: D,
_error_callback: E,
) -> Result<Stream, BuildStreamError>
Expand All @@ -70,14 +72,14 @@ impl Device {
let stream_type = self.driver.input_data_type().map_err(build_stream_err)?;

// Ensure that the desired sample type is supported.
let sample_format = super::device::convert_data_type(&stream_type)
let expected_sample_format = super::device::convert_data_type(&stream_type)
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
if config.sample_format != sample_format {
if sample_format != expected_sample_format {
return Err(BuildStreamError::StreamConfigNotSupported);
}

let num_channels = config.channels.clone();
let buffer_size = self.get_or_create_input_stream(config)?;
let buffer_size = self.get_or_create_input_stream(config, sample_format)?;
let cpal_num_samples = buffer_size * num_channels as usize;

// Create the buffer depending on the size of the data type.
Expand Down Expand Up @@ -225,7 +227,8 @@ impl Device {

pub fn build_output_stream_raw<D, E>(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
mut data_callback: D,
_error_callback: E,
) -> Result<Stream, BuildStreamError>
Expand All @@ -236,14 +239,14 @@ impl Device {
let stream_type = self.driver.output_data_type().map_err(build_stream_err)?;

// Ensure that the desired sample type is supported.
let sample_format = super::device::convert_data_type(&stream_type)
let expected_sample_format = super::device::convert_data_type(&stream_type)
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
if config.sample_format != sample_format {
if sample_format != expected_sample_format {
return Err(BuildStreamError::StreamConfigNotSupported);
}

let num_channels = config.channels.clone();
let buffer_size = self.get_or_create_output_stream(config)?;
let buffer_size = self.get_or_create_output_stream(config, sample_format)?;
let cpal_num_samples = buffer_size * num_channels as usize;

// Create buffers depending on data type.
Expand Down Expand Up @@ -438,12 +441,13 @@ impl Device {
/// On success, the buffer size of the stream is returned.
fn get_or_create_input_stream(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
) -> Result<usize, BuildStreamError> {
match self.default_input_config() {
Ok(f) => {
let num_asio_channels = f.channels;
check_config(&self.driver, config, num_asio_channels)
check_config(&self.driver, config, sample_format, num_asio_channels)
}
Err(_) => Err(BuildStreamError::StreamConfigNotSupported),
}?;
Expand Down Expand Up @@ -478,12 +482,13 @@ impl Device {
/// If there is no existing ASIO Output Stream it will be created.
fn get_or_create_output_stream(
&self,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
) -> Result<usize, BuildStreamError> {
match self.default_output_config() {
Ok(f) => {
let num_asio_channels = f.channels;
check_config(&self.driver, config, num_asio_channels)
check_config(&self.driver, config, sample_format, num_asio_channels)
}
Err(_) => Err(BuildStreamError::StreamConfigNotSupported),
}?;
Expand Down Expand Up @@ -581,13 +586,13 @@ impl AsioSample for f64 {
/// Checks sample rate, data type and then finally the number of channels.
fn check_config(
driver: &sys::Driver,
config: &SupportedStreamConfig,
config: &StreamConfig,
sample_format: SampleFormat,
num_asio_channels: u16,
) -> Result<(), BuildStreamError> {
let SupportedStreamConfig {
let StreamConfig {
channels,
sample_rate,
sample_format,
} = config;
// Try and set the sample rate to what the user selected.
let sample_rate = sample_rate.0.into();
Expand Down
Loading

0 comments on commit a2e6232

Please sign in to comment.