Merge pull request #365 from mitchmindtree/rustfmt

Remove old `.rustfmt.toml` config. Run default `cargo fmt` on repo. Add formatting check github action.
This commit is contained in:
mitchmindtree 2020-01-21 20:02:17 +01:00 committed by GitHub
commit 5390c01641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 3050 additions and 1417 deletions

View File

@ -24,6 +24,23 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
args: --all --all-features args: --all --all-features
rustfmt-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install stable
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: Run rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
cargo-publish: cargo-publish:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' if: github.event_name == 'push' && github.ref == 'refs/heads/master'

View File

@ -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"

File diff suppressed because it is too large Load Diff

View File

@ -64,8 +64,8 @@ fn create_lib(cpal_asio_dir: &PathBuf) {
let entry = match entry { let entry = match entry {
Err(e) => { Err(e) => {
println!("error: {}", e); println!("error: {}", e);
continue continue;
}, }
Ok(entry) => entry, Ok(entry) => entry,
}; };
match entry.path().extension().and_then(|s| s.to_str()) { match entry.path().extension().and_then(|s| s.to_str()) {
@ -127,8 +127,13 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
($opt_header:expr, $FILE_NAME:expr) => { ($opt_header:expr, $FILE_NAME:expr) => {
match $opt_header.as_ref() { match $opt_header.as_ref() {
None => { None => {
panic!("Could not find {} in {}: {}", $FILE_NAME, CPAL_ASIO_DIR, cpal_asio_dir.display()); panic!(
}, "Could not find {} in {}: {}",
$FILE_NAME,
CPAL_ASIO_DIR,
cpal_asio_dir.display()
);
}
Some(path) => path.to_str().expect("Could not convert path to str"), Some(path) => path.to_str().expect("Could not convert path to str"),
} }
}; };
@ -152,9 +157,9 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
.clang_arg("-x") .clang_arg("-x")
.clang_arg("c++") .clang_arg("c++")
.clang_arg("-std=c++14") .clang_arg("-std=c++14")
.clang_arg( format!("-I{}/{}", cpal_asio_dir.display(), "host/pc") ) .clang_arg(format!("-I{}/{}", cpal_asio_dir.display(), "host/pc"))
.clang_arg( format!("-I{}/{}", cpal_asio_dir.display(), "host") ) .clang_arg(format!("-I{}/{}", cpal_asio_dir.display(), "host"))
.clang_arg( format!("-I{}/{}", cpal_asio_dir.display(), "common") ) .clang_arg(format!("-I{}/{}", cpal_asio_dir.display(), "common"))
// Need to whitelist to avoid binding tp c++ std::* // Need to whitelist to avoid binding tp c++ std::*
.whitelist_type("AsioDrivers") .whitelist_type("AsioDrivers")
.whitelist_type("AsioDriver") .whitelist_type("AsioDriver")

View File

@ -38,8 +38,12 @@ fn main() {
for name in asio.driver_names() { for name in asio.driver_names() {
println!("Driver: {:?}", name); println!("Driver: {:?}", name);
let driver = asio.load_driver(&name).expect("failed to load driver"); let driver = asio.load_driver(&name).expect("failed to load driver");
let channels = driver.channels().expect("failed to retrieve channel counts"); let channels = driver
let sample_rate = driver.sample_rate().expect("failed to retrieve sample rate"); .channels()
.expect("failed to retrieve channel counts");
let sample_rate = driver
.sample_rate()
.expect("failed to retrieve sample rate");
let in_fmt = Format { let in_fmt = Format {
channels: channels.ins as _, channels: channels.ins as _,
sample_rate: SampleRate(sample_rate as _), sample_rate: SampleRate(sample_rate as _),

View File

@ -5,7 +5,13 @@ fn main() {
for driver in asio.driver_names() { for driver in asio.driver_names() {
println!("Driver: {}", driver); println!("Driver: {}", driver);
let driver = asio.load_driver(&driver).expect("failed to load drivers"); let driver = asio.load_driver(&driver).expect("failed to load drivers");
println!(" Channels: {:?}", driver.channels().expect("failed to get channels")); println!(
println!(" Sample rate: {:?}", driver.sample_rate().expect("failed to get sample rate")); " Channels: {:?}",
driver.channels().expect("failed to get channels")
);
println!(
" Sample rate: {:?}",
driver.sample_rate().expect("failed to get sample rate")
);
} }
} }

View File

@ -112,7 +112,9 @@ macro_rules! asio_result {
r if r == AsioErrorWrapper::ASE_OK as i32 => Ok(()), r if r == AsioErrorWrapper::ASE_OK as i32 => Ok(()),
r if r == AsioErrorWrapper::ASE_SUCCESS as i32 => Ok(()), r if r == AsioErrorWrapper::ASE_SUCCESS as i32 => Ok(()),
r if r == AsioErrorWrapper::ASE_NotPresent as i32 => Err(AsioError::NoDrivers), r if r == AsioErrorWrapper::ASE_NotPresent as i32 => Err(AsioError::NoDrivers),
r if r == AsioErrorWrapper::ASE_HWMalfunction as i32 => Err(AsioError::HardwareMalfunction), r if r == AsioErrorWrapper::ASE_HWMalfunction as i32 => {
Err(AsioError::HardwareMalfunction)
}
r if r == AsioErrorWrapper::ASE_InvalidParameter as i32 => Err(AsioError::InvalidInput), r if r == AsioErrorWrapper::ASE_InvalidParameter as i32 => Err(AsioError::InvalidInput),
r if r == AsioErrorWrapper::ASE_InvalidMode as i32 => Err(AsioError::BadMode), r if r == AsioErrorWrapper::ASE_InvalidMode as i32 => Err(AsioError::BadMode),
r if r == AsioErrorWrapper::ASE_SPNotAdvancing as i32 => Err(AsioError::HardwareStuck), r if r == AsioErrorWrapper::ASE_SPNotAdvancing as i32 => Err(AsioError::HardwareStuck),

View File

@ -2,8 +2,8 @@ pub mod asio_import;
#[macro_use] #[macro_use]
pub mod errors; pub mod errors;
use num_traits::FromPrimitive;
use self::errors::{AsioError, AsioErrorWrapper, LoadDriverError}; use self::errors::{AsioError, AsioErrorWrapper, LoadDriverError};
use num_traits::FromPrimitive;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::{c_char, c_double, c_long, c_void}; use std::os::raw::{c_char, c_double, c_long, c_void};
@ -165,9 +165,12 @@ pub struct AsioBufferInfo {
struct AsioCallbacks { struct AsioCallbacks {
buffer_switch: extern "C" fn(double_buffer_index: c_long, direct_process: c_long) -> (), buffer_switch: extern "C" fn(double_buffer_index: c_long, direct_process: c_long) -> (),
sample_rate_did_change: extern "C" fn(s_rate: c_double) -> (), sample_rate_did_change: extern "C" fn(s_rate: c_double) -> (),
asio_message: asio_message: extern "C" fn(
extern "C" fn(selector: c_long, value: c_long, message: *mut (), opt: *mut c_double) selector: c_long,
-> c_long, value: c_long,
message: *mut (),
opt: *mut c_double,
) -> c_long,
buffer_switch_time_info: extern "C" fn( buffer_switch_time_info: extern "C" fn(
params: *mut ai::ASIOTime, params: *mut ai::ASIOTime,
double_buffer_index: c_long, double_buffer_index: c_long,
@ -276,8 +279,9 @@ impl Asio {
} }
unsafe { unsafe {
let num_drivers = ai::get_driver_names(driver_name_ptrs.as_mut_ptr(), MAX_DRIVERS as i32); let num_drivers =
(0 .. num_drivers) ai::get_driver_names(driver_name_ptrs.as_mut_ptr(), MAX_DRIVERS as i32);
(0..num_drivers)
.map(|i| driver_name_to_utf8(&driver_names[i as usize]).to_string()) .map(|i| driver_name_to_utf8(&driver_names[i as usize]).to_string())
.collect() .collect()
} }
@ -317,8 +321,8 @@ impl Asio {
} }
// Make owned CString to send to load driver // Make owned CString to send to load driver
let driver_name_cstring = CString::new(driver_name) let driver_name_cstring =
.expect("failed to create `CString` from driver name"); CString::new(driver_name).expect("failed to create `CString` from driver name");
let mut driver_info = std::mem::MaybeUninit::<ai::ASIODriverInfo>::uninit(); let mut driver_info = std::mem::MaybeUninit::<ai::ASIODriverInfo>::uninit();
unsafe { unsafe {
@ -332,9 +336,15 @@ impl Asio {
let state = Mutex::new(DriverState::Initialized); let state = Mutex::new(DriverState::Initialized);
let name = driver_name.to_string(); let name = driver_name.to_string();
let destroyed = false; let destroyed = false;
let inner = Arc::new(DriverInner { name, state, destroyed }); let inner = Arc::new(DriverInner {
*self.loaded_driver.lock().expect("failed to acquire loaded driver lock") = name,
Arc::downgrade(&inner); state,
destroyed,
});
*self
.loaded_driver
.lock()
.expect("failed to acquire loaded driver lock") = Arc::downgrade(&inner);
let driver = Driver { inner }; let driver = Driver { inner };
Ok(driver) Ok(driver)
} }
@ -461,7 +471,10 @@ impl Driver {
mut input_buffer_infos: Vec<AsioBufferInfo>, mut input_buffer_infos: Vec<AsioBufferInfo>,
mut output_buffer_infos: Vec<AsioBufferInfo>, mut output_buffer_infos: Vec<AsioBufferInfo>,
) -> Result<AsioStreams, AsioError> { ) -> Result<AsioStreams, AsioError> {
let (input, output) = match (input_buffer_infos.is_empty(), output_buffer_infos.is_empty()) { let (input, output) = match (
input_buffer_infos.is_empty(),
output_buffer_infos.is_empty(),
) {
// Both stream exist. // Both stream exist.
(false, false) => { (false, false) => {
// Create one continuous slice of buffers. // Create one continuous slice of buffers.
@ -481,7 +494,7 @@ impl Driver {
buffer_size, buffer_size,
}); });
(input, output) (input, output)
}, }
// Just input // Just input
(false, true) => { (false, true) => {
let buffer_size = self.create_buffers(&mut input_buffer_infos)?; let buffer_size = self.create_buffers(&mut input_buffer_infos)?;
@ -491,7 +504,7 @@ impl Driver {
}); });
let output = None; let output = None;
(input, output) (input, output)
}, }
// Just output // Just output
(true, false) => { (true, false) => {
let buffer_size = self.create_buffers(&mut output_buffer_infos)?; let buffer_size = self.create_buffers(&mut output_buffer_infos)?;
@ -501,7 +514,7 @@ impl Driver {
buffer_size, buffer_size,
}); });
(input, output) (input, output)
}, }
// Impossible // Impossible
(true, true) => unreachable!("Trying to create streams without preparing"), (true, true) => unreachable!("Trying to create streams without preparing"),
}; };
@ -729,7 +742,11 @@ fn prepare_buffer_infos(is_input: bool, n_channels: usize) -> Vec<AsioBufferInfo
let channel_num = ch as c_long; let channel_num = ch as c_long;
// To be filled by ASIOCreateBuffers. // To be filled by ASIOCreateBuffers.
let buffers = [std::ptr::null_mut(); 2]; let buffers = [std::ptr::null_mut(); 2];
AsioBufferInfo { is_input, channel_num, buffers } AsioBufferInfo {
is_input,
channel_num,
buffers,
}
}) })
.collect() .collect()
} }
@ -788,18 +805,14 @@ fn stream_data_type(is_input: bool) -> Result<AsioSampleType, AsioError> {
/// ///
/// This converts to utf8. /// This converts to utf8.
fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> { fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> {
unsafe { unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() }
CStr::from_ptr(bytes.as_ptr()).to_string_lossy()
}
} }
/// ASIO uses null terminated c strings for channel names. /// ASIO uses null terminated c strings for channel names.
/// ///
/// This converts to utf8. /// This converts to utf8.
fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> { fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> {
unsafe { unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() }
CStr::from_ptr(bytes.as_ptr()).to_string_lossy()
}
} }
/// Indicates the stream sample rate has changed. /// Indicates the stream sample rate has changed.
@ -917,8 +930,9 @@ extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long)
&mut time.time_info.system_time, &mut time.time_info.system_time,
); );
if let Ok(()) = asio_result!(res) { if let Ok(()) = asio_result!(res) {
time.time_info.flags = time.time_info.flags = (ai::AsioTimeInfoFlags::kSystemTimeValid
(ai::AsioTimeInfoFlags::kSystemTimeValid | ai::AsioTimeInfoFlags::kSamplePositionValid).0; | ai::AsioTimeInfoFlags::kSamplePositionValid)
.0;
} }
time time
}; };
@ -930,7 +944,16 @@ extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long)
#[test] #[test]
fn check_type_sizes() { fn check_type_sizes() {
assert_eq!(std::mem::size_of::<AsioSampleRate>(), std::mem::size_of::<ai::ASIOSampleRate>()); assert_eq!(
assert_eq!(std::mem::size_of::<AsioTimeCode>(), std::mem::size_of::<ai::ASIOTimeCode>()); std::mem::size_of::<AsioSampleRate>(),
assert_eq!(std::mem::size_of::<AsioTime>(), std::mem::size_of::<ai::ASIOTime>()); std::mem::size_of::<ai::ASIOSampleRate>()
);
assert_eq!(
std::mem::size_of::<AsioTimeCode>(),
std::mem::size_of::<ai::ASIOTimeCode>()
);
assert_eq!(
std::mem::size_of::<AsioTime>(),
std::mem::size_of::<ai::ASIOTime>()
);
} }

View File

@ -13,6 +13,6 @@ extern crate num_traits;
#[cfg(asio)] #[cfg(asio)]
pub mod bindings; pub mod bindings;
#[cfg(asio)] #[cfg(asio)]
pub use bindings::*;
#[cfg(asio)]
pub use bindings::errors::{AsioError, LoadDriverError}; pub use bindings::errors::{AsioError, LoadDriverError};
#[cfg(asio)]
pub use bindings::*;

View File

@ -3,10 +3,10 @@ use std::env;
const CPAL_ASIO_DIR: &'static str = "CPAL_ASIO_DIR"; const CPAL_ASIO_DIR: &'static str = "CPAL_ASIO_DIR";
fn main() { 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 // otherwise set the asio config flag
match env::var(CPAL_ASIO_DIR) { match env::var(CPAL_ASIO_DIR) {
Err(_) => return, Err(_) => return,
Ok(_) => println!("cargo:rustc-cfg=asio"), Ok(_) => println!("cargo:rustc-cfg=asio"),
}; };
} }

View File

@ -1,5 +1,5 @@
extern crate cpal;
extern crate anyhow; extern crate anyhow;
extern crate cpal;
use cpal::traits::{DeviceTrait, HostTrait}; use cpal::traits::{DeviceTrait, HostTrait};
@ -30,12 +30,17 @@ fn main() -> Result<(), anyhow::Error> {
Err(e) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {:?}", e);
continue; continue;
}, }
}; };
if input_formats.peek().is_some() { if input_formats.peek().is_some() {
println!(" All supported input stream formats:"); println!(" All supported input stream formats:");
for (format_index, format) in input_formats.enumerate() { 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) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {:?}", e);
continue; continue;
}, }
}; };
if output_formats.peek().is_some() { if output_formats.peek().is_some() {
println!(" All supported output stream formats:"); println!(" All supported output stream formats:");
for (format_index, format) in output_formats.enumerate() { for (format_index, format) in output_formats.enumerate() {
println!(" {}.{}. {:?}", device_index + 1, format_index + 1, format); println!(
" {}.{}. {:?}",
device_index + 1,
format_index + 1,
format
);
} }
} }
} }

View File

@ -69,11 +69,14 @@ fn main() -> Result<(), anyhow::Error> {
Err(err) => { Err(err) => {
input_fell_behind = Some(err); input_fell_behind = Some(err);
0.0 0.0
}, }
}; };
} }
if let Some(err) = input_fell_behind { 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
);
} }
}; };

View File

@ -7,9 +7,9 @@ extern crate cpal;
extern crate hound; extern crate hound;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::sync::{Arc, Mutex};
use std::fs::File; use std::fs::File;
use std::io::BufWriter; use std::io::BufWriter;
use std::sync::{Arc, Mutex};
fn main() -> Result<(), anyhow::Error> { fn main() -> Result<(), anyhow::Error> {
// Use the default host for working with audio devices. // 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); eprintln!("an error occurred on stream: {}", err);
}; };
let data_fn = move |data: &cpal::Data| { let data_fn = move |data: &cpal::Data| match data.sample_format() {
match data.sample_format() { cpal::SampleFormat::F32 => write_input_data::<f32, f32>(data, &writer_2),
cpal::SampleFormat::F32 => write_input_data::<f32, f32>(data, &writer_2), cpal::SampleFormat::I16 => write_input_data::<i16, i16>(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),
cpal::SampleFormat::U16 => write_input_data::<u16, i16>(data, &writer_2),
}
}; };
let stream = device.build_input_stream(&format, data_fn, err_fn)?; let stream = device.build_input_stream(&format, data_fn, err_fn)?;

View File

@ -1,9 +1,9 @@
use {BackendSpecificError, DevicesError};
use super::Device;
use super::alsa; use super::alsa;
use super::check_errors; use super::check_errors;
use super::Device;
use std::ffi::CString; use std::ffi::CString;
use std::ptr; use std::ptr;
use {BackendSpecificError, DevicesError};
/// ALSA implementation for `Devices`. /// ALSA implementation for `Devices`.
pub struct Devices { pub struct Devices {
@ -36,10 +36,8 @@ impl Devices {
} }
} }
unsafe impl Send for Devices { unsafe impl Send for Devices {}
} unsafe impl Sync for Devices {}
unsafe impl Sync for Devices {
}
impl Drop for Devices { impl Drop for Devices {
#[inline] #[inline]
@ -61,8 +59,10 @@ impl Iterator for Devices {
} }
let name = { let name = {
let n_ptr = alsa::snd_device_name_get_hint(*self.next_str as *const _, let n_ptr = alsa::snd_device_name_get_hint(
b"NAME\0".as_ptr() as *const _); *self.next_str as *const _,
b"NAME\0".as_ptr() as *const _,
);
if !n_ptr.is_null() { if !n_ptr.is_null() {
let bytes = CString::from_raw(n_ptr).into_bytes(); let bytes = CString::from_raw(n_ptr).into_bytes();
let string = String::from_utf8(bytes).unwrap(); let string = String::from_utf8(bytes).unwrap();
@ -73,8 +73,10 @@ impl Iterator for Devices {
}; };
let io = { let io = {
let n_ptr = alsa::snd_device_name_get_hint(*self.next_str as *const _, let n_ptr = alsa::snd_device_name_get_hint(
b"IOID\0".as_ptr() as *const _); *self.next_str as *const _,
b"IOID\0".as_ptr() as *const _,
);
if !n_ptr.is_null() { if !n_ptr.is_null() {
let bytes = CString::from_raw(n_ptr).into_bytes(); let bytes = CString::from_raw(n_ptr).into_bytes();
let string = String::from_utf8(bytes).unwrap(); let string = String::from_utf8(bytes).unwrap();
@ -99,7 +101,7 @@ impl Iterator for Devices {
continue; continue;
} }
name name
}, }
_ => continue, _ => continue,
}; };

View File

@ -2,26 +2,14 @@ extern crate alsa_sys as alsa;
extern crate libc; extern crate libc;
use crate::{ use crate::{
BackendSpecificError, BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultFormatError,
BuildStreamError, DeviceNameError, DevicesError, Format, PauseStreamError, PlayStreamError, SampleFormat,
ChannelCount, SampleRate, StreamError, SupportedFormat, SupportedFormatsError,
Data,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
PauseStreamError,
PlayStreamError,
SampleFormat,
SampleRate,
StreamError,
SupportedFormat,
SupportedFormatsError,
}; };
use std::{cmp, ffi, io, ptr};
use std::sync::Arc; use std::sync::Arc;
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
use std::vec::IntoIter as VecIntoIter; use std::vec::IntoIter as VecIntoIter;
use std::{cmp, ffi, io, ptr};
use traits::{DeviceTrait, HostTrait, StreamTrait}; use traits::{DeviceTrait, HostTrait, StreamTrait};
pub use self::enumerate::{default_input_device, default_output_device, Devices}; pub use self::enumerate::{default_input_device, default_output_device, Devices};
@ -72,11 +60,15 @@ impl DeviceTrait for Device {
Device::name(self) 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) 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) Device::supported_output_formats(self)
} }
@ -119,7 +111,6 @@ impl DeviceTrait for Device {
} }
} }
struct TriggerSender(libc::c_int); struct TriggerSender(libc::c_int);
struct TriggerReceiver(libc::c_int); struct TriggerReceiver(libc::c_int);
@ -247,8 +238,7 @@ impl Device {
unsafe fn supported_formats( unsafe fn supported_formats(
&self, &self,
stream_t: alsa::snd_pcm_stream_t, stream_t: alsa::snd_pcm_stream_t,
) -> Result<VecIntoIter<SupportedFormat>, SupportedFormatsError> ) -> Result<VecIntoIter<SupportedFormat>, SupportedFormatsError> {
{
let mut handle = ptr::null_mut(); let mut handle = ptr::null_mut();
let device_name = match ffi::CString::new(&self.0[..]) { let device_name = match ffi::CString::new(&self.0[..]) {
Ok(name) => name, Ok(name) => name,
@ -284,53 +274,50 @@ impl Device {
}; };
// TODO: check endianess // TODO: check endianess
const FORMATS: [(SampleFormat, alsa::snd_pcm_format_t); 3] = const FORMATS: [(SampleFormat, alsa::snd_pcm_format_t); 3] = [
[ //SND_PCM_FORMAT_S8,
//SND_PCM_FORMAT_S8, //SND_PCM_FORMAT_U8,
//SND_PCM_FORMAT_U8, (SampleFormat::I16, alsa::SND_PCM_FORMAT_S16_LE),
(SampleFormat::I16, alsa::SND_PCM_FORMAT_S16_LE), //SND_PCM_FORMAT_S16_BE,
//SND_PCM_FORMAT_S16_BE, (SampleFormat::U16, alsa::SND_PCM_FORMAT_U16_LE),
(SampleFormat::U16, alsa::SND_PCM_FORMAT_U16_LE), //SND_PCM_FORMAT_U16_BE,
//SND_PCM_FORMAT_U16_BE, //SND_PCM_FORMAT_S24_LE,
/*SND_PCM_FORMAT_S24_LE, //SND_PCM_FORMAT_S24_BE,
SND_PCM_FORMAT_S24_BE, //SND_PCM_FORMAT_U24_LE,
SND_PCM_FORMAT_U24_LE, //SND_PCM_FORMAT_U24_BE,
SND_PCM_FORMAT_U24_BE, //SND_PCM_FORMAT_S32_LE,
SND_PCM_FORMAT_S32_LE, //SND_PCM_FORMAT_S32_BE,
SND_PCM_FORMAT_S32_BE, //SND_PCM_FORMAT_U32_LE,
SND_PCM_FORMAT_U32_LE, //SND_PCM_FORMAT_U32_BE,
SND_PCM_FORMAT_U32_BE,*/ (SampleFormat::F32, alsa::SND_PCM_FORMAT_FLOAT_LE),
(SampleFormat::F32, alsa::SND_PCM_FORMAT_FLOAT_LE) /*SND_PCM_FORMAT_FLOAT_BE, //SND_PCM_FORMAT_FLOAT_BE,
SND_PCM_FORMAT_FLOAT64_LE, //SND_PCM_FORMAT_FLOAT64_LE,
SND_PCM_FORMAT_FLOAT64_BE, //SND_PCM_FORMAT_FLOAT64_BE,
SND_PCM_FORMAT_IEC958_SUBFRAME_LE, //SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
SND_PCM_FORMAT_IEC958_SUBFRAME_BE, //SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
SND_PCM_FORMAT_MU_LAW, //SND_PCM_FORMAT_MU_LAW,
SND_PCM_FORMAT_A_LAW, //SND_PCM_FORMAT_A_LAW,
SND_PCM_FORMAT_IMA_ADPCM, //SND_PCM_FORMAT_IMA_ADPCM,
SND_PCM_FORMAT_MPEG, //SND_PCM_FORMAT_MPEG,
SND_PCM_FORMAT_GSM, //SND_PCM_FORMAT_GSM,
SND_PCM_FORMAT_SPECIAL, //SND_PCM_FORMAT_SPECIAL,
SND_PCM_FORMAT_S24_3LE, //SND_PCM_FORMAT_S24_3LE,
SND_PCM_FORMAT_S24_3BE, //SND_PCM_FORMAT_S24_3BE,
SND_PCM_FORMAT_U24_3LE, //SND_PCM_FORMAT_U24_3LE,
SND_PCM_FORMAT_U24_3BE, //SND_PCM_FORMAT_U24_3BE,
SND_PCM_FORMAT_S20_3LE, //SND_PCM_FORMAT_S20_3LE,
SND_PCM_FORMAT_S20_3BE, //SND_PCM_FORMAT_S20_3BE,
SND_PCM_FORMAT_U20_3LE, //SND_PCM_FORMAT_U20_3LE,
SND_PCM_FORMAT_U20_3BE, //SND_PCM_FORMAT_U20_3BE,
SND_PCM_FORMAT_S18_3LE, //SND_PCM_FORMAT_S18_3LE,
SND_PCM_FORMAT_S18_3BE, //SND_PCM_FORMAT_S18_3BE,
SND_PCM_FORMAT_U18_3LE, //SND_PCM_FORMAT_U18_3LE,
SND_PCM_FORMAT_U18_3BE,*/, //SND_PCM_FORMAT_U18_3BE,
]; ];
let mut supported_formats = Vec::new(); let mut supported_formats = Vec::new();
for &(sample_format, alsa_format) in FORMATS.iter() { for &(sample_format, alsa_format) in FORMATS.iter() {
if alsa::snd_pcm_hw_params_test_format(handle, if alsa::snd_pcm_hw_params_test_format(handle, hw_params.0, alsa_format) == 0 {
hw_params.0,
alsa_format) == 0
{
supported_formats.push(sample_format); supported_formats.push(sample_format);
} }
} }
@ -357,34 +344,19 @@ impl Device {
return Err(err.into()); return Err(err.into());
} }
let sample_rates = if min_rate == max_rate || let sample_rates = if min_rate == max_rate
alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, min_rate + 1, 0) == 0 || alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, min_rate + 1, 0) == 0
{ {
vec![(min_rate, max_rate)] vec![(min_rate, max_rate)]
} else { } else {
const RATES: [libc::c_uint; 13] = [ const RATES: [libc::c_uint; 13] = [
5512, 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400,
8000,
11025,
16000,
22050,
32000,
44100,
48000,
64000,
88200,
96000,
176400,
192000, 192000,
]; ];
let mut rates = Vec::new(); let mut rates = Vec::new();
for &rate in RATES.iter() { for &rate in RATES.iter() {
if alsa::snd_pcm_hw_params_test_rate(handle, if alsa::snd_pcm_hw_params_test_rate(handle, hw_params.0, rate, 0) == 0 {
hw_params.0,
rate,
0) == 0
{
rates.push((rate, rate)); rates.push((rate, rate));
} }
} }
@ -397,44 +369,48 @@ impl Device {
}; };
let mut min_channels = 0; 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 description = format!("unable to get minimum supported channel count: {}", desc);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
} }
let mut max_channels = 0; 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 description = format!("unable to get maximum supported channel count: {}", desc);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
} }
let max_channels = cmp::min(max_channels, 32); // TODO: limiting to 32 channels or too much stuff is returned 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) let supported_channels = (min_channels..max_channels + 1)
.filter_map(|num| if alsa::snd_pcm_hw_params_test_channels( .filter_map(|num| {
handle, if alsa::snd_pcm_hw_params_test_channels(handle, hw_params.0, num) == 0 {
hw_params.0, Some(num as ChannelCount)
num, } else {
) == 0 None
{ }
Some(num as ChannelCount)
} else {
None
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut output = Vec::with_capacity(supported_formats.len() * supported_channels.len() * let mut output = Vec::with_capacity(
sample_rates.len()); supported_formats.len() * supported_channels.len() * sample_rates.len(),
);
for &data_type in supported_formats.iter() { for &data_type in supported_formats.iter() {
for channels in supported_channels.iter() { for channels in supported_channels.iter() {
for &(min_rate, max_rate) in sample_rates.iter() { for &(min_rate, max_rate) in sample_rates.iter() {
output.push(SupportedFormat { output.push(SupportedFormat {
channels: channels.clone(), channels: channels.clone(),
min_sample_rate: SampleRate(min_rate as u32), min_sample_rate: SampleRate(min_rate as u32),
max_sample_rate: SampleRate(max_rate as u32), max_sample_rate: SampleRate(max_rate as u32),
data_type: data_type, data_type: data_type,
}); });
} }
} }
} }
@ -445,15 +421,11 @@ impl Device {
} }
fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> { fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
unsafe { unsafe { self.supported_formats(alsa::SND_PCM_STREAM_CAPTURE) }
self.supported_formats(alsa::SND_PCM_STREAM_CAPTURE)
}
} }
fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> { fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> {
unsafe { unsafe { self.supported_formats(alsa::SND_PCM_STREAM_PLAYBACK) }
self.supported_formats(alsa::SND_PCM_STREAM_PLAYBACK)
}
} }
// ALSA does not offer default stream formats, so instead we compare all supported formats by // ALSA does not offer default stream formats, so instead we compare all supported formats by
@ -461,13 +433,12 @@ impl Device {
fn default_format( fn default_format(
&self, &self,
stream_t: alsa::snd_pcm_stream_t, stream_t: alsa::snd_pcm_stream_t,
) -> Result<Format, DefaultFormatError> ) -> Result<Format, DefaultFormatError> {
{
let mut formats: Vec<_> = unsafe { let mut formats: Vec<_> = unsafe {
match self.supported_formats(stream_t) { match self.supported_formats(stream_t) {
Err(SupportedFormatsError::DeviceNotAvailable) => { Err(SupportedFormatsError::DeviceNotAvailable) => {
return Err(DefaultFormatError::DeviceNotAvailable); return Err(DefaultFormatError::DeviceNotAvailable);
}, }
Err(SupportedFormatsError::InvalidArgument) => { Err(SupportedFormatsError::InvalidArgument) => {
// this happens sometimes when querying for input and output capabilities but // this happens sometimes when querying for input and output capabilities but
// the device supports only one // the device supports only one
@ -492,8 +463,8 @@ impl Device {
format.sample_rate = HZ_44100; format.sample_rate = HZ_44100;
} }
Ok(format) Ok(format)
}, }
None => Err(DefaultFormatError::StreamTypeNotSupported) None => Err(DefaultFormatError::StreamTypeNotSupported),
} }
} }
@ -536,7 +507,10 @@ unsafe impl Send for StreamInner {}
unsafe impl Sync for StreamInner {} unsafe impl Sync for StreamInner {}
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
enum StreamType { Input, Output } enum StreamType {
Input,
Output,
}
pub struct Stream { pub struct Stream {
/// The high-priority audio processing thread calling callbacks. /// The high-priority audio processing thread calling callbacks.
@ -567,7 +541,10 @@ fn input_stream_worker(
match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) { match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) {
PollDescriptorsFlow::Continue => continue, PollDescriptorsFlow::Continue => continue,
PollDescriptorsFlow::Return => return, PollDescriptorsFlow::Return => return,
PollDescriptorsFlow::Ready { available_frames, stream_type } => { PollDescriptorsFlow::Ready {
available_frames,
stream_type,
} => {
assert_eq!( assert_eq!(
stream_type, stream_type,
StreamType::Input, StreamType::Input,
@ -596,7 +573,10 @@ fn output_stream_worker(
match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) { match poll_descriptors_and_prepare_buffer(&rx, stream, &mut ctxt, error_callback) {
PollDescriptorsFlow::Continue => continue, PollDescriptorsFlow::Continue => continue,
PollDescriptorsFlow::Return => return, PollDescriptorsFlow::Return => return,
PollDescriptorsFlow::Ready { available_frames, stream_type } => { PollDescriptorsFlow::Ready {
available_frames,
stream_type,
} => {
assert_eq!( assert_eq!(
stream_type, stream_type,
StreamType::Output, StreamType::Output,
@ -620,7 +600,7 @@ enum PollDescriptorsFlow {
Ready { Ready {
stream_type: StreamType, stream_type: StreamType,
available_frames: usize, available_frames: usize,
} },
} }
// This block is shared between both input and output stream worker functions. // This block is shared between both input and output stream worker functions.
@ -661,7 +641,11 @@ fn poll_descriptors_and_prepare_buffer(
let res = unsafe { let res = unsafe {
// Don't timeout, wait forever. // 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 { if res < 0 {
let description = format!("`libc::poll()` failed: {}", io::Error::last_os_error()); let description = format!("`libc::poll()` failed: {}", io::Error::last_os_error());
@ -684,7 +668,7 @@ fn poll_descriptors_and_prepare_buffer(
Ok(None) => { Ok(None) => {
// Nothing to process, poll again // Nothing to process, poll again
return PollDescriptorsFlow::Continue; return PollDescriptorsFlow::Continue;
}, }
Err(err) => { Err(err) => {
error_callback(err.into()); error_callback(err.into());
return PollDescriptorsFlow::Continue; return PollDescriptorsFlow::Continue;
@ -739,9 +723,7 @@ fn process_input(
let sample_format = stream.sample_format; let sample_format = stream.sample_format;
let data = buffer.as_mut_ptr() as *mut (); let data = buffer.as_mut_ptr() as *mut ();
let len = buffer.len() / sample_format.sample_size(); let len = buffer.len() / sample_format.sample_size();
let data = unsafe { let data = unsafe { Data::from_parts(data, len, sample_format) };
Data::from_parts(data, len, sample_format)
};
data_callback(&data); data_callback(&data);
} }
@ -760,9 +742,7 @@ fn process_output(
let sample_format = stream.sample_format; let sample_format = stream.sample_format;
let data = buffer.as_mut_ptr() as *mut (); let data = buffer.as_mut_ptr() as *mut ();
let len = buffer.len() / sample_format.sample_size(); let len = buffer.len() / sample_format.sample_size();
let mut data = unsafe { let mut data = unsafe { Data::from_parts(data, len, sample_format) };
Data::from_parts(data, len, sample_format)
};
data_callback(&mut data); data_callback(&mut data);
} }
loop { loop {
@ -784,9 +764,8 @@ fn process_output(
} else if result as usize != available_frames { } else if result as usize != available_frames {
let description = format!( let description = format!(
"unexpected number of frames written: expected {}, \ "unexpected number of frames written: expected {}, \
result {} (this should never happen)", result {} (this should never happen)",
available_frames, available_frames, result,
result,
); );
error_callback(BackendSpecificError { description }.into()); error_callback(BackendSpecificError { description }.into());
continue; continue;
@ -857,7 +836,7 @@ impl StreamTrait for Stream {
// TODO: error handling // TODO: error handling
Ok(()) Ok(())
} }
fn pause(&self)-> Result<(), PauseStreamError> { fn pause(&self) -> Result<(), PauseStreamError> {
unsafe { unsafe {
alsa::snd_pcm_pause(self.inner.channel, 1); alsa::snd_pcm_pause(self.inner.channel, 1);
} }
@ -888,8 +867,7 @@ fn check_for_pollout_or_pollin(
(revent, res) (revent, res)
}; };
if let Err(desc) = check_errors(res) { if let Err(desc) = check_errors(res) {
let description = let description = format!("`snd_pcm_poll_descriptors_revents` failed: {}", desc);
format!("`snd_pcm_poll_descriptors_revents` failed: {}",desc);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err); return Err(err);
} }
@ -905,9 +883,7 @@ fn check_for_pollout_or_pollin(
// Determine the number of samples that are available to read/write. // Determine the number of samples that are available to read/write.
fn get_available_samples(stream: &StreamInner) -> Result<usize, BackendSpecificError> { fn get_available_samples(stream: &StreamInner) -> Result<usize, BackendSpecificError> {
let available = unsafe { let available = unsafe { alsa::snd_pcm_avail_update(stream.channel) };
alsa::snd_pcm_avail_update(stream.channel)
};
if available == -32 { if available == -32 {
// buffer underrun // buffer underrun
// TODO: Notify the user some how. // TODO: Notify the user some how.
@ -929,9 +905,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)) { 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));
} }
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(pcm_handle, if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(
hw_params.0, pcm_handle,
alsa::SND_PCM_ACCESS_RW_INTERLEAVED)) { hw_params.0,
alsa::SND_PCM_ACCESS_RW_INTERLEAVED,
)) {
return Err(format!("handle not acessible: {}", e)); return Err(format!("handle not acessible: {}", e));
} }
@ -949,21 +927,26 @@ unsafe fn set_hw_params_from_format(
} }
}; };
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(pcm_handle, if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(
hw_params.0, pcm_handle,
data_type)) { hw_params.0,
data_type,
)) {
return Err(format!("format could not be set: {}", e)); return Err(format!("format could not be set: {}", e));
} }
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(pcm_handle, if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(
hw_params.0, pcm_handle,
format.sample_rate.0 as libc::c_uint, hw_params.0,
0)) { format.sample_rate.0 as libc::c_uint,
0,
)) {
return Err(format!("sample rate could not be set: {}", e)); 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, if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(
hw_params.0, pcm_handle,
format.channels as hw_params.0,
libc::c_uint)) { format.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));
} }
@ -987,8 +970,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: &Format, format: &Format,
) -> 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)) {
return Err(format!("snd_pcm_sw_params_malloc failed: {}", e)); return Err(format!("snd_pcm_sw_params_malloc failed: {}", e));
@ -996,20 +978,31 @@ unsafe fn set_sw_params_from_format(
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_current(pcm_handle, sw_params)) { 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)); 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)) { if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_start_threshold(
return Err(format!("snd_pcm_sw_params_set_start_threshold failed: {}", e)); pcm_handle, sw_params, 0,
)) {
return Err(format!(
"snd_pcm_sw_params_set_start_threshold failed: {}",
e
));
} }
let (buffer_len, period_len) = { let (buffer_len, period_len) = {
let mut buffer = 0; let mut buffer = 0;
let mut period = 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)); return Err(format!("failed to initialize buffer: {}", e));
} }
if buffer == 0 { if buffer == 0 {
return Err(format!("initialization resulted in a null buffer")); 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)); 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 * format.channels as usize;

View File

@ -2,8 +2,10 @@ use std;
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
pub type SupportedOutputFormats = 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::hash::{Hash, Hasher};
use std::sync::{Arc}; use std::sync::Arc;
use BackendSpecificError; use BackendSpecificError;
use DefaultFormatError; use DefaultFormatError;
use DeviceNameError; use DeviceNameError;
@ -13,8 +15,6 @@ use SampleFormat;
use SampleRate; use SampleRate;
use SupportedFormat; use SupportedFormat;
use SupportedFormatsError; use SupportedFormatsError;
use super::sys;
use super::parking_lot::Mutex;
/// A ASIO Device /// A ASIO Device
pub struct Device { pub struct Device {
@ -55,9 +55,7 @@ impl Device {
/// Gets the supported input formats. /// Gets the supported input formats.
/// TODO currently only supports the default. /// TODO currently only supports the default.
/// Need to find all possible formats. /// Need to find all possible formats.
pub fn supported_input_formats( pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> {
&self,
) -> Result<SupportedInputFormats, SupportedFormatsError> {
// Retrieve the default format for the total supported channels and supported sample // Retrieve the default format for the total supported channels and supported sample
// format. // format.
let mut f = match self.default_input_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. // Collect a format for every combination of supported sample rate and number of channels.
let mut supported_formats = vec![]; let mut supported_formats = vec![];
for &rate in ::COMMON_SAMPLE_RATES { 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; continue;
} }
for channels in 1..f.channels + 1 { 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. // Collect a format for every combination of supported sample rate and number of channels.
let mut supported_formats = vec![]; let mut supported_formats = vec![];
for &rate in ::COMMON_SAMPLE_RATES { 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; continue;
} }
for channels in 1..f.channels + 1 { 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 _); let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _);
// Map th ASIO sample type to a CPAL sample type // 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 = self.driver.input_data_type().map_err(default_format_err)?;
let data_type = convert_data_type(&data_type) let data_type =
.ok_or(DefaultFormatError::StreamTypeNotSupported)?; convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?;
Ok(Format { Ok(Format {
channels, channels,
sample_rate, sample_rate,
@ -128,8 +136,8 @@ impl Device {
let channels = self.driver.channels().map_err(default_format_err)?.outs as u16; 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 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 = self.driver.output_data_type().map_err(default_format_err)?;
let data_type = convert_data_type(&data_type) let data_type =
.ok_or(DefaultFormatError::StreamTypeNotSupported)?; convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?;
Ok(Format { Ok(Format {
channels, channels,
sample_rate, sample_rate,
@ -159,10 +167,13 @@ impl Iterator for Devices {
input: None, input: None,
output: None, output: None,
})); }));
return Some(Device { driver, asio_streams }); return Some(Device {
driver,
asio_streams,
});
} }
Err(_) => continue, Err(_) => continue,
} },
None => return None, 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 { fn default_format_err(e: sys::AsioError) -> DefaultFormatError {
match e { match e {
sys::AsioError::NoDrivers | sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => {
sys::AsioError::HardwareMalfunction => DefaultFormatError::DeviceNotAvailable, DefaultFormatError::DeviceNotAvailable
}
sys::AsioError::NoRate => DefaultFormatError::StreamTypeNotSupported, sys::AsioError::NoRate => DefaultFormatError::StreamTypeNotSupported,
err => { err => {
let description = format!("{}", err); let description = format!("{}", err);

View File

@ -2,22 +2,10 @@ extern crate asio_sys as sys;
extern crate parking_lot; extern crate parking_lot;
use crate::{ use crate::{
BuildStreamError, BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
Data, PauseStreamError, PlayStreamError, StreamError, SupportedFormatsError,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
PauseStreamError,
PlayStreamError,
StreamError,
SupportedFormatsError,
};
use traits::{
DeviceTrait,
HostTrait,
StreamTrait,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait};
pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats}; pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats};
pub use self::stream::Stream; pub use self::stream::Stream;
@ -73,11 +61,15 @@ impl DeviceTrait for Device {
Device::name(self) 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) 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) Device::supported_output_formats(self)
} }
@ -97,7 +89,7 @@ impl DeviceTrait for Device {
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(&Data) + Send + 'static, 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) Device::build_input_stream(self, format, data_callback, error_callback)
} }
@ -110,7 +102,7 @@ impl DeviceTrait for Device {
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
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(self, format, data_callback, error_callback) Device::build_output_stream(self, format, data_callback, error_callback)
} }

View File

@ -2,11 +2,11 @@ extern crate asio_sys as sys;
extern crate num_traits; extern crate num_traits;
use self::num_traits::PrimInt; use self::num_traits::PrimInt;
use super::parking_lot::Mutex;
use super::Device; use super::Device;
use std; use std;
use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use super::parking_lot::Mutex;
use BackendSpecificError; use BackendSpecificError;
use BuildStreamError; use BuildStreamError;
use Data; use Data;
@ -93,7 +93,7 @@ impl Device {
let callback_id = self.driver.add_callback(move |buffer_index| unsafe { let callback_id = self.driver.add_callback(move |buffer_index| unsafe {
// If not playing return early. // If not playing return early.
if !playing.load(Ordering::SeqCst) { if !playing.load(Ordering::SeqCst) {
return return;
} }
// There is 0% chance of lock contention the host only locks when recreating streams. // There is 0% chance of lock contention the host only locks when recreating streams.
@ -111,8 +111,7 @@ impl Device {
asio_stream: &sys::AsioStream, asio_stream: &sys::AsioStream,
buffer_index: usize, buffer_index: usize,
from_endianness: F, from_endianness: F,
) ) where
where
A: AsioSample, A: AsioSample,
B: Sample, B: Sample,
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data) + Send + 'static,
@ -157,8 +156,8 @@ impl Device {
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt` // 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. // trait for the `to_le` and `to_be` methods, but this does not support floats.
(&sys::AsioSampleType::ASIOSTFloat32LSB, SampleFormat::F32) | (&sys::AsioSampleType::ASIOSTFloat32LSB, SampleFormat::F32)
(&sys::AsioSampleType::ASIOSTFloat32MSB, SampleFormat::F32) => { | (&sys::AsioSampleType::ASIOSTFloat32MSB, SampleFormat::F32) => {
process_input_callback::<f32, f32, _, _>( process_input_callback::<f32, f32, _, _>(
&mut data_callback, &mut data_callback,
&mut interleaved, &mut interleaved,
@ -191,8 +190,8 @@ impl Device {
} }
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt` // 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. // trait for the `to_le` and `to_be` methods, but this does not support floats.
(&sys::AsioSampleType::ASIOSTFloat64LSB, SampleFormat::F32) | (&sys::AsioSampleType::ASIOSTFloat64LSB, SampleFormat::F32)
(&sys::AsioSampleType::ASIOSTFloat64MSB, SampleFormat::F32) => { | (&sys::AsioSampleType::ASIOSTFloat64MSB, SampleFormat::F32) => {
process_input_callback::<f64, f32, _, _>( process_input_callback::<f64, f32, _, _>(
&mut data_callback, &mut data_callback,
&mut interleaved, &mut interleaved,
@ -202,10 +201,11 @@ impl Device {
); );
} }
unsupported_format_pair => { unsupported_format_pair => unreachable!(
unreachable!("`build_input_stream` should have returned with unsupported \ "`build_input_stream` should have returned with unsupported \
format {:?}", unsupported_format_pair) format {:?}",
} unsupported_format_pair
),
} }
}); });
@ -258,7 +258,7 @@ impl Device {
let callback_id = self.driver.add_callback(move |buffer_index| unsafe { let callback_id = self.driver.add_callback(move |buffer_index| unsafe {
// If not playing, return early. // If not playing, return early.
if !playing.load(Ordering::SeqCst) { if !playing.load(Ordering::SeqCst) {
return return;
} }
// There is 0% chance of lock contention the host only locks when recreating streams. // There is 0% chance of lock contention the host only locks when recreating streams.
@ -301,8 +301,7 @@ impl Device {
asio_stream: &sys::AsioStream, asio_stream: &sys::AsioStream,
buffer_index: usize, buffer_index: usize,
to_endianness: F, to_endianness: F,
) ) where
where
A: Sample, A: Sample,
B: AsioSample, B: AsioSample,
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data) + Send + 'static,
@ -321,7 +320,9 @@ impl Device {
for ch_ix in 0..n_channels { for ch_ix in 0..n_channels {
let asio_channel = let asio_channel =
asio_channel_slice_mut::<B>(asio_stream, buffer_index, ch_ix); 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` // 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. // trait for the `to_le` and `to_be` methods, but this does not support floats.
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32LSB) | (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32LSB)
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32MSB) => { | (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat32MSB) => {
process_output_callback::<f32, f32, _, _>( process_output_callback::<f32, f32, _, _>(
&mut data_callback, &mut data_callback,
&mut interleaved, &mut interleaved,
@ -396,8 +397,8 @@ impl Device {
} }
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt` // 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. // trait for the `to_le` and `to_be` methods, but this does not support floats.
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64LSB) | (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64LSB)
(SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64MSB) => { | (SampleFormat::F32, &sys::AsioSampleType::ASIOSTFloat64MSB) => {
process_output_callback::<f32, f64, _, _>( process_output_callback::<f32, f64, _, _>(
&mut data_callback, &mut data_callback,
&mut interleaved, &mut interleaved,
@ -408,10 +409,11 @@ impl Device {
); );
} }
unsupported_format_pair => { unsupported_format_pair => unreachable!(
unreachable!("`build_output_stream` should have returned with unsupported \ "`build_output_stream` should have returned with unsupported \
format {:?}", unsupported_format_pair) format {:?}",
} unsupported_format_pair
),
} }
}); });
@ -434,15 +436,12 @@ impl Device {
/// If there is no existing ASIO Input Stream it will be created. /// If there is no existing ASIO Input Stream it will be created.
/// ///
/// 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, format: &Format) -> Result<usize, BuildStreamError> {
&self,
format: &Format,
) -> Result<usize, BuildStreamError> {
match self.default_input_format() { match self.default_input_format() {
Ok(f) => { Ok(f) => {
let num_asio_channels = f.channels; let num_asio_channels = f.channels;
check_format(&self.driver, format, num_asio_channels) check_format(&self.driver, format, num_asio_channels)
}, }
Err(_) => Err(BuildStreamError::FormatNotSupported), Err(_) => Err(BuildStreamError::FormatNotSupported),
}?; }?;
let num_channels = format.channels as usize; let num_channels = format.channels as usize;
@ -462,7 +461,8 @@ impl Device {
}; };
*streams = new_streams; *streams = new_streams;
bs bs
}).map_err(|ref e| { })
.map_err(|ref e| {
println!("Error preparing stream: {}", e); println!("Error preparing stream: {}", e);
BuildStreamError::DeviceNotAvailable BuildStreamError::DeviceNotAvailable
}) })
@ -473,15 +473,12 @@ impl Device {
/// Create a new CPAL Output Stream. /// Create a new CPAL Output Stream.
/// ///
/// 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, format: &Format) -> Result<usize, BuildStreamError> {
&self,
format: &Format,
) -> Result<usize, BuildStreamError> {
match self.default_output_format() { match self.default_output_format() {
Ok(f) => { Ok(f) => {
let num_asio_channels = f.channels; let num_asio_channels = f.channels;
check_format(&self.driver, format, num_asio_channels) check_format(&self.driver, format, num_asio_channels)
}, }
Err(_) => Err(BuildStreamError::FormatNotSupported), Err(_) => Err(BuildStreamError::FormatNotSupported),
}?; }?;
let num_channels = format.channels as usize; let num_channels = format.channels as usize;
@ -501,7 +498,8 @@ impl Device {
}; };
*streams = new_streams; *streams = new_streams;
bs bs
}).map_err(|ref e| { })
.map_err(|ref e| {
println!("Error preparing stream: {}", e); println!("Error preparing stream: {}", e);
BuildStreamError::DeviceNotAvailable BuildStreamError::DeviceNotAvailable
}) })
@ -588,7 +586,10 @@ fn check_format(
// 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();
if sample_rate != driver.sample_rate().map_err(build_stream_err)? { 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 driver
.set_sample_rate(sample_rate) .set_sample_rate(sample_rate)
.map_err(build_stream_err)?; .map_err(build_stream_err)?;
@ -656,19 +657,17 @@ unsafe fn asio_channel_slice_mut<T>(
buffer_index: usize, buffer_index: usize,
channel_index: usize, channel_index: usize,
) -> &mut [T] { ) -> &mut [T] {
let buff_ptr: *mut T = asio_stream let buff_ptr: *mut T =
.buffer_infos[channel_index] asio_stream.buffer_infos[channel_index].buffers[buffer_index as usize] as *mut _;
.buffers[buffer_index as usize]
as *mut _;
std::slice::from_raw_parts_mut(buff_ptr, asio_stream.buffer_size as usize) std::slice::from_raw_parts_mut(buff_ptr, asio_stream.buffer_size as usize)
} }
fn build_stream_err(e: sys::AsioError) -> BuildStreamError { fn build_stream_err(e: sys::AsioError) -> BuildStreamError {
match e { match e {
sys::AsioError::NoDrivers | sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => {
sys::AsioError::HardwareMalfunction => BuildStreamError::DeviceNotAvailable, BuildStreamError::DeviceNotAvailable
sys::AsioError::InvalidInput | }
sys::AsioError::BadMode => BuildStreamError::InvalidArgument, sys::AsioError::InvalidInput | sys::AsioError::BadMode => BuildStreamError::InvalidArgument,
err => { err => {
let description = format!("{}", err); let description = format!("{}", err);
BackendSpecificError { description }.into() BackendSpecificError { description }.into()

View File

@ -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::mem;
use std::ptr::null; use std::ptr::null;
use std::vec::IntoIter as VecIntoIter; use std::vec::IntoIter as VecIntoIter;
use super::coreaudio::sys::{ use {BackendSpecificError, DevicesError, SupportedFormat};
AudioDeviceID,
AudioObjectPropertyAddress,
AudioObjectGetPropertyData,
AudioObjectGetPropertyDataSize,
kAudioHardwareNoError,
kAudioHardwarePropertyDefaultInputDevice,
kAudioHardwarePropertyDefaultOutputDevice,
kAudioHardwarePropertyDevices,
kAudioObjectPropertyElementMaster,
kAudioObjectPropertyScopeGlobal,
kAudioObjectSystemObject,
OSStatus,
};
use super::Device;
unsafe fn audio_devices() -> Result<Vec<AudioDeviceID>, OSStatus> { unsafe fn audio_devices() -> Result<Vec<AudioDeviceID>, OSStatus> {
let property_address = AudioObjectPropertyAddress { let property_address = AudioObjectPropertyAddress {
@ -80,15 +73,15 @@ impl Devices {
} }
} }
unsafe impl Send for Devices { unsafe impl Send for Devices {}
} unsafe impl Sync for Devices {}
unsafe impl Sync for Devices {
}
impl Iterator for Devices { impl Iterator for Devices {
type Item = Device; type Item = Device;
fn next(&mut self) -> Option<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,
})
} }
} }

View File

@ -1,67 +1,33 @@
extern crate coreaudio;
extern crate core_foundation_sys; extern crate core_foundation_sys;
extern crate coreaudio;
use crate::{ use self::core_foundation_sys::string::{CFStringGetCStringPtr, CFStringRef};
ChannelCount, use self::coreaudio::audio_unit::render_callback::{self, data};
BackendSpecificError, use self::coreaudio::audio_unit::{AudioUnit, Element, Scope};
BuildStreamError, use self::coreaudio::sys::{
Data, kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceNameCFString,
DefaultFormatError, kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput,
DeviceNameError, kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyStreamFormat,
DevicesError, kAudioFormatFlagIsFloat, kAudioFormatFlagIsPacked, kAudioFormatLinearPCM,
Format, kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal,
PauseStreamError, kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput,
PlayStreamError, kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO,
SampleFormat, kAudioUnitProperty_StreamFormat, kCFStringEncodingUTF8, AudioBuffer, AudioBufferList,
SampleRate, AudioDeviceID, AudioObjectAddPropertyListener, AudioObjectGetPropertyData,
StreamError, AudioObjectGetPropertyDataSize, AudioObjectID, AudioObjectPropertyAddress,
SupportedFormat, AudioObjectPropertyScope, AudioObjectRemovePropertyListener, AudioObjectSetPropertyData,
SupportedFormatsError, AudioStreamBasicDescription, AudioValueRange, OSStatus,
}; };
use crate::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
use self::coreaudio::audio_unit::{AudioUnit, Scope, Element}; use crate::{
use self::coreaudio::audio_unit::render_callback::{self, data}; BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultFormatError,
use self::coreaudio::sys::{ DeviceNameError, DevicesError, Format, PauseStreamError, PlayStreamError, SampleFormat,
AudioBuffer, SampleRate, StreamError, SupportedFormat, SupportedFormatsError,
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 std::cell::RefCell;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::mem; use std::mem;
use std::cell::RefCell;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::ptr::null; use std::ptr::null;
use std::slice; use std::slice;
@ -70,7 +36,10 @@ use std::time::Duration;
mod enumerate; 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. /// Coreaudio host, the default host on macOS and iOS.
#[derive(Debug)] #[derive(Debug)]
@ -107,17 +76,21 @@ impl HostTrait for Host {
impl DeviceTrait for Device { impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats; type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats; type SupportedOutputFormats = SupportedOutputFormats;
type Stream = Stream; type Stream = Stream;
fn name(&self) -> Result<String, DeviceNameError> { fn name(&self) -> Result<String, DeviceNameError> {
Device::name(self) 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) 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) Device::supported_output_formats(self)
} }
@ -196,8 +169,7 @@ impl Device {
fn supported_formats( fn supported_formats(
&self, &self,
scope: AudioObjectPropertyScope, scope: AudioObjectPropertyScope,
) -> Result<SupportedOutputFormats, SupportedFormatsError> ) -> Result<SupportedOutputFormats, SupportedFormatsError> {
{
let mut property_address = AudioObjectPropertyAddress { let mut property_address = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyStreamConfiguration, mSelector: kAudioDevicePropertyStreamConfiguration,
mScope: scope, mScope: scope,
@ -307,17 +279,18 @@ impl Device {
fn default_format( fn default_format(
&self, &self,
scope: AudioObjectPropertyScope, scope: AudioObjectPropertyScope,
) -> Result<Format, DefaultFormatError> ) -> Result<Format, DefaultFormatError> {
{
fn default_format_error_from_os_status(status: OSStatus) -> Result<(), DefaultFormatError> { fn default_format_error_from_os_status(status: OSStatus) -> Result<(), DefaultFormatError> {
let err = match coreaudio::Error::from_os_status(status) { let err = match coreaudio::Error::from_os_status(status) {
Err(err) => err, Err(err) => err,
Ok(_) => return Ok(()), Ok(_) => return Ok(()),
}; };
match err { match err {
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported) | coreaudio::Error::AudioUnit(
coreaudio::Error::AudioCodec(_) | coreaudio::error::AudioUnitError::FormatNotSupported,
coreaudio::Error::AudioFormat(_) => { )
| coreaudio::Error::AudioCodec(_)
| coreaudio::Error::AudioFormat(_) => {
Err(DefaultFormatError::StreamTypeNotSupported) Err(DefaultFormatError::StreamTypeNotSupported)
} }
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::NoConnection) => { coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::NoConnection) => {
@ -412,11 +385,11 @@ struct StreamInner {
impl From<coreaudio::Error> for BuildStreamError { impl From<coreaudio::Error> for BuildStreamError {
fn from(err: coreaudio::Error) -> BuildStreamError { fn from(err: coreaudio::Error) -> BuildStreamError {
match err { match err {
coreaudio::Error::RenderCallbackBufferFormatDoesNotMatchAudioUnitStreamFormat | coreaudio::Error::RenderCallbackBufferFormatDoesNotMatchAudioUnitStreamFormat
coreaudio::Error::NoKnownSubtype | | coreaudio::Error::NoKnownSubtype
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported) | | coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported)
coreaudio::Error::AudioCodec(_) | | coreaudio::Error::AudioCodec(_)
coreaudio::Error::AudioFormat(_) => BuildStreamError::FormatNotSupported, | coreaudio::Error::AudioFormat(_) => BuildStreamError::FormatNotSupported,
_ => BuildStreamError::DeviceNotAvailable, _ => BuildStreamError::DeviceNotAvailable,
} }
} }
@ -513,8 +486,8 @@ impl Device {
// Get the current sample rate. // Get the current sample rate.
let mut property_address = AudioObjectPropertyAddress { let mut property_address = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyNominalSampleRate, mSelector: kAudioDevicePropertyNominalSampleRate,
mScope: kAudioObjectPropertyScopeGlobal, mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster, mElement: kAudioObjectPropertyElementMaster,
}; };
let sample_rate: f64 = 0.0; let sample_rate: f64 = 0.0;
let data_size = mem::size_of::<f64>() as u32; 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. // Now that we have the available ranges, pick the one matching the desired rate.
let sample_rate = format.sample_rate.0; let sample_rate = format.sample_rate.0;
let maybe_index = ranges let maybe_index = ranges.iter().position(|r| {
.iter() r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate
.position(|r| r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate); });
let range_index = match maybe_index { let range_index = match maybe_index {
None => return Err(BuildStreamError::FormatNotSupported), None => return Err(BuildStreamError::FormatNotSupported),
Some(i) => i, Some(i) => i,
@ -583,8 +556,8 @@ impl Device {
let data_size = mem::size_of::<f64>(); let data_size = mem::size_of::<f64>();
let property_address = AudioObjectPropertyAddress { let property_address = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyNominalSampleRate, mSelector: kAudioDevicePropertyNominalSampleRate,
mScope: kAudioObjectPropertyScopeGlobal, mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster, mElement: kAudioObjectPropertyElementMaster,
}; };
AudioObjectGetPropertyData( AudioObjectGetPropertyData(
device_id, device_id,
@ -624,7 +597,8 @@ impl Device {
let timer = ::std::time::Instant::now(); let timer = ::std::time::Instant::now();
while sample_rate != reported_rate { while sample_rate != reported_rate {
if timer.elapsed() > Duration::from_secs(1) { 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 }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
} }
@ -662,7 +636,7 @@ impl Device {
let AudioBuffer { let AudioBuffer {
mNumberChannels: _num_channels, mNumberChannels: _num_channels,
mDataByteSize: data_byte_size, mDataByteSize: data_byte_size,
mData: data mData: data,
} = buffers[0]; } = buffers[0];
let data = data as *mut (); let data = data as *mut ();
@ -713,7 +687,7 @@ impl Device {
let AudioBuffer { let AudioBuffer {
mNumberChannels: _num_channels, mNumberChannels: _num_channels,
mDataByteSize: data_byte_size, mDataByteSize: data_byte_size,
mData: data mData: data,
} = (*args.data.data).mBuffers[0]; } = (*args.data.data).mBuffers[0];
let data = data as *mut (); let data = data as *mut ();

View File

@ -2,23 +2,14 @@ use std::mem;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::slice::from_raw_parts; use std::slice::from_raw_parts;
use stdweb; use stdweb;
use stdweb::Reference;
use stdweb::unstable::TryInto; use stdweb::unstable::TryInto;
use stdweb::web::TypedArray;
use stdweb::web::set_timeout; use stdweb::web::set_timeout;
use stdweb::web::TypedArray;
use stdweb::Reference;
use crate::{ use crate::{
BuildStreamError, BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
Data, PauseStreamError, PlayStreamError, SampleFormat, StreamError, SupportedFormat,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
PauseStreamError,
PlayStreamError,
SampleFormat,
StreamError,
SupportedFormat,
SupportedFormatsError, SupportedFormatsError,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; 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 // 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. // filter out those that lay outside the range specified above.
Ok( Ok(vec![SupportedFormat {
vec![ channels: 2,
SupportedFormat { min_sample_rate: ::SampleRate(44100),
channels: 2, max_sample_rate: ::SampleRate(44100),
min_sample_rate: ::SampleRate(44100), data_type: ::SampleFormat::F32,
max_sample_rate: ::SampleRate(44100), }]
data_type: ::SampleFormat::F32, .into_iter())
},
].into_iter(),
)
} }
fn default_input_format(&self) -> Result<Format, DefaultFormatError> { fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
@ -101,13 +89,11 @@ impl Device {
fn default_output_format(&self) -> Result<Format, DefaultFormatError> { fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
// TODO: because it is hard coded, see supported_output_formats. // TODO: because it is hard coded, see supported_output_formats.
Ok( Ok(Format {
Format { channels: 2,
channels: 2, sample_rate: ::SampleRate(44100),
sample_rate: ::SampleRate(44100), data_type: ::SampleFormat::F32,
data_type: ::SampleFormat::F32, })
},
)
} }
} }
@ -142,11 +128,15 @@ impl DeviceTrait for Device {
Device::name(self) 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) 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) 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 // See also: The call to `set_timeout` at the end of the `audio_callback_fn` which creates
// the loop. // 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) Ok(stream)
} }
@ -323,9 +316,10 @@ fn default_output_device() -> Option<Device> {
fn is_webaudio_available() -> bool { fn is_webaudio_available() -> bool {
stdweb::initialize(); stdweb::initialize();
js!(if (!AudioContext) { js!(if (!AudioContext) {
return false; return false;
} else { } else {
return true; return true;
}).try_into() })
.unwrap() .try_into()
.unwrap()
} }

View File

@ -1,15 +1,6 @@
use crate::{ use crate::{
BuildStreamError, BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
Data, PauseStreamError, PlayStreamError, StreamError, SupportedFormat, SupportedFormatsError,
DefaultFormatError,
DevicesError,
DeviceNameError,
Format,
PauseStreamError,
PlayStreamError,
StreamError,
SupportedFormatsError,
SupportedFormat,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; use traits::{DeviceTrait, HostTrait, StreamTrait};

View File

@ -1,15 +1,6 @@
use crate::{ use crate::{
BackendSpecificError, BackendSpecificError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
Data, SampleFormat, SampleRate, SupportedFormat, SupportedFormatsError, COMMON_SAMPLE_RATES,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
SampleFormat,
SampleRate,
SupportedFormat,
SupportedFormatsError,
COMMON_SAMPLE_RATES,
}; };
use std; use std;
use std::ffi::OsString; use std::ffi::OsString;
@ -115,7 +106,11 @@ impl DeviceTrait for Device {
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_input_stream_inner(format)?; 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>( fn build_output_stream<D, E>(
@ -129,7 +124,11 @@ impl DeviceTrait for Device {
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_output_stream_inner(format)?; 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. // Building a `IAudioCaptureClient` that will be used to read captured samples.
let capture_client = { let capture_client = {
let mut capture_client: *mut audioclient::IAudioCaptureClient = let mut capture_client: *mut audioclient::IAudioCaptureClient = ptr::null_mut();
ptr::null_mut();
let hresult = (*audio_client).GetService( let hresult = (*audio_client).GetService(
&audioclient::IID_IAudioCaptureClient, &audioclient::IID_IAudioCaptureClient,
&mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _, &mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _,

View File

@ -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::check_result;
use super::winapi::shared::basetsd::UINT32; use super::winapi::shared::basetsd::UINT32;
use super::winapi::shared::minwindef::{BYTE, FALSE, WORD}; 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::synchapi;
use super::winapi::um::winbase; use super::winapi::um::winbase;
use super::winapi::um::winnt; 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 { pub struct Stream {
/// The high-priority audio processing thread calling callbacks. /// The high-priority audio processing thread calling callbacks.
@ -295,7 +290,12 @@ fn run_input(
AudioClientFlow::Capture { capture_client } => capture_client, AudioClientFlow::Capture { capture_client } => capture_client,
_ => unreachable!(), _ => 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::Break => break,
ControlFlow::Continue => continue, ControlFlow::Continue => continue,
} }
@ -317,7 +317,12 @@ fn run_output(
AudioClientFlow::Render { render_client } => render_client, AudioClientFlow::Render { render_client } => render_client,
_ => unreachable!(), _ => 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::Break => break,
ControlFlow::Continue => continue, ControlFlow::Continue => continue,
} }
@ -401,8 +406,7 @@ fn process_input(
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let data = buffer as *mut (); let data = buffer as *mut ();
let len = frames_available as usize let len = frames_available as usize * stream.bytes_per_frame as usize
* stream.bytes_per_frame as usize
/ stream.sample_format.sample_size(); / stream.sample_format.sample_size();
let data = Data::from_parts(data, len, stream.sample_format); let data = Data::from_parts(data, len, stream.sample_format);
data_callback(&data); data_callback(&data);
@ -436,8 +440,7 @@ fn process_output(
unsafe { unsafe {
let mut buffer: *mut BYTE = ptr::null_mut(); let mut buffer: *mut BYTE = ptr::null_mut();
let hresult = let hresult = (*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
(*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
@ -447,8 +450,7 @@ fn process_output(
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let data = buffer as *mut (); let data = buffer as *mut ();
let len = frames_available as usize let len = frames_available as usize * stream.bytes_per_frame as usize
* stream.bytes_per_frame as usize
/ stream.sample_format.sample_size(); / stream.sample_format.sample_size();
let mut data = Data::from_parts(data, len, stream.sample_format); let mut data = Data::from_parts(data, len, stream.sample_format);
data_callback(&mut data); data_callback(&mut data);

View File

@ -149,8 +149,8 @@ extern crate thiserror;
pub use error::*; pub use error::*;
pub use platform::{ pub use platform::{
ALL_HOSTS, available_hosts, default_host, Device, Devices, Host, host_from_id, available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream,
HostId, Stream, SupportedInputFormats, SupportedOutputFormats, SupportedInputFormats, SupportedOutputFormats, ALL_HOSTS,
}; };
pub use samples_formats::{Sample, SampleFormat}; pub use samples_formats::{Sample, SampleFormat};
@ -218,7 +218,11 @@ impl Data {
len: usize, len: usize,
sample_format: SampleFormat, sample_format: SampleFormat,
) -> Self { ) -> Self {
Data { data, len, sample_format } Data {
data,
len,
sample_format,
}
} }
/// The sample format of the internal audio data. /// The sample format of the internal audio data.
@ -241,9 +245,7 @@ impl Data {
let len = self.len * self.sample_format.sample_size(); let len = self.len * self.sample_format.sample_size();
// The safety of this block relies on correct construction of the `Data` instance. See // The safety of this block relies on correct construction of the `Data` instance. See
// the unsafe `from_parts` constructor for these requirements. // the unsafe `from_parts` constructor for these requirements.
unsafe { unsafe { std::slice::from_raw_parts(self.data as *const u8, len) }
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. /// 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(); let len = self.len * self.sample_format.sample_size();
// The safety of this block relies on correct construction of the `Data` instance. See // The safety of this block relies on correct construction of the `Data` instance. See
// the unsafe `from_parts` constructor for these requirements. // the unsafe `from_parts` constructor for these requirements.
unsafe { unsafe { std::slice::from_raw_parts_mut(self.data as *mut u8, len) }
std::slice::from_raw_parts_mut(self.data as *mut u8, len)
}
} }
/// Access the data as a slice of sample type `T`. /// Access the data as a slice of sample type `T`.
@ -268,9 +268,7 @@ impl Data {
if T::FORMAT == self.sample_format { if T::FORMAT == self.sample_format {
// The safety of this block relies on correct construction of the `Data` instance. See // The safety of this block relies on correct construction of the `Data` instance. See
// the unsafe `from_parts` constructor for these requirements. // the unsafe `from_parts` constructor for these requirements.
unsafe { unsafe { Some(std::slice::from_raw_parts(self.data as *const T, self.len)) }
Some(std::slice::from_raw_parts(self.data as *const T, self.len))
}
} else { } else {
None None
} }
@ -287,7 +285,10 @@ impl Data {
// The safety of this block relies on correct construction of the `Data` instance. See // The safety of this block relies on correct construction of the `Data` instance. See
// the unsafe `from_parts` constructor for these requirements. // the unsafe `from_parts` constructor for these requirements.
unsafe { 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 { } else {
None None
@ -365,10 +366,9 @@ impl SupportedFormat {
} }
const HZ_44100: SampleRate = SampleRate(44_100); const HZ_44100: SampleRate = SampleRate(44_100);
let r44100_in_self = self.min_sample_rate <= HZ_44100 let r44100_in_self = self.min_sample_rate <= HZ_44100 && HZ_44100 <= self.max_sample_rate;
&& HZ_44100 <= self.max_sample_rate; let r44100_in_other =
let r44100_in_other = other.min_sample_rate <= HZ_44100 other.min_sample_rate <= HZ_44100 && HZ_44100 <= other.max_sample_rate;
&& HZ_44100 <= other.max_sample_rate;
let cmp_r44100 = r44100_in_self.cmp(&r44100_in_other); let cmp_r44100 = r44100_in_self.cmp(&r44100_in_other);
if cmp_r44100 != Equal { if cmp_r44100 != Equal {
return cmp_r44100; return cmp_r44100;

View File

@ -435,10 +435,7 @@ macro_rules! impl_platform_host {
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))] #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))]
mod platform_impl { mod platform_impl {
pub use crate::host::alsa::{ pub use crate::host::alsa::{
Device as AlsaDevice, Device as AlsaDevice, Devices as AlsaDevices, Host as AlsaHost, Stream as AlsaStream,
Devices as AlsaDevices,
Host as AlsaHost,
Stream as AlsaStream,
SupportedInputFormats as AlsaSupportedInputFormats, SupportedInputFormats as AlsaSupportedInputFormats,
SupportedOutputFormats as AlsaSupportedOutputFormats, SupportedOutputFormats as AlsaSupportedOutputFormats,
}; };
@ -453,15 +450,11 @@ mod platform_impl {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
mod platform_impl { mod platform_impl {
pub use crate::host::coreaudio::{ pub use crate::host::coreaudio::{
Device as CoreAudioDevice, Device as CoreAudioDevice, Devices as CoreAudioDevices, Host as CoreAudioHost,
Devices as CoreAudioDevices, Stream as CoreAudioStream, SupportedInputFormats as CoreAudioSupportedInputFormats,
Host as CoreAudioHost,
Stream as CoreAudioStream,
SupportedInputFormats as CoreAudioSupportedInputFormats,
SupportedOutputFormats as CoreAudioSupportedOutputFormats, SupportedOutputFormats as CoreAudioSupportedOutputFormats,
}; };
@ -478,11 +471,8 @@ mod platform_impl {
#[cfg(target_os = "emscripten")] #[cfg(target_os = "emscripten")]
mod platform_impl { mod platform_impl {
pub use crate::host::emscripten::{ pub use crate::host::emscripten::{
Device as EmscriptenDevice, Device as EmscriptenDevice, Devices as EmscriptenDevices, Host as EmscriptenHost,
Devices as EmscriptenDevices, Stream as EmscriptenStream, SupportedInputFormats as EmscriptenSupportedInputFormats,
Host as EmscriptenHost,
Stream as EmscriptenStream,
SupportedInputFormats as EmscriptenSupportedInputFormats,
SupportedOutputFormats as EmscriptenSupportedOutputFormats, SupportedOutputFormats as EmscriptenSupportedOutputFormats,
}; };
@ -500,19 +490,13 @@ mod platform_impl {
mod platform_impl { mod platform_impl {
#[cfg(feature = "asio")] #[cfg(feature = "asio")]
pub use crate::host::asio::{ pub use crate::host::asio::{
Device as AsioDevice, Device as AsioDevice, Devices as AsioDevices, Host as AsioHost, Stream as AsioStream,
Devices as AsioDevices,
Stream as AsioStream,
Host as AsioHost,
SupportedInputFormats as AsioSupportedInputFormats, SupportedInputFormats as AsioSupportedInputFormats,
SupportedOutputFormats as AsioSupportedOutputFormats, SupportedOutputFormats as AsioSupportedOutputFormats,
}; };
pub use crate::host::wasapi::{ pub use crate::host::wasapi::{
Device as WasapiDevice, Device as WasapiDevice, Devices as WasapiDevices, Host as WasapiHost,
Devices as WasapiDevices, Stream as WasapiStream, SupportedInputFormats as WasapiSupportedInputFormats,
Stream as WasapiStream,
Host as WasapiHost,
SupportedInputFormats as WasapiSupportedInputFormats,
SupportedOutputFormats as WasapiSupportedOutputFormats, 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", #[cfg(not(any(
target_os = "ios", target_os = "emscripten")))] windows,
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
target_os = "ios",
target_os = "emscripten"
)))]
mod platform_impl { mod platform_impl {
pub use crate::host::null::{ pub use crate::host::null::{
Device as NullDevice, Device as NullDevice, Devices as NullDevices, EventLoop as NullEventLoop, Host as NullHost,
Devices as NullDevices, StreamId as NullStreamId, SupportedInputFormats as NullSupportedInputFormats,
EventLoop as NullEventLoop,
Host as NullHost,
StreamId as NullStreamId,
SupportedInputFormats as NullSupportedInputFormats,
SupportedOutputFormats as NullSupportedOutputFormats, SupportedOutputFormats as NullSupportedOutputFormats,
}; };

View File

@ -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`. /// Converts any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`.
fn from<S>(&S) -> Self fn from<S>(&S) -> Self
where S: Sample; where
S: Sample;
} }
unsafe impl Sample for u16 { unsafe impl Sample for u16 {
@ -64,7 +65,8 @@ unsafe impl Sample for u16 {
#[inline] #[inline]
fn from<S>(sample: &S) -> Self fn from<S>(sample: &S) -> Self
where S: Sample where
S: Sample,
{ {
sample.to_u16() sample.to_u16()
} }
@ -98,7 +100,8 @@ unsafe impl Sample for i16 {
#[inline] #[inline]
fn from<S>(sample: &S) -> Self fn from<S>(sample: &S) -> Self
where S: Sample where
S: Sample,
{ {
sample.to_i16() sample.to_i16()
} }
@ -128,7 +131,8 @@ unsafe impl Sample for f32 {
#[inline] #[inline]
fn from<S>(sample: &S) -> Self fn from<S>(sample: &S) -> Self
where S: Sample where
S: Sample,
{ {
sample.to_f32() sample.to_f32()
} }

View File

@ -1,18 +1,8 @@
//! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs. //! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs.
use { use {
BuildStreamError, BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format,
Data, InputDevices, OutputDevices, PauseStreamError, PlayStreamError, StreamError, SupportedFormat,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
InputDevices,
OutputDevices,
PauseStreamError,
PlayStreamError,
StreamError,
SupportedFormat,
SupportedFormatsError, SupportedFormatsError,
}; };
@ -65,7 +55,8 @@ pub trait HostTrait {
/// Can be empty if the system does not support audio input. /// Can be empty if the system does not support audio input.
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> { fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
fn supports_input<D: DeviceTrait>(device: &D) -> bool { fn supports_input<D: DeviceTrait>(device: &D) -> bool {
device.supported_input_formats() device
.supported_input_formats()
.map(|mut iter| iter.next().is_some()) .map(|mut iter| iter.next().is_some())
.unwrap_or(false) .unwrap_or(false)
} }
@ -78,7 +69,8 @@ pub trait HostTrait {
/// Can be empty if the system does not support audio output. /// Can be empty if the system does not support audio output.
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> { fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
fn supports_output<D: DeviceTrait>(device: &D) -> bool { fn supports_output<D: DeviceTrait>(device: &D) -> bool {
device.supported_output_formats() device
.supported_output_formats()
.map(|mut iter| iter.next().is_some()) .map(|mut iter| iter.next().is_some())
.unwrap_or(false) .unwrap_or(false)
} }
@ -104,12 +96,15 @@ pub trait DeviceTrait {
/// An iterator yielding formats that are supported by the backend. /// 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). /// 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. /// 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). /// 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. /// The default input stream format for the device.
fn default_input_format(&self) -> Result<Format, DefaultFormatError>; fn default_input_format(&self) -> Result<Format, DefaultFormatError>;