Merge pull request #4 from mitchmindtree/stream_config_pub
Restrict the ways in which `SupportedStreamConfig/Range`s can be constructed
This commit is contained in:
commit
a2e6232cd8
|
@ -10,7 +10,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
.expect("failed to find a default output device");
|
.expect("failed to find a default output device");
|
||||||
let config = device.default_output_config()?;
|
let config = device.default_output_config()?;
|
||||||
|
|
||||||
match config.sample_format {
|
match config.sample_format() {
|
||||||
cpal::SampleFormat::F32 => run::<f32>(&device, &config.into())?,
|
cpal::SampleFormat::F32 => run::<f32>(&device, &config.into())?,
|
||||||
cpal::SampleFormat::I16 => run::<i16>(&device, &config.into())?,
|
cpal::SampleFormat::I16 => run::<i16>(&device, &config.into())?,
|
||||||
cpal::SampleFormat::U16 => run::<u16>(&device, &config.into())?,
|
cpal::SampleFormat::U16 => run::<u16>(&device, &config.into())?,
|
||||||
|
|
|
@ -22,8 +22,8 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
println!(" {}. \"{}\"", device_index + 1, device.name()?);
|
println!(" {}. \"{}\"", device_index + 1, device.name()?);
|
||||||
|
|
||||||
// Input configs
|
// Input configs
|
||||||
if let Ok(fmt) = device.default_input_config() {
|
if let Ok(conf) = device.default_input_config() {
|
||||||
println!(" Default input stream config:\n {:?}", fmt);
|
println!(" Default input stream config:\n {:?}", conf);
|
||||||
}
|
}
|
||||||
let mut input_configs = match device.supported_input_configs() {
|
let mut input_configs = match device.supported_input_configs() {
|
||||||
Ok(f) => f.peekable(),
|
Ok(f) => f.peekable(),
|
||||||
|
@ -45,8 +45,8 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output configs
|
// Output configs
|
||||||
if let Ok(fmt) = device.default_output_config() {
|
if let Ok(conf) = device.default_output_config() {
|
||||||
println!(" Default output stream config:\n {:?}", fmt);
|
println!(" Default output stream config:\n {:?}", conf);
|
||||||
}
|
}
|
||||||
let mut output_configs = match device.supported_output_configs() {
|
let mut output_configs = match device.supported_output_configs() {
|
||||||
Ok(f) => f.peekable(),
|
Ok(f) => f.peekable(),
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
eprintln!("an error occurred on stream: {}", err);
|
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(
|
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),
|
||||||
|
@ -78,10 +78,10 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat {
|
||||||
|
|
||||||
fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec {
|
fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec {
|
||||||
hound::WavSpec {
|
hound::WavSpec {
|
||||||
channels: config.channels as _,
|
channels: config.channels() as _,
|
||||||
sample_rate: config.sample_rate.0 as _,
|
sample_rate: config.sample_rate().0 as _,
|
||||||
bits_per_sample: (config.sample_format.sample_size() * 8) as _,
|
bits_per_sample: (config.sample_format().sample_size() * 8) as _,
|
||||||
sample_format: sample_format(config.sample_format),
|
sample_format: sample_format(config.sample_format()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ extern crate libc;
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
|
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
|
||||||
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
|
DeviceNameError, DevicesError, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
|
||||||
StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
|
SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread::{self, JoinHandle};
|
use std::thread::{self, JoinHandle};
|
||||||
|
@ -82,7 +83,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
conf: &SupportedStreamConfig,
|
conf: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -90,14 +92,16 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&Data) + Send + 'static,
|
D: FnMut(&Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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);
|
let stream = Stream::new_input(Arc::new(stream_inner), data_callback, error_callback);
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
conf: &SupportedStreamConfig,
|
conf: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -105,7 +109,8 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&mut Data) + Send + 'static,
|
D: FnMut(&mut Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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);
|
let stream = Stream::new_output(Arc::new(stream_inner), data_callback, error_callback);
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
@ -161,7 +166,8 @@ pub struct Device(String);
|
||||||
impl Device {
|
impl Device {
|
||||||
fn build_stream_inner(
|
fn build_stream_inner(
|
||||||
&self,
|
&self,
|
||||||
conf: &SupportedStreamConfig,
|
conf: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
stream_type: alsa::snd_pcm_stream_t,
|
stream_type: alsa::snd_pcm_stream_t,
|
||||||
) -> Result<StreamInner, BuildStreamError> {
|
) -> Result<StreamInner, BuildStreamError> {
|
||||||
let name = ffi::CString::new(self.0.clone()).expect("unable to clone device");
|
let name = ffi::CString::new(self.0.clone()).expect("unable to clone device");
|
||||||
|
@ -185,7 +191,7 @@ impl Device {
|
||||||
};
|
};
|
||||||
let can_pause = unsafe {
|
let can_pause = unsafe {
|
||||||
let hw_params = HwParams::alloc();
|
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 })?;
|
.map_err(|description| BackendSpecificError { description })?;
|
||||||
|
|
||||||
alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1
|
alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1
|
||||||
|
@ -213,7 +219,7 @@ impl Device {
|
||||||
|
|
||||||
let stream_inner = StreamInner {
|
let stream_inner = StreamInner {
|
||||||
channel: handle,
|
channel: handle,
|
||||||
sample_format: conf.sample_format,
|
sample_format,
|
||||||
num_descriptors,
|
num_descriptors,
|
||||||
num_channels: conf.channels as u16,
|
num_channels: conf.channels as u16,
|
||||||
buffer_len,
|
buffer_len,
|
||||||
|
@ -904,7 +910,8 @@ fn get_available_samples(stream: &StreamInner) -> Result<usize, BackendSpecificE
|
||||||
unsafe fn set_hw_params_from_format(
|
unsafe fn set_hw_params_from_format(
|
||||||
pcm_handle: *mut alsa::snd_pcm_t,
|
pcm_handle: *mut alsa::snd_pcm_t,
|
||||||
hw_params: &HwParams,
|
hw_params: &HwParams,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_any(pcm_handle, hw_params.0)) {
|
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));
|
return Err(format!("errors on pcm handle: {}", e));
|
||||||
|
@ -918,13 +925,13 @@ unsafe fn set_hw_params_from_format(
|
||||||
}
|
}
|
||||||
|
|
||||||
let sample_format = if cfg!(target_endian = "big") {
|
let sample_format = if cfg!(target_endian = "big") {
|
||||||
match format.sample_format {
|
match sample_format {
|
||||||
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_BE,
|
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_BE,
|
||||||
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_BE,
|
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_BE,
|
||||||
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_BE,
|
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_BE,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match format.sample_format {
|
match sample_format {
|
||||||
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_LE,
|
SampleFormat::I16 => alsa::SND_PCM_FORMAT_S16_LE,
|
||||||
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_LE,
|
SampleFormat::U16 => alsa::SND_PCM_FORMAT_U16_LE,
|
||||||
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_LE,
|
SampleFormat::F32 => alsa::SND_PCM_FORMAT_FLOAT_LE,
|
||||||
|
@ -941,7 +948,7 @@ unsafe fn set_hw_params_from_format(
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(
|
||||||
pcm_handle,
|
pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
format.sample_rate.0 as libc::c_uint,
|
config.sample_rate.0 as libc::c_uint,
|
||||||
0,
|
0,
|
||||||
)) {
|
)) {
|
||||||
return Err(format!("sample rate could not be set: {}", e));
|
return Err(format!("sample rate could not be set: {}", e));
|
||||||
|
@ -949,7 +956,7 @@ unsafe fn set_hw_params_from_format(
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(
|
||||||
pcm_handle,
|
pcm_handle,
|
||||||
hw_params.0,
|
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));
|
return Err(format!("channel count could not be set: {}", e));
|
||||||
}
|
}
|
||||||
|
@ -973,7 +980,7 @@ unsafe fn set_hw_params_from_format(
|
||||||
|
|
||||||
unsafe fn set_sw_params_from_format(
|
unsafe fn set_sw_params_from_format(
|
||||||
pcm_handle: *mut alsa::snd_pcm_t,
|
pcm_handle: *mut alsa::snd_pcm_t,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
) -> Result<(usize, usize), String> {
|
) -> Result<(usize, usize), String> {
|
||||||
let mut sw_params = ptr::null_mut(); // TODO: RAII
|
let mut sw_params = ptr::null_mut(); // TODO: RAII
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)) {
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)) {
|
||||||
|
@ -1009,8 +1016,8 @@ unsafe fn set_sw_params_from_format(
|
||||||
)) {
|
)) {
|
||||||
return Err(format!("snd_pcm_sw_params_set_avail_min failed: {}", e));
|
return Err(format!("snd_pcm_sw_params_set_avail_min failed: {}", e));
|
||||||
}
|
}
|
||||||
let buffer = buffer as usize * format.channels as usize;
|
let buffer = buffer as usize * config.channels as usize;
|
||||||
let period = period as usize * format.channels as usize;
|
let period = period as usize * config.channels as usize;
|
||||||
(buffer, period)
|
(buffer, period)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ extern crate parking_lot;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
||||||
PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig,
|
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError,
|
||||||
SupportedStreamConfigsError,
|
SupportedStreamConfig, SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
|
||||||
|
@ -84,7 +84,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -92,12 +93,13 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&Data) + Send + 'static,
|
D: FnMut(&Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -105,7 +107,7 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&mut Data) + Send + 'static,
|
D: FnMut(&mut Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use PauseStreamError;
|
||||||
use PlayStreamError;
|
use PlayStreamError;
|
||||||
use Sample;
|
use Sample;
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
|
use StreamConfig;
|
||||||
use StreamError;
|
use StreamError;
|
||||||
use SupportedStreamConfig;
|
use SupportedStreamConfig;
|
||||||
|
|
||||||
|
@ -59,7 +60,8 @@ impl Stream {
|
||||||
impl Device {
|
impl Device {
|
||||||
pub fn build_input_stream_raw<D, E>(
|
pub fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
mut data_callback: D,
|
mut data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Stream, BuildStreamError>
|
) -> Result<Stream, BuildStreamError>
|
||||||
|
@ -70,14 +72,14 @@ impl Device {
|
||||||
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)?;
|
||||||
|
|
||||||
// Ensure that the desired sample type is supported.
|
// 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)?;
|
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
||||||
if config.sample_format != sample_format {
|
if sample_format != expected_sample_format {
|
||||||
return Err(BuildStreamError::StreamConfigNotSupported);
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_channels = config.channels.clone();
|
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;
|
let cpal_num_samples = buffer_size * num_channels as usize;
|
||||||
|
|
||||||
// Create the buffer depending on the size of the data type.
|
// Create the buffer depending on the size of the data type.
|
||||||
|
@ -225,7 +227,8 @@ impl Device {
|
||||||
|
|
||||||
pub fn build_output_stream_raw<D, E>(
|
pub fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
mut data_callback: D,
|
mut data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Stream, BuildStreamError>
|
) -> Result<Stream, BuildStreamError>
|
||||||
|
@ -236,14 +239,14 @@ impl Device {
|
||||||
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)?;
|
||||||
|
|
||||||
// Ensure that the desired sample type is supported.
|
// 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)?;
|
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
||||||
if config.sample_format != sample_format {
|
if sample_format != expected_sample_format {
|
||||||
return Err(BuildStreamError::StreamConfigNotSupported);
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_channels = config.channels.clone();
|
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;
|
let cpal_num_samples = buffer_size * num_channels as usize;
|
||||||
|
|
||||||
// Create buffers depending on data type.
|
// Create buffers depending on data type.
|
||||||
|
@ -438,12 +441,13 @@ impl Device {
|
||||||
/// On success, the buffer size of the stream is returned.
|
/// On success, the buffer size of the stream is returned.
|
||||||
fn get_or_create_input_stream(
|
fn get_or_create_input_stream(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Result<usize, BuildStreamError> {
|
) -> Result<usize, BuildStreamError> {
|
||||||
match self.default_input_config() {
|
match self.default_input_config() {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
let num_asio_channels = f.channels;
|
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),
|
Err(_) => Err(BuildStreamError::StreamConfigNotSupported),
|
||||||
}?;
|
}?;
|
||||||
|
@ -478,12 +482,13 @@ impl Device {
|
||||||
/// If there is no existing ASIO Output Stream it will be created.
|
/// If there is no existing ASIO Output Stream it will be created.
|
||||||
fn get_or_create_output_stream(
|
fn get_or_create_output_stream(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Result<usize, BuildStreamError> {
|
) -> Result<usize, BuildStreamError> {
|
||||||
match self.default_output_config() {
|
match self.default_output_config() {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
let num_asio_channels = f.channels;
|
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),
|
Err(_) => Err(BuildStreamError::StreamConfigNotSupported),
|
||||||
}?;
|
}?;
|
||||||
|
@ -581,13 +586,13 @@ impl AsioSample for f64 {
|
||||||
/// Checks sample rate, data type and then finally the number of channels.
|
/// Checks sample rate, data type and then finally the number of channels.
|
||||||
fn check_config(
|
fn check_config(
|
||||||
driver: &sys::Driver,
|
driver: &sys::Driver,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
num_asio_channels: u16,
|
num_asio_channels: u16,
|
||||||
) -> Result<(), BuildStreamError> {
|
) -> Result<(), BuildStreamError> {
|
||||||
let SupportedStreamConfig {
|
let StreamConfig {
|
||||||
channels,
|
channels,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
sample_format,
|
|
||||||
} = config;
|
} = config;
|
||||||
// Try and set the sample rate to what the user selected.
|
// Try and set the sample rate to what the user selected.
|
||||||
let sample_rate = sample_rate.0.into();
|
let sample_rate = sample_rate.0.into();
|
||||||
|
|
|
@ -22,7 +22,8 @@ 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, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
|
||||||
StreamError, SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
|
SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
@ -104,7 +105,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -112,12 +114,13 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&Data) + Send + 'static,
|
D: FnMut(&Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -125,7 +128,7 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&mut Data) + Send + 'static,
|
D: FnMut(&mut Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,15 +405,17 @@ impl From<coreaudio::Error> for BuildStreamError {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a coreaudio AudioStreamBasicDescription from a CPAL Format.
|
// Create a coreaudio AudioStreamBasicDescription from a CPAL Format.
|
||||||
fn asbd_from_config(config: &SupportedStreamConfig) -> AudioStreamBasicDescription {
|
fn asbd_from_config(
|
||||||
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
|
) -> AudioStreamBasicDescription {
|
||||||
let n_channels = config.channels as usize;
|
let n_channels = config.channels as usize;
|
||||||
let sample_rate = config.sample_rate.0;
|
let sample_rate = config.sample_rate.0;
|
||||||
let bytes_per_channel = config.sample_format.sample_size();
|
let bytes_per_channel = sample_format.sample_size();
|
||||||
let bits_per_channel = bytes_per_channel * 8;
|
let bits_per_channel = bytes_per_channel * 8;
|
||||||
let bytes_per_frame = n_channels * bytes_per_channel;
|
let bytes_per_frame = n_channels * bytes_per_channel;
|
||||||
let frames_per_packet = 1;
|
let frames_per_packet = 1;
|
||||||
let bytes_per_packet = frames_per_packet * bytes_per_frame;
|
let bytes_per_packet = frames_per_packet * bytes_per_frame;
|
||||||
let sample_format = config.sample_format;
|
|
||||||
let format_flags = match sample_format {
|
let format_flags = match sample_format {
|
||||||
SampleFormat::F32 => (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked) as u32,
|
SampleFormat::F32 => (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked) as u32,
|
||||||
_ => kAudioFormatFlagIsPacked as u32,
|
_ => kAudioFormatFlagIsPacked as u32,
|
||||||
|
@ -475,7 +480,8 @@ fn audio_unit_from_device(device: &Device, input: bool) -> Result<AudioUnit, cor
|
||||||
impl Device {
|
impl Device {
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
mut data_callback: D,
|
mut data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Stream, BuildStreamError>
|
) -> Result<Stream, BuildStreamError>
|
||||||
|
@ -625,12 +631,11 @@ impl Device {
|
||||||
let mut audio_unit = audio_unit_from_device(self, true)?;
|
let mut audio_unit = audio_unit_from_device(self, true)?;
|
||||||
|
|
||||||
// Set the stream in interleaved mode.
|
// Set the stream in interleaved mode.
|
||||||
let asbd = asbd_from_config(config);
|
let asbd = asbd_from_config(config, sample_format);
|
||||||
audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
|
audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
|
||||||
|
|
||||||
// Register the callback that is being called by coreaudio whenever it needs data to be
|
// Register the callback that is being called by coreaudio whenever it needs data to be
|
||||||
// fed to the audio buffer.
|
// fed to the audio buffer.
|
||||||
let sample_format = config.sample_format;
|
|
||||||
let bytes_per_channel = sample_format.sample_size();
|
let bytes_per_channel = sample_format.sample_size();
|
||||||
type Args = render_callback::Args<data::Raw>;
|
type Args = render_callback::Args<data::Raw>;
|
||||||
audio_unit.set_input_callback(move |args: Args| unsafe {
|
audio_unit.set_input_callback(move |args: Args| unsafe {
|
||||||
|
@ -663,7 +668,8 @@ impl Device {
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
mut data_callback: D,
|
mut data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Stream, BuildStreamError>
|
) -> Result<Stream, BuildStreamError>
|
||||||
|
@ -678,12 +684,11 @@ impl Device {
|
||||||
let element = Element::Output;
|
let element = Element::Output;
|
||||||
|
|
||||||
// Set the stream in interleaved mode.
|
// Set the stream in interleaved mode.
|
||||||
let asbd = asbd_from_config(config);
|
let asbd = asbd_from_config(config, sample_format);
|
||||||
audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
|
audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
|
||||||
|
|
||||||
// Register the callback that is being called by coreaudio whenever it needs data to be
|
// Register the callback that is being called by coreaudio whenever it needs data to be
|
||||||
// fed to the audio buffer.
|
// fed to the audio buffer.
|
||||||
let sample_format = config.sample_format;
|
|
||||||
let bytes_per_channel = sample_format.sample_size();
|
let bytes_per_channel = sample_format.sample_size();
|
||||||
type Args = render_callback::Args<data::Raw>;
|
type Args = render_callback::Args<data::Raw>;
|
||||||
audio_unit.set_render_callback(move |args: Args| unsafe {
|
audio_unit.set_render_callback(move |args: Args| unsafe {
|
||||||
|
|
|
@ -9,8 +9,8 @@ use stdweb::Reference;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
||||||
PauseStreamError, PlayStreamError, SampleFormat, StreamError, SupportedStreamConfig,
|
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError,
|
||||||
SupportedStreamConfigRange, SupportedStreamConfigsError,
|
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
|
||||||
|
@ -154,7 +154,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
_config: &SupportedStreamConfig,
|
_config: &StreamConfig,
|
||||||
|
_sample_format: SampleFormat,
|
||||||
_data_callback: D,
|
_data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -167,7 +168,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
_config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -176,7 +178,7 @@ impl DeviceTrait for Device {
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.sample_format,
|
sample_format,
|
||||||
SampleFormat::F32,
|
SampleFormat::F32,
|
||||||
"emscripten backend currently only supports `f32` data",
|
"emscripten backend currently only supports `f32` data",
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
||||||
PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig,
|
PauseStreamError, PlayStreamError, SampleFormat, StreamConfig, StreamError,
|
||||||
SupportedStreamConfigRange, SupportedStreamConfigsError,
|
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
|
||||||
|
@ -68,7 +68,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
_format: &SupportedStreamConfig,
|
_config: &StreamConfig,
|
||||||
|
_sample_format: SampleFormat,
|
||||||
_data_callback: D,
|
_data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -82,7 +83,8 @@ impl DeviceTrait for Device {
|
||||||
/// Create an output stream.
|
/// Create an output stream.
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
_format: &SupportedStreamConfig,
|
_config: &StreamConfig,
|
||||||
|
_sample_format: SampleFormat,
|
||||||
_data_callback: D,
|
_data_callback: D,
|
||||||
_error_callback: E,
|
_error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
||||||
SampleFormat, SampleRate, SupportedStreamConfig, SupportedStreamConfigRange,
|
SampleFormat, SampleRate, StreamConfig, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
|
SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
|
||||||
};
|
};
|
||||||
use std;
|
use std;
|
||||||
|
@ -98,7 +98,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -106,7 +107,7 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&Data) + Send + 'static,
|
D: FnMut(&Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
let stream_inner = self.build_input_stream_raw_inner(config)?;
|
let stream_inner = self.build_input_stream_raw_inner(config, sample_format)?;
|
||||||
Ok(Stream::new_input(
|
Ok(Stream::new_input(
|
||||||
stream_inner,
|
stream_inner,
|
||||||
data_callback,
|
data_callback,
|
||||||
|
@ -116,7 +117,8 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -124,7 +126,7 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&mut Data) + Send + 'static,
|
D: FnMut(&mut Data) + Send + 'static,
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
let stream_inner = self.build_output_stream_raw_inner(config)?;
|
let stream_inner = self.build_output_stream_raw_inner(config, sample_format)?;
|
||||||
Ok(Stream::new_output(
|
Ok(Stream::new_output(
|
||||||
stream_inner,
|
stream_inner,
|
||||||
data_callback,
|
data_callback,
|
||||||
|
@ -616,7 +618,8 @@ impl Device {
|
||||||
|
|
||||||
pub(crate) fn build_input_stream_raw_inner(
|
pub(crate) fn build_input_stream_raw_inner(
|
||||||
&self,
|
&self,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Result<StreamInner, BuildStreamError> {
|
) -> Result<StreamInner, BuildStreamError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Making sure that COM is initialized.
|
// Making sure that COM is initialized.
|
||||||
|
@ -638,7 +641,7 @@ impl Device {
|
||||||
|
|
||||||
// Computing the format and initializing the device.
|
// Computing the format and initializing the device.
|
||||||
let waveformatex = {
|
let waveformatex = {
|
||||||
let format_attempt = format_to_waveformatextensible(format)
|
let format_attempt = config_to_waveformatextensible(config, sample_format)
|
||||||
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
||||||
let share_mode = AUDCLNT_SHAREMODE_SHARED;
|
let share_mode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
|
|
||||||
|
@ -753,14 +756,15 @@ impl Device {
|
||||||
playing: false,
|
playing: false,
|
||||||
max_frames_in_buffer,
|
max_frames_in_buffer,
|
||||||
bytes_per_frame: waveformatex.nBlockAlign,
|
bytes_per_frame: waveformatex.nBlockAlign,
|
||||||
sample_format: format.sample_format,
|
sample_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build_output_stream_raw_inner(
|
pub(crate) fn build_output_stream_raw_inner(
|
||||||
&self,
|
&self,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Result<StreamInner, BuildStreamError> {
|
) -> Result<StreamInner, BuildStreamError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Making sure that COM is initialized.
|
// Making sure that COM is initialized.
|
||||||
|
@ -782,7 +786,7 @@ impl Device {
|
||||||
|
|
||||||
// Computing the format and initializing the device.
|
// Computing the format and initializing the device.
|
||||||
let waveformatex = {
|
let waveformatex = {
|
||||||
let format_attempt = format_to_waveformatextensible(format)
|
let format_attempt = config_to_waveformatextensible(config, sample_format)
|
||||||
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
.ok_or(BuildStreamError::StreamConfigNotSupported)?;
|
||||||
let share_mode = AUDCLNT_SHAREMODE_SHARED;
|
let share_mode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
|
|
||||||
|
@ -897,7 +901,7 @@ impl Device {
|
||||||
playing: false,
|
playing: false,
|
||||||
max_frames_in_buffer,
|
max_frames_in_buffer,
|
||||||
bytes_per_frame: waveformatex.nBlockAlign,
|
bytes_per_frame: waveformatex.nBlockAlign,
|
||||||
sample_format: format.sample_format,
|
sample_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1145,21 +1149,22 @@ pub fn default_output_device() -> Option<Device> {
|
||||||
// Turns a `Format` into a `WAVEFORMATEXTENSIBLE`.
|
// Turns a `Format` into a `WAVEFORMATEXTENSIBLE`.
|
||||||
//
|
//
|
||||||
// Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format.
|
// Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format.
|
||||||
fn format_to_waveformatextensible(
|
fn config_to_waveformatextensible(
|
||||||
config: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
) -> Option<mmreg::WAVEFORMATEXTENSIBLE> {
|
) -> Option<mmreg::WAVEFORMATEXTENSIBLE> {
|
||||||
let format_tag = match config.sample_format {
|
let format_tag = match sample_format {
|
||||||
SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM,
|
SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM,
|
||||||
SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE,
|
SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE,
|
||||||
SampleFormat::U16 => return None,
|
SampleFormat::U16 => return None,
|
||||||
};
|
};
|
||||||
let channels = config.channels as WORD;
|
let channels = config.channels as WORD;
|
||||||
let sample_rate = config.sample_rate.0 as DWORD;
|
let sample_rate = config.sample_rate.0 as DWORD;
|
||||||
let sample_bytes = config.sample_format.sample_size() as WORD;
|
let sample_bytes = sample_format.sample_size() as WORD;
|
||||||
let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes);
|
let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes);
|
||||||
let block_align = channels * sample_bytes;
|
let block_align = channels * sample_bytes;
|
||||||
let bits_per_sample = 8 * sample_bytes;
|
let bits_per_sample = 8 * sample_bytes;
|
||||||
let cb_size = match config.sample_format {
|
let cb_size = match sample_format {
|
||||||
SampleFormat::I16 => 0,
|
SampleFormat::I16 => 0,
|
||||||
SampleFormat::F32 => {
|
SampleFormat::F32 => {
|
||||||
let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>();
|
let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>();
|
||||||
|
@ -1183,7 +1188,7 @@ fn format_to_waveformatextensible(
|
||||||
const KSAUDIO_SPEAKER_DIRECTOUT: DWORD = 0;
|
const KSAUDIO_SPEAKER_DIRECTOUT: DWORD = 0;
|
||||||
let channel_mask = KSAUDIO_SPEAKER_DIRECTOUT;
|
let channel_mask = KSAUDIO_SPEAKER_DIRECTOUT;
|
||||||
|
|
||||||
let sub_format = match config.sample_format {
|
let sub_format = match sample_format {
|
||||||
SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM,
|
SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM,
|
||||||
SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
|
SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
|
||||||
SampleFormat::U16 => return None,
|
SampleFormat::U16 => return None,
|
||||||
|
|
80
src/lib.rs
80
src/lib.rs
|
@ -94,7 +94,7 @@
|
||||||
//! # let device = host.default_output_device().unwrap();
|
//! # let device = host.default_output_device().unwrap();
|
||||||
//! # let supported_config = device.default_output_config().unwrap();
|
//! # let supported_config = device.default_output_config().unwrap();
|
||||||
//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
|
//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
|
||||||
//! 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 stream = match sample_format {
|
//! let stream = match sample_format {
|
||||||
//! SampleFormat::F32 => device.build_output_stream(&config, write_silence::<f32>, err_fn),
|
//! SampleFormat::F32 => device.build_output_stream(&config, write_silence::<f32>, err_fn),
|
||||||
|
@ -117,10 +117,11 @@
|
||||||
//! # let host = cpal::default_host();
|
//! # let host = cpal::default_host();
|
||||||
//! # let device = host.default_output_device().unwrap();
|
//! # let device = host.default_output_device().unwrap();
|
||||||
//! # let supported_config = device.default_output_config().unwrap();
|
//! # let supported_config = device.default_output_config().unwrap();
|
||||||
|
//! # 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| {};
|
||||||
//! # let err_fn = move |_err| {};
|
//! # let err_fn = move |_err| {};
|
||||||
//! # let stream = device.build_output_stream_raw(&config, 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();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -132,10 +133,11 @@
|
||||||
//! # let host = cpal::default_host();
|
//! # let host = cpal::default_host();
|
||||||
//! # let device = host.default_output_device().unwrap();
|
//! # let device = host.default_output_device().unwrap();
|
||||||
//! # let supported_config = device.default_output_config().unwrap();
|
//! # let supported_config = device.default_output_config().unwrap();
|
||||||
|
//! # 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| {};
|
||||||
//! # let err_fn = move |_err| {};
|
//! # let err_fn = move |_err| {};
|
||||||
//! # let stream = device.build_output_stream_raw(&config, 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();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -189,22 +191,22 @@ pub struct StreamConfig {
|
||||||
/// `Device::supported_input/output_configs` method.
|
/// `Device::supported_input/output_configs` method.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct SupportedStreamConfigRange {
|
pub struct SupportedStreamConfigRange {
|
||||||
pub channels: ChannelCount,
|
pub(crate) channels: ChannelCount,
|
||||||
/// Minimum value for the samples rate of the supported formats.
|
/// Minimum value for the samples rate of the supported formats.
|
||||||
pub min_sample_rate: SampleRate,
|
pub(crate) min_sample_rate: SampleRate,
|
||||||
/// Maximum value for the samples rate of the supported formats.
|
/// Maximum value for the samples rate of the supported formats.
|
||||||
pub max_sample_rate: SampleRate,
|
pub(crate) max_sample_rate: SampleRate,
|
||||||
/// Type of data expected by the device.
|
/// Type of data expected by the device.
|
||||||
pub sample_format: SampleFormat,
|
pub(crate) sample_format: SampleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a single supported stream configuration, retrieved via either a
|
/// Describes a single supported stream configuration, retrieved via either a
|
||||||
/// `SupportedStreamConfigRange` instance or one of the `Device::default_input/output_config` methods.
|
/// `SupportedStreamConfigRange` instance or one of the `Device::default_input/output_config` methods.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct SupportedStreamConfig {
|
pub struct SupportedStreamConfig {
|
||||||
pub channels: ChannelCount,
|
channels: ChannelCount,
|
||||||
pub sample_rate: SampleRate,
|
sample_rate: SampleRate,
|
||||||
pub sample_format: SampleFormat,
|
sample_format: SampleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A buffer of dynamically typed audio data, passed to raw stream callbacks.
|
/// A buffer of dynamically typed audio data, passed to raw stream callbacks.
|
||||||
|
@ -219,12 +221,22 @@ pub struct Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupportedStreamConfig {
|
impl SupportedStreamConfig {
|
||||||
/// Construct a `SupportedStreamConfig` from an existing `StreamConfig`.
|
pub fn channels(&self) -> ChannelCount {
|
||||||
pub fn from_config(conf: &StreamConfig, fmt: SampleFormat) -> Self {
|
self.channels
|
||||||
Self {
|
}
|
||||||
channels: conf.channels,
|
|
||||||
sample_rate: conf.sample_rate,
|
pub fn sample_rate(&self) -> SampleRate {
|
||||||
sample_format: fmt,
|
self.sample_rate
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_format(&self) -> SampleFormat {
|
||||||
|
self.sample_format
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config(&self) -> StreamConfig {
|
||||||
|
StreamConfig {
|
||||||
|
channels: self.channels,
|
||||||
|
sample_rate: self.sample_rate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,6 +335,35 @@ impl Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupportedStreamConfigRange {
|
impl SupportedStreamConfigRange {
|
||||||
|
pub fn channels(&self) -> ChannelCount {
|
||||||
|
self.channels
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min_sample_rate(&self) -> SampleRate {
|
||||||
|
self.min_sample_rate
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_sample_rate(&self) -> SampleRate {
|
||||||
|
self.max_sample_rate
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_format(&self) -> SampleFormat {
|
||||||
|
self.sample_format
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve a `SupportedStreamConfig` with the given sample rate.
|
||||||
|
///
|
||||||
|
/// **panic!**s if the given `sample_rate` is outside the range specified within this
|
||||||
|
/// `SupportedStreamConfigRange` instance.
|
||||||
|
pub fn with_sample_rate(self, sample_rate: SampleRate) -> SupportedStreamConfig {
|
||||||
|
assert!(sample_rate <= self.min_sample_rate && sample_rate <= self.max_sample_rate);
|
||||||
|
SupportedStreamConfig {
|
||||||
|
channels: self.channels,
|
||||||
|
sample_format: self.sample_format,
|
||||||
|
sample_rate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Turns this `SupportedStreamConfigRange` into a `SupportedStreamConfig` corresponding to the maximum samples rate.
|
/// Turns this `SupportedStreamConfigRange` into a `SupportedStreamConfig` corresponding to the maximum samples rate.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_max_sample_rate(self) -> SupportedStreamConfig {
|
pub fn with_max_sample_rate(self) -> SupportedStreamConfig {
|
||||||
|
@ -406,12 +447,7 @@ impl SupportedStreamConfigRange {
|
||||||
|
|
||||||
impl From<SupportedStreamConfig> for StreamConfig {
|
impl From<SupportedStreamConfig> for StreamConfig {
|
||||||
fn from(conf: SupportedStreamConfig) -> Self {
|
fn from(conf: SupportedStreamConfig) -> Self {
|
||||||
let channels = conf.channels;
|
conf.config()
|
||||||
let sample_rate = conf.sample_rate;
|
|
||||||
StreamConfig {
|
|
||||||
channels,
|
|
||||||
sample_rate,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,8 @@ macro_rules! impl_platform_host {
|
||||||
|
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
format: &crate::SupportedStreamConfig,
|
config: &crate::StreamConfig,
|
||||||
|
sample_format: crate::SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, crate::BuildStreamError>
|
) -> Result<Self::Stream, crate::BuildStreamError>
|
||||||
|
@ -267,7 +268,13 @@ macro_rules! impl_platform_host {
|
||||||
{
|
{
|
||||||
match self.0 {
|
match self.0 {
|
||||||
$(
|
$(
|
||||||
DeviceInner::$HostVariant(ref d) => d.build_input_stream_raw(format, data_callback, error_callback)
|
DeviceInner::$HostVariant(ref d) => d
|
||||||
|
.build_input_stream_raw(
|
||||||
|
config,
|
||||||
|
sample_format,
|
||||||
|
data_callback,
|
||||||
|
error_callback,
|
||||||
|
)
|
||||||
.map(StreamInner::$HostVariant)
|
.map(StreamInner::$HostVariant)
|
||||||
.map(Stream::from),
|
.map(Stream::from),
|
||||||
)*
|
)*
|
||||||
|
@ -276,7 +283,8 @@ macro_rules! impl_platform_host {
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
format: &crate::SupportedStreamConfig,
|
config: &crate::StreamConfig,
|
||||||
|
sample_format: crate::SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, crate::BuildStreamError>
|
) -> Result<Self::Stream, crate::BuildStreamError>
|
||||||
|
@ -286,7 +294,13 @@ macro_rules! impl_platform_host {
|
||||||
{
|
{
|
||||||
match self.0 {
|
match self.0 {
|
||||||
$(
|
$(
|
||||||
DeviceInner::$HostVariant(ref d) => d.build_output_stream_raw(format, data_callback, error_callback)
|
DeviceInner::$HostVariant(ref d) => d
|
||||||
|
.build_output_stream_raw(
|
||||||
|
config,
|
||||||
|
sample_format,
|
||||||
|
data_callback,
|
||||||
|
error_callback,
|
||||||
|
)
|
||||||
.map(StreamInner::$HostVariant)
|
.map(StreamInner::$HostVariant)
|
||||||
.map(Stream::from),
|
.map(Stream::from),
|
||||||
)*
|
)*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, InputDevices,
|
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, InputDevices,
|
||||||
OutputDevices, PauseStreamError, PlayStreamError, Sample, StreamConfig, StreamError,
|
OutputDevices, PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig,
|
||||||
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
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.
|
||||||
|
@ -126,7 +126,8 @@ pub trait DeviceTrait {
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
self.build_input_stream_raw(
|
self.build_input_stream_raw(
|
||||||
&SupportedStreamConfig::from_config(config, T::FORMAT),
|
config,
|
||||||
|
T::FORMAT,
|
||||||
move |data| {
|
move |data| {
|
||||||
data_callback(
|
data_callback(
|
||||||
data.as_slice()
|
data.as_slice()
|
||||||
|
@ -150,7 +151,8 @@ pub trait DeviceTrait {
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
self.build_output_stream_raw(
|
self.build_output_stream_raw(
|
||||||
&SupportedStreamConfig::from_config(config, T::FORMAT),
|
config,
|
||||||
|
T::FORMAT,
|
||||||
move |data| {
|
move |data| {
|
||||||
data_callback(
|
data_callback(
|
||||||
data.as_slice_mut()
|
data.as_slice_mut()
|
||||||
|
@ -164,7 +166,8 @@ pub trait DeviceTrait {
|
||||||
/// Create a dynamically typed input stream.
|
/// Create a dynamically typed input stream.
|
||||||
fn build_input_stream_raw<D, E>(
|
fn build_input_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
@ -175,7 +178,8 @@ pub trait DeviceTrait {
|
||||||
/// Create a dynamically typed output stream.
|
/// Create a dynamically typed output stream.
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
format: &SupportedStreamConfig,
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
) -> Result<Self::Stream, BuildStreamError>
|
) -> Result<Self::Stream, BuildStreamError>
|
||||||
|
|
Loading…
Reference in New Issue