From bf051dd16f2f8fd160e398a4ff5e0c3e70b3aae4 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 12 Aug 2016 18:06:17 +0200 Subject: [PATCH] Add some documentation to the winapi implementation --- src/wasapi/voice.rs | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/wasapi/voice.rs b/src/wasapi/voice.rs index ef8a795..6be243b 100644 --- a/src/wasapi/voice.rs +++ b/src/wasapi/voice.rs @@ -32,10 +32,25 @@ unsafe impl Send for EventLoop {} unsafe impl Sync for EventLoop {} struct EventLoopInner { - // This event is signalled after elements have been added to `pending_scheduled`. - pending_scheduled_event: winapi::HANDLE, + // 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? scheduled: Mutex, + + // 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. pending_scheduled: Mutex, + + // 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, } struct EventLoopScheduled { @@ -44,7 +59,8 @@ struct EventLoopScheduled { // `WaitForMultipleObjectsEx` on the array without having to perform any conversion. handles: Vec, - // List of task handles corresponding to `handles`. + // List of task handles corresponding to `handles`. The second element is used to signal + // the voice that it has been signaled. task_handles: Vec<(TaskHandle, Arc)>, } @@ -74,7 +90,10 @@ impl EventLoop { let mut scheduled = self.inner.scheduled.lock().unwrap(); loop { + debug_assert!(scheduled.handles.len() == 1 + scheduled.task_handles.len()); + // Creating a voice checks for the MAXIMUM_WAIT_OBJECTS limit. + // FIXME: this is not the case ^ 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 @@ -89,6 +108,8 @@ impl EventLoop { let handle_id = (result - winapi::WAIT_OBJECT_0) as usize; if handle_id == 0 { + // The `pending_scheduled_event` handle has been notified, which means that we + // should pick up the content of `pending_scheduled`. let mut pending = self.inner.pending_scheduled.lock().unwrap(); scheduled.handles.append(&mut pending.handles); scheduled.task_handles.append(&mut pending.task_handles); @@ -144,18 +165,18 @@ impl Voice { -> Result<(Voice, SamplesStream), CreationError> { unsafe { - // making sure that COM is initialized - // it's not actually sure that this is required, but when in doubt do it + // Making sure that COM is initialized. + // It's not actually sure that this is required, but when in doubt do it. com::com_initialized(); - // obtaining a `IAudioClient` + // Obtaining a `IAudioClient`. 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(), }; - // computing the format and initializing the device + // Computing the format and initializing the device. let format = { let format_attempt = try!(format_to_waveformatextensible(format)); let share_mode = winapi::AUDCLNT_SHAREMODE_SHARED; @@ -334,9 +355,10 @@ impl Stream for SamplesStream { fn poll(&mut self, _: &mut Task) -> Poll, Self::Error> { unsafe { if self.ready.swap(false, Ordering::Relaxed) == false { + // Despite its name this function does not block, because we pass `0`. let result = kernel32::WaitForSingleObject(self.event, 0); - // Returning if timeout. + // Returning if the event is not ready. match result { winapi::WAIT_OBJECT_0 => (), winapi::WAIT_TIMEOUT => return Poll::NotReady, @@ -344,6 +366,8 @@ impl Stream for SamplesStream { }; } + // If we reach here, that means we're ready to accept new samples. + let mut inner = self.inner.lock().unwrap(); // Obtaining the number of frames that are available to be written.