Run rustfmt on the code (#162)
This commit is contained in:
parent
cdcef96279
commit
2028d5907f
|
@ -0,0 +1,18 @@
|
||||||
|
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"
|
|
@ -20,12 +20,17 @@ impl Executor for MyExecutor {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let endpoint = cpal::default_endpoint().expect("Failed to get default endpoint");
|
let endpoint = cpal::default_endpoint().expect("Failed to get default endpoint");
|
||||||
let format = endpoint.supported_formats().unwrap().next().expect("Failed to get endpoint format");
|
let format = endpoint
|
||||||
|
.supported_formats()
|
||||||
|
.unwrap()
|
||||||
|
.next()
|
||||||
|
.expect("Failed to get endpoint format");
|
||||||
|
|
||||||
let event_loop = cpal::EventLoop::new();
|
let event_loop = cpal::EventLoop::new();
|
||||||
let executor = Arc::new(MyExecutor);
|
let executor = Arc::new(MyExecutor);
|
||||||
|
|
||||||
let (mut voice, stream) = cpal::Voice::new(&endpoint, &format, &event_loop).expect("Failed to create a voice");
|
let (mut voice, stream) = cpal::Voice::new(&endpoint, &format, &event_loop)
|
||||||
|
.expect("Failed to create a voice");
|
||||||
|
|
||||||
// Produce a sinusoid of maximum amplitude.
|
// Produce a sinusoid of maximum amplitude.
|
||||||
let samples_rate = format.samples_rate.0 as f32;
|
let samples_rate = format.samples_rate.0 as f32;
|
||||||
|
@ -36,22 +41,37 @@ fn main() {
|
||||||
task::spawn(stream.for_each(move |buffer| -> Result<_, ()> {
|
task::spawn(stream.for_each(move |buffer| -> Result<_, ()> {
|
||||||
match buffer {
|
match buffer {
|
||||||
cpal::UnknownTypeBuffer::U16(mut buffer) => {
|
cpal::UnknownTypeBuffer::U16(mut buffer) => {
|
||||||
for (sample, value) in buffer.chunks_mut(format.channels.len()).zip(&mut data_source) {
|
for (sample, value) in buffer
|
||||||
|
.chunks_mut(format.channels.len())
|
||||||
|
.zip(&mut data_source)
|
||||||
|
{
|
||||||
let value = ((value * 0.5 + 0.5) * std::u16::MAX as f32) as u16;
|
let value = ((value * 0.5 + 0.5) * std::u16::MAX as f32) as u16;
|
||||||
for out in sample.iter_mut() { *out = value; }
|
for out in sample.iter_mut() {
|
||||||
|
*out = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cpal::UnknownTypeBuffer::I16(mut buffer) => {
|
cpal::UnknownTypeBuffer::I16(mut buffer) => {
|
||||||
for (sample, value) in buffer.chunks_mut(format.channels.len()).zip(&mut data_source) {
|
for (sample, value) in buffer
|
||||||
|
.chunks_mut(format.channels.len())
|
||||||
|
.zip(&mut data_source)
|
||||||
|
{
|
||||||
let value = (value * std::i16::MAX as f32) as i16;
|
let value = (value * std::i16::MAX as f32) as i16;
|
||||||
for out in sample.iter_mut() { *out = value; }
|
for out in sample.iter_mut() {
|
||||||
|
*out = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cpal::UnknownTypeBuffer::F32(mut buffer) => {
|
cpal::UnknownTypeBuffer::F32(mut buffer) => {
|
||||||
for (sample, value) in buffer.chunks_mut(format.channels.len()).zip(&mut data_source) {
|
for (sample, value) in buffer
|
||||||
for out in sample.iter_mut() { *out = value; }
|
.chunks_mut(format.channels.len())
|
||||||
|
.zip(&mut data_source)
|
||||||
|
{
|
||||||
|
for out in sample.iter_mut() {
|
||||||
|
*out = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -59,13 +79,11 @@ fn main() {
|
||||||
Ok(())
|
Ok(())
|
||||||
})).execute(executor);
|
})).execute(executor);
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || loop {
|
||||||
loop {
|
|
||||||
thread::sleep(Duration::from_millis(500));
|
thread::sleep(Duration::from_millis(500));
|
||||||
voice.pause();
|
voice.pause();
|
||||||
thread::sleep(Duration::from_millis(500));
|
thread::sleep(Duration::from_millis(500));
|
||||||
voice.play();
|
voice.play();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
event_loop.run();
|
event_loop.run();
|
||||||
|
|
|
@ -5,11 +5,16 @@ fn main() {
|
||||||
|
|
||||||
println!("Endpoints: ");
|
println!("Endpoints: ");
|
||||||
for (endpoint_index, endpoint) in endpoints.enumerate() {
|
for (endpoint_index, endpoint) in endpoints.enumerate() {
|
||||||
println!("{}. Endpoint \"{}\" Audio formats: ", endpoint_index + 1, endpoint.name());
|
println!("{}. Endpoint \"{}\" Audio formats: ",
|
||||||
|
endpoint_index + 1,
|
||||||
|
endpoint.name());
|
||||||
|
|
||||||
let formats = match endpoint.supported_formats() {
|
let formats = match endpoint.supported_formats() {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => { println!("Error: {:?}", e); continue; }
|
Err(e) => {
|
||||||
|
println!("Error: {:?}", e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (format_index, format) in formats.enumerate() {
|
for (format_index, format) in formats.enumerate() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
|
use super::Endpoint;
|
||||||
use super::alsa;
|
use super::alsa;
|
||||||
use super::check_errors;
|
use super::check_errors;
|
||||||
use super::Endpoint;
|
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -17,8 +18,10 @@ pub struct EndpointsIterator {
|
||||||
next_str: *const *const u8,
|
next_str: *const *const u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for EndpointsIterator {}
|
unsafe impl Send for EndpointsIterator {
|
||||||
unsafe impl Sync for EndpointsIterator {}
|
}
|
||||||
|
unsafe impl Sync for EndpointsIterator {
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for EndpointsIterator {
|
impl Drop for EndpointsIterator {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -34,8 +37,8 @@ impl Default for EndpointsIterator {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut hints = mem::uninitialized();
|
let mut hints = mem::uninitialized();
|
||||||
// TODO: check in which situation this can fail
|
// TODO: check in which situation this can fail
|
||||||
check_errors(alsa::snd_device_name_hint(-1, b"pcm\0".as_ptr() as *const _,
|
check_errors(alsa::snd_device_name_hint(-1, b"pcm\0".as_ptr() as *const _, &mut hints))
|
||||||
&mut hints)).unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let hints = hints as *const *const u8;
|
let hints = hints as *const *const u8;
|
||||||
|
|
||||||
|
@ -95,8 +98,10 @@ impl Iterator for EndpointsIterator {
|
||||||
// trying to open the PCM device to see if it can be opened
|
// trying to open the PCM device to see if it can be opened
|
||||||
let name_zeroed = CString::new(name.clone()).unwrap();
|
let name_zeroed = CString::new(name.clone()).unwrap();
|
||||||
let mut playback_handle = mem::uninitialized();
|
let mut playback_handle = mem::uninitialized();
|
||||||
if alsa::snd_pcm_open(&mut playback_handle, name_zeroed.as_ptr() as *const _,
|
if alsa::snd_pcm_open(&mut playback_handle,
|
||||||
alsa::SND_PCM_STREAM_PLAYBACK, alsa::SND_PCM_NONBLOCK) == 0
|
name_zeroed.as_ptr() as *const _,
|
||||||
|
alsa::SND_PCM_STREAM_PLAYBACK,
|
||||||
|
alsa::SND_PCM_NONBLOCK) == 0
|
||||||
{
|
{
|
||||||
alsa::snd_pcm_close(playback_handle);
|
alsa::snd_pcm_close(playback_handle);
|
||||||
} else {
|
} else {
|
||||||
|
|
248
src/alsa/mod.rs
248
src/alsa/mod.rs
|
@ -11,16 +11,16 @@ use SampleFormat;
|
||||||
use SamplesRate;
|
use SamplesRate;
|
||||||
use UnknownTypeBuffer;
|
use UnknownTypeBuffer;
|
||||||
|
|
||||||
use std::{ffi, cmp, iter, mem, ptr};
|
use std::{cmp, ffi, iter, mem, ptr};
|
||||||
use std::vec::IntoIter as VecIntoIter;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::vec::IntoIter as VecIntoIter;
|
||||||
|
|
||||||
use futures::Poll;
|
|
||||||
use futures::task::Task;
|
|
||||||
use futures::task;
|
|
||||||
use futures::stream::Stream;
|
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
|
use futures::Poll;
|
||||||
|
use futures::stream::Stream;
|
||||||
|
use futures::task;
|
||||||
|
use futures::task::Task;
|
||||||
|
|
||||||
pub type SupportedFormatsIterator = VecIntoIter<Format>;
|
pub type SupportedFormatsIterator = VecIntoIter<Format>;
|
||||||
|
|
||||||
|
@ -34,10 +34,10 @@ struct Trigger {
|
||||||
|
|
||||||
impl Trigger {
|
impl Trigger {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let mut fds = [0,0];
|
let mut fds = [0, 0];
|
||||||
match unsafe { libc::pipe(fds.as_mut_ptr()) } {
|
match unsafe { libc::pipe(fds.as_mut_ptr()) } {
|
||||||
0 => Trigger { fds: fds },
|
0 => Trigger { fds: fds },
|
||||||
_ => panic!("Could not create pipe")
|
_ => panic!("Could not create pipe"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_fd(&self) -> libc::c_int {
|
fn read_fd(&self) -> libc::c_int {
|
||||||
|
@ -72,9 +72,9 @@ impl Drop for Trigger {
|
||||||
pub struct Endpoint(String);
|
pub struct Endpoint(String);
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
pub fn get_supported_formats_list(&self)
|
pub fn get_supported_formats_list(
|
||||||
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
|
&self)
|
||||||
{
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut playback_handle = mem::uninitialized();
|
let mut playback_handle = mem::uninitialized();
|
||||||
let device_name = ffi::CString::new(self.0.clone()).expect("Unable to get device name");
|
let device_name = ffi::CString::new(self.0.clone()).expect("Unable to get device name");
|
||||||
|
@ -90,11 +90,12 @@ impl Endpoint {
|
||||||
let hw_params = HwParams::alloc();
|
let hw_params = HwParams::alloc();
|
||||||
match check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0)) {
|
match check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0)) {
|
||||||
Err(_) => return Ok(Vec::new().into_iter()),
|
Err(_) => return Ok(Vec::new().into_iter()),
|
||||||
Ok(_) => ()
|
Ok(_) => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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),
|
||||||
|
@ -109,7 +110,7 @@ impl Endpoint {
|
||||||
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,
|
||||||
|
@ -132,25 +133,35 @@ impl Endpoint {
|
||||||
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(playback_handle, hw_params.0, alsa_format) == 0 {
|
if alsa::snd_pcm_hw_params_test_format(playback_handle,
|
||||||
|
hw_params.0,
|
||||||
|
alsa_format) == 0
|
||||||
|
{
|
||||||
supported_formats.push(sample_format);
|
supported_formats.push(sample_format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut min_rate = mem::uninitialized();
|
let mut min_rate = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_get_rate_min(hw_params.0, &mut min_rate, ptr::null_mut())).expect("unable to get minimum supported rete");
|
check_errors(alsa::snd_pcm_hw_params_get_rate_min(hw_params.0,
|
||||||
|
&mut min_rate,
|
||||||
|
ptr::null_mut()))
|
||||||
|
.expect("unable to get minimum supported rete");
|
||||||
let mut max_rate = mem::uninitialized();
|
let mut max_rate = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_get_rate_max(hw_params.0, &mut max_rate, ptr::null_mut())).expect("unable to get maximum supported rate");
|
check_errors(alsa::snd_pcm_hw_params_get_rate_max(hw_params.0,
|
||||||
|
&mut max_rate,
|
||||||
|
ptr::null_mut()))
|
||||||
|
.expect("unable to get maximum supported rate");
|
||||||
|
|
||||||
let samples_rates = if min_rate == max_rate {
|
let samples_rates = if min_rate == max_rate {
|
||||||
vec![min_rate]
|
vec![min_rate]
|
||||||
/*} else if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, min_rate + 1, 0) == 0 {
|
/*} else if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, min_rate + 1, 0) == 0 {
|
||||||
(min_rate .. max_rate + 1).collect()*/ // TODO: code is correct but returns lots of stuff
|
(min_rate .. max_rate + 1).collect()*/
|
||||||
|
// TODO: code is correct but returns lots of stuff
|
||||||
} else {
|
} else {
|
||||||
const RATES: [libc::c_uint; 13] = [
|
const RATES: [libc::c_uint; 13] = [
|
||||||
5512,
|
5512,
|
||||||
|
@ -170,7 +181,11 @@ impl Endpoint {
|
||||||
|
|
||||||
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(playback_handle, hw_params.0, rate, 0) == 0 {
|
if alsa::snd_pcm_hw_params_test_rate(playback_handle,
|
||||||
|
hw_params.0,
|
||||||
|
rate,
|
||||||
|
0) == 0
|
||||||
|
{
|
||||||
rates.push(rate);
|
rates.push(rate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,20 +198,36 @@ impl Endpoint {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut min_channels = mem::uninitialized();
|
let mut min_channels = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_get_channels_min(hw_params.0, &mut min_channels)).expect("unable to get minimum supported channel count");
|
check_errors(alsa::snd_pcm_hw_params_get_channels_min(hw_params.0, &mut min_channels))
|
||||||
|
.expect("unable to get minimum supported channel count");
|
||||||
let mut max_channels = mem::uninitialized();
|
let mut max_channels = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_get_channels_max(hw_params.0, &mut max_channels)).expect("unable to get maximum supported channel count");
|
check_errors(alsa::snd_pcm_hw_params_get_channels_max(hw_params.0, &mut max_channels))
|
||||||
|
.expect("unable to get maximum supported channel count");
|
||||||
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).filter_map(|num| {
|
let supported_channels = (min_channels .. max_channels + 1)
|
||||||
if alsa::snd_pcm_hw_params_test_channels(playback_handle, hw_params.0, num) == 0 {
|
.filter_map(|num| if alsa::snd_pcm_hw_params_test_channels(
|
||||||
Some([ChannelPosition::FrontLeft, ChannelPosition::FrontRight,
|
playback_handle,
|
||||||
ChannelPosition::BackLeft, ChannelPosition::BackRight,
|
hw_params.0,
|
||||||
ChannelPosition::FrontCenter, ChannelPosition::LowFrequency]
|
num,
|
||||||
.iter().take(num as usize).cloned().collect::<Vec<_>>())
|
) == 0
|
||||||
|
{
|
||||||
|
Some(
|
||||||
|
[
|
||||||
|
ChannelPosition::FrontLeft,
|
||||||
|
ChannelPosition::FrontRight,
|
||||||
|
ChannelPosition::BackLeft,
|
||||||
|
ChannelPosition::BackRight,
|
||||||
|
ChannelPosition::FrontCenter,
|
||||||
|
ChannelPosition::LowFrequency,
|
||||||
|
].iter()
|
||||||
|
.take(num as usize)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
})
|
||||||
}).collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut output = Vec::with_capacity(supported_formats.len() * supported_channels.len() *
|
let mut output = Vec::with_capacity(supported_formats.len() * supported_channels.len() *
|
||||||
samples_rates.len());
|
samples_rates.len());
|
||||||
|
@ -256,8 +287,10 @@ struct PollDescriptors {
|
||||||
voices: Vec<Arc<VoiceInner>>,
|
voices: Vec<Arc<VoiceInner>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for EventLoopInner {}
|
unsafe impl Send for EventLoopInner {
|
||||||
unsafe impl Sync for EventLoopInner {}
|
}
|
||||||
|
unsafe impl Sync for EventLoopInner {
|
||||||
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -267,11 +300,13 @@ impl EventLoop {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
inner: Arc::new(EventLoopInner {
|
inner: Arc::new(EventLoopInner {
|
||||||
current_wait: Mutex::new(PollDescriptors {
|
current_wait: Mutex::new(PollDescriptors {
|
||||||
descriptors: vec![libc::pollfd {
|
descriptors: vec![
|
||||||
|
libc::pollfd {
|
||||||
fd: pending_trigger.read_fd(),
|
fd: pending_trigger.read_fd(),
|
||||||
events: libc::POLLIN,
|
events: libc::POLLIN,
|
||||||
revents: 0,
|
revents: 0,
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
voices: Vec::new(),
|
voices: Vec::new(),
|
||||||
}),
|
}),
|
||||||
pending_wait: Mutex::new(PollDescriptors {
|
pending_wait: Mutex::new(PollDescriptors {
|
||||||
|
@ -279,7 +314,7 @@ impl EventLoop {
|
||||||
voices: Vec::new(),
|
voices: Vec::new(),
|
||||||
}),
|
}),
|
||||||
pending_trigger: pending_trigger,
|
pending_trigger: pending_trigger,
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,14 +366,19 @@ impl EventLoop {
|
||||||
|
|
||||||
{
|
{
|
||||||
let channel = *current_wait.voices[i_voice].channel.lock().unwrap();
|
let channel = *current_wait.voices[i_voice].channel.lock().unwrap();
|
||||||
let num_descriptors = current_wait.voices[i_voice].num_descriptors as libc::c_uint;
|
let num_descriptors =
|
||||||
|
current_wait.voices[i_voice].num_descriptors as libc::c_uint;
|
||||||
check_errors(alsa::snd_pcm_poll_descriptors_revents(channel, current_wait.descriptors
|
check_errors(alsa::snd_pcm_poll_descriptors_revents(channel, current_wait.descriptors
|
||||||
.as_mut_ptr().offset(i_descriptor),
|
.as_mut_ptr().offset(i_descriptor),
|
||||||
num_descriptors, &mut revent)).unwrap();
|
num_descriptors, &mut revent)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revent as libc::c_short & libc::POLLOUT) != 0 {
|
if (revent as libc::c_short & libc::POLLOUT) != 0 {
|
||||||
let scheduled = current_wait.voices[i_voice].scheduled.lock().unwrap().take();
|
let scheduled = current_wait.voices[i_voice]
|
||||||
|
.scheduled
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.take();
|
||||||
scheduled.unwrap().task.unpark();
|
scheduled.unwrap().task.unpark();
|
||||||
|
|
||||||
for _ in 0 .. current_wait.voices[i_voice].num_descriptors {
|
for _ in 0 .. current_wait.voices[i_voice].num_descriptors {
|
||||||
|
@ -347,20 +387,27 @@ impl EventLoop {
|
||||||
current_wait.voices.remove(i_voice);
|
current_wait.voices.remove(i_voice);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
i_descriptor += current_wait.voices[i_voice].num_descriptors as isize;
|
i_descriptor += current_wait.voices[i_voice].num_descriptors as
|
||||||
|
isize;
|
||||||
i_voice += 1;
|
i_voice += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ScheduledKind::WaitResume => {
|
ScheduledKind::WaitResume => {
|
||||||
if current_wait.descriptors[i_descriptor as usize].revents != 0 {
|
if current_wait.descriptors[i_descriptor as usize].revents != 0 {
|
||||||
// Unpark the task
|
// Unpark the task
|
||||||
let scheduled = current_wait.voices[i_voice].scheduled.lock().unwrap().take();
|
let scheduled = current_wait.voices[i_voice]
|
||||||
|
.scheduled
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.take();
|
||||||
scheduled.unwrap().task.unpark();
|
scheduled.unwrap().task.unpark();
|
||||||
|
|
||||||
// Emptying the signal.
|
// Emptying the signal.
|
||||||
let mut out = 0u64;
|
let mut out = 0u64;
|
||||||
let ret = libc::read(current_wait.descriptors[i_descriptor as usize].fd,
|
let ret =
|
||||||
&mut out as *mut u64 as *mut _, 8);
|
libc::read(current_wait.descriptors[i_descriptor as usize].fd,
|
||||||
|
&mut out as *mut u64 as *mut _,
|
||||||
|
8);
|
||||||
assert_eq!(ret, 8);
|
assert_eq!(ret, 8);
|
||||||
|
|
||||||
// Remove from current waiting poll descriptors
|
// Remove from current waiting poll descriptors
|
||||||
|
@ -370,7 +417,7 @@ impl EventLoop {
|
||||||
i_descriptor += 1;
|
i_descriptor += 1;
|
||||||
i_voice += 1;
|
i_voice += 1;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +443,7 @@ pub struct Scheduled {
|
||||||
kind: ScheduledKind,
|
kind: ScheduledKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ScheduledKind {
|
pub enum ScheduledKind {
|
||||||
WaitResume,
|
WaitResume,
|
||||||
WaitPCM,
|
WaitPCM,
|
||||||
|
@ -436,8 +483,10 @@ struct VoiceInner {
|
||||||
resume_trigger: Trigger,
|
resume_trigger: Trigger,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for VoiceInner {}
|
unsafe impl Send for VoiceInner {
|
||||||
unsafe impl Sync for VoiceInner {}
|
}
|
||||||
|
unsafe impl Sync for VoiceInner {
|
||||||
|
}
|
||||||
|
|
||||||
impl SamplesStream {
|
impl SamplesStream {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -460,11 +509,16 @@ impl SamplesStream {
|
||||||
|
|
||||||
let len = pending_wait.descriptors.len();
|
let len = pending_wait.descriptors.len();
|
||||||
let filled = alsa::snd_pcm_poll_descriptors(*channel,
|
let filled = alsa::snd_pcm_poll_descriptors(*channel,
|
||||||
pending_wait.descriptors.as_mut_ptr()
|
pending_wait
|
||||||
|
.descriptors
|
||||||
|
.as_mut_ptr()
|
||||||
.offset(len as isize),
|
.offset(len as isize),
|
||||||
self.inner.num_descriptors as libc::c_uint);
|
self.inner.num_descriptors as
|
||||||
|
libc::c_uint);
|
||||||
debug_assert_eq!(filled, self.inner.num_descriptors as libc::c_int);
|
debug_assert_eq!(filled, self.inner.num_descriptors as libc::c_int);
|
||||||
pending_wait.descriptors.set_len(len + self.inner.num_descriptors);
|
pending_wait
|
||||||
|
.descriptors
|
||||||
|
.set_len(len + self.inner.num_descriptors);
|
||||||
},
|
},
|
||||||
ScheduledKind::WaitResume => {
|
ScheduledKind::WaitResume => {
|
||||||
// And we add the descriptor corresponding to the resume signal
|
// And we add the descriptor corresponding to the resume signal
|
||||||
|
@ -474,7 +528,7 @@ impl SamplesStream {
|
||||||
events: libc::POLLIN,
|
events: libc::POLLIN,
|
||||||
revents: 0,
|
revents: 0,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also fill `voices`.
|
// We also fill `voices`.
|
||||||
|
@ -525,7 +579,9 @@ impl Stream for SamplesStream {
|
||||||
match self.inner.sample_format {
|
match self.inner.sample_format {
|
||||||
SampleFormat::I16 => {
|
SampleFormat::I16 => {
|
||||||
let buffer = Buffer {
|
let buffer = Buffer {
|
||||||
buffer: iter::repeat(unsafe { mem::uninitialized() }).take(available).collect(),
|
buffer: iter::repeat(unsafe { mem::uninitialized() })
|
||||||
|
.take(available)
|
||||||
|
.collect(),
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -533,7 +589,9 @@ impl Stream for SamplesStream {
|
||||||
},
|
},
|
||||||
SampleFormat::U16 => {
|
SampleFormat::U16 => {
|
||||||
let buffer = Buffer {
|
let buffer = Buffer {
|
||||||
buffer: iter::repeat(unsafe { mem::uninitialized() }).take(available).collect(),
|
buffer: iter::repeat(unsafe { mem::uninitialized() })
|
||||||
|
.take(available)
|
||||||
|
.collect(),
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,7 +599,9 @@ impl Stream for SamplesStream {
|
||||||
},
|
},
|
||||||
SampleFormat::F32 => {
|
SampleFormat::F32 => {
|
||||||
let buffer = Buffer {
|
let buffer = Buffer {
|
||||||
buffer: iter::repeat(unsafe { mem::uninitialized() }).take(available).collect(),
|
buffer: iter::repeat(unsafe { mem::uninitialized() })
|
||||||
|
.take(available)
|
||||||
|
.collect(),
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -558,7 +618,8 @@ impl HwParams {
|
||||||
pub fn alloc() -> HwParams {
|
pub fn alloc() -> HwParams {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut hw_params = mem::uninitialized();
|
let mut hw_params = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_malloc(&mut hw_params)).expect("unable to get hardware parameters");
|
check_errors(alsa::snd_pcm_hw_params_malloc(&mut hw_params))
|
||||||
|
.expect("unable to get hardware parameters");
|
||||||
HwParams(hw_params)
|
HwParams(hw_params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -574,8 +635,7 @@ impl Drop for HwParams {
|
||||||
|
|
||||||
impl Voice {
|
impl Voice {
|
||||||
pub fn new(endpoint: &Endpoint, format: &Format, event_loop: &EventLoop)
|
pub fn new(endpoint: &Endpoint, format: &Format, event_loop: &EventLoop)
|
||||||
-> Result<(Voice, SamplesStream), CreationError>
|
-> Result<(Voice, SamplesStream), CreationError> {
|
||||||
{
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = ffi::CString::new(endpoint.0.clone()).expect("unable to clone endpoint");
|
let name = ffi::CString::new(endpoint.0.clone()).expect("unable to clone endpoint");
|
||||||
|
|
||||||
|
@ -595,33 +655,62 @@ impl Voice {
|
||||||
};
|
};
|
||||||
|
|
||||||
let hw_params = HwParams::alloc();
|
let hw_params = HwParams::alloc();
|
||||||
check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0)).expect("Errors on playback handle");
|
check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0))
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_access(playback_handle, hw_params.0, alsa::SND_PCM_ACCESS_RW_INTERLEAVED)).expect("handle not acessible");
|
.expect("Errors on playback handle");
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_format(playback_handle, hw_params.0, data_type)).expect("format could not be set");
|
check_errors(alsa::snd_pcm_hw_params_set_access(playback_handle,
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_rate(playback_handle, hw_params.0, format.samples_rate.0 as libc::c_uint, 0)).expect("sample rate could not be set");
|
hw_params.0,
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_channels(playback_handle, hw_params.0, format.channels.len() as libc::c_uint)).expect("channel count could not be set");
|
alsa::SND_PCM_ACCESS_RW_INTERLEAVED))
|
||||||
let mut max_buffer_size = format.samples_rate.0 as alsa::snd_pcm_uframes_t / format.channels.len() as alsa::snd_pcm_uframes_t / 5; // 200ms of buffer
|
.expect("handle not acessible");
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_buffer_size_max(playback_handle, hw_params.0, &mut max_buffer_size)).unwrap();
|
check_errors(alsa::snd_pcm_hw_params_set_format(playback_handle,
|
||||||
check_errors(alsa::snd_pcm_hw_params(playback_handle, hw_params.0)).expect("hardware params could not be set");
|
hw_params.0,
|
||||||
|
data_type))
|
||||||
|
.expect("format could not be set");
|
||||||
|
check_errors(alsa::snd_pcm_hw_params_set_rate(playback_handle,
|
||||||
|
hw_params.0,
|
||||||
|
format.samples_rate.0 as libc::c_uint,
|
||||||
|
0))
|
||||||
|
.expect("sample rate could not be set");
|
||||||
|
check_errors(alsa::snd_pcm_hw_params_set_channels(playback_handle,
|
||||||
|
hw_params.0,
|
||||||
|
format.channels.len() as
|
||||||
|
libc::c_uint))
|
||||||
|
.expect("channel count could not be set");
|
||||||
|
let mut max_buffer_size = format.samples_rate.0 as alsa::snd_pcm_uframes_t /
|
||||||
|
format.channels.len() as alsa::snd_pcm_uframes_t /
|
||||||
|
5; // 200ms of buffer
|
||||||
|
check_errors(alsa::snd_pcm_hw_params_set_buffer_size_max(playback_handle,
|
||||||
|
hw_params.0,
|
||||||
|
&mut max_buffer_size))
|
||||||
|
.unwrap();
|
||||||
|
check_errors(alsa::snd_pcm_hw_params(playback_handle, hw_params.0))
|
||||||
|
.expect("hardware params could not be set");
|
||||||
|
|
||||||
let mut sw_params = mem::uninitialized(); // TODO: RAII
|
let mut sw_params = mem::uninitialized(); // TODO: RAII
|
||||||
check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)).unwrap();
|
check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)).unwrap();
|
||||||
check_errors(alsa::snd_pcm_sw_params_current(playback_handle, sw_params)).unwrap();
|
check_errors(alsa::snd_pcm_sw_params_current(playback_handle, sw_params)).unwrap();
|
||||||
check_errors(alsa::snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params, 0)).unwrap();
|
check_errors(alsa::snd_pcm_sw_params_set_start_threshold(playback_handle,
|
||||||
|
sw_params,
|
||||||
|
0))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (buffer_len, period_len) = {
|
let (buffer_len, period_len) = {
|
||||||
let mut buffer = mem::uninitialized();
|
let mut buffer = mem::uninitialized();
|
||||||
let mut period = mem::uninitialized();
|
let mut period = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_get_params(playback_handle, &mut buffer, &mut period)).expect("could not initialize buffer");
|
check_errors(alsa::snd_pcm_get_params(playback_handle, &mut buffer, &mut period))
|
||||||
|
.expect("could not initialize buffer");
|
||||||
assert!(buffer != 0);
|
assert!(buffer != 0);
|
||||||
check_errors(alsa::snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, period)).unwrap();
|
check_errors(alsa::snd_pcm_sw_params_set_avail_min(playback_handle,
|
||||||
|
sw_params,
|
||||||
|
period))
|
||||||
|
.unwrap();
|
||||||
let buffer = buffer as usize * format.channels.len();
|
let buffer = buffer as usize * format.channels.len();
|
||||||
let period = period as usize * format.channels.len();
|
let period = period as usize * format.channels.len();
|
||||||
(buffer, period)
|
(buffer, period)
|
||||||
};
|
};
|
||||||
|
|
||||||
check_errors(alsa::snd_pcm_sw_params(playback_handle, sw_params)).unwrap();
|
check_errors(alsa::snd_pcm_sw_params(playback_handle, sw_params)).unwrap();
|
||||||
check_errors(alsa::snd_pcm_prepare(playback_handle)).expect("could not get playback handle");
|
check_errors(alsa::snd_pcm_prepare(playback_handle))
|
||||||
|
.expect("could not get playback handle");
|
||||||
|
|
||||||
let num_descriptors = {
|
let num_descriptors = {
|
||||||
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(playback_handle);
|
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(playback_handle);
|
||||||
|
@ -642,11 +731,8 @@ impl Voice {
|
||||||
resume_trigger: Trigger::new(),
|
resume_trigger: Trigger::new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok((Voice {
|
Ok((Voice { inner: samples_stream_inner.clone() },
|
||||||
inner: samples_stream_inner.clone()
|
SamplesStream { inner: samples_stream_inner }))
|
||||||
}, SamplesStream {
|
|
||||||
inner: samples_stream_inner
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,15 +772,17 @@ impl<T> Buffer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self) {
|
pub fn finish(self) {
|
||||||
let to_write = (self.buffer.len() / self.inner.num_channels as usize)
|
let to_write = (self.buffer.len() / self.inner.num_channels as usize) as
|
||||||
as alsa::snd_pcm_uframes_t;
|
alsa::snd_pcm_uframes_t;
|
||||||
let channel = self.inner.channel.lock().expect("Buffer channel lock failed");
|
let channel = self.inner
|
||||||
|
.channel
|
||||||
|
.lock()
|
||||||
|
.expect("Buffer channel lock failed");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
loop {
|
loop {
|
||||||
let result = alsa::snd_pcm_writei(*channel,
|
let result =
|
||||||
self.buffer.as_ptr() as *const _,
|
alsa::snd_pcm_writei(*channel, self.buffer.as_ptr() as *const _, to_write);
|
||||||
to_write);
|
|
||||||
|
|
||||||
if result == -32 {
|
if result == -32 {
|
||||||
// buffer underrun
|
// buffer underrun
|
||||||
|
@ -716,7 +804,9 @@ fn check_errors(err: libc::c_int) -> Result<(), String> {
|
||||||
|
|
||||||
if err < 0 {
|
if err < 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err)).to_bytes().to_vec();
|
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err))
|
||||||
|
.to_bytes()
|
||||||
|
.to_vec();
|
||||||
let s = String::from_utf8(s).expect("Streaming error occured");
|
let s = String::from_utf8(s).expect("Streaming error occured");
|
||||||
return Err(s);
|
return Err(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use super::Endpoint;
|
use super::Endpoint;
|
||||||
|
|
||||||
use ::Format;
|
use Format;
|
||||||
|
|
||||||
use std::vec::IntoIter as VecIntoIter;
|
use std::vec::IntoIter as VecIntoIter;
|
||||||
|
|
||||||
pub struct EndpointsIterator(bool);
|
pub struct EndpointsIterator(bool);
|
||||||
|
|
||||||
unsafe impl Send for EndpointsIterator {}
|
unsafe impl Send for EndpointsIterator {
|
||||||
unsafe impl Sync for EndpointsIterator {}
|
}
|
||||||
|
unsafe impl Sync for EndpointsIterator {
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for EndpointsIterator {
|
impl Default for EndpointsIterator {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -18,7 +20,12 @@ impl Default for EndpointsIterator {
|
||||||
impl Iterator for EndpointsIterator {
|
impl Iterator for EndpointsIterator {
|
||||||
type Item = Endpoint;
|
type Item = Endpoint;
|
||||||
fn next(&mut self) -> Option<Endpoint> {
|
fn next(&mut self) -> Option<Endpoint> {
|
||||||
if self.0 { None } else { self.0 = true; Some(Endpoint) }
|
if self.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.0 = true;
|
||||||
|
Some(Endpoint)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
extern crate coreaudio;
|
extern crate coreaudio;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
use ChannelPosition;
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use Format;
|
use Format;
|
||||||
use FormatsEnumerationError;
|
use FormatsEnumerationError;
|
||||||
use Sample;
|
use Sample;
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
use SamplesRate;
|
use SamplesRate;
|
||||||
use ChannelPosition;
|
|
||||||
use UnknownTypeBuffer;
|
use UnknownTypeBuffer;
|
||||||
|
|
||||||
use futures::Poll;
|
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
use futures::task::Task;
|
use futures::Poll;
|
||||||
use futures::task;
|
|
||||||
use futures::stream::Stream;
|
use futures::stream::Stream;
|
||||||
|
use futures::task;
|
||||||
|
use futures::task::Task;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -24,22 +24,24 @@ use self::coreaudio::audio_unit::render_callback::{self, data};
|
||||||
|
|
||||||
mod enumerate;
|
mod enumerate;
|
||||||
|
|
||||||
pub use self::enumerate::{EndpointsIterator,
|
pub use self::enumerate::{EndpointsIterator, SupportedFormatsIterator, get_default_endpoint};
|
||||||
SupportedFormatsIterator,
|
|
||||||
get_default_endpoint};
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Endpoint;
|
pub struct Endpoint;
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
pub fn get_supported_formats_list(&self)
|
pub fn get_supported_formats_list(
|
||||||
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
|
&self)
|
||||||
{
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
Ok(vec!(Format {
|
Ok(
|
||||||
|
vec![
|
||||||
|
Format {
|
||||||
channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
||||||
samples_rate: SamplesRate(44100),
|
samples_rate: SamplesRate(44100),
|
||||||
data_type: SampleFormat::F32
|
data_type: SampleFormat::F32,
|
||||||
}).into_iter())
|
},
|
||||||
|
].into_iter(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
|
@ -50,7 +52,9 @@ impl Endpoint {
|
||||||
pub struct EventLoop;
|
pub struct EventLoop;
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> EventLoop { EventLoop }
|
pub fn new() -> EventLoop {
|
||||||
|
EventLoop
|
||||||
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
loop {
|
loop {
|
||||||
|
@ -65,7 +69,9 @@ pub struct Buffer<T> {
|
||||||
buffer: Vec<T>,
|
buffer: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Buffer<T> where T: Sample {
|
impl<T> Buffer<T>
|
||||||
|
where T: Sample
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_buffer(&mut self) -> &mut [T] {
|
pub fn get_buffer(&mut self) -> &mut [T] {
|
||||||
&mut self.buffer[..]
|
&mut self.buffer[..]
|
||||||
|
@ -123,7 +129,7 @@ impl Stream for SamplesStream {
|
||||||
None => {
|
None => {
|
||||||
inner.scheduled_task = Some(task::park());
|
inner.scheduled_task = Some(task::park());
|
||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer_len = current_callback.num_frames * current_callback.data.channels().count();
|
let buffer_len = current_callback.num_frames * current_callback.data.channels().count();
|
||||||
|
@ -139,8 +145,7 @@ impl Stream for SamplesStream {
|
||||||
|
|
||||||
impl Voice {
|
impl Voice {
|
||||||
pub fn new(_: &Endpoint, _: &Format, _: &EventLoop)
|
pub fn new(_: &Endpoint, _: &Format, _: &EventLoop)
|
||||||
-> Result<(Voice, SamplesStream), CreationError>
|
-> Result<(Voice, SamplesStream), CreationError> {
|
||||||
{
|
|
||||||
let inner = Arc::new(Mutex::new(SamplesStreamInner {
|
let inner = Arc::new(Mutex::new(SamplesStreamInner {
|
||||||
scheduled_task: None,
|
scheduled_task: None,
|
||||||
current_callback: None,
|
current_callback: None,
|
||||||
|
@ -165,7 +170,7 @@ impl Voice {
|
||||||
} else {
|
} else {
|
||||||
coreaudio::audio_unit::IOType::DefaultOutput
|
coreaudio::audio_unit::IOType::DefaultOutput
|
||||||
};
|
};
|
||||||
let mut audio_unit = try!(AudioUnit::new(au_type).map_err(convert_error));
|
let mut audio_unit = AudioUnit::new(au_type).map_err(convert_error)?;
|
||||||
|
|
||||||
// TODO: iOS uses integer and fixed-point data
|
// TODO: iOS uses integer and fixed-point data
|
||||||
|
|
||||||
|
@ -199,10 +204,10 @@ impl Voice {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
try!(result.map_err(convert_error));
|
result.map_err(convert_error)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(audio_unit.start().map_err(convert_error));
|
audio_unit.start().map_err(convert_error)?;
|
||||||
|
|
||||||
let au_arc = Arc::new(Mutex::new(audio_unit));
|
let au_arc = Arc::new(Mutex::new(audio_unit));
|
||||||
|
|
||||||
|
@ -214,7 +219,8 @@ impl Voice {
|
||||||
Ok((Voice {
|
Ok((Voice {
|
||||||
playing: true,
|
playing: true,
|
||||||
audio_unit: au_arc.clone(),
|
audio_unit: au_arc.clone(),
|
||||||
}, samples_stream))
|
},
|
||||||
|
samples_stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -74,31 +74,32 @@ extern crate futures;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
pub use samples_formats::{SampleFormat, Sample};
|
pub use samples_formats::{Sample, SampleFormat};
|
||||||
|
|
||||||
#[cfg(all(not(windows), not(target_os = "linux"), not(target_os = "freebsd"), not(target_os = "macos"), not(target_os = "ios")))]
|
#[cfg(all(not(windows), not(target_os = "linux"), not(target_os = "freebsd"),
|
||||||
|
not(target_os = "macos"), not(target_os = "ios")))]
|
||||||
use null as cpal_impl;
|
use null as cpal_impl;
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use futures::stream::Stream;
|
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
|
use futures::stream::Stream;
|
||||||
|
|
||||||
mod null;
|
mod null;
|
||||||
mod samples_formats;
|
mod samples_formats;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
#[path="alsa/mod.rs"]
|
#[path = "alsa/mod.rs"]
|
||||||
mod cpal_impl;
|
mod cpal_impl;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
#[path="wasapi/mod.rs"]
|
#[path = "wasapi/mod.rs"]
|
||||||
mod cpal_impl;
|
mod cpal_impl;
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
#[path="coreaudio/mod.rs"]
|
#[path = "coreaudio/mod.rs"]
|
||||||
mod cpal_impl;
|
mod cpal_impl;
|
||||||
|
|
||||||
/// An iterator for the list of formats that are supported by the backend.
|
/// An iterator for the list of formats that are supported by the backend.
|
||||||
|
@ -151,18 +152,16 @@ pub struct Endpoint(cpal_impl::Endpoint);
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
/// Returns an iterator that produces the list of formats that are supported by the backend.
|
/// Returns an iterator that produces the list of formats that are supported by the backend.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn supported_formats(&self) -> Result<SupportedFormatsIterator,
|
pub fn supported_formats(&self) -> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
FormatsEnumerationError>
|
Ok(SupportedFormatsIterator(self.0.get_supported_formats_list()?))
|
||||||
{
|
|
||||||
Ok(SupportedFormatsIterator(try!(self.0.get_supported_formats_list())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated. Use `supported_formats` instead.
|
/// Deprecated. Use `supported_formats` instead.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
pub fn get_supported_formats_list(&self) -> Result<SupportedFormatsIterator,
|
pub fn get_supported_formats_list(
|
||||||
FormatsEnumerationError>
|
&self)
|
||||||
{
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
self.supported_formats()
|
self.supported_formats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +253,9 @@ impl EventLoop {
|
||||||
/// You should destroy this object as soon as possible. Data is only committed when it
|
/// You should destroy this object as soon as possible. Data is only committed when it
|
||||||
/// is destroyed.
|
/// is destroyed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Buffer<T> where T: Sample {
|
pub struct Buffer<T>
|
||||||
|
where T: Sample
|
||||||
|
{
|
||||||
// also contains something, taken by `Drop`
|
// also contains something, taken by `Drop`
|
||||||
target: Option<cpal_impl::Buffer<T>>,
|
target: Option<cpal_impl::Buffer<T>>,
|
||||||
}
|
}
|
||||||
|
@ -363,9 +364,8 @@ impl Voice {
|
||||||
/// Builds a new channel.
|
/// Builds a new channel.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(endpoint: &Endpoint, format: &Format, event_loop: &EventLoop)
|
pub fn new(endpoint: &Endpoint, format: &Format, event_loop: &EventLoop)
|
||||||
-> Result<(Voice, SamplesStream), CreationError>
|
-> Result<(Voice, SamplesStream), CreationError> {
|
||||||
{
|
let (voice, stream) = cpal_impl::Voice::new(&endpoint.0, format, &event_loop.0)?;
|
||||||
let (voice, stream) = try!(cpal_impl::Voice::new(&endpoint.0, format, &event_loop.0));
|
|
||||||
|
|
||||||
let voice = Voice {
|
let voice = Voice {
|
||||||
voice: voice,
|
voice: voice,
|
||||||
|
@ -447,7 +447,9 @@ impl Stream for SamplesStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Buffer<T> where T: Sample {
|
impl<T> Deref for Buffer<T>
|
||||||
|
where T: Sample
|
||||||
|
{
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -456,14 +458,18 @@ impl<T> Deref for Buffer<T> where T: Sample {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for Buffer<T> where T: Sample {
|
impl<T> DerefMut for Buffer<T>
|
||||||
|
where T: Sample
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut [T] {
|
fn deref_mut(&mut self) -> &mut [T] {
|
||||||
self.target.as_mut().unwrap().get_buffer()
|
self.target.as_mut().unwrap().get_buffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for Buffer<T> where T: Sample {
|
impl<T> Drop for Buffer<T>
|
||||||
|
where T: Sample
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.target.take().unwrap().finish();
|
self.target.take().unwrap().finish();
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use futures::Async;
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
use futures::stream::Stream;
|
use futures::stream::Stream;
|
||||||
use futures::Async;
|
|
||||||
|
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use Format;
|
use Format;
|
||||||
|
@ -14,9 +14,13 @@ use UnknownTypeBuffer;
|
||||||
pub struct EventLoop;
|
pub struct EventLoop;
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> EventLoop { EventLoop }
|
pub fn new() -> EventLoop {
|
||||||
|
EventLoop
|
||||||
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run(&self) { loop { /* TODO: don't spin */ } }
|
pub fn run(&self) {
|
||||||
|
loop { /* TODO: don't spin */ }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -41,9 +45,9 @@ pub struct Endpoint;
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_supported_formats_list(&self)
|
pub fn get_supported_formats_list(
|
||||||
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
|
&self)
|
||||||
{
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +74,7 @@ pub struct SamplesStream;
|
||||||
impl Voice {
|
impl Voice {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(_: &Endpoint, _: &Format, _: &EventLoop)
|
pub fn new(_: &Endpoint, _: &Format, _: &EventLoop)
|
||||||
-> Result<(Voice, SamplesStream), CreationError>
|
-> Result<(Voice, SamplesStream), CreationError> {
|
||||||
{
|
|
||||||
Err(CreationError::DeviceNotAvailable)
|
Err(CreationError::DeviceNotAvailable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Handles COM initialization and cleanup.
|
//! Handles COM initialization and cleanup.
|
||||||
|
|
||||||
use std::ptr;
|
|
||||||
use super::winapi;
|
|
||||||
use super::ole32;
|
|
||||||
use super::check_result;
|
use super::check_result;
|
||||||
|
use super::ole32;
|
||||||
|
use super::winapi;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
thread_local!(static COM_INITIALIZED: ComInitialized = {
|
thread_local!(static COM_INITIALIZED: ComInitialized = {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use super::winapi;
|
|
||||||
use super::ole32;
|
|
||||||
use super::com;
|
|
||||||
use super::Endpoint;
|
use super::Endpoint;
|
||||||
use super::check_result;
|
use super::check_result;
|
||||||
|
use super::com;
|
||||||
|
use super::ole32;
|
||||||
|
use super::winapi;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -33,8 +34,10 @@ lazy_static! {
|
||||||
/// RAII object around `winapi::IMMDeviceEnumerator`.
|
/// RAII object around `winapi::IMMDeviceEnumerator`.
|
||||||
struct Enumerator(*mut winapi::IMMDeviceEnumerator);
|
struct Enumerator(*mut winapi::IMMDeviceEnumerator);
|
||||||
|
|
||||||
unsafe impl Send for Enumerator {}
|
unsafe impl Send for Enumerator {
|
||||||
unsafe impl Sync for Enumerator {}
|
}
|
||||||
|
unsafe impl Sync for Enumerator {
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for Enumerator {
|
impl Drop for Enumerator {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -52,8 +55,10 @@ pub struct EndpointsIterator {
|
||||||
next_item: u32,
|
next_item: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for EndpointsIterator {}
|
unsafe impl Send for EndpointsIterator {
|
||||||
unsafe impl Sync for EndpointsIterator {}
|
}
|
||||||
|
unsafe impl Sync for EndpointsIterator {
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for EndpointsIterator {
|
impl Drop for EndpointsIterator {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -116,8 +121,8 @@ impl Iterator for EndpointsIterator {
|
||||||
pub fn get_default_endpoint() -> Option<Endpoint> {
|
pub fn get_default_endpoint() -> Option<Endpoint> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut device = mem::uninitialized();
|
let mut device = mem::uninitialized();
|
||||||
let hres = (*ENUMERATOR.0).GetDefaultAudioEndpoint(winapi::eRender,
|
let hres = (*ENUMERATOR.0)
|
||||||
winapi::eConsole, &mut device);
|
.GetDefaultAudioEndpoint(winapi::eRender, winapi::eConsole, &mut device);
|
||||||
|
|
||||||
if let Err(_err) = check_result(hres) {
|
if let Err(_err) = check_result(hres) {
|
||||||
return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise
|
return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise
|
||||||
|
|
|
@ -2,23 +2,23 @@ extern crate winapi;
|
||||||
extern crate ole32;
|
extern crate ole32;
|
||||||
extern crate kernel32;
|
extern crate kernel32;
|
||||||
|
|
||||||
use std::io::Error as IoError;
|
|
||||||
use std::os::windows::ffi::OsStringExt;
|
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::io::Error as IoError;
|
||||||
use std::ptr;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::os::windows::ffi::OsStringExt;
|
||||||
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
|
use ChannelPosition;
|
||||||
use Format;
|
use Format;
|
||||||
use FormatsEnumerationError;
|
use FormatsEnumerationError;
|
||||||
use ChannelPosition;
|
|
||||||
use SamplesRate;
|
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
|
use SamplesRate;
|
||||||
|
|
||||||
pub use std::option::IntoIter as OptionIntoIter;
|
|
||||||
pub use self::enumerate::{EndpointsIterator, get_default_endpoint};
|
pub use self::enumerate::{EndpointsIterator, get_default_endpoint};
|
||||||
pub use self::voice::{Voice, Buffer, EventLoop, SamplesStream};
|
pub use self::voice::{Buffer, EventLoop, SamplesStream, Voice};
|
||||||
|
pub use std::option::IntoIter as OptionIntoIter;
|
||||||
|
|
||||||
pub type SupportedFormatsIterator = OptionIntoIter<Format>;
|
pub type SupportedFormatsIterator = OptionIntoIter<Format>;
|
||||||
|
|
||||||
|
@ -38,8 +38,10 @@ fn check_result(result: winapi::HRESULT) -> Result<(), IoError> {
|
||||||
/// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
|
/// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct IAudioClientWrapper(*mut winapi::IAudioClient);
|
struct IAudioClientWrapper(*mut winapi::IAudioClient);
|
||||||
unsafe impl Send for IAudioClientWrapper {}
|
unsafe impl Send for IAudioClientWrapper {
|
||||||
unsafe impl Sync for IAudioClientWrapper {}
|
}
|
||||||
|
unsafe impl Sync for IAudioClientWrapper {
|
||||||
|
}
|
||||||
|
|
||||||
/// An opaque type that identifies an end point.
|
/// An opaque type that identifies an end point.
|
||||||
pub struct Endpoint {
|
pub struct Endpoint {
|
||||||
|
@ -50,8 +52,10 @@ pub struct Endpoint {
|
||||||
future_audio_client: Arc<Mutex<Option<IAudioClientWrapper>>>, // TODO: add NonZero around the ptr
|
future_audio_client: Arc<Mutex<Option<IAudioClientWrapper>>>, // TODO: add NonZero around the ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Endpoint {}
|
unsafe impl Send for Endpoint {
|
||||||
unsafe impl Sync for Endpoint {}
|
}
|
||||||
|
unsafe impl Sync for Endpoint {
|
||||||
|
}
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
// TODO: this function returns a GUID of the endpoin
|
// TODO: this function returns a GUID of the endpoin
|
||||||
|
@ -87,7 +91,8 @@ impl Endpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that `future_audio_client` contains a `Some` and returns a locked mutex to it.
|
/// Ensures that `future_audio_client` contains a `Some` and returns a locked mutex to it.
|
||||||
fn ensure_future_audio_client(&self) -> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> {
|
fn ensure_future_audio_client(&self)
|
||||||
|
-> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> {
|
||||||
let mut lock = self.future_audio_client.lock().unwrap();
|
let mut lock = self.future_audio_client.lock().unwrap();
|
||||||
if lock.is_some() {
|
if lock.is_some() {
|
||||||
return Ok(lock);
|
return Ok(lock);
|
||||||
|
@ -95,12 +100,14 @@ impl Endpoint {
|
||||||
|
|
||||||
let audio_client: *mut winapi::IAudioClient = unsafe {
|
let audio_client: *mut winapi::IAudioClient = unsafe {
|
||||||
let mut audio_client = mem::uninitialized();
|
let mut audio_client = mem::uninitialized();
|
||||||
let hresult = (*self.device).Activate(&winapi::IID_IAudioClient, winapi::CLSCTX_ALL,
|
let hresult = (*self.device).Activate(&winapi::IID_IAudioClient,
|
||||||
ptr::null_mut(), &mut audio_client);
|
winapi::CLSCTX_ALL,
|
||||||
|
ptr::null_mut(),
|
||||||
|
&mut audio_client);
|
||||||
|
|
||||||
// can fail if the device has been disconnected since we enumerated it, or if
|
// can fail if the device has been disconnected since we enumerated it, or if
|
||||||
// the device doesn't support playback for some reason
|
// the device doesn't support playback for some reason
|
||||||
try!(check_result(hresult));
|
check_result(hresult)?;
|
||||||
assert!(!audio_client.is_null());
|
assert!(!audio_client.is_null());
|
||||||
audio_client as *mut _
|
audio_client as *mut _
|
||||||
};
|
};
|
||||||
|
@ -112,15 +119,15 @@ impl Endpoint {
|
||||||
/// Returns an uninitialized `IAudioClient`.
|
/// Returns an uninitialized `IAudioClient`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn build_audioclient(&self) -> Result<*mut winapi::IAudioClient, IoError> {
|
fn build_audioclient(&self) -> Result<*mut winapi::IAudioClient, IoError> {
|
||||||
let mut lock = try!(self.ensure_future_audio_client());
|
let mut lock = self.ensure_future_audio_client()?;
|
||||||
let client = lock.unwrap().0;
|
let client = lock.unwrap().0;
|
||||||
*lock = None;
|
*lock = None;
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_supported_formats_list(&self)
|
pub fn get_supported_formats_list(
|
||||||
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
|
&self)
|
||||||
{
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError> {
|
||||||
// We always create voices in shared mode, therefore all samples go through an audio
|
// We always create voices in shared mode, therefore all samples go through an audio
|
||||||
// processor to mix them together.
|
// processor to mix them together.
|
||||||
// However there is no way to query the list of all formats that are supported by the
|
// However there is no way to query the list of all formats that are supported by the
|
||||||
|
@ -150,10 +157,8 @@ impl Endpoint {
|
||||||
let format = {
|
let format = {
|
||||||
let (channels, data_type) = match (*format_ptr).wFormatTag {
|
let (channels, data_type) = match (*format_ptr).wFormatTag {
|
||||||
winapi::WAVE_FORMAT_PCM => {
|
winapi::WAVE_FORMAT_PCM => {
|
||||||
(
|
(vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
||||||
vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
SampleFormat::I16)
|
||||||
SampleFormat::I16
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
winapi::WAVE_FORMAT_EXTENSIBLE => {
|
winapi::WAVE_FORMAT_EXTENSIBLE => {
|
||||||
let format_ptr = format_ptr as *const winapi::WAVEFORMATEXTENSIBLE;
|
let format_ptr = format_ptr as *const winapi::WAVEFORMATEXTENSIBLE;
|
||||||
|
@ -162,24 +167,60 @@ impl Endpoint {
|
||||||
let mut channels = Vec::new();
|
let mut channels = Vec::new();
|
||||||
|
|
||||||
let mask = (*format_ptr).dwChannelMask;
|
let mask = (*format_ptr).dwChannelMask;
|
||||||
if (mask & winapi::SPEAKER_FRONT_LEFT) != 0 { channels.push(ChannelPosition::FrontLeft); }
|
if (mask & winapi::SPEAKER_FRONT_LEFT) != 0 {
|
||||||
if (mask & winapi::SPEAKER_FRONT_RIGHT) != 0 { channels.push(ChannelPosition::FrontRight); }
|
channels.push(ChannelPosition::FrontLeft);
|
||||||
if (mask & winapi::SPEAKER_FRONT_CENTER) != 0 { channels.push(ChannelPosition::FrontCenter); }
|
}
|
||||||
if (mask & winapi::SPEAKER_LOW_FREQUENCY) != 0 { channels.push(ChannelPosition::LowFrequency); }
|
if (mask & winapi::SPEAKER_FRONT_RIGHT) != 0 {
|
||||||
if (mask & winapi::SPEAKER_BACK_LEFT) != 0 { channels.push(ChannelPosition::BackLeft); }
|
channels.push(ChannelPosition::FrontRight);
|
||||||
if (mask & winapi::SPEAKER_BACK_RIGHT) != 0 { channels.push(ChannelPosition::BackRight); }
|
}
|
||||||
if (mask & winapi::SPEAKER_FRONT_LEFT_OF_CENTER) != 0 { channels.push(ChannelPosition::FrontLeftOfCenter); }
|
if (mask & winapi::SPEAKER_FRONT_CENTER) != 0 {
|
||||||
if (mask & winapi::SPEAKER_FRONT_RIGHT_OF_CENTER) != 0 { channels.push(ChannelPosition::FrontRightOfCenter); }
|
channels.push(ChannelPosition::FrontCenter);
|
||||||
if (mask & winapi::SPEAKER_BACK_CENTER) != 0 { channels.push(ChannelPosition::BackCenter); }
|
}
|
||||||
if (mask & winapi::SPEAKER_SIDE_LEFT) != 0 { channels.push(ChannelPosition::SideLeft); }
|
if (mask & winapi::SPEAKER_LOW_FREQUENCY) != 0 {
|
||||||
if (mask & winapi::SPEAKER_SIDE_RIGHT) != 0 { channels.push(ChannelPosition::SideRight); }
|
channels.push(ChannelPosition::LowFrequency);
|
||||||
if (mask & winapi::SPEAKER_TOP_CENTER) != 0 { channels.push(ChannelPosition::TopCenter); }
|
}
|
||||||
if (mask & winapi::SPEAKER_TOP_FRONT_LEFT) != 0 { channels.push(ChannelPosition::TopFrontLeft); }
|
if (mask & winapi::SPEAKER_BACK_LEFT) != 0 {
|
||||||
if (mask & winapi::SPEAKER_TOP_FRONT_CENTER) != 0 { channels.push(ChannelPosition::TopFrontCenter); }
|
channels.push(ChannelPosition::BackLeft);
|
||||||
if (mask & winapi::SPEAKER_TOP_FRONT_RIGHT) != 0 { channels.push(ChannelPosition::TopFrontRight); }
|
}
|
||||||
if (mask & winapi::SPEAKER_TOP_BACK_LEFT) != 0 { channels.push(ChannelPosition::TopBackLeft); }
|
if (mask & winapi::SPEAKER_BACK_RIGHT) != 0 {
|
||||||
if (mask & winapi::SPEAKER_TOP_BACK_CENTER) != 0 { channels.push(ChannelPosition::TopBackCenter); }
|
channels.push(ChannelPosition::BackRight);
|
||||||
if (mask & winapi::SPEAKER_TOP_BACK_RIGHT) != 0 { channels.push(ChannelPosition::TopBackRight); }
|
}
|
||||||
|
if (mask & winapi::SPEAKER_FRONT_LEFT_OF_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::FrontLeftOfCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_FRONT_RIGHT_OF_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::FrontRightOfCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_BACK_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::BackCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_SIDE_LEFT) != 0 {
|
||||||
|
channels.push(ChannelPosition::SideLeft);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_SIDE_RIGHT) != 0 {
|
||||||
|
channels.push(ChannelPosition::SideRight);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_FRONT_LEFT) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopFrontLeft);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_FRONT_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopFrontCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_FRONT_RIGHT) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopFrontRight);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_BACK_LEFT) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopBackLeft);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_BACK_CENTER) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopBackCenter);
|
||||||
|
}
|
||||||
|
if (mask & winapi::SPEAKER_TOP_BACK_RIGHT) != 0 {
|
||||||
|
channels.push(ChannelPosition::TopBackRight);
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!((*format_ptr).Format.nChannels as usize, channels.len());
|
assert_eq!((*format_ptr).Format.nChannels as usize, channels.len());
|
||||||
channels
|
channels
|
||||||
|
@ -187,8 +228,8 @@ impl Endpoint {
|
||||||
|
|
||||||
let format = {
|
let format = {
|
||||||
fn cmp_guid(a: &winapi::GUID, b: &winapi::GUID) -> bool {
|
fn cmp_guid(a: &winapi::GUID, b: &winapi::GUID) -> bool {
|
||||||
a.Data1 == b.Data1 && a.Data2 == b.Data2 &&
|
a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 &&
|
||||||
a.Data3 == b.Data3 && a.Data4 == b.Data4
|
a.Data4 == b.Data4
|
||||||
}
|
}
|
||||||
if cmp_guid(&(*format_ptr).SubFormat,
|
if cmp_guid(&(*format_ptr).SubFormat,
|
||||||
&winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
|
&winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
|
||||||
|
@ -207,7 +248,7 @@ impl Endpoint {
|
||||||
(channels, format)
|
(channels, format)
|
||||||
},
|
},
|
||||||
|
|
||||||
f => panic!("Unknown data format returned by GetMixFormat: {:?}", f)
|
f => panic!("Unknown data format returned by GetMixFormat: {:?}", f),
|
||||||
};
|
};
|
||||||
|
|
||||||
Format {
|
Format {
|
||||||
|
@ -231,12 +272,15 @@ impl PartialEq for Endpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Endpoint {}
|
impl Eq for Endpoint {
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for Endpoint {
|
impl Clone for Endpoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Endpoint {
|
fn clone(&self) -> Endpoint {
|
||||||
unsafe { (*self.device).AddRef(); }
|
unsafe {
|
||||||
|
(*self.device).AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
Endpoint {
|
Endpoint {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
|
@ -248,10 +292,14 @@ impl Clone for Endpoint {
|
||||||
impl Drop for Endpoint {
|
impl Drop for Endpoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { (*self.device).Release(); }
|
unsafe {
|
||||||
|
(*self.device).Release();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(client) = self.future_audio_client.lock().unwrap().take() {
|
if let Some(client) = self.future_audio_client.lock().unwrap().take() {
|
||||||
unsafe { (*client.0).Release(); }
|
unsafe {
|
||||||
|
(*client.0).Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
|
|
||||||
|
use super::Endpoint;
|
||||||
|
use super::check_result;
|
||||||
use super::com;
|
use super::com;
|
||||||
use super::kernel32;
|
use super::kernel32;
|
||||||
use super::ole32;
|
use super::ole32;
|
||||||
use super::winapi;
|
use super::winapi;
|
||||||
use super::Endpoint;
|
|
||||||
use super::check_result;
|
|
||||||
|
|
||||||
use std::slice;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::slice;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use futures::Poll;
|
|
||||||
use futures::task::Task;
|
|
||||||
use futures::task;
|
|
||||||
use futures::stream::Stream;
|
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
|
use futures::Poll;
|
||||||
|
use futures::stream::Stream;
|
||||||
|
use futures::task;
|
||||||
|
use futures::task::Task;
|
||||||
|
|
||||||
use CreationError;
|
|
||||||
use ChannelPosition;
|
use ChannelPosition;
|
||||||
|
use CreationError;
|
||||||
use Format;
|
use Format;
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
use UnknownTypeBuffer;
|
use UnknownTypeBuffer;
|
||||||
|
@ -29,8 +30,10 @@ pub struct EventLoop {
|
||||||
inner: Arc<EventLoopInner>,
|
inner: Arc<EventLoopInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for EventLoop {}
|
unsafe impl Send for EventLoop {
|
||||||
unsafe impl Sync for EventLoop {}
|
}
|
||||||
|
unsafe impl Sync for EventLoop {
|
||||||
|
}
|
||||||
|
|
||||||
struct EventLoopInner {
|
struct EventLoopInner {
|
||||||
// List of handles that are currently being polled or that are going to be polled. This mutex
|
// List of handles that are currently being polled or that are going to be polled. This mutex
|
||||||
|
@ -67,9 +70,8 @@ struct EventLoopScheduled {
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub fn new() -> EventLoop {
|
pub fn new() -> EventLoop {
|
||||||
let pending_scheduled_event = unsafe {
|
let pending_scheduled_event =
|
||||||
kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null())
|
unsafe { kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) };
|
||||||
};
|
|
||||||
|
|
||||||
EventLoop {
|
EventLoop {
|
||||||
inner: Arc::new(EventLoopInner {
|
inner: Arc::new(EventLoopInner {
|
||||||
|
@ -81,8 +83,8 @@ impl EventLoop {
|
||||||
pending_scheduled: Mutex::new(EventLoopScheduled {
|
pending_scheduled: Mutex::new(EventLoopScheduled {
|
||||||
handles: vec![],
|
handles: vec![],
|
||||||
task_handles: vec![],
|
task_handles: vec![],
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +103,8 @@ impl EventLoop {
|
||||||
// sound needs a buffer.
|
// sound needs a buffer.
|
||||||
let result = kernel32::WaitForMultipleObjectsEx(scheduled.handles.len() as u32,
|
let result = kernel32::WaitForMultipleObjectsEx(scheduled.handles.len() as u32,
|
||||||
scheduled.handles.as_ptr(),
|
scheduled.handles.as_ptr(),
|
||||||
winapi::FALSE, winapi::INFINITE, /* TODO: allow setting a timeout */
|
winapi::FALSE,
|
||||||
|
winapi::INFINITE, /* TODO: allow setting a timeout */
|
||||||
winapi::FALSE /* irrelevant parameter here */);
|
winapi::FALSE /* irrelevant parameter here */);
|
||||||
|
|
||||||
// Notifying the corresponding task handler.
|
// Notifying the corresponding task handler.
|
||||||
|
@ -150,21 +153,24 @@ pub struct SamplesStream {
|
||||||
ready: Arc<AtomicBool>,
|
ready: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for SamplesStream {}
|
unsafe impl Send for SamplesStream {
|
||||||
unsafe impl Sync for SamplesStream {}
|
}
|
||||||
|
unsafe impl Sync for SamplesStream {
|
||||||
|
}
|
||||||
|
|
||||||
struct VoiceInner {
|
struct VoiceInner {
|
||||||
audio_client: *mut winapi::IAudioClient,
|
audio_client: *mut winapi::IAudioClient,
|
||||||
render_client: *mut winapi::IAudioRenderClient,
|
render_client: *mut winapi::IAudioRenderClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Voice {}
|
unsafe impl Send for Voice {
|
||||||
unsafe impl Sync for Voice {}
|
}
|
||||||
|
unsafe impl Sync for Voice {
|
||||||
|
}
|
||||||
|
|
||||||
impl Voice {
|
impl Voice {
|
||||||
pub fn new(end_point: &Endpoint, format: &Format, event_loop: &EventLoop)
|
pub fn new(end_point: &Endpoint, format: &Format, event_loop: &EventLoop)
|
||||||
-> Result<(Voice, SamplesStream), CreationError>
|
-> Result<(Voice, SamplesStream), CreationError> {
|
||||||
{
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Making sure that COM is initialized.
|
// Making sure that COM is initialized.
|
||||||
// It's not actually sure that this is required, but when in doubt do it.
|
// It's not actually sure that this is required, but when in doubt do it.
|
||||||
|
@ -179,14 +185,15 @@ impl Voice {
|
||||||
|
|
||||||
// Computing the format and initializing the device.
|
// Computing the format and initializing the device.
|
||||||
let format = {
|
let format = {
|
||||||
let format_attempt = try!(format_to_waveformatextensible(format));
|
let format_attempt = format_to_waveformatextensible(format)?;
|
||||||
let share_mode = winapi::AUDCLNT_SHAREMODE_SHARED;
|
let share_mode = winapi::AUDCLNT_SHAREMODE_SHARED;
|
||||||
|
|
||||||
// `IsFormatSupported` checks whether the format is supported and fills
|
// `IsFormatSupported` checks whether the format is supported and fills
|
||||||
// a `WAVEFORMATEX`
|
// a `WAVEFORMATEX`
|
||||||
let mut dummy_fmt_ptr: *mut winapi::WAVEFORMATEX = mem::uninitialized();
|
let mut dummy_fmt_ptr: *mut winapi::WAVEFORMATEX = mem::uninitialized();
|
||||||
let hresult = (*audio_client).IsFormatSupported(share_mode, &format_attempt.Format,
|
let hresult =
|
||||||
&mut dummy_fmt_ptr);
|
(*audio_client)
|
||||||
|
.IsFormatSupported(share_mode, &format_attempt.Format, &mut dummy_fmt_ptr);
|
||||||
// we free that `WAVEFORMATEX` immediately after because we don't need it
|
// we free that `WAVEFORMATEX` immediately after because we don't need it
|
||||||
if !dummy_fmt_ptr.is_null() {
|
if !dummy_fmt_ptr.is_null() {
|
||||||
ole32::CoTaskMemFree(dummy_fmt_ptr as *mut _);
|
ole32::CoTaskMemFree(dummy_fmt_ptr as *mut _);
|
||||||
|
@ -196,8 +203,7 @@ impl Voice {
|
||||||
// has been found) but we also treat this as an error
|
// has been found) but we also treat this as an error
|
||||||
match (hresult, check_result(hresult)) {
|
match (hresult, check_result(hresult)) {
|
||||||
(_, Err(ref e))
|
(_, Err(ref e))
|
||||||
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => {
|
||||||
{
|
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
return Err(CreationError::DeviceNotAvailable);
|
return Err(CreationError::DeviceNotAvailable);
|
||||||
},
|
},
|
||||||
|
@ -215,10 +221,13 @@ impl Voice {
|
||||||
// finally initializing the audio client
|
// finally initializing the audio client
|
||||||
let hresult = (*audio_client).Initialize(share_mode,
|
let hresult = (*audio_client).Initialize(share_mode,
|
||||||
winapi::AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
winapi::AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
||||||
0, 0, &format_attempt.Format, ptr::null());
|
0,
|
||||||
|
0,
|
||||||
|
&format_attempt.Format,
|
||||||
|
ptr::null());
|
||||||
match check_result(hresult) {
|
match check_result(hresult) {
|
||||||
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
Err(ref e)
|
||||||
{
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
return Err(CreationError::DeviceNotAvailable);
|
return Err(CreationError::DeviceNotAvailable);
|
||||||
},
|
},
|
||||||
|
@ -245,7 +254,7 @@ impl Voice {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("Failed to call SetEventHandle")
|
panic!("Failed to call SetEventHandle")
|
||||||
},
|
},
|
||||||
Ok(_) => ()
|
Ok(_) => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
event
|
event
|
||||||
|
@ -257,8 +266,8 @@ impl Voice {
|
||||||
let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
|
let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
|
||||||
|
|
||||||
match check_result(hresult) {
|
match check_result(hresult) {
|
||||||
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
Err(ref e)
|
||||||
{
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
return Err(CreationError::DeviceNotAvailable);
|
return Err(CreationError::DeviceNotAvailable);
|
||||||
},
|
},
|
||||||
|
@ -276,13 +285,13 @@ impl Voice {
|
||||||
let render_client = {
|
let render_client = {
|
||||||
let mut render_client: *mut winapi::IAudioRenderClient = mem::uninitialized();
|
let mut render_client: *mut winapi::IAudioRenderClient = mem::uninitialized();
|
||||||
let hresult = (*audio_client).GetService(&winapi::IID_IAudioRenderClient,
|
let hresult = (*audio_client).GetService(&winapi::IID_IAudioRenderClient,
|
||||||
&mut render_client
|
&mut render_client as
|
||||||
as *mut *mut winapi::IAudioRenderClient
|
*mut *mut winapi::IAudioRenderClient as
|
||||||
as *mut _);
|
*mut _);
|
||||||
|
|
||||||
match check_result(hresult) {
|
match check_result(hresult) {
|
||||||
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
Err(ref e)
|
||||||
{
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
return Err(CreationError::DeviceNotAvailable);
|
return Err(CreationError::DeviceNotAvailable);
|
||||||
},
|
},
|
||||||
|
@ -354,7 +363,9 @@ impl SamplesStream {
|
||||||
fn schedule(&mut self) {
|
fn schedule(&mut self) {
|
||||||
let mut pending = self.event_loop.pending_scheduled.lock().unwrap();
|
let mut pending = self.event_loop.pending_scheduled.lock().unwrap();
|
||||||
pending.handles.push(self.event);
|
pending.handles.push(self.event);
|
||||||
pending.task_handles.push((task::park(), self.ready.clone()));
|
pending
|
||||||
|
.task_handles
|
||||||
|
.push((task::park(), self.ready.clone()));
|
||||||
drop(pending);
|
drop(pending);
|
||||||
|
|
||||||
let result = unsafe { kernel32::SetEvent(self.event_loop.pending_scheduled_event) };
|
let result = unsafe { kernel32::SetEvent(self.event_loop.pending_scheduled_event) };
|
||||||
|
@ -379,7 +390,7 @@ impl Stream for SamplesStream {
|
||||||
self.schedule();
|
self.schedule();
|
||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
},
|
},
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,13 +414,14 @@ impl Stream for SamplesStream {
|
||||||
// Obtaining a pointer to the buffer.
|
// Obtaining a pointer to the buffer.
|
||||||
let (buffer_data, buffer_len) = {
|
let (buffer_data, buffer_len) = {
|
||||||
let mut buffer: *mut winapi::BYTE = mem::uninitialized();
|
let mut buffer: *mut winapi::BYTE = mem::uninitialized();
|
||||||
let hresult = (*inner.render_client).GetBuffer(frames_available,
|
let hresult = (*inner.render_client)
|
||||||
&mut buffer as *mut *mut _);
|
.GetBuffer(frames_available, &mut buffer as *mut *mut _);
|
||||||
check_result(hresult).unwrap(); // FIXME: can return `AUDCLNT_E_DEVICE_INVALIDATED`
|
check_result(hresult).unwrap(); // FIXME: can return `AUDCLNT_E_DEVICE_INVALIDATED`
|
||||||
debug_assert!(!buffer.is_null());
|
debug_assert!(!buffer.is_null());
|
||||||
|
|
||||||
(buffer as *mut _,
|
(buffer as *mut _,
|
||||||
frames_available as usize * self.bytes_per_frame as usize / mem::size_of::<f32>()) // FIXME: correct size
|
frames_available as usize * self.bytes_per_frame as usize /
|
||||||
|
mem::size_of::<f32>()) // FIXME: correct size
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = Buffer {
|
let buffer = Buffer {
|
||||||
|
@ -419,7 +431,9 @@ impl Stream for SamplesStream {
|
||||||
frames: frames_available,
|
frames: frames_available,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Async::Ready(Some(UnknownTypeBuffer::F32(::Buffer { target: Some(buffer) })))) // FIXME: not necessarily F32
|
Ok(Async::Ready(Some(UnknownTypeBuffer::F32(::Buffer {
|
||||||
|
target: Some(buffer),
|
||||||
|
})))) // FIXME: not necessarily F32
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,14 +464,13 @@ pub struct Buffer<T> {
|
||||||
frames: winapi::UINT32,
|
frames: winapi::UINT32,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> Send for Buffer<T> {}
|
unsafe impl<T> Send for Buffer<T> {
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Buffer<T> {
|
impl<T> Buffer<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_buffer(&mut self) -> &mut [T] {
|
pub fn get_buffer(&mut self) -> &mut [T] {
|
||||||
unsafe {
|
unsafe { slice::from_raw_parts_mut(self.buffer_data, self.buffer_len) }
|
||||||
slice::from_raw_parts_mut(self.buffer_data, self.buffer_len)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -472,8 +485,7 @@ impl<T> Buffer<T> {
|
||||||
let hresult = (*inner.render_client).ReleaseBuffer(self.frames as u32, 0);
|
let hresult = (*inner.render_client).ReleaseBuffer(self.frames as u32, 0);
|
||||||
match check_result(hresult) {
|
match check_result(hresult) {
|
||||||
// ignoring the error that is produced if the device has been disconnected
|
// ignoring the error that is produced if the device has been disconnected
|
||||||
Err(ref e)
|
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => (),
|
||||||
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => (),
|
|
||||||
e => e.unwrap(),
|
e => e.unwrap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -481,8 +493,7 @@ impl<T> Buffer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_to_waveformatextensible(format: &Format)
|
fn format_to_waveformatextensible(format: &Format)
|
||||||
-> Result<winapi::WAVEFORMATEXTENSIBLE, CreationError>
|
-> Result<winapi::WAVEFORMATEXTENSIBLE, CreationError> {
|
||||||
{
|
|
||||||
Ok(winapi::WAVEFORMATEXTENSIBLE {
|
Ok(winapi::WAVEFORMATEXTENSIBLE {
|
||||||
Format: winapi::WAVEFORMATEX {
|
Format: winapi::WAVEFORMATEX {
|
||||||
wFormatTag: match format.data_type {
|
wFormatTag: match format.data_type {
|
||||||
|
@ -501,7 +512,8 @@ fn format_to_waveformatextensible(format: &Format)
|
||||||
cbSize: match format.data_type {
|
cbSize: match format.data_type {
|
||||||
SampleFormat::I16 => 0,
|
SampleFormat::I16 => 0,
|
||||||
SampleFormat::F32 => (mem::size_of::<winapi::WAVEFORMATEXTENSIBLE>() -
|
SampleFormat::F32 => (mem::size_of::<winapi::WAVEFORMATEXTENSIBLE>() -
|
||||||
mem::size_of::<winapi::WAVEFORMATEX>()) as winapi::WORD,
|
mem::size_of::<winapi::WAVEFORMATEX>()) as
|
||||||
|
winapi::WORD,
|
||||||
SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
|
SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue