Remove old `.rustfmt.toml` config. Run default `cargo fmt` on repo.
Seeing as a few large refactors have landed recently, I thought I'd take this opportunity to do a `cargo fmt` run and standardise on the default rustfmt settings.
This commit is contained in:
parent
95cda0dbe8
commit
aab0d90add
|
@ -1,18 +0,0 @@
|
|||
fn_args_density = "Compressed"
|
||||
fn_args_layout = "Visual"
|
||||
fn_brace_style = "SameLineWhere"
|
||||
fn_call_style = "Visual"
|
||||
fn_empty_single_line = false
|
||||
format_strings = true
|
||||
generics_indent = "Visual"
|
||||
impl_empty_single_line = false
|
||||
match_block_trailing_comma = true
|
||||
reorder_imported_names = true
|
||||
reorder_imports = true
|
||||
reorder_imports_in_group = true
|
||||
spaces_around_ranges = true
|
||||
use_try_shorthand = true
|
||||
where_density = "Tall"
|
||||
where_style = "Legacy"
|
||||
wrap_match_arms = false
|
||||
write_mode = "Overwrite"
|
4
build.rs
4
build.rs
|
@ -3,10 +3,10 @@ use std::env;
|
|||
const CPAL_ASIO_DIR: &'static str = "CPAL_ASIO_DIR";
|
||||
|
||||
fn main() {
|
||||
// If ASIO directory isn't set silently return early
|
||||
// If ASIO directory isn't set silently return early
|
||||
// otherwise set the asio config flag
|
||||
match env::var(CPAL_ASIO_DIR) {
|
||||
Err(_) => return,
|
||||
Ok(_) => println!("cargo:rustc-cfg=asio"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
extern crate cpal;
|
||||
extern crate anyhow;
|
||||
extern crate cpal;
|
||||
|
||||
use cpal::traits::{DeviceTrait, HostTrait};
|
||||
|
||||
|
@ -30,12 +30,17 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
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() {
|
||||
println!(" {}.{}. {:?}", device_index + 1, format_index + 1, format);
|
||||
println!(
|
||||
" {}.{}. {:?}",
|
||||
device_index + 1,
|
||||
format_index + 1,
|
||||
format
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,12 +53,17 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
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() {
|
||||
println!(" {}.{}. {:?}", device_index + 1, format_index + 1, format);
|
||||
println!(
|
||||
" {}.{}. {:?}",
|
||||
device_index + 1,
|
||||
format_index + 1,
|
||||
format
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,11 +69,14 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
Err(err) => {
|
||||
input_fell_behind = Some(err);
|
||||
0.0
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
if let Some(err) = input_fell_behind {
|
||||
eprintln!("input stream fell behind: {:?}: try increasing latency", err);
|
||||
eprintln!(
|
||||
"input stream fell behind: {:?}: try increasing latency",
|
||||
err
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ extern crate cpal;
|
|||
extern crate hound;
|
||||
|
||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
// Use the default host for working with audio devices.
|
||||
|
@ -40,12 +40,10 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
eprintln!("an error occurred on stream: {}", err);
|
||||
};
|
||||
|
||||
let data_fn = move |data: &cpal::Data| {
|
||||
match data.sample_format() {
|
||||
cpal::SampleFormat::F32 => write_input_data::<f32, f32>(data, &writer_2),
|
||||
cpal::SampleFormat::I16 => write_input_data::<i16, i16>(data, &writer_2),
|
||||
cpal::SampleFormat::U16 => write_input_data::<u16, i16>(data, &writer_2),
|
||||
}
|
||||
let data_fn = move |data: &cpal::Data| match data.sample_format() {
|
||||
cpal::SampleFormat::F32 => write_input_data::<f32, f32>(data, &writer_2),
|
||||
cpal::SampleFormat::I16 => write_input_data::<i16, i16>(data, &writer_2),
|
||||
cpal::SampleFormat::U16 => write_input_data::<u16, i16>(data, &writer_2),
|
||||
};
|
||||
|
||||
let stream = device.build_input_stream(&format, data_fn, err_fn)?;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use {BackendSpecificError, DevicesError};
|
||||
use super::Device;
|
||||
use super::alsa;
|
||||
use super::check_errors;
|
||||
use super::Device;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
use {BackendSpecificError, DevicesError};
|
||||
|
||||
/// ALSA implementation for `Devices`.
|
||||
pub struct Devices {
|
||||
|
@ -36,10 +36,8 @@ impl Devices {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Devices {
|
||||
}
|
||||
unsafe impl Sync for Devices {
|
||||
}
|
||||
unsafe impl Send for Devices {}
|
||||
unsafe impl Sync for Devices {}
|
||||
|
||||
impl Drop for Devices {
|
||||
#[inline]
|
||||
|
@ -61,8 +59,10 @@ impl Iterator for Devices {
|
|||
}
|
||||
|
||||
let name = {
|
||||
let n_ptr = alsa::snd_device_name_get_hint(*self.next_str as *const _,
|
||||
b"NAME\0".as_ptr() as *const _);
|
||||
let n_ptr = alsa::snd_device_name_get_hint(
|
||||
*self.next_str as *const _,
|
||||
b"NAME\0".as_ptr() as *const _,
|
||||
);
|
||||
if !n_ptr.is_null() {
|
||||
let bytes = CString::from_raw(n_ptr).into_bytes();
|
||||
let string = String::from_utf8(bytes).unwrap();
|
||||
|
@ -73,8 +73,10 @@ impl Iterator for Devices {
|
|||
};
|
||||
|
||||
let io = {
|
||||
let n_ptr = alsa::snd_device_name_get_hint(*self.next_str as *const _,
|
||||
b"IOID\0".as_ptr() as *const _);
|
||||
let n_ptr = alsa::snd_device_name_get_hint(
|
||||
*self.next_str as *const _,
|
||||
b"IOID\0".as_ptr() as *const _,
|
||||
);
|
||||
if !n_ptr.is_null() {
|
||||
let bytes = CString::from_raw(n_ptr).into_bytes();
|
||||
let string = String::from_utf8(bytes).unwrap();
|
||||
|
@ -99,7 +101,7 @@ impl Iterator for Devices {
|
|||
continue;
|
||||
}
|
||||
name
|
||||
},
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
|
|
@ -2,26 +2,14 @@ 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, DefaultFormatError,
|
||||
DeviceNameError, DevicesError, Format, PauseStreamError, PlayStreamError, SampleFormat,
|
||||
SampleRate, StreamError, SupportedFormat, SupportedFormatsError,
|
||||
};
|
||||
use std::{cmp, ffi, io, ptr};
|
||||
use std::sync::Arc;
|
||||
use std::thread::{self, JoinHandle};
|
||||
use std::vec::IntoIter as VecIntoIter;
|
||||
use std::{cmp, ffi, io, ptr};
|
||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
|
||||
pub use self::enumerate::{default_input_device, default_output_device, Devices};
|
||||
|
@ -72,11 +60,15 @@ impl DeviceTrait for Device {
|
|||
Device::name(self)
|
||||
}
|
||||
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
fn supported_input_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
Device::supported_input_formats(self)
|
||||
}
|
||||
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
fn supported_output_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
Device::supported_output_formats(self)
|
||||
}
|
||||
|
||||
|
@ -119,7 +111,6 @@ impl DeviceTrait for Device {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct TriggerSender(libc::c_int);
|
||||
|
||||
struct TriggerReceiver(libc::c_int);
|
||||
|
@ -247,8 +238,7 @@ impl Device {
|
|||
unsafe fn supported_formats(
|
||||
&self,
|
||||
stream_t: alsa::snd_pcm_stream_t,
|
||||
) -> Result<VecIntoIter<SupportedFormat>, SupportedFormatsError>
|
||||
{
|
||||
) -> Result<VecIntoIter<SupportedFormat>, SupportedFormatsError> {
|
||||
let mut handle = ptr::null_mut();
|
||||
let device_name = match ffi::CString::new(&self.0[..]) {
|
||||
Ok(name) => name,
|
||||
|
@ -284,14 +274,13 @@ impl Device {
|
|||
};
|
||||
|
||||
// TODO: check endianess
|
||||
const FORMATS: [(SampleFormat, alsa::snd_pcm_format_t); 3] =
|
||||
[
|
||||
//SND_PCM_FORMAT_S8,
|
||||
//SND_PCM_FORMAT_U8,
|
||||
(SampleFormat::I16, alsa::SND_PCM_FORMAT_S16_LE),
|
||||
//SND_PCM_FORMAT_S16_BE,
|
||||
(SampleFormat::U16, alsa::SND_PCM_FORMAT_U16_LE),
|
||||
//SND_PCM_FORMAT_U16_BE,
|
||||
const FORMATS: [(SampleFormat, alsa::snd_pcm_format_t); 3] = [
|
||||
//SND_PCM_FORMAT_S8,
|
||||
//SND_PCM_FORMAT_U8,
|
||||
(SampleFormat::I16, alsa::SND_PCM_FORMAT_S16_LE),
|
||||
//SND_PCM_FORMAT_S16_BE,
|
||||
(SampleFormat::U16, alsa::SND_PCM_FORMAT_U16_LE),
|
||||
//SND_PCM_FORMAT_U16_BE,
|
||||
/*SND_PCM_FORMAT_S24_LE,
|
||||
SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_U24_LE,
|
||||
|
@ -300,37 +289,34 @@ impl Device {
|
|||
SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_U32_LE,
|
||||
SND_PCM_FORMAT_U32_BE,*/
|
||||
(SampleFormat::F32, alsa::SND_PCM_FORMAT_FLOAT_LE) /*SND_PCM_FORMAT_FLOAT_BE,
|
||||
SND_PCM_FORMAT_FLOAT64_LE,
|
||||
SND_PCM_FORMAT_FLOAT64_BE,
|
||||
SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
|
||||
SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
|
||||
SND_PCM_FORMAT_MU_LAW,
|
||||
SND_PCM_FORMAT_A_LAW,
|
||||
SND_PCM_FORMAT_IMA_ADPCM,
|
||||
SND_PCM_FORMAT_MPEG,
|
||||
SND_PCM_FORMAT_GSM,
|
||||
SND_PCM_FORMAT_SPECIAL,
|
||||
SND_PCM_FORMAT_S24_3LE,
|
||||
SND_PCM_FORMAT_S24_3BE,
|
||||
SND_PCM_FORMAT_U24_3LE,
|
||||
SND_PCM_FORMAT_U24_3BE,
|
||||
SND_PCM_FORMAT_S20_3LE,
|
||||
SND_PCM_FORMAT_S20_3BE,
|
||||
SND_PCM_FORMAT_U20_3LE,
|
||||
SND_PCM_FORMAT_U20_3BE,
|
||||
SND_PCM_FORMAT_S18_3LE,
|
||||
SND_PCM_FORMAT_S18_3BE,
|
||||
SND_PCM_FORMAT_U18_3LE,
|
||||
SND_PCM_FORMAT_U18_3BE,*/,
|
||||
];
|
||||
(SampleFormat::F32, alsa::SND_PCM_FORMAT_FLOAT_LE), /*SND_PCM_FORMAT_FLOAT_BE,
|
||||
SND_PCM_FORMAT_FLOAT64_LE,
|
||||
SND_PCM_FORMAT_FLOAT64_BE,
|
||||
SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
|
||||
SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
|
||||
SND_PCM_FORMAT_MU_LAW,
|
||||
SND_PCM_FORMAT_A_LAW,
|
||||
SND_PCM_FORMAT_IMA_ADPCM,
|
||||
SND_PCM_FORMAT_MPEG,
|
||||
SND_PCM_FORMAT_GSM,
|
||||
SND_PCM_FORMAT_SPECIAL,
|
||||
SND_PCM_FORMAT_S24_3LE,
|
||||
SND_PCM_FORMAT_S24_3BE,
|
||||
SND_PCM_FORMAT_U24_3LE,
|
||||
SND_PCM_FORMAT_U24_3BE,
|
||||
SND_PCM_FORMAT_S20_3LE,
|
||||
SND_PCM_FORMAT_S20_3BE,
|
||||
SND_PCM_FORMAT_U20_3LE,
|
||||
SND_PCM_FORMAT_U20_3BE,
|
||||
SND_PCM_FORMAT_S18_3LE,
|
||||
SND_PCM_FORMAT_S18_3BE,
|
||||
SND_PCM_FORMAT_U18_3LE,
|
||||
SND_PCM_FORMAT_U18_3BE,*/
|
||||
];
|
||||
|
||||
let mut supported_formats = Vec::new();
|
||||
for &(sample_format, alsa_format) in FORMATS.iter() {
|
||||
if alsa::snd_pcm_hw_params_test_format(handle,
|
||||
hw_params.0,
|
||||
alsa_format) == 0
|
||||
{
|
||||
if alsa::snd_pcm_hw_params_test_format(handle, hw_params.0, alsa_format) == 0 {
|
||||
supported_formats.push(sample_format);
|
||||
}
|
||||
}
|
||||
|
@ -357,34 +343,19 @@ impl Device {
|
|||
return Err(err.into());
|
||||
}
|
||||
|
||||
let sample_rates = if min_rate == max_rate ||
|
||||
alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, min_rate + 1, 0) == 0
|
||||
let sample_rates = if min_rate == max_rate
|
||||
|| alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, min_rate + 1, 0) == 0
|
||||
{
|
||||
vec![(min_rate, max_rate)]
|
||||
} else {
|
||||
const RATES: [libc::c_uint; 13] = [
|
||||
5512,
|
||||
8000,
|
||||
11025,
|
||||
16000,
|
||||
22050,
|
||||
32000,
|
||||
44100,
|
||||
48000,
|
||||
64000,
|
||||
88200,
|
||||
96000,
|
||||
176400,
|
||||
5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400,
|
||||
192000,
|
||||
];
|
||||
|
||||
let mut rates = Vec::new();
|
||||
for &rate in RATES.iter() {
|
||||
if alsa::snd_pcm_hw_params_test_rate(handle,
|
||||
hw_params.0,
|
||||
rate,
|
||||
0) == 0
|
||||
{
|
||||
if alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, rate, 0) == 0 {
|
||||
rates.push((rate, rate));
|
||||
}
|
||||
}
|
||||
|
@ -397,44 +368,48 @@ impl Device {
|
|||
};
|
||||
|
||||
let mut min_channels = 0;
|
||||
if let Err(desc) = check_errors(alsa::snd_pcm_hw_params_get_channels_min(hw_params.0, &mut min_channels)) {
|
||||
if let Err(desc) = check_errors(alsa::snd_pcm_hw_params_get_channels_min(
|
||||
hw_params.0,
|
||||
&mut min_channels,
|
||||
)) {
|
||||
let description = format!("unable to get minimum supported channel count: {}", desc);
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
let mut max_channels = 0;
|
||||
if let Err(desc) = check_errors(alsa::snd_pcm_hw_params_get_channels_max(hw_params.0, &mut max_channels)) {
|
||||
if let Err(desc) = check_errors(alsa::snd_pcm_hw_params_get_channels_max(
|
||||
hw_params.0,
|
||||
&mut max_channels,
|
||||
)) {
|
||||
let description = format!("unable to get maximum supported channel count: {}", desc);
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
let max_channels = cmp::min(max_channels, 32); // TODO: limiting to 32 channels or too much stuff is returned
|
||||
let supported_channels = (min_channels .. max_channels + 1)
|
||||
.filter_map(|num| if alsa::snd_pcm_hw_params_test_channels(
|
||||
handle,
|
||||
hw_params.0,
|
||||
num,
|
||||
) == 0
|
||||
{
|
||||
Some(num as ChannelCount)
|
||||
} else {
|
||||
None
|
||||
let supported_channels = (min_channels..max_channels + 1)
|
||||
.filter_map(|num| {
|
||||
if alsa::snd_pcm_hw_params_test_channels(handle, hw_params.0, num) == 0 {
|
||||
Some(num as ChannelCount)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut output = Vec::with_capacity(supported_formats.len() * supported_channels.len() *
|
||||
sample_rates.len());
|
||||
let mut output = Vec::with_capacity(
|
||||
supported_formats.len() * supported_channels.len() * sample_rates.len(),
|
||||
);
|
||||
for &data_type in supported_formats.iter() {
|
||||
for channels in supported_channels.iter() {
|
||||
for &(min_rate, max_rate) in sample_rates.iter() {
|
||||
output.push(SupportedFormat {
|
||||
channels: channels.clone(),
|
||||
min_sample_rate: SampleRate(min_rate as u32),
|
||||
max_sample_rate: SampleRate(max_rate as u32),
|
||||
data_type: data_type,
|
||||
});
|
||||
channels: channels.clone(),
|
||||
min_sample_rate: SampleRate(min_rate as u32),
|
||||
max_sample_rate: SampleRate(max_rate as u32),
|
||||
data_type: data_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,15 +420,11 @@ impl Device {
|
|||
}
|
||||
|
||||
fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
|
||||
unsafe {
|
||||
self.supported_formats(alsa::SND_PCM_STREAM_CAPTURE)
|
||||
}
|
||||
unsafe { self.supported_formats(alsa::SND_PCM_STREAM_CAPTURE) }
|
||||
}
|
||||
|
||||
fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> {
|
||||
unsafe {
|
||||
self.supported_formats(alsa::SND_PCM_STREAM_PLAYBACK)
|
||||
}
|
||||
unsafe { self.supported_formats(alsa::SND_PCM_STREAM_PLAYBACK) }
|
||||
}
|
||||
|
||||
// ALSA does not offer default stream formats, so instead we compare all supported formats by
|
||||
|
@ -461,13 +432,12 @@ impl Device {
|
|||
fn default_format(
|
||||
&self,
|
||||
stream_t: alsa::snd_pcm_stream_t,
|
||||
) -> Result<Format, DefaultFormatError>
|
||||
{
|
||||
) -> Result<Format, DefaultFormatError> {
|
||||
let mut formats: Vec<_> = unsafe {
|
||||
match self.supported_formats(stream_t) {
|
||||
Err(SupportedFormatsError::DeviceNotAvailable) => {
|
||||
return Err(DefaultFormatError::DeviceNotAvailable);
|
||||
},
|
||||
}
|
||||
Err(SupportedFormatsError::InvalidArgument) => {
|
||||
// this happens sometimes when querying for input and output capabilities but
|
||||
// the device supports only one
|
||||
|
@ -492,8 +462,8 @@ impl Device {
|
|||
format.sample_rate = HZ_44100;
|
||||
}
|
||||
Ok(format)
|
||||
},
|
||||
None => Err(DefaultFormatError::StreamTypeNotSupported)
|
||||
}
|
||||
None => Err(DefaultFormatError::StreamTypeNotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,7 +506,10 @@ unsafe impl Send for StreamInner {}
|
|||
unsafe impl Sync for StreamInner {}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum StreamType { Input, Output }
|
||||
enum StreamType {
|
||||
Input,
|
||||
Output,
|
||||
}
|
||||
|
||||
pub struct Stream {
|
||||
/// The high-priority audio processing thread calling callbacks.
|
||||
|
@ -567,7 +540,10 @@ fn input_stream_worker(
|
|||
match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) {
|
||||
PollDescriptorsFlow::Continue => continue,
|
||||
PollDescriptorsFlow::Return => return,
|
||||
PollDescriptorsFlow::Ready { available_frames, stream_type } => {
|
||||
PollDescriptorsFlow::Ready {
|
||||
available_frames,
|
||||
stream_type,
|
||||
} => {
|
||||
assert_eq!(
|
||||
stream_type,
|
||||
StreamType::Input,
|
||||
|
@ -596,7 +572,10 @@ fn output_stream_worker(
|
|||
match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) {
|
||||
PollDescriptorsFlow::Continue => continue,
|
||||
PollDescriptorsFlow::Return => return,
|
||||
PollDescriptorsFlow::Ready { available_frames, stream_type } => {
|
||||
PollDescriptorsFlow::Ready {
|
||||
available_frames,
|
||||
stream_type,
|
||||
} => {
|
||||
assert_eq!(
|
||||
stream_type,
|
||||
StreamType::Output,
|
||||
|
@ -620,7 +599,7 @@ enum PollDescriptorsFlow {
|
|||
Ready {
|
||||
stream_type: StreamType,
|
||||
available_frames: usize,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// This block is shared between both input and output stream worker functions.
|
||||
|
@ -661,7 +640,11 @@ fn poll_descriptors_and_prepare_buffer(
|
|||
|
||||
let res = unsafe {
|
||||
// Don't timeout, wait forever.
|
||||
libc::poll(descriptors.as_mut_ptr(), descriptors.len() as libc::nfds_t, -1)
|
||||
libc::poll(
|
||||
descriptors.as_mut_ptr(),
|
||||
descriptors.len() as libc::nfds_t,
|
||||
-1,
|
||||
)
|
||||
};
|
||||
if res < 0 {
|
||||
let description = format!("`libc::poll()` failed: {}", io::Error::last_os_error());
|
||||
|
@ -684,7 +667,7 @@ fn poll_descriptors_and_prepare_buffer(
|
|||
Ok(None) => {
|
||||
// Nothing to process, poll again
|
||||
return PollDescriptorsFlow::Continue;
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
error_callback(err.into());
|
||||
return PollDescriptorsFlow::Continue;
|
||||
|
@ -739,9 +722,7 @@ fn process_input(
|
|||
let sample_format = stream.sample_format;
|
||||
let data = buffer.as_mut_ptr() as *mut ();
|
||||
let len = buffer.len() / sample_format.sample_size();
|
||||
let data = unsafe {
|
||||
Data::from_parts(data, len, sample_format)
|
||||
};
|
||||
let data = unsafe { Data::from_parts(data, len, sample_format) };
|
||||
data_callback(&data);
|
||||
}
|
||||
|
||||
|
@ -760,9 +741,7 @@ fn process_output(
|
|||
let sample_format = stream.sample_format;
|
||||
let data = buffer.as_mut_ptr() as *mut ();
|
||||
let len = buffer.len() / sample_format.sample_size();
|
||||
let mut data = unsafe {
|
||||
Data::from_parts(data, len, sample_format)
|
||||
};
|
||||
let mut data = unsafe { Data::from_parts(data, len, sample_format) };
|
||||
data_callback(&mut data);
|
||||
}
|
||||
loop {
|
||||
|
@ -784,9 +763,8 @@ fn process_output(
|
|||
} else if result as usize != available_frames {
|
||||
let description = format!(
|
||||
"unexpected number of frames written: expected {}, \
|
||||
result {} (this should never happen)",
|
||||
available_frames,
|
||||
result,
|
||||
result {} (this should never happen)",
|
||||
available_frames, result,
|
||||
);
|
||||
error_callback(BackendSpecificError { description }.into());
|
||||
continue;
|
||||
|
@ -857,7 +835,7 @@ impl StreamTrait for Stream {
|
|||
// TODO: error handling
|
||||
Ok(())
|
||||
}
|
||||
fn pause(&self)-> Result<(), PauseStreamError> {
|
||||
fn pause(&self) -> Result<(), PauseStreamError> {
|
||||
unsafe {
|
||||
alsa::snd_pcm_pause(self.inner.channel, 1);
|
||||
}
|
||||
|
@ -888,8 +866,7 @@ fn check_for_pollout_or_pollin(
|
|||
(revent, res)
|
||||
};
|
||||
if let Err(desc) = check_errors(res) {
|
||||
let description =
|
||||
format!("`snd_pcm_poll_descriptors_revents` failed: {}",desc);
|
||||
let description = format!("`snd_pcm_poll_descriptors_revents` failed: {}", desc);
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err);
|
||||
}
|
||||
|
@ -905,9 +882,7 @@ fn check_for_pollout_or_pollin(
|
|||
|
||||
// Determine the number of samples that are available to read/write.
|
||||
fn get_available_samples(stream: &StreamInner) -> Result<usize, BackendSpecificError> {
|
||||
let available = unsafe {
|
||||
alsa::snd_pcm_avail_update(stream.channel)
|
||||
};
|
||||
let available = unsafe { alsa::snd_pcm_avail_update(stream.channel) };
|
||||
if available == -32 {
|
||||
// buffer underrun
|
||||
// TODO: Notify the user some how.
|
||||
|
@ -929,9 +904,11 @@ unsafe fn set_hw_params_from_format(
|
|||
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));
|
||||
}
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(pcm_handle,
|
||||
hw_params.0,
|
||||
alsa::SND_PCM_ACCESS_RW_INTERLEAVED)) {
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(
|
||||
pcm_handle,
|
||||
hw_params.0,
|
||||
alsa::SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
)) {
|
||||
return Err(format!("handle not acessible: {}", e));
|
||||
}
|
||||
|
||||
|
@ -949,21 +926,26 @@ 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)) {
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(
|
||||
pcm_handle,
|
||||
hw_params.0,
|
||||
data_type,
|
||||
)) {
|
||||
return Err(format!("format could not be set: {}", e));
|
||||
}
|
||||
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,
|
||||
0)) {
|
||||
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,
|
||||
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)) {
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(
|
||||
pcm_handle,
|
||||
hw_params.0,
|
||||
format.channels as libc::c_uint,
|
||||
)) {
|
||||
return Err(format!("channel count could not be set: {}", e));
|
||||
}
|
||||
|
||||
|
@ -987,8 +969,7 @@ unsafe fn set_hw_params_from_format(
|
|||
unsafe fn set_sw_params_from_format(
|
||||
pcm_handle: *mut alsa::snd_pcm_t,
|
||||
format: &Format,
|
||||
) -> Result<(usize, usize), String>
|
||||
{
|
||||
) -> 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)) {
|
||||
return Err(format!("snd_pcm_sw_params_malloc failed: {}", e));
|
||||
|
@ -996,20 +977,31 @@ unsafe fn set_sw_params_from_format(
|
|||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_current(pcm_handle, sw_params)) {
|
||||
return Err(format!("snd_pcm_sw_params_current failed: {}", e));
|
||||
}
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, 0)) {
|
||||
return Err(format!("snd_pcm_sw_params_set_start_threshold failed: {}", e));
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_start_threshold(
|
||||
pcm_handle, sw_params, 0,
|
||||
)) {
|
||||
return Err(format!(
|
||||
"snd_pcm_sw_params_set_start_threshold failed: {}",
|
||||
e
|
||||
));
|
||||
}
|
||||
|
||||
let (buffer_len, period_len) = {
|
||||
let mut buffer = 0;
|
||||
let mut period = 0;
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_get_params(pcm_handle, &mut buffer, &mut period)) {
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_get_params(
|
||||
pcm_handle,
|
||||
&mut buffer,
|
||||
&mut period,
|
||||
)) {
|
||||
return Err(format!("failed to initialize buffer: {}", e));
|
||||
}
|
||||
if buffer == 0 {
|
||||
return Err(format!("initialization resulted in a null buffer"));
|
||||
}
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_avail_min(pcm_handle, sw_params, period)) {
|
||||
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_avail_min(
|
||||
pcm_handle, sw_params, period,
|
||||
)) {
|
||||
return Err(format!("snd_pcm_sw_params_set_avail_min failed: {}", e));
|
||||
}
|
||||
let buffer = buffer as usize * format.channels as usize;
|
||||
|
|
|
@ -2,8 +2,10 @@ use std;
|
|||
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
|
||||
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
|
||||
|
||||
use super::parking_lot::Mutex;
|
||||
use super::sys;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::{Arc};
|
||||
use std::sync::Arc;
|
||||
use BackendSpecificError;
|
||||
use DefaultFormatError;
|
||||
use DeviceNameError;
|
||||
|
@ -13,8 +15,6 @@ use SampleFormat;
|
|||
use SampleRate;
|
||||
use SupportedFormat;
|
||||
use SupportedFormatsError;
|
||||
use super::sys;
|
||||
use super::parking_lot::Mutex;
|
||||
|
||||
/// A ASIO Device
|
||||
pub struct Device {
|
||||
|
@ -55,9 +55,7 @@ impl Device {
|
|||
/// Gets the supported input formats.
|
||||
/// TODO currently only supports the default.
|
||||
/// Need to find all possible formats.
|
||||
pub fn supported_input_formats(
|
||||
&self,
|
||||
) -> Result<SupportedInputFormats, SupportedFormatsError> {
|
||||
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
|
||||
// Retrieve the default format for the total supported channels and supported sample
|
||||
// format.
|
||||
let mut f = match self.default_input_format() {
|
||||
|
@ -68,7 +66,12 @@ impl Device {
|
|||
// Collect a format for every combination of supported sample rate and number of channels.
|
||||
let mut supported_formats = vec![];
|
||||
for &rate in ::COMMON_SAMPLE_RATES {
|
||||
if !self.driver.can_sample_rate(rate.0.into()).ok().unwrap_or(false) {
|
||||
if !self
|
||||
.driver
|
||||
.can_sample_rate(rate.0.into())
|
||||
.ok()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for channels in 1..f.channels + 1 {
|
||||
|
@ -96,7 +99,12 @@ impl Device {
|
|||
// Collect a format for every combination of supported sample rate and number of channels.
|
||||
let mut supported_formats = vec![];
|
||||
for &rate in ::COMMON_SAMPLE_RATES {
|
||||
if !self.driver.can_sample_rate(rate.0.into()).ok().unwrap_or(false) {
|
||||
if !self
|
||||
.driver
|
||||
.can_sample_rate(rate.0.into())
|
||||
.ok()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for channels in 1..f.channels + 1 {
|
||||
|
@ -114,8 +122,8 @@ impl Device {
|
|||
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _);
|
||||
// Map th ASIO sample type to a CPAL sample type
|
||||
let data_type = self.driver.input_data_type().map_err(default_format_err)?;
|
||||
let data_type = convert_data_type(&data_type)
|
||||
.ok_or(DefaultFormatError::StreamTypeNotSupported)?;
|
||||
let data_type =
|
||||
convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?;
|
||||
Ok(Format {
|
||||
channels,
|
||||
sample_rate,
|
||||
|
@ -128,8 +136,8 @@ impl Device {
|
|||
let channels = self.driver.channels().map_err(default_format_err)?.outs as u16;
|
||||
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _);
|
||||
let data_type = self.driver.output_data_type().map_err(default_format_err)?;
|
||||
let data_type = convert_data_type(&data_type)
|
||||
.ok_or(DefaultFormatError::StreamTypeNotSupported)?;
|
||||
let data_type =
|
||||
convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?;
|
||||
Ok(Format {
|
||||
channels,
|
||||
sample_rate,
|
||||
|
@ -159,10 +167,13 @@ impl Iterator for Devices {
|
|||
input: None,
|
||||
output: None,
|
||||
}));
|
||||
return Some(Device { driver, asio_streams });
|
||||
return Some(Device {
|
||||
driver,
|
||||
asio_streams,
|
||||
});
|
||||
}
|
||||
Err(_) => continue,
|
||||
}
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
|
@ -193,8 +204,9 @@ pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option<SampleFormat
|
|||
|
||||
fn default_format_err(e: sys::AsioError) -> DefaultFormatError {
|
||||
match e {
|
||||
sys::AsioError::NoDrivers |
|
||||
sys::AsioError::HardwareMalfunction => DefaultFormatError::DeviceNotAvailable,
|
||||
sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => {
|
||||
DefaultFormatError::DeviceNotAvailable
|
||||
}
|
||||
sys::AsioError::NoRate => DefaultFormatError::StreamTypeNotSupported,
|
||||
err => {
|
||||
let description = format!("{}", err);
|
||||
|
|
|
@ -2,22 +2,10 @@ extern crate asio_sys as sys;
|
|||
extern crate parking_lot;
|
||||
|
||||
use crate::{
|
||||
BuildStreamError,
|
||||
Data,
|
||||
DefaultFormatError,
|
||||
DeviceNameError,
|
||||
DevicesError,
|
||||
Format,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
StreamError,
|
||||
SupportedFormatsError,
|
||||
};
|
||||
use traits::{
|
||||
DeviceTrait,
|
||||
HostTrait,
|
||||
StreamTrait,
|
||||
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
|
||||
PauseStreamError, PlayStreamError, StreamError, SupportedFormatsError,
|
||||
};
|
||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
|
||||
pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats};
|
||||
pub use self::stream::Stream;
|
||||
|
@ -73,11 +61,15 @@ impl DeviceTrait for Device {
|
|||
Device::name(self)
|
||||
}
|
||||
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
fn supported_input_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
Device::supported_input_formats(self)
|
||||
}
|
||||
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
fn supported_output_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
Device::supported_output_formats(self)
|
||||
}
|
||||
|
||||
|
@ -97,7 +89,7 @@ impl DeviceTrait for Device {
|
|||
) -> Result<Self::Stream, BuildStreamError>
|
||||
where
|
||||
D: FnMut(&Data) + Send + 'static,
|
||||
E: FnMut(StreamError) + Send + 'static
|
||||
E: FnMut(StreamError) + Send + 'static,
|
||||
{
|
||||
Device::build_input_stream(self, format, data_callback, error_callback)
|
||||
}
|
||||
|
@ -110,7 +102,7 @@ impl DeviceTrait for Device {
|
|||
) -> Result<Self::Stream, BuildStreamError>
|
||||
where
|
||||
D: FnMut(&mut Data) + Send + 'static,
|
||||
E: FnMut(StreamError) + Send + 'static
|
||||
E: FnMut(StreamError) + Send + 'static,
|
||||
{
|
||||
Device::build_output_stream(self, format, data_callback, error_callback)
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ extern crate asio_sys as sys;
|
|||
extern crate num_traits;
|
||||
|
||||
use self::num_traits::PrimInt;
|
||||
use super::parking_lot::Mutex;
|
||||
use super::Device;
|
||||
use std;
|
||||
use std::sync::atomic::{Ordering, AtomicBool};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use super::parking_lot::Mutex;
|
||||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use Data;
|
||||
|
@ -93,7 +93,7 @@ impl Device {
|
|||
let callback_id = self.driver.add_callback(move |buffer_index| unsafe {
|
||||
// If not playing return early.
|
||||
if !playing.load(Ordering::SeqCst) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
// There is 0% chance of lock contention the host only locks when recreating streams.
|
||||
|
@ -111,8 +111,7 @@ impl Device {
|
|||
asio_stream: &sys::AsioStream,
|
||||
buffer_index: usize,
|
||||
from_endianness: F,
|
||||
)
|
||||
where
|
||||
) where
|
||||
A: AsioSample,
|
||||
B: Sample,
|
||||
D: FnMut(&Data) + Send + 'static,
|
||||
|
@ -157,8 +156,8 @@ impl Device {
|
|||
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(&sys::AsioSampleType::ASIOSTFloat32LSB, SampleFormat::F32) |
|
||||
(&sys::AsioSampleType::ASIOSTFloat32MSB, SampleFormat::F32) => {
|
||||
(&sys::AsioSampleType::ASIOSTFloat32LSB, SampleFormat::F32)
|
||||
| (&sys::AsioSampleType::ASIOSTFloat32MSB, SampleFormat::F32) => {
|
||||
process_input_callback::<f32, f32, _, _>(
|
||||
&mut data_callback,
|
||||
&mut interleaved,
|
||||
|
@ -191,8 +190,8 @@ impl Device {
|
|||
}
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(&sys::AsioSampleType::ASIOSTFloat64LSB, SampleFormat::F32) |
|
||||
(&sys::AsioSampleType::ASIOSTFloat64MSB, SampleFormat::F32) => {
|
||||
(&sys::AsioSampleType::ASIOSTFloat64LSB, SampleFormat::F32)
|
||||
| (&sys::AsioSampleType::ASIOSTFloat64MSB, SampleFormat::F32) => {
|
||||
process_input_callback::<f64, f32, _, _>(
|
||||
&mut data_callback,
|
||||
&mut interleaved,
|
||||
|
@ -202,10 +201,11 @@ impl Device {
|
|||
);
|
||||
}
|
||||
|
||||
unsupported_format_pair => {
|
||||
unreachable!("`build_input_stream` should have returned with unsupported \
|
||||
format {:?}", unsupported_format_pair)
|
||||
}
|
||||
unsupported_format_pair => unreachable!(
|
||||
"`build_input_stream` should have returned with unsupported \
|
||||
format {:?}",
|
||||
unsupported_format_pair
|
||||
),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -258,7 +258,7 @@ impl Device {
|
|||
let callback_id = self.driver.add_callback(move |buffer_index| unsafe {
|
||||
// If not playing, return early.
|
||||
if !playing.load(Ordering::SeqCst) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
// There is 0% chance of lock contention the host only locks when recreating streams.
|
||||
|
@ -301,8 +301,7 @@ impl Device {
|
|||
asio_stream: &sys::AsioStream,
|
||||
buffer_index: usize,
|
||||
to_endianness: F,
|
||||
)
|
||||
where
|
||||
) where
|
||||
A: Sample,
|
||||
B: AsioSample,
|
||||
D: FnMut(&mut Data) + Send + 'static,
|
||||
|
@ -321,7 +320,9 @@ impl Device {
|
|||
for ch_ix in 0..n_channels {
|
||||
let asio_channel =
|
||||
asio_channel_slice_mut::<B>(asio_stream, buffer_index, ch_ix);
|
||||
asio_channel.iter_mut().for_each(|s| *s = to_endianness(B::SILENCE));
|
||||
asio_channel
|
||||
.iter_mut()
|
||||
.for_each(|s| *s = to_endianness(B::SILENCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,8 +360,8 @@ impl Device {
|
|||
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32LSB) |
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32MSB) => {
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32LSB)
|
||||
| (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32MSB) => {
|
||||
process_output_callback::<f32, f32, _, _>(
|
||||
&mut data_callback,
|
||||
&mut interleaved,
|
||||
|
@ -396,8 +397,8 @@ impl Device {
|
|||
}
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64LSB) |
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64MSB) => {
|
||||
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64LSB)
|
||||
| (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64MSB) => {
|
||||
process_output_callback::<f32, f64, _, _>(
|
||||
&mut data_callback,
|
||||
&mut interleaved,
|
||||
|
@ -408,10 +409,11 @@ impl Device {
|
|||
);
|
||||
}
|
||||
|
||||
unsupported_format_pair => {
|
||||
unreachable!("`build_output_stream` should have returned with unsupported \
|
||||
format {:?}", unsupported_format_pair)
|
||||
}
|
||||
unsupported_format_pair => unreachable!(
|
||||
"`build_output_stream` should have returned with unsupported \
|
||||
format {:?}",
|
||||
unsupported_format_pair
|
||||
),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -434,15 +436,12 @@ impl Device {
|
|||
/// If there is no existing ASIO Input Stream it will be created.
|
||||
///
|
||||
/// On success, the buffer size of the stream is returned.
|
||||
fn get_or_create_input_stream(
|
||||
&self,
|
||||
format: &Format,
|
||||
) -> Result<usize, BuildStreamError> {
|
||||
fn get_or_create_input_stream(&self, format: &Format) -> Result<usize, BuildStreamError> {
|
||||
match self.default_input_format() {
|
||||
Ok(f) => {
|
||||
let num_asio_channels = f.channels;
|
||||
check_format(&self.driver, format, num_asio_channels)
|
||||
},
|
||||
}
|
||||
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
||||
}?;
|
||||
let num_channels = format.channels as usize;
|
||||
|
@ -462,7 +461,8 @@ impl Device {
|
|||
};
|
||||
*streams = new_streams;
|
||||
bs
|
||||
}).map_err(|ref e| {
|
||||
})
|
||||
.map_err(|ref e| {
|
||||
println!("Error preparing stream: {}", e);
|
||||
BuildStreamError::DeviceNotAvailable
|
||||
})
|
||||
|
@ -473,15 +473,12 @@ impl Device {
|
|||
/// Create a new CPAL Output Stream.
|
||||
///
|
||||
/// If there is no existing ASIO Output Stream it will be created.
|
||||
fn get_or_create_output_stream(
|
||||
&self,
|
||||
format: &Format,
|
||||
) -> Result<usize, BuildStreamError> {
|
||||
fn get_or_create_output_stream(&self, format: &Format) -> Result<usize, BuildStreamError> {
|
||||
match self.default_output_format() {
|
||||
Ok(f) => {
|
||||
let num_asio_channels = f.channels;
|
||||
check_format(&self.driver, format, num_asio_channels)
|
||||
},
|
||||
}
|
||||
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
||||
}?;
|
||||
let num_channels = format.channels as usize;
|
||||
|
@ -501,7 +498,8 @@ impl Device {
|
|||
};
|
||||
*streams = new_streams;
|
||||
bs
|
||||
}).map_err(|ref e| {
|
||||
})
|
||||
.map_err(|ref e| {
|
||||
println!("Error preparing stream: {}", e);
|
||||
BuildStreamError::DeviceNotAvailable
|
||||
})
|
||||
|
@ -588,7 +586,10 @@ fn check_format(
|
|||
// Try and set the sample rate to what the user selected.
|
||||
let sample_rate = sample_rate.0.into();
|
||||
if sample_rate != driver.sample_rate().map_err(build_stream_err)? {
|
||||
if driver.can_sample_rate(sample_rate).map_err(build_stream_err)? {
|
||||
if driver
|
||||
.can_sample_rate(sample_rate)
|
||||
.map_err(build_stream_err)?
|
||||
{
|
||||
driver
|
||||
.set_sample_rate(sample_rate)
|
||||
.map_err(build_stream_err)?;
|
||||
|
@ -656,19 +657,17 @@ unsafe fn asio_channel_slice_mut<T>(
|
|||
buffer_index: usize,
|
||||
channel_index: usize,
|
||||
) -> &mut [T] {
|
||||
let buff_ptr: *mut T = asio_stream
|
||||
.buffer_infos[channel_index]
|
||||
.buffers[buffer_index as usize]
|
||||
as *mut _;
|
||||
let buff_ptr: *mut T =
|
||||
asio_stream.buffer_infos[channel_index].buffers[buffer_index as usize] as *mut _;
|
||||
std::slice::from_raw_parts_mut(buff_ptr, asio_stream.buffer_size as usize)
|
||||
}
|
||||
|
||||
fn build_stream_err(e: sys::AsioError) -> BuildStreamError {
|
||||
match e {
|
||||
sys::AsioError::NoDrivers |
|
||||
sys::AsioError::HardwareMalfunction => BuildStreamError::DeviceNotAvailable,
|
||||
sys::AsioError::InvalidInput |
|
||||
sys::AsioError::BadMode => BuildStreamError::InvalidArgument,
|
||||
sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => {
|
||||
BuildStreamError::DeviceNotAvailable
|
||||
}
|
||||
sys::AsioError::InvalidInput | sys::AsioError::BadMode => BuildStreamError::InvalidArgument,
|
||||
err => {
|
||||
let description = format!("{}", err);
|
||||
BackendSpecificError { description }.into()
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
use {BackendSpecificError, DevicesError, SupportedFormat};
|
||||
use super::coreaudio::sys::{
|
||||
kAudioHardwareNoError, kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioHardwarePropertyDefaultOutputDevice, kAudioHardwarePropertyDevices,
|
||||
kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal, kAudioObjectSystemObject,
|
||||
AudioDeviceID, AudioObjectGetPropertyData, AudioObjectGetPropertyDataSize,
|
||||
AudioObjectPropertyAddress, OSStatus,
|
||||
};
|
||||
use super::Device;
|
||||
use std::mem;
|
||||
use std::ptr::null;
|
||||
use std::vec::IntoIter as VecIntoIter;
|
||||
use super::coreaudio::sys::{
|
||||
AudioDeviceID,
|
||||
AudioObjectPropertyAddress,
|
||||
AudioObjectGetPropertyData,
|
||||
AudioObjectGetPropertyDataSize,
|
||||
kAudioHardwareNoError,
|
||||
kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioHardwarePropertyDevices,
|
||||
kAudioObjectPropertyElementMaster,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectSystemObject,
|
||||
OSStatus,
|
||||
};
|
||||
use super::Device;
|
||||
use {BackendSpecificError, DevicesError, SupportedFormat};
|
||||
|
||||
unsafe fn audio_devices() -> Result<Vec<AudioDeviceID>, OSStatus> {
|
||||
let property_address = AudioObjectPropertyAddress {
|
||||
|
@ -80,15 +73,15 @@ impl Devices {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Devices {
|
||||
}
|
||||
unsafe impl Sync for Devices {
|
||||
}
|
||||
unsafe impl Send for Devices {}
|
||||
unsafe impl Sync for Devices {}
|
||||
|
||||
impl Iterator for Devices {
|
||||
type Item = Device;
|
||||
fn next(&mut self) -> Option<Device> {
|
||||
self.0.next().map(|id| Device { audio_device_id: id })
|
||||
self.0.next().map(|id| Device {
|
||||
audio_device_id: id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,67 +1,33 @@
|
|||
extern crate coreaudio;
|
||||
extern crate core_foundation_sys;
|
||||
extern crate coreaudio;
|
||||
|
||||
use crate::{
|
||||
ChannelCount,
|
||||
BackendSpecificError,
|
||||
BuildStreamError,
|
||||
Data,
|
||||
DefaultFormatError,
|
||||
DeviceNameError,
|
||||
DevicesError,
|
||||
Format,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
SampleFormat,
|
||||
SampleRate,
|
||||
StreamError,
|
||||
SupportedFormat,
|
||||
SupportedFormatsError,
|
||||
use self::core_foundation_sys::string::{CFStringGetCStringPtr, CFStringRef};
|
||||
use self::coreaudio::audio_unit::render_callback::{self, data};
|
||||
use self::coreaudio::audio_unit::{AudioUnit, Element, Scope};
|
||||
use self::coreaudio::sys::{
|
||||
kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceNameCFString,
|
||||
kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput,
|
||||
kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyStreamFormat,
|
||||
kAudioFormatFlagIsFloat, kAudioFormatFlagIsPacked, kAudioFormatLinearPCM,
|
||||
kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput,
|
||||
kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitProperty_StreamFormat, kCFStringEncodingUTF8, AudioBuffer, AudioBufferList,
|
||||
AudioDeviceID, AudioObjectAddPropertyListener, AudioObjectGetPropertyData,
|
||||
AudioObjectGetPropertyDataSize, AudioObjectID, AudioObjectPropertyAddress,
|
||||
AudioObjectPropertyScope, AudioObjectRemovePropertyListener, AudioObjectSetPropertyData,
|
||||
AudioStreamBasicDescription, AudioValueRange, OSStatus,
|
||||
};
|
||||
use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
use self::coreaudio::audio_unit::{AudioUnit, Scope, Element};
|
||||
use self::coreaudio::audio_unit::render_callback::{self, data};
|
||||
use self::coreaudio::sys::{
|
||||
AudioBuffer,
|
||||
AudioBufferList,
|
||||
AudioDeviceID,
|
||||
AudioObjectAddPropertyListener,
|
||||
AudioObjectGetPropertyData,
|
||||
AudioObjectGetPropertyDataSize,
|
||||
AudioObjectID,
|
||||
AudioObjectPropertyAddress,
|
||||
AudioObjectPropertyScope,
|
||||
AudioObjectRemovePropertyListener,
|
||||
AudioObjectSetPropertyData,
|
||||
AudioStreamBasicDescription,
|
||||
AudioValueRange,
|
||||
kAudioDevicePropertyAvailableNominalSampleRates,
|
||||
kAudioDevicePropertyDeviceNameCFString,
|
||||
kAudioDevicePropertyNominalSampleRate,
|
||||
kAudioObjectPropertyScopeInput,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioDevicePropertyStreamConfiguration,
|
||||
kAudioDevicePropertyStreamFormat,
|
||||
kAudioFormatFlagIsFloat,
|
||||
kAudioFormatFlagIsPacked,
|
||||
kAudioFormatLinearPCM,
|
||||
kAudioObjectPropertyElementMaster,
|
||||
kAudioObjectPropertyScopeOutput,
|
||||
kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kCFStringEncodingUTF8,
|
||||
OSStatus,
|
||||
};
|
||||
use self::core_foundation_sys::string::{
|
||||
CFStringRef,
|
||||
CFStringGetCStringPtr,
|
||||
use crate::{
|
||||
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultFormatError,
|
||||
DeviceNameError, DevicesError, Format, PauseStreamError, PlayStreamError, SampleFormat,
|
||||
SampleRate, StreamError, SupportedFormat, SupportedFormatsError,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::cell::RefCell;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr::null;
|
||||
use std::slice;
|
||||
|
@ -70,7 +36,10 @@ use std::time::Duration;
|
|||
|
||||
mod enumerate;
|
||||
|
||||
pub use self::enumerate::{Devices, SupportedInputFormats, SupportedOutputFormats, default_input_device, default_output_device};
|
||||
pub use self::enumerate::{
|
||||
default_input_device, default_output_device, Devices, SupportedInputFormats,
|
||||
SupportedOutputFormats,
|
||||
};
|
||||
|
||||
/// Coreaudio host, the default host on macOS and iOS.
|
||||
#[derive(Debug)]
|
||||
|
@ -107,17 +76,21 @@ impl HostTrait for Host {
|
|||
impl DeviceTrait for Device {
|
||||
type SupportedInputFormats = SupportedInputFormats;
|
||||
type SupportedOutputFormats = SupportedOutputFormats;
|
||||
type Stream = Stream;
|
||||
type Stream = Stream;
|
||||
|
||||
fn name(&self) -> Result<String, DeviceNameError> {
|
||||
Device::name(self)
|
||||
}
|
||||
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
fn supported_input_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
Device::supported_input_formats(self)
|
||||
}
|
||||
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
fn supported_output_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
Device::supported_output_formats(self)
|
||||
}
|
||||
|
||||
|
@ -196,8 +169,7 @@ impl Device {
|
|||
fn supported_formats(
|
||||
&self,
|
||||
scope: AudioObjectPropertyScope,
|
||||
) -> Result<SupportedOutputFormats, SupportedFormatsError>
|
||||
{
|
||||
) -> Result<SupportedOutputFormats, SupportedFormatsError> {
|
||||
let mut property_address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioDevicePropertyStreamConfiguration,
|
||||
mScope: scope,
|
||||
|
@ -307,17 +279,18 @@ impl Device {
|
|||
fn default_format(
|
||||
&self,
|
||||
scope: AudioObjectPropertyScope,
|
||||
) -> Result<Format, DefaultFormatError>
|
||||
{
|
||||
) -> Result<Format, DefaultFormatError> {
|
||||
fn default_format_error_from_os_status(status: OSStatus) -> Result<(), DefaultFormatError> {
|
||||
let err = match coreaudio::Error::from_os_status(status) {
|
||||
Err(err) => err,
|
||||
Ok(_) => return Ok(()),
|
||||
};
|
||||
match err {
|
||||
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported) |
|
||||
coreaudio::Error::AudioCodec(_) |
|
||||
coreaudio::Error::AudioFormat(_) => {
|
||||
coreaudio::Error::AudioUnit(
|
||||
coreaudio::error::AudioUnitError::FormatNotSupported,
|
||||
)
|
||||
| coreaudio::Error::AudioCodec(_)
|
||||
| coreaudio::Error::AudioFormat(_) => {
|
||||
Err(DefaultFormatError::StreamTypeNotSupported)
|
||||
}
|
||||
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::NoConnection) => {
|
||||
|
@ -412,11 +385,11 @@ struct StreamInner {
|
|||
impl From<coreaudio::Error> for BuildStreamError {
|
||||
fn from(err: coreaudio::Error) -> BuildStreamError {
|
||||
match err {
|
||||
coreaudio::Error::RenderCallbackBufferFormatDoesNotMatchAudioUnitStreamFormat |
|
||||
coreaudio::Error::NoKnownSubtype |
|
||||
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported) |
|
||||
coreaudio::Error::AudioCodec(_) |
|
||||
coreaudio::Error::AudioFormat(_) => BuildStreamError::FormatNotSupported,
|
||||
coreaudio::Error::RenderCallbackBufferFormatDoesNotMatchAudioUnitStreamFormat
|
||||
| coreaudio::Error::NoKnownSubtype
|
||||
| coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported)
|
||||
| coreaudio::Error::AudioCodec(_)
|
||||
| coreaudio::Error::AudioFormat(_) => BuildStreamError::FormatNotSupported,
|
||||
_ => BuildStreamError::DeviceNotAvailable,
|
||||
}
|
||||
}
|
||||
|
@ -513,8 +486,8 @@ impl Device {
|
|||
// Get the current sample rate.
|
||||
let mut property_address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioDevicePropertyNominalSampleRate,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
};
|
||||
let sample_rate: f64 = 0.0;
|
||||
let data_size = mem::size_of::<f64>() as u32;
|
||||
|
@ -558,9 +531,9 @@ impl Device {
|
|||
|
||||
// Now that we have the available ranges, pick the one matching the desired rate.
|
||||
let sample_rate = format.sample_rate.0;
|
||||
let maybe_index = ranges
|
||||
.iter()
|
||||
.position(|r| r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate);
|
||||
let maybe_index = ranges.iter().position(|r| {
|
||||
r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate
|
||||
});
|
||||
let range_index = match maybe_index {
|
||||
None => return Err(BuildStreamError::FormatNotSupported),
|
||||
Some(i) => i,
|
||||
|
@ -583,8 +556,8 @@ impl Device {
|
|||
let data_size = mem::size_of::<f64>();
|
||||
let property_address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioDevicePropertyNominalSampleRate,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
};
|
||||
AudioObjectGetPropertyData(
|
||||
device_id,
|
||||
|
@ -624,7 +597,8 @@ impl Device {
|
|||
let timer = ::std::time::Instant::now();
|
||||
while sample_rate != reported_rate {
|
||||
if timer.elapsed() > Duration::from_secs(1) {
|
||||
let description = "timeout waiting for sample rate update for device".into();
|
||||
let description =
|
||||
"timeout waiting for sample rate update for device".into();
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
|
@ -662,7 +636,7 @@ impl Device {
|
|||
let AudioBuffer {
|
||||
mNumberChannels: _num_channels,
|
||||
mDataByteSize: data_byte_size,
|
||||
mData: data
|
||||
mData: data,
|
||||
} = buffers[0];
|
||||
|
||||
let data = data as *mut ();
|
||||
|
@ -713,7 +687,7 @@ impl Device {
|
|||
let AudioBuffer {
|
||||
mNumberChannels: _num_channels,
|
||||
mDataByteSize: data_byte_size,
|
||||
mData: data
|
||||
mData: data,
|
||||
} = (*args.data.data).mBuffers[0];
|
||||
|
||||
let data = data as *mut ();
|
||||
|
|
|
@ -2,23 +2,14 @@ use std::mem;
|
|||
use std::os::raw::c_void;
|
||||
use std::slice::from_raw_parts;
|
||||
use stdweb;
|
||||
use stdweb::Reference;
|
||||
use stdweb::unstable::TryInto;
|
||||
use stdweb::web::TypedArray;
|
||||
use stdweb::web::set_timeout;
|
||||
use stdweb::web::TypedArray;
|
||||
use stdweb::Reference;
|
||||
|
||||
use crate::{
|
||||
BuildStreamError,
|
||||
Data,
|
||||
DefaultFormatError,
|
||||
DeviceNameError,
|
||||
DevicesError,
|
||||
Format,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
SampleFormat,
|
||||
StreamError,
|
||||
SupportedFormat,
|
||||
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
|
||||
PauseStreamError, PlayStreamError, SampleFormat, StreamError, SupportedFormat,
|
||||
SupportedFormatsError,
|
||||
};
|
||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
|
@ -83,16 +74,13 @@ impl Device {
|
|||
//
|
||||
// UPDATE: We can do this now. Might be best to use `crate::COMMON_SAMPLE_RATES` and
|
||||
// filter out those that lay outside the range specified above.
|
||||
Ok(
|
||||
vec![
|
||||
SupportedFormat {
|
||||
channels: 2,
|
||||
min_sample_rate: ::SampleRate(44100),
|
||||
max_sample_rate: ::SampleRate(44100),
|
||||
data_type: ::SampleFormat::F32,
|
||||
},
|
||||
].into_iter(),
|
||||
)
|
||||
Ok(vec![SupportedFormat {
|
||||
channels: 2,
|
||||
min_sample_rate: ::SampleRate(44100),
|
||||
max_sample_rate: ::SampleRate(44100),
|
||||
data_type: ::SampleFormat::F32,
|
||||
}]
|
||||
.into_iter())
|
||||
}
|
||||
|
||||
fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
|
||||
|
@ -101,13 +89,11 @@ impl Device {
|
|||
|
||||
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
|
||||
// TODO: because it is hard coded, see supported_output_formats.
|
||||
Ok(
|
||||
Format {
|
||||
channels: 2,
|
||||
sample_rate: ::SampleRate(44100),
|
||||
data_type: ::SampleFormat::F32,
|
||||
},
|
||||
)
|
||||
Ok(Format {
|
||||
channels: 2,
|
||||
sample_rate: ::SampleRate(44100),
|
||||
data_type: ::SampleFormat::F32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,11 +128,15 @@ impl DeviceTrait for Device {
|
|||
Device::name(self)
|
||||
}
|
||||
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
fn supported_input_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
|
||||
Device::supported_input_formats(self)
|
||||
}
|
||||
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
fn supported_output_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
|
||||
Device::supported_output_formats(self)
|
||||
}
|
||||
|
||||
|
@ -201,7 +191,10 @@ impl DeviceTrait for Device {
|
|||
//
|
||||
// See also: The call to `set_timeout` at the end of the `audio_callback_fn` which creates
|
||||
// the loop.
|
||||
set_timeout(|| audio_callback_fn::<D, E>(user_data_ptr as *mut c_void), 10);
|
||||
set_timeout(
|
||||
|| audio_callback_fn::<D, E>(user_data_ptr as *mut c_void),
|
||||
10,
|
||||
);
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
@ -323,9 +316,10 @@ fn default_output_device() -> Option<Device> {
|
|||
fn is_webaudio_available() -> bool {
|
||||
stdweb::initialize();
|
||||
js!(if (!AudioContext) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}).try_into()
|
||||
.unwrap()
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
})
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
use crate::{
|
||||
BuildStreamError,
|
||||
Data,
|
||||
DefaultFormatError,
|
||||
DevicesError,
|
||||
DeviceNameError,
|
||||
Format,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
StreamError,
|
||||
SupportedFormatsError,
|
||||
SupportedFormat,
|
||||
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
|
||||
PauseStreamError, PlayStreamError, StreamError, SupportedFormat, SupportedFormatsError,
|
||||
};
|
||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
use crate::{
|
||||
BackendSpecificError,
|
||||
Data,
|
||||
DefaultFormatError,
|
||||
DeviceNameError,
|
||||
DevicesError,
|
||||
Format,
|
||||
SampleFormat,
|
||||
SampleRate,
|
||||
SupportedFormat,
|
||||
SupportedFormatsError,
|
||||
COMMON_SAMPLE_RATES,
|
||||
BackendSpecificError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
|
||||
SampleFormat, SampleRate, SupportedFormat, SupportedFormatsError, COMMON_SAMPLE_RATES,
|
||||
};
|
||||
use std;
|
||||
use std::ffi::OsString;
|
||||
|
@ -115,7 +106,11 @@ impl DeviceTrait for Device {
|
|||
E: FnMut(StreamError) + Send + 'static,
|
||||
{
|
||||
let stream_inner = self.build_input_stream_inner(format)?;
|
||||
Ok(Stream::new_input(stream_inner, data_callback, error_callback))
|
||||
Ok(Stream::new_input(
|
||||
stream_inner,
|
||||
data_callback,
|
||||
error_callback,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_output_stream<D, E>(
|
||||
|
@ -129,7 +124,11 @@ impl DeviceTrait for Device {
|
|||
E: FnMut(StreamError) + Send + 'static,
|
||||
{
|
||||
let stream_inner = self.build_output_stream_inner(format)?;
|
||||
Ok(Stream::new_output(stream_inner, data_callback, error_callback))
|
||||
Ok(Stream::new_output(
|
||||
stream_inner,
|
||||
data_callback,
|
||||
error_callback,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,8 +715,7 @@ impl Device {
|
|||
|
||||
// Building a `IAudioCaptureClient` that will be used to read captured samples.
|
||||
let capture_client = {
|
||||
let mut capture_client: *mut audioclient::IAudioCaptureClient =
|
||||
ptr::null_mut();
|
||||
let mut capture_client: *mut audioclient::IAudioCaptureClient = ptr::null_mut();
|
||||
let hresult = (*audio_client).GetService(
|
||||
&audioclient::IID_IAudioCaptureClient,
|
||||
&mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _,
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
use crate::{
|
||||
BackendSpecificError,
|
||||
Data,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
SampleFormat,
|
||||
StreamError,
|
||||
};
|
||||
use crate::traits::StreamTrait;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread::{self, JoinHandle};
|
||||
use super::check_result;
|
||||
use super::winapi::shared::basetsd::UINT32;
|
||||
use super::winapi::shared::minwindef::{BYTE, FALSE, WORD};
|
||||
|
@ -19,6 +6,14 @@ use super::winapi::um::handleapi;
|
|||
use super::winapi::um::synchapi;
|
||||
use super::winapi::um::winbase;
|
||||
use super::winapi::um::winnt;
|
||||
use crate::traits::StreamTrait;
|
||||
use crate::{
|
||||
BackendSpecificError, Data, PauseStreamError, PlayStreamError, SampleFormat, StreamError,
|
||||
};
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread::{self, JoinHandle};
|
||||
|
||||
pub struct Stream {
|
||||
/// The high-priority audio processing thread calling callbacks.
|
||||
|
@ -295,7 +290,12 @@ fn run_input(
|
|||
AudioClientFlow::Capture { capture_client } => capture_client,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match process_input(&mut run_ctxt.stream, capture_client, data_callback, error_callback) {
|
||||
match process_input(
|
||||
&mut run_ctxt.stream,
|
||||
capture_client,
|
||||
data_callback,
|
||||
error_callback,
|
||||
) {
|
||||
ControlFlow::Break => break,
|
||||
ControlFlow::Continue => continue,
|
||||
}
|
||||
|
@ -317,7 +317,12 @@ fn run_output(
|
|||
AudioClientFlow::Render { render_client } => render_client,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match process_output(&mut run_ctxt.stream, render_client, data_callback, error_callback) {
|
||||
match process_output(
|
||||
&mut run_ctxt.stream,
|
||||
render_client,
|
||||
data_callback,
|
||||
error_callback,
|
||||
) {
|
||||
ControlFlow::Break => break,
|
||||
ControlFlow::Continue => continue,
|
||||
}
|
||||
|
@ -401,8 +406,7 @@ fn process_input(
|
|||
debug_assert!(!buffer.is_null());
|
||||
|
||||
let data = buffer as *mut ();
|
||||
let len = frames_available as usize
|
||||
* stream.bytes_per_frame as usize
|
||||
let len = frames_available as usize * stream.bytes_per_frame as usize
|
||||
/ stream.sample_format.sample_size();
|
||||
let data = Data::from_parts(data, len, stream.sample_format);
|
||||
data_callback(&data);
|
||||
|
@ -436,8 +440,7 @@ fn process_output(
|
|||
|
||||
unsafe {
|
||||
let mut buffer: *mut BYTE = ptr::null_mut();
|
||||
let hresult =
|
||||
(*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
|
||||
let hresult = (*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
|
||||
|
||||
if let Err(err) = stream_error_from_hresult(hresult) {
|
||||
error_callback(err);
|
||||
|
@ -447,8 +450,7 @@ fn process_output(
|
|||
debug_assert!(!buffer.is_null());
|
||||
|
||||
let data = buffer as *mut ();
|
||||
let len = frames_available as usize
|
||||
* stream.bytes_per_frame as usize
|
||||
let len = frames_available as usize * stream.bytes_per_frame as usize
|
||||
/ stream.sample_format.sample_size();
|
||||
let mut data = Data::from_parts(data, len, stream.sample_format);
|
||||
data_callback(&mut data);
|
||||
|
|
34
src/lib.rs
34
src/lib.rs
|
@ -149,8 +149,8 @@ extern crate thiserror;
|
|||
|
||||
pub use error::*;
|
||||
pub use platform::{
|
||||
ALL_HOSTS, available_hosts, default_host, Device, Devices, Host, host_from_id,
|
||||
HostId, Stream, SupportedInputFormats, SupportedOutputFormats,
|
||||
available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream,
|
||||
SupportedInputFormats, SupportedOutputFormats, ALL_HOSTS,
|
||||
};
|
||||
pub use samples_formats::{Sample, SampleFormat};
|
||||
|
||||
|
@ -218,7 +218,11 @@ impl Data {
|
|||
len: usize,
|
||||
sample_format: SampleFormat,
|
||||
) -> Self {
|
||||
Data { data, len, sample_format }
|
||||
Data {
|
||||
data,
|
||||
len,
|
||||
sample_format,
|
||||
}
|
||||
}
|
||||
|
||||
/// The sample format of the internal audio data.
|
||||
|
@ -241,9 +245,7 @@ impl Data {
|
|||
let len = self.len * self.sample_format.sample_size();
|
||||
// The safety of this block relies on correct construction of the `Data` instance. See
|
||||
// the unsafe `from_parts` constructor for these requirements.
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(self.data as *const u8, len)
|
||||
}
|
||||
unsafe { std::slice::from_raw_parts(self.data as *const u8, len) }
|
||||
}
|
||||
|
||||
/// The raw slice of memory representing the underlying audio data as a slice of bytes.
|
||||
|
@ -253,9 +255,7 @@ impl Data {
|
|||
let len = self.len * self.sample_format.sample_size();
|
||||
// The safety of this block relies on correct construction of the `Data` instance. See
|
||||
// the unsafe `from_parts` constructor for these requirements.
|
||||
unsafe {
|
||||
std::slice::from_raw_parts_mut(self.data as *mut u8, len)
|
||||
}
|
||||
unsafe { std::slice::from_raw_parts_mut(self.data as *mut u8, len) }
|
||||
}
|
||||
|
||||
/// Access the data as a slice of sample type `T`.
|
||||
|
@ -268,9 +268,7 @@ impl Data {
|
|||
if T::FORMAT == self.sample_format {
|
||||
// The safety of this block relies on correct construction of the `Data` instance. See
|
||||
// the unsafe `from_parts` constructor for these requirements.
|
||||
unsafe {
|
||||
Some(std::slice::from_raw_parts(self.data as *const T, self.len))
|
||||
}
|
||||
unsafe { Some(std::slice::from_raw_parts(self.data as *const T, self.len)) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -287,7 +285,10 @@ impl Data {
|
|||
// The safety of this block relies on correct construction of the `Data` instance. See
|
||||
// the unsafe `from_parts` constructor for these requirements.
|
||||
unsafe {
|
||||
Some(std::slice::from_raw_parts_mut(self.data as *mut T, self.len))
|
||||
Some(std::slice::from_raw_parts_mut(
|
||||
self.data as *mut T,
|
||||
self.len,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -365,10 +366,9 @@ impl SupportedFormat {
|
|||
}
|
||||
|
||||
const HZ_44100: SampleRate = SampleRate(44_100);
|
||||
let r44100_in_self = self.min_sample_rate <= HZ_44100
|
||||
&& HZ_44100 <= self.max_sample_rate;
|
||||
let r44100_in_other = other.min_sample_rate <= HZ_44100
|
||||
&& HZ_44100 <= other.max_sample_rate;
|
||||
let r44100_in_self = self.min_sample_rate <= HZ_44100 && HZ_44100 <= self.max_sample_rate;
|
||||
let r44100_in_other =
|
||||
other.min_sample_rate <= HZ_44100 && HZ_44100 <= other.max_sample_rate;
|
||||
let cmp_r44100 = r44100_in_self.cmp(&r44100_in_other);
|
||||
if cmp_r44100 != Equal {
|
||||
return cmp_r44100;
|
||||
|
|
|
@ -435,10 +435,7 @@ macro_rules! impl_platform_host {
|
|||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))]
|
||||
mod platform_impl {
|
||||
pub use crate::host::alsa::{
|
||||
Device as AlsaDevice,
|
||||
Devices as AlsaDevices,
|
||||
Host as AlsaHost,
|
||||
Stream as AlsaStream,
|
||||
Device as AlsaDevice, Devices as AlsaDevices, Host as AlsaHost, Stream as AlsaStream,
|
||||
SupportedInputFormats as AlsaSupportedInputFormats,
|
||||
SupportedOutputFormats as AlsaSupportedOutputFormats,
|
||||
};
|
||||
|
@ -453,15 +450,11 @@ mod platform_impl {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
mod platform_impl {
|
||||
pub use crate::host::coreaudio::{
|
||||
Device as CoreAudioDevice,
|
||||
Devices as CoreAudioDevices,
|
||||
Host as CoreAudioHost,
|
||||
Stream as CoreAudioStream,
|
||||
SupportedInputFormats as CoreAudioSupportedInputFormats,
|
||||
Device as CoreAudioDevice, Devices as CoreAudioDevices, Host as CoreAudioHost,
|
||||
Stream as CoreAudioStream, SupportedInputFormats as CoreAudioSupportedInputFormats,
|
||||
SupportedOutputFormats as CoreAudioSupportedOutputFormats,
|
||||
};
|
||||
|
||||
|
@ -478,11 +471,8 @@ mod platform_impl {
|
|||
#[cfg(target_os = "emscripten")]
|
||||
mod platform_impl {
|
||||
pub use crate::host::emscripten::{
|
||||
Device as EmscriptenDevice,
|
||||
Devices as EmscriptenDevices,
|
||||
Host as EmscriptenHost,
|
||||
Stream as EmscriptenStream,
|
||||
SupportedInputFormats as EmscriptenSupportedInputFormats,
|
||||
Device as EmscriptenDevice, Devices as EmscriptenDevices, Host as EmscriptenHost,
|
||||
Stream as EmscriptenStream, SupportedInputFormats as EmscriptenSupportedInputFormats,
|
||||
SupportedOutputFormats as EmscriptenSupportedOutputFormats,
|
||||
};
|
||||
|
||||
|
@ -500,19 +490,13 @@ mod platform_impl {
|
|||
mod platform_impl {
|
||||
#[cfg(feature = "asio")]
|
||||
pub use crate::host::asio::{
|
||||
Device as AsioDevice,
|
||||
Devices as AsioDevices,
|
||||
Stream as AsioStream,
|
||||
Host as AsioHost,
|
||||
Device as AsioDevice, Devices as AsioDevices, Host as AsioHost, Stream as AsioStream,
|
||||
SupportedInputFormats as AsioSupportedInputFormats,
|
||||
SupportedOutputFormats as AsioSupportedOutputFormats,
|
||||
};
|
||||
pub use crate::host::wasapi::{
|
||||
Device as WasapiDevice,
|
||||
Devices as WasapiDevices,
|
||||
Stream as WasapiStream,
|
||||
Host as WasapiHost,
|
||||
SupportedInputFormats as WasapiSupportedInputFormats,
|
||||
Device as WasapiDevice, Devices as WasapiDevices, Host as WasapiHost,
|
||||
Stream as WasapiStream, SupportedInputFormats as WasapiSupportedInputFormats,
|
||||
SupportedOutputFormats as WasapiSupportedOutputFormats,
|
||||
};
|
||||
|
||||
|
@ -530,16 +514,19 @@ mod platform_impl {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(windows, target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "macos",
|
||||
target_os = "ios", target_os = "emscripten")))]
|
||||
#[cfg(not(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "emscripten"
|
||||
)))]
|
||||
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,
|
||||
Device as NullDevice, Devices as NullDevices, EventLoop as NullEventLoop, Host as NullHost,
|
||||
StreamId as NullStreamId, SupportedInputFormats as NullSupportedInputFormats,
|
||||
SupportedOutputFormats as NullSupportedOutputFormats,
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ pub unsafe trait Sample: Copy + Clone {
|
|||
|
||||
/// Converts any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`.
|
||||
fn from<S>(&S) -> Self
|
||||
where S: Sample;
|
||||
where
|
||||
S: Sample;
|
||||
}
|
||||
|
||||
unsafe impl Sample for u16 {
|
||||
|
@ -64,7 +65,8 @@ unsafe impl Sample for u16 {
|
|||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self
|
||||
where S: Sample
|
||||
where
|
||||
S: Sample,
|
||||
{
|
||||
sample.to_u16()
|
||||
}
|
||||
|
@ -98,7 +100,8 @@ unsafe impl Sample for i16 {
|
|||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self
|
||||
where S: Sample
|
||||
where
|
||||
S: Sample,
|
||||
{
|
||||
sample.to_i16()
|
||||
}
|
||||
|
@ -128,7 +131,8 @@ unsafe impl Sample for f32 {
|
|||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self
|
||||
where S: Sample
|
||||
where
|
||||
S: Sample,
|
||||
{
|
||||
sample.to_f32()
|
||||
}
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
//! 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,
|
||||
StreamError,
|
||||
SupportedFormat,
|
||||
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
|
||||
InputDevices, OutputDevices, PauseStreamError, PlayStreamError, StreamError, SupportedFormat,
|
||||
SupportedFormatsError,
|
||||
};
|
||||
|
||||
|
@ -65,7 +55,8 @@ pub trait HostTrait {
|
|||
/// Can be empty if the system does not support audio input.
|
||||
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_input<D: DeviceTrait>(device: &D) -> bool {
|
||||
device.supported_input_formats()
|
||||
device
|
||||
.supported_input_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
@ -78,7 +69,8 @@ pub trait HostTrait {
|
|||
/// Can be empty if the system does not support audio output.
|
||||
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_output<D: DeviceTrait>(device: &D) -> bool {
|
||||
device.supported_output_formats()
|
||||
device
|
||||
.supported_output_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
@ -104,12 +96,15 @@ 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_formats(&self)
|
||||
-> Result<Self::SupportedInputFormats, SupportedFormatsError>;
|
||||
|
||||
/// 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(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError>;
|
||||
fn supported_output_formats(
|
||||
&self,
|
||||
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError>;
|
||||
|
||||
/// The default input stream format for the device.
|
||||
fn default_input_format(&self) -> Result<Format, DefaultFormatError>;
|
||||
|
|
Loading…
Reference in New Issue