2015-09-01 09:23:41 +00:00
|
|
|
use super::com;
|
2016-08-02 14:13:59 +00:00
|
|
|
use super::kernel32;
|
2015-09-01 09:23:41 +00:00
|
|
|
use super::ole32;
|
|
|
|
use super::winapi;
|
|
|
|
use super::Endpoint;
|
|
|
|
use super::check_result;
|
|
|
|
|
|
|
|
use std::slice;
|
|
|
|
use std::mem;
|
|
|
|
use std::ptr;
|
2016-08-02 14:13:59 +00:00
|
|
|
use std::sync::atomic::AtomicBool;
|
|
|
|
use std::sync::atomic::Ordering;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use std::sync::Mutex;
|
|
|
|
|
|
|
|
use futures::Poll;
|
|
|
|
use futures::Task;
|
|
|
|
use futures::TaskHandle;
|
|
|
|
use futures::stream::Stream;
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2015-09-01 12:17:57 +00:00
|
|
|
use CreationError;
|
2015-09-10 09:44:19 +00:00
|
|
|
use ChannelPosition;
|
2015-09-01 11:53:54 +00:00
|
|
|
use Format;
|
2015-09-01 12:51:35 +00:00
|
|
|
use SampleFormat;
|
2016-08-02 14:13:59 +00:00
|
|
|
use UnknownTypeBuffer;
|
|
|
|
|
|
|
|
pub struct EventLoop {
|
|
|
|
inner: Arc<EventLoopInner>,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for EventLoop {}
|
|
|
|
unsafe impl Sync for EventLoop {}
|
|
|
|
|
|
|
|
struct EventLoopInner {
|
2016-08-12 16:06:17 +00:00
|
|
|
// List of handles that are currently being polled or that are going to be polled. This mutex
|
|
|
|
// is locked for as long as the event loop is running.
|
|
|
|
//
|
|
|
|
// In the `EventLoopScheduled`, the first handle in the list of handles is always
|
|
|
|
// `pending_scheduled_event`. This means that the length of `handles` is always 1 + the length
|
|
|
|
// of `task_handles`.
|
|
|
|
// FIXME: no way to remove elements from that list?
|
2016-08-02 14:13:59 +00:00
|
|
|
scheduled: Mutex<EventLoopScheduled>,
|
2016-08-12 16:06:17 +00:00
|
|
|
|
|
|
|
// Since the above mutex is locked most of the time, we add new handles to this list instead.
|
|
|
|
// After a new element is added to this list, you should notify `pending_scheduled_event`
|
|
|
|
// so that they get transferred to `scheduled`.
|
|
|
|
//
|
|
|
|
// The length of `handles` and `task_handles` should always be equal.
|
2016-08-02 14:13:59 +00:00
|
|
|
pending_scheduled: Mutex<EventLoopScheduled>,
|
2016-08-12 16:06:17 +00:00
|
|
|
|
|
|
|
// This event is signalled after elements have been added to `pending_scheduled` in order to
|
|
|
|
// notify that they should be picked up.
|
|
|
|
pending_scheduled_event: winapi::HANDLE,
|
2016-08-02 14:13:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct EventLoopScheduled {
|
|
|
|
// List of handles that correspond to voices.
|
|
|
|
// They are linked to `task_handles`, but we store them separately in order to easily call
|
|
|
|
// `WaitForMultipleObjectsEx` on the array without having to perform any conversion.
|
|
|
|
handles: Vec<winapi::HANDLE>,
|
|
|
|
|
2016-08-12 16:06:17 +00:00
|
|
|
// List of task handles corresponding to `handles`. The second element is used to signal
|
|
|
|
// the voice that it has been signaled.
|
2016-08-02 14:13:59 +00:00
|
|
|
task_handles: Vec<(TaskHandle, Arc<AtomicBool>)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EventLoop {
|
|
|
|
pub fn new() -> EventLoop {
|
|
|
|
let pending_scheduled_event = unsafe {
|
|
|
|
kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null())
|
|
|
|
};
|
|
|
|
|
|
|
|
EventLoop {
|
|
|
|
inner: Arc::new(EventLoopInner {
|
|
|
|
pending_scheduled_event: pending_scheduled_event,
|
|
|
|
scheduled: Mutex::new(EventLoopScheduled {
|
|
|
|
handles: vec![pending_scheduled_event],
|
|
|
|
task_handles: vec![],
|
|
|
|
}),
|
|
|
|
pending_scheduled: Mutex::new(EventLoopScheduled {
|
|
|
|
handles: vec![],
|
|
|
|
task_handles: vec![],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(&self) {
|
|
|
|
unsafe {
|
|
|
|
let mut scheduled = self.inner.scheduled.lock().unwrap();
|
|
|
|
|
|
|
|
loop {
|
2016-08-12 16:06:17 +00:00
|
|
|
debug_assert!(scheduled.handles.len() == 1 + scheduled.task_handles.len());
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
// Creating a voice checks for the MAXIMUM_WAIT_OBJECTS limit.
|
2016-08-12 16:06:17 +00:00
|
|
|
// FIXME: this is not the case ^
|
2016-08-02 14:13:59 +00:00
|
|
|
debug_assert!(scheduled.handles.len() <= winapi::MAXIMUM_WAIT_OBJECTS as usize);
|
|
|
|
|
|
|
|
// Wait for any of the handles to be signalled, which means that the corresponding
|
|
|
|
// sound needs a buffer.
|
|
|
|
let result = kernel32::WaitForMultipleObjectsEx(scheduled.handles.len() as u32,
|
|
|
|
scheduled.handles.as_ptr(),
|
|
|
|
winapi::FALSE, winapi::INFINITE, /* TODO: allow setting a timeout */
|
|
|
|
winapi::FALSE /* irrelevant parameter here */);
|
|
|
|
|
|
|
|
// Notifying the corresponding task handler.
|
|
|
|
assert!(result >= winapi::WAIT_OBJECT_0);
|
|
|
|
let handle_id = (result - winapi::WAIT_OBJECT_0) as usize;
|
|
|
|
|
|
|
|
if handle_id == 0 {
|
2016-08-12 16:06:17 +00:00
|
|
|
// The `pending_scheduled_event` handle has been notified, which means that we
|
|
|
|
// should pick up the content of `pending_scheduled`.
|
2016-08-02 14:13:59 +00:00
|
|
|
let mut pending = self.inner.pending_scheduled.lock().unwrap();
|
|
|
|
scheduled.handles.append(&mut pending.handles);
|
|
|
|
scheduled.task_handles.append(&mut pending.task_handles);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
scheduled.handles.remove(handle_id);
|
|
|
|
let (task_handle, ready) = scheduled.task_handles.remove(handle_id - 1);
|
|
|
|
ready.store(true, Ordering::Relaxed);
|
|
|
|
task_handle.notify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for EventLoop {
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
kernel32::CloseHandle(self.inner.pending_scheduled_event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-01 11:53:54 +00:00
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
pub struct Voice {
|
2016-08-02 14:13:59 +00:00
|
|
|
inner: Arc<Mutex<VoiceInner>>,
|
|
|
|
playing: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SamplesStream {
|
|
|
|
event_loop: Arc<EventLoopInner>,
|
|
|
|
inner: Arc<Mutex<VoiceInner>>,
|
|
|
|
// The event that is signalled whenever a buffer is ready to be submitted to the voice.
|
|
|
|
event: winapi::HANDLE, // TODO: not deleted
|
2015-09-01 09:23:41 +00:00
|
|
|
max_frames_in_buffer: winapi::UINT32,
|
|
|
|
bytes_per_frame: winapi::WORD,
|
2016-08-02 14:13:59 +00:00
|
|
|
ready: Arc<AtomicBool>,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for SamplesStream {}
|
|
|
|
unsafe impl Sync for SamplesStream {}
|
|
|
|
|
|
|
|
struct VoiceInner {
|
|
|
|
audio_client: *mut winapi::IAudioClient,
|
|
|
|
render_client: *mut winapi::IAudioRenderClient,
|
2015-09-01 09:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Voice {}
|
|
|
|
unsafe impl Sync for Voice {}
|
|
|
|
|
|
|
|
impl Voice {
|
2016-08-02 14:13:59 +00:00
|
|
|
pub fn new(end_point: &Endpoint, format: &Format, event_loop: &EventLoop)
|
|
|
|
-> Result<(Voice, SamplesStream), CreationError>
|
|
|
|
{
|
2015-09-01 09:23:41 +00:00
|
|
|
unsafe {
|
2016-08-12 16:06:17 +00:00
|
|
|
// Making sure that COM is initialized.
|
|
|
|
// It's not actually sure that this is required, but when in doubt do it.
|
2015-09-01 09:23:41 +00:00
|
|
|
com::com_initialized();
|
|
|
|
|
2016-08-12 16:06:17 +00:00
|
|
|
// Obtaining a `IAudioClient`.
|
2015-09-01 12:17:57 +00:00
|
|
|
let audio_client = match end_point.build_audioclient() {
|
|
|
|
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
|
|
|
return Err(CreationError::DeviceNotAvailable),
|
|
|
|
e => e.unwrap(),
|
2015-09-01 09:23:41 +00:00
|
|
|
};
|
|
|
|
|
2016-08-12 16:06:17 +00:00
|
|
|
// Computing the format and initializing the device.
|
2015-09-01 09:23:41 +00:00
|
|
|
let format = {
|
2015-09-22 11:25:42 +00:00
|
|
|
let format_attempt = try!(format_to_waveformatextensible(format));
|
2015-11-09 22:52:43 +00:00
|
|
|
let share_mode = winapi::AUDCLNT_SHAREMODE_SHARED;
|
2015-09-22 11:25:42 +00:00
|
|
|
|
|
|
|
// `IsFormatSupported` checks whether the format is supported and fills
|
|
|
|
// a `WAVEFORMATEX`
|
|
|
|
let mut dummy_fmt_ptr: *mut winapi::WAVEFORMATEX = mem::uninitialized();
|
|
|
|
let hresult = (*audio_client).IsFormatSupported(share_mode, &format_attempt.Format,
|
|
|
|
&mut dummy_fmt_ptr);
|
|
|
|
// we free that `WAVEFORMATEX` immediately after because we don't need it
|
|
|
|
if !dummy_fmt_ptr.is_null() {
|
|
|
|
ole32::CoTaskMemFree(dummy_fmt_ptr as *mut _);
|
2015-09-01 12:26:25 +00:00
|
|
|
}
|
2015-09-01 12:17:57 +00:00
|
|
|
|
2015-09-22 11:25:42 +00:00
|
|
|
// `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
|
|
|
|
// has been found) but we also treat this as an error
|
|
|
|
match (hresult, check_result(hresult)) {
|
|
|
|
(_, Err(ref e))
|
|
|
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
2015-09-01 12:26:25 +00:00
|
|
|
{
|
|
|
|
(*audio_client).Release();
|
|
|
|
return Err(CreationError::DeviceNotAvailable);
|
|
|
|
},
|
2015-09-22 11:25:42 +00:00
|
|
|
(_, Err(e)) => {
|
2015-09-01 12:26:25 +00:00
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("{:?}", e);
|
|
|
|
},
|
2015-09-22 11:25:42 +00:00
|
|
|
(winapi::S_FALSE, _) => {
|
|
|
|
(*audio_client).Release();
|
|
|
|
return Err(CreationError::FormatNotSupported);
|
|
|
|
},
|
|
|
|
(_, Ok(())) => (),
|
2015-09-01 12:17:57 +00:00
|
|
|
};
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2015-09-22 11:25:42 +00:00
|
|
|
// finally initializing the audio client
|
2016-08-02 14:13:59 +00:00
|
|
|
let hresult = (*audio_client).Initialize(share_mode,
|
|
|
|
winapi::AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
|
|
|
0, 0, &format_attempt.Format, ptr::null());
|
2015-09-01 12:17:57 +00:00
|
|
|
match check_result(hresult) {
|
|
|
|
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
2015-09-01 12:26:25 +00:00
|
|
|
{
|
|
|
|
(*audio_client).Release();
|
|
|
|
return Err(CreationError::DeviceNotAvailable);
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("{:?}", e);
|
|
|
|
},
|
|
|
|
Ok(()) => (),
|
2015-09-01 12:17:57 +00:00
|
|
|
};
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2015-09-01 12:51:35 +00:00
|
|
|
format_attempt.Format
|
2015-09-01 09:23:41 +00:00
|
|
|
};
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
// Creating the event that will be signalled whenever we need to submit some samples.
|
|
|
|
let event = {
|
|
|
|
let event = kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
|
|
|
|
if event == ptr::null_mut() {
|
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("Failed to create event");
|
|
|
|
}
|
|
|
|
|
|
|
|
match check_result((*audio_client).SetEventHandle(event)) {
|
2016-08-12 15:57:06 +00:00
|
|
|
Err(_) => {
|
2016-08-02 14:13:59 +00:00
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("Failed to call SetEventHandle")
|
|
|
|
},
|
|
|
|
Ok(_) => ()
|
|
|
|
};
|
|
|
|
|
|
|
|
event
|
|
|
|
};
|
|
|
|
|
2015-09-22 11:25:42 +00:00
|
|
|
// obtaining the size of the samples buffer in number of frames
|
2015-09-01 09:23:41 +00:00
|
|
|
let max_frames_in_buffer = {
|
|
|
|
let mut max_frames_in_buffer = mem::uninitialized();
|
|
|
|
let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
|
2015-09-01 12:26:25 +00:00
|
|
|
|
2015-09-01 12:17:57 +00:00
|
|
|
match check_result(hresult) {
|
|
|
|
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
2015-09-01 12:26:25 +00:00
|
|
|
{
|
|
|
|
(*audio_client).Release();
|
|
|
|
return Err(CreationError::DeviceNotAvailable);
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("{:?}", e);
|
|
|
|
},
|
|
|
|
Ok(()) => (),
|
2015-09-01 12:17:57 +00:00
|
|
|
};
|
2015-09-01 12:26:25 +00:00
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
max_frames_in_buffer
|
|
|
|
};
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
// Building a `IAudioRenderClient` that will be used to fill the samples buffer.
|
2015-09-01 09:23:41 +00:00
|
|
|
let render_client = {
|
|
|
|
let mut render_client: *mut winapi::IAudioRenderClient = mem::uninitialized();
|
|
|
|
let hresult = (*audio_client).GetService(&winapi::IID_IAudioRenderClient,
|
2015-09-22 11:25:42 +00:00
|
|
|
&mut render_client
|
|
|
|
as *mut *mut winapi::IAudioRenderClient
|
|
|
|
as *mut _);
|
2015-09-01 12:26:25 +00:00
|
|
|
|
2015-09-01 12:17:57 +00:00
|
|
|
match check_result(hresult) {
|
|
|
|
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) =>
|
2015-09-01 12:26:25 +00:00
|
|
|
{
|
|
|
|
(*audio_client).Release();
|
|
|
|
return Err(CreationError::DeviceNotAvailable);
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
(*audio_client).Release();
|
|
|
|
panic!("{:?}", e);
|
|
|
|
},
|
|
|
|
Ok(()) => (),
|
2015-09-01 12:17:57 +00:00
|
|
|
};
|
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
&mut *render_client
|
|
|
|
};
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
// Everything went fine.
|
|
|
|
let inner = Arc::new(Mutex::new(VoiceInner {
|
2015-09-01 09:23:41 +00:00
|
|
|
audio_client: audio_client,
|
|
|
|
render_client: render_client,
|
2016-08-02 14:13:59 +00:00
|
|
|
}));
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
let voice = Voice {
|
|
|
|
inner: inner.clone(),
|
|
|
|
playing: false,
|
2015-09-22 08:26:11 +00:00
|
|
|
};
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
let samples_stream = SamplesStream {
|
|
|
|
event_loop: event_loop.inner.clone(),
|
|
|
|
inner: inner,
|
|
|
|
event: event,
|
|
|
|
max_frames_in_buffer: max_frames_in_buffer,
|
|
|
|
bytes_per_frame: format.nBlockAlign,
|
|
|
|
ready: Arc::new(AtomicBool::new(false)),
|
2015-09-22 08:26:11 +00:00
|
|
|
};
|
2015-09-01 09:23:41 +00:00
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
Ok((voice, samples_stream))
|
2015-09-22 15:52:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
pub fn play(&mut self) {
|
|
|
|
if !self.playing {
|
2016-08-02 14:13:59 +00:00
|
|
|
let mut inner = self.inner.lock().unwrap();
|
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
unsafe {
|
2016-08-02 14:13:59 +00:00
|
|
|
let hresult = (*inner.audio_client).Start();
|
2015-09-01 09:23:41 +00:00
|
|
|
check_result(hresult).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.playing = true;
|
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
pub fn pause(&mut self) {
|
|
|
|
if self.playing {
|
2016-08-02 14:13:59 +00:00
|
|
|
let mut inner = self.inner.lock().unwrap();
|
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
unsafe {
|
2016-08-02 14:13:59 +00:00
|
|
|
let hresult = (*inner.audio_client).Stop();
|
2015-09-01 09:23:41 +00:00
|
|
|
check_result(hresult).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.playing = false;
|
|
|
|
}
|
2016-08-02 14:13:59 +00:00
|
|
|
}
|
2015-09-10 19:03:40 +00:00
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
impl Stream for SamplesStream {
|
|
|
|
type Item = UnknownTypeBuffer;
|
|
|
|
type Error = ();
|
|
|
|
|
2016-08-12 15:57:06 +00:00
|
|
|
fn poll(&mut self, _: &mut Task) -> Poll<Option<Self::Item>, Self::Error> {
|
2015-09-10 19:03:40 +00:00
|
|
|
unsafe {
|
2016-08-02 14:13:59 +00:00
|
|
|
if self.ready.swap(false, Ordering::Relaxed) == false {
|
2016-08-12 16:06:17 +00:00
|
|
|
// Despite its name this function does not block, because we pass `0`.
|
2016-08-02 14:13:59 +00:00
|
|
|
let result = kernel32::WaitForSingleObject(self.event, 0);
|
|
|
|
|
2016-08-12 16:06:17 +00:00
|
|
|
// Returning if the event is not ready.
|
2016-08-02 14:13:59 +00:00
|
|
|
match result {
|
|
|
|
winapi::WAIT_OBJECT_0 => (),
|
|
|
|
winapi::WAIT_TIMEOUT => return Poll::NotReady,
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-12 16:06:17 +00:00
|
|
|
// If we reach here, that means we're ready to accept new samples.
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
let mut inner = self.inner.lock().unwrap();
|
|
|
|
|
|
|
|
// Obtaining the number of frames that are available to be written.
|
|
|
|
let frames_available = {
|
|
|
|
let mut padding = mem::uninitialized();
|
|
|
|
let hresult = (*inner.audio_client).GetCurrentPadding(&mut padding);
|
|
|
|
check_result(hresult).unwrap();
|
|
|
|
self.max_frames_in_buffer - padding
|
|
|
|
};
|
|
|
|
|
|
|
|
// Obtaining a pointer to the buffer.
|
|
|
|
let (buffer_data, buffer_len) = {
|
|
|
|
let mut buffer: *mut winapi::BYTE = mem::uninitialized();
|
|
|
|
let hresult = (*inner.render_client).GetBuffer(frames_available,
|
|
|
|
&mut buffer as *mut *mut _);
|
|
|
|
check_result(hresult).unwrap(); // FIXME: can return `AUDCLNT_E_DEVICE_INVALIDATED`
|
|
|
|
debug_assert!(!buffer.is_null());
|
|
|
|
|
|
|
|
(buffer as *mut _,
|
|
|
|
frames_available as usize * self.bytes_per_frame as usize / mem::size_of::<f32>()) // FIXME: correct size
|
|
|
|
};
|
|
|
|
|
|
|
|
let buffer = Buffer {
|
|
|
|
voice: self.inner.clone(),
|
|
|
|
buffer_data: buffer_data,
|
|
|
|
buffer_len: buffer_len,
|
|
|
|
frames: frames_available,
|
|
|
|
};
|
|
|
|
|
|
|
|
Poll::Ok(Some(UnknownTypeBuffer::F32(::Buffer { target: Some(buffer) }))) // FIXME: not necessarily F32
|
2015-09-10 19:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-02 14:13:59 +00:00
|
|
|
|
|
|
|
fn schedule(&mut self, task: &mut Task) {
|
|
|
|
let mut pending = self.event_loop.pending_scheduled.lock().unwrap();
|
|
|
|
pending.handles.push(self.event);
|
|
|
|
pending.task_handles.push((task.handle().clone(), self.ready.clone()));
|
|
|
|
drop(pending);
|
|
|
|
|
|
|
|
let result = unsafe { kernel32::SetEvent(self.event_loop.pending_scheduled_event) };
|
|
|
|
assert!(result != 0);
|
|
|
|
}
|
2015-09-01 09:23:41 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
impl Drop for VoiceInner {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
(*self.render_client).Release();
|
|
|
|
(*self.audio_client).Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
pub struct Buffer<T> {
|
|
|
|
voice: Arc<Mutex<VoiceInner>>,
|
|
|
|
|
|
|
|
buffer_data: *mut T,
|
|
|
|
buffer_len: usize,
|
|
|
|
frames: winapi::UINT32,
|
2015-09-01 09:23:41 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 14:13:59 +00:00
|
|
|
unsafe impl<T> Send for Buffer<T> {}
|
|
|
|
|
|
|
|
impl<T> Buffer<T> {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2016-08-02 14:13:59 +00:00
|
|
|
pub fn get_buffer(&mut self) -> &mut [T] {
|
|
|
|
unsafe {
|
|
|
|
slice::from_raw_parts_mut(self.buffer_data, self.buffer_len)
|
2015-09-01 09:23:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-10 19:21:46 +00:00
|
|
|
pub fn len(&self) -> usize {
|
2016-08-02 14:13:59 +00:00
|
|
|
self.buffer_len
|
2015-09-10 19:21:46 +00:00
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
pub fn finish(self) {
|
2016-08-02 14:13:59 +00:00
|
|
|
unsafe {
|
|
|
|
let mut inner = self.voice.lock().unwrap();
|
|
|
|
let hresult = (*inner.render_client).ReleaseBuffer(self.frames as u32, 0);
|
|
|
|
match check_result(hresult) {
|
|
|
|
// ignoring the error that is produced if the device has been disconnected
|
|
|
|
Err(ref e)
|
|
|
|
if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => (),
|
|
|
|
e => e.unwrap(),
|
|
|
|
};
|
2015-09-22 08:26:11 +00:00
|
|
|
}
|
2015-09-01 09:23:41 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-22 11:25:42 +00:00
|
|
|
|
|
|
|
fn format_to_waveformatextensible(format: &Format)
|
|
|
|
-> Result<winapi::WAVEFORMATEXTENSIBLE, CreationError>
|
|
|
|
{
|
|
|
|
Ok(winapi::WAVEFORMATEXTENSIBLE {
|
|
|
|
Format: winapi::WAVEFORMATEX {
|
|
|
|
wFormatTag: match format.data_type {
|
|
|
|
SampleFormat::I16 => winapi::WAVE_FORMAT_PCM,
|
|
|
|
SampleFormat::F32 => winapi::WAVE_FORMAT_EXTENSIBLE,
|
|
|
|
SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
|
|
|
|
},
|
|
|
|
nChannels: format.channels.len() as winapi::WORD,
|
|
|
|
nSamplesPerSec: format.samples_rate.0 as winapi::DWORD,
|
|
|
|
nAvgBytesPerSec: format.channels.len() as winapi::DWORD *
|
|
|
|
format.samples_rate.0 as winapi::DWORD *
|
|
|
|
format.data_type.get_sample_size() as winapi::DWORD,
|
|
|
|
nBlockAlign: format.channels.len() as winapi::WORD *
|
|
|
|
format.data_type.get_sample_size() as winapi::WORD,
|
|
|
|
wBitsPerSample: 8 * format.data_type.get_sample_size() as winapi::WORD,
|
|
|
|
cbSize: match format.data_type {
|
|
|
|
SampleFormat::I16 => 0,
|
|
|
|
SampleFormat::F32 => (mem::size_of::<winapi::WAVEFORMATEXTENSIBLE>() -
|
|
|
|
mem::size_of::<winapi::WAVEFORMATEX>()) as winapi::WORD,
|
|
|
|
SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Samples: 8 * format.data_type.get_sample_size() as winapi::WORD,
|
|
|
|
dwChannelMask: {
|
|
|
|
let mut mask = 0;
|
|
|
|
for &channel in format.channels.iter() {
|
|
|
|
let raw_value = match channel {
|
|
|
|
ChannelPosition::FrontLeft => winapi::SPEAKER_FRONT_LEFT,
|
|
|
|
ChannelPosition::FrontRight => winapi::SPEAKER_FRONT_RIGHT,
|
|
|
|
ChannelPosition::FrontCenter => winapi::SPEAKER_FRONT_CENTER,
|
|
|
|
ChannelPosition::LowFrequency => winapi::SPEAKER_LOW_FREQUENCY,
|
|
|
|
ChannelPosition::BackLeft => winapi::SPEAKER_BACK_LEFT,
|
|
|
|
ChannelPosition::BackRight => winapi::SPEAKER_BACK_RIGHT,
|
|
|
|
ChannelPosition::FrontLeftOfCenter => winapi::SPEAKER_FRONT_LEFT_OF_CENTER,
|
|
|
|
ChannelPosition::FrontRightOfCenter => winapi::SPEAKER_FRONT_RIGHT_OF_CENTER,
|
|
|
|
ChannelPosition::BackCenter => winapi::SPEAKER_BACK_CENTER,
|
|
|
|
ChannelPosition::SideLeft => winapi::SPEAKER_SIDE_LEFT,
|
|
|
|
ChannelPosition::SideRight => winapi::SPEAKER_SIDE_RIGHT,
|
|
|
|
ChannelPosition::TopCenter => winapi::SPEAKER_TOP_CENTER,
|
|
|
|
ChannelPosition::TopFrontLeft => winapi::SPEAKER_TOP_FRONT_LEFT,
|
|
|
|
ChannelPosition::TopFrontCenter => winapi::SPEAKER_TOP_FRONT_CENTER,
|
|
|
|
ChannelPosition::TopFrontRight => winapi::SPEAKER_TOP_FRONT_RIGHT,
|
|
|
|
ChannelPosition::TopBackLeft => winapi::SPEAKER_TOP_BACK_LEFT,
|
|
|
|
ChannelPosition::TopBackCenter => winapi::SPEAKER_TOP_BACK_CENTER,
|
|
|
|
ChannelPosition::TopBackRight => winapi::SPEAKER_TOP_BACK_RIGHT,
|
|
|
|
};
|
|
|
|
|
|
|
|
// channels must be in the right order
|
|
|
|
if raw_value <= mask {
|
|
|
|
return Err(CreationError::FormatNotSupported);
|
|
|
|
}
|
|
|
|
|
|
|
|
mask = mask | raw_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
mask
|
|
|
|
},
|
|
|
|
SubFormat: match format.data_type {
|
|
|
|
SampleFormat::I16 => winapi::KSDATAFORMAT_SUBTYPE_PCM,
|
|
|
|
SampleFormat::F32 => winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
|
|
|
|
SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|