Update winapi version from 0.2 to 0.3 (#202)

Adds only the necessary cargo features to reduce compile time and reduce
the chance of linking errors occurring for unused libraries (e.g.
d3d12.dll fails to link on my win10 VM).

I thought I'd try and land this before before working on the wasapi
backend implementation for #201.

Tested both beep.rs and enumerate.rs and they work fine with the update.
This commit is contained in:
mitchmindtree 2018-02-08 03:36:59 +11:00 committed by Pierre Krieger
parent 3ff9e6fe65
commit b47e46a4ac
5 changed files with 158 additions and 122 deletions

View File

@ -12,9 +12,7 @@ keywords = ["audio", "sound"]
lazy_static = "0.2" lazy_static = "0.2"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.2.8" winapi = { version = "0.3", features = ["audiosessiontypes", "audioclient", "combaseapi", "debug", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "std", "synchapi", "winuser"] }
ole32-sys = "0.2"
kernel32-sys = "0.2"
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
alsa-sys = { version = "0.1", path = "alsa-sys" } alsa-sys = { version = "0.1", path = "alsa-sys" }

View File

@ -1,15 +1,16 @@
//! Handles COM initialization and cleanup. //! Handles COM initialization and cleanup.
use super::check_result; use super::check_result;
use super::ole32;
use super::winapi;
use std::ptr; use std::ptr;
use super::winapi::um::objbase::{COINIT_MULTITHREADED};
use super::winapi::um::combaseapi::{CoInitializeEx, CoUninitialize};
thread_local!(static COM_INITIALIZED: ComInitialized = { thread_local!(static COM_INITIALIZED: ComInitialized = {
unsafe { unsafe {
// this call can fail if another library initialized COM in single-threaded mode // this call can fail if another library initialized COM in single-threaded mode
// handling this situation properly would make the API more annoying, so we just don't care // handling this situation properly would make the API more annoying, so we just don't care
check_result(ole32::CoInitializeEx(ptr::null_mut(), winapi::COINIT_MULTITHREADED)).unwrap(); check_result(CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED)).unwrap();
ComInitialized(ptr::null_mut()) ComInitialized(ptr::null_mut())
} }
}); });
@ -23,7 +24,7 @@ struct ComInitialized(*mut ());
impl Drop for ComInitialized { impl Drop for ComInitialized {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ole32::CoUninitialize() }; unsafe { CoUninitialize() };
} }
} }

View File

@ -15,14 +15,41 @@ use SupportedFormat;
use super::check_result; use super::check_result;
use super::com; use super::com;
use super::ole32; use super::winapi::Interface;
use super::winapi; use super::winapi::shared::ksmedia;
use super::winapi::shared::guiddef::{
GUID,
};
use super::winapi::shared::mmreg::{
WAVE_FORMAT_PCM,
WAVE_FORMAT_EXTENSIBLE,
WAVEFORMATEXTENSIBLE,
};
use super::winapi::um::audioclient::{
IAudioClient,
IID_IAudioClient,
AUDCLNT_E_DEVICE_INVALIDATED,
};
use super::winapi::um::combaseapi::{
CoCreateInstance,
CoTaskMemFree,
CLSCTX_ALL,
};
use super::winapi::um::mmdeviceapi::{
eConsole,
eRender,
CLSID_MMDeviceEnumerator,
DEVICE_STATE_ACTIVE,
IMMDevice,
IMMDeviceCollection,
IMMDeviceEnumerator,
};
pub type SupportedFormatsIterator = OptionIntoIter<SupportedFormat>; pub type SupportedFormatsIterator = OptionIntoIter<SupportedFormat>;
/// 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 IAudioClient);
unsafe impl Send for IAudioClientWrapper { unsafe impl Send for IAudioClientWrapper {
} }
unsafe impl Sync for IAudioClientWrapper { unsafe impl Sync for IAudioClientWrapper {
@ -30,7 +57,7 @@ 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 {
device: *mut winapi::IMMDevice, device: *mut IMMDevice,
/// We cache an uninitialized `IAudioClient` so that we can call functions from it without /// We cache an uninitialized `IAudioClient` so that we can call functions from it without
/// having to create/destroy audio clients all the time. /// having to create/destroy audio clients all the time.
@ -62,13 +89,13 @@ impl Endpoint {
// and turning it into a string // and turning it into a string
let name_string: OsString = OsStringExt::from_wide(name_slice); let name_string: OsString = OsStringExt::from_wide(name_slice);
ole32::CoTaskMemFree(name_ptr as *mut _); CoTaskMemFree(name_ptr as *mut _);
name_string.into_string().unwrap() name_string.into_string().unwrap()
} }
} }
#[inline] #[inline]
fn from_immdevice(device: *mut winapi::IMMDevice) -> Endpoint { fn from_immdevice(device: *mut IMMDevice) -> Endpoint {
Endpoint { Endpoint {
device: device, device: device,
future_audio_client: Arc::new(Mutex::new(None)), future_audio_client: Arc::new(Mutex::new(None)),
@ -83,10 +110,10 @@ impl Endpoint {
return Ok(lock); return Ok(lock);
} }
let audio_client: *mut winapi::IAudioClient = unsafe { let audio_client: *mut IAudioClient = unsafe {
let mut audio_client = mem::uninitialized(); let mut audio_client = mem::uninitialized();
let hresult = (*self.device).Activate(&winapi::IID_IAudioClient, let hresult = (*self.device).Activate(&IID_IAudioClient,
winapi::CLSCTX_ALL, CLSCTX_ALL,
ptr::null_mut(), ptr::null_mut(),
&mut audio_client); &mut audio_client);
@ -103,7 +130,7 @@ impl Endpoint {
/// Returns an uninitialized `IAudioClient`. /// Returns an uninitialized `IAudioClient`.
#[inline] #[inline]
pub(crate) fn build_audioclient(&self) -> Result<*mut winapi::IAudioClient, IoError> { pub(crate) fn build_audioclient(&self) -> Result<*mut IAudioClient, IoError> {
let mut lock = 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;
@ -121,7 +148,7 @@ impl Endpoint {
com::com_initialized(); com::com_initialized();
let lock = match self.ensure_future_audio_client() { let lock = match self.ensure_future_audio_client() {
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
return Err(FormatsEnumerationError::DeviceNotAvailable), return Err(FormatsEnumerationError::DeviceNotAvailable),
e => e.unwrap(), e => e.unwrap(),
}; };
@ -130,7 +157,7 @@ impl Endpoint {
unsafe { unsafe {
let mut format_ptr = mem::uninitialized(); let mut format_ptr = mem::uninitialized();
match check_result((*client).GetMixFormat(&mut format_ptr)) { match check_result((*client).GetMixFormat(&mut format_ptr)) {
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
return Err(FormatsEnumerationError::DeviceNotAvailable); return Err(FormatsEnumerationError::DeviceNotAvailable);
}, },
Err(e) => panic!("{:?}", e), Err(e) => panic!("{:?}", e),
@ -139,28 +166,30 @@ 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 => { WAVE_FORMAT_PCM => {
(2, SampleFormat::I16) (2, SampleFormat::I16)
}, },
winapi::WAVE_FORMAT_EXTENSIBLE => { WAVE_FORMAT_EXTENSIBLE => {
let format_ptr = format_ptr as *const winapi::WAVEFORMATEXTENSIBLE; let format_ptr = format_ptr as *const WAVEFORMATEXTENSIBLE;
let channels = (*format_ptr).Format.nChannels as ChannelCount; let channels = (*format_ptr).Format.nChannels as ChannelCount;
let format = { let format = {
fn cmp_guid(a: &winapi::GUID, b: &winapi::GUID) -> bool { fn cmp_guid(a: &GUID, b: &GUID) -> bool {
a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data1 == b.Data1 && a.Data2 == b.Data2 && 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) &ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
{ {
SampleFormat::F32 SampleFormat::F32
} else if cmp_guid(&(*format_ptr).SubFormat, } else if cmp_guid(&(*format_ptr).SubFormat,
&winapi::KSDATAFORMAT_SUBTYPE_PCM) &ksmedia::KSDATAFORMAT_SUBTYPE_PCM)
{ {
SampleFormat::I16 SampleFormat::I16
} else { } else {
panic!("Unknown SubFormat GUID returned by GetMixFormat: {:?}", panic!("Unknown SubFormat GUID returned by GetMixFormat");
(*format_ptr).SubFormat) // TODO: Re-add this to end of panic. Getting
// `trait Debug is not satisfied` error.
//(*format_ptr).SubFormat)
} }
}; };
@ -178,7 +207,7 @@ impl Endpoint {
} }
}; };
ole32::CoTaskMemFree(format_ptr as *mut _); CoTaskMemFree(format_ptr as *mut _);
Ok(Some(format).into_iter()) Ok(Some(format).into_iter())
} }
@ -232,13 +261,13 @@ lazy_static! {
// building the devices enumerator object // building the devices enumerator object
unsafe { unsafe {
let mut enumerator: *mut winapi::IMMDeviceEnumerator = mem::uninitialized(); let mut enumerator: *mut IMMDeviceEnumerator = mem::uninitialized();
let hresult = ole32::CoCreateInstance(&winapi::CLSID_MMDeviceEnumerator, let hresult = CoCreateInstance(&CLSID_MMDeviceEnumerator,
ptr::null_mut(), winapi::CLSCTX_ALL, ptr::null_mut(), CLSCTX_ALL,
&winapi::IID_IMMDeviceEnumerator, &IMMDeviceEnumerator::uuidof(),
&mut enumerator &mut enumerator
as *mut *mut winapi::IMMDeviceEnumerator as *mut *mut IMMDeviceEnumerator
as *mut _); as *mut _);
check_result(hresult).unwrap(); check_result(hresult).unwrap();
@ -247,8 +276,8 @@ lazy_static! {
}; };
} }
/// RAII object around `winapi::IMMDeviceEnumerator`. /// RAII object around `IMMDeviceEnumerator`.
struct Enumerator(*mut winapi::IMMDeviceEnumerator); struct Enumerator(*mut IMMDeviceEnumerator);
unsafe impl Send for Enumerator { unsafe impl Send for Enumerator {
} }
@ -266,7 +295,7 @@ impl Drop for Enumerator {
/// WASAPI implementation for `EndpointsIterator`. /// WASAPI implementation for `EndpointsIterator`.
pub struct EndpointsIterator { pub struct EndpointsIterator {
collection: *mut winapi::IMMDeviceCollection, collection: *mut IMMDeviceCollection,
total_count: u32, total_count: u32,
next_item: u32, next_item: u32,
} }
@ -288,10 +317,10 @@ impl Drop for EndpointsIterator {
impl Default for EndpointsIterator { impl Default for EndpointsIterator {
fn default() -> EndpointsIterator { fn default() -> EndpointsIterator {
unsafe { unsafe {
let mut collection: *mut winapi::IMMDeviceCollection = mem::uninitialized(); let mut collection: *mut IMMDeviceCollection = mem::uninitialized();
// can fail because of wrong parameters (should never happen) or out of memory // can fail because of wrong parameters (should never happen) or out of memory
check_result((*ENUMERATOR.0).EnumAudioEndpoints(winapi::eRender, check_result((*ENUMERATOR.0).EnumAudioEndpoints(eRender,
winapi::DEVICE_STATE_ACTIVE, DEVICE_STATE_ACTIVE,
&mut collection)) &mut collection))
.unwrap(); .unwrap();
@ -338,7 +367,7 @@ pub fn default_endpoint() -> Option<Endpoint> {
unsafe { unsafe {
let mut device = mem::uninitialized(); let mut device = mem::uninitialized();
let hres = (*ENUMERATOR.0) let hres = (*ENUMERATOR.0)
.GetDefaultAudioEndpoint(winapi::eRender, winapi::eConsole, &mut device); .GetDefaultAudioEndpoint(eRender, 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

View File

@ -1,18 +1,17 @@
extern crate winapi; extern crate winapi;
extern crate ole32;
extern crate kernel32;
use std::io::Error as IoError; use std::io::Error as IoError;
pub use self::endpoint::{Endpoint, EndpointsIterator, SupportedFormatsIterator, default_endpoint}; pub use self::endpoint::{Endpoint, EndpointsIterator, SupportedFormatsIterator, default_endpoint};
pub use self::voice::{Buffer, EventLoop, VoiceId}; pub use self::voice::{Buffer, EventLoop, VoiceId};
use self::winapi::um::winnt::HRESULT;
mod com; mod com;
mod endpoint; mod endpoint;
mod voice; mod voice;
#[inline] #[inline]
fn check_result(result: winapi::HRESULT) -> Result<(), IoError> { fn check_result(result: HRESULT) -> Result<(), IoError> {
if result < 0 { if result < 0 {
Err(IoError::from_raw_os_error(result)) Err(IoError::from_raw_os_error(result))
} else { } else {

View File

@ -1,9 +1,18 @@
use super::Endpoint; use super::Endpoint;
use super::check_result; use super::check_result;
use super::com; use super::com;
use super::kernel32; use super::winapi::shared::basetsd::UINT32;
use super::ole32; use super::winapi::shared::ksmedia;
use super::winapi; use super::winapi::shared::minwindef::{BYTE, DWORD, FALSE, WORD};
use super::winapi::shared::mmreg;
use super::winapi::shared::winerror;
use super::winapi::um::audioclient::{self, AUDCLNT_E_DEVICE_INVALIDATED};
use super::winapi::um::audiosessiontypes::{AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK};
use super::winapi::um::combaseapi::CoTaskMemFree;
use super::winapi::um::handleapi;
use super::winapi::um::synchapi;
use super::winapi::um::winbase;
use super::winapi::um::winnt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
@ -37,7 +46,7 @@ pub struct EventLoop {
// This event is signalled after a new entry is added to `commands`, so that the `run()` // This event is signalled after a new entry is added to `commands`, so that the `run()`
// method can be notified. // method can be notified.
pending_scheduled_event: winapi::HANDLE, pending_scheduled_event: winnt::HANDLE,
} }
struct RunContext { struct RunContext {
@ -46,7 +55,7 @@ struct RunContext {
// Handles corresponding to the `event` field of each element of `voices`. Must always be in // Handles corresponding to the `event` field of each element of `voices`. Must always be in
// sync with `voices`, except that the first element is always `pending_scheduled_event`. // sync with `voices`, except that the first element is always `pending_scheduled_event`.
handles: Vec<winapi::HANDLE>, handles: Vec<winnt::HANDLE>,
} }
enum Command { enum Command {
@ -58,23 +67,23 @@ enum Command {
struct VoiceInner { struct VoiceInner {
id: VoiceId, id: VoiceId,
audio_client: *mut winapi::IAudioClient, audio_client: *mut audioclient::IAudioClient,
render_client: *mut winapi::IAudioRenderClient, render_client: *mut audioclient::IAudioRenderClient,
// Event that is signalled by WASAPI whenever audio data must be written. // Event that is signalled by WASAPI whenever audio data must be written.
event: winapi::HANDLE, event: winnt::HANDLE,
// True if the voice is currently playing. False if paused. // True if the voice is currently playing. False if paused.
playing: bool, playing: bool,
// Number of frames of audio data in the underlying buffer allocated by WASAPI. // Number of frames of audio data in the underlying buffer allocated by WASAPI.
max_frames_in_buffer: winapi::UINT32, max_frames_in_buffer: UINT32,
// Number of bytes that each frame occupies. // Number of bytes that each frame occupies.
bytes_per_frame: winapi::WORD, bytes_per_frame: WORD,
} }
impl EventLoop { impl EventLoop {
pub fn new() -> EventLoop { pub fn new() -> EventLoop {
let pending_scheduled_event = let pending_scheduled_event =
unsafe { kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) }; unsafe { synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) };
EventLoop { EventLoop {
pending_scheduled_event: pending_scheduled_event, pending_scheduled_event: pending_scheduled_event,
@ -96,7 +105,7 @@ impl EventLoop {
// Obtaining a `IAudioClient`. // Obtaining a `IAudioClient`.
let audio_client = match end_point.build_audioclient() { let audio_client = match end_point.build_audioclient() {
Err(ref e) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
return Err(CreationError::DeviceNotAvailable), return Err(CreationError::DeviceNotAvailable),
e => e.unwrap(), e => e.unwrap(),
}; };
@ -104,24 +113,24 @@ impl EventLoop {
// Computing the format and initializing the device. // Computing the format and initializing the device.
let format = { let format = {
let format_attempt = format_to_waveformatextensible(format)?; let format_attempt = format_to_waveformatextensible(format)?;
let share_mode = winapi::AUDCLNT_SHAREMODE_SHARED; let share_mode = 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 mmreg::WAVEFORMATEX = mem::uninitialized();
let hresult = let hresult =
(*audio_client) (*audio_client)
.IsFormatSupported(share_mode, &format_attempt.Format, &mut dummy_fmt_ptr); .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 _); CoTaskMemFree(dummy_fmt_ptr as *mut _);
} }
// `IsFormatSupported` can return `S_FALSE` (which means that a compatible format // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
// 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(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(CreationError::DeviceNotAvailable); return Err(CreationError::DeviceNotAvailable);
}, },
@ -129,7 +138,7 @@ impl EventLoop {
(*audio_client).Release(); (*audio_client).Release();
panic!("{:?}", e); panic!("{:?}", e);
}, },
(winapi::S_FALSE, _) => { (winerror::S_FALSE, _) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(CreationError::FormatNotSupported); return Err(CreationError::FormatNotSupported);
}, },
@ -138,14 +147,14 @@ impl EventLoop {
// 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, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0,
0, 0,
&format_attempt.Format, &format_attempt.Format,
ptr::null()); ptr::null());
match check_result(hresult) { match 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(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(CreationError::DeviceNotAvailable); return Err(CreationError::DeviceNotAvailable);
}, },
@ -161,7 +170,7 @@ impl EventLoop {
// Creating the event that will be signalled whenever we need to submit some samples. // Creating the event that will be signalled whenever we need to submit some samples.
let event = { let event = {
let event = kernel32::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()); let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
if event == ptr::null_mut() { if event == ptr::null_mut() {
(*audio_client).Release(); (*audio_client).Release();
panic!("Failed to create event"); panic!("Failed to create event");
@ -185,7 +194,7 @@ impl EventLoop {
match check_result(hresult) { match 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(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(CreationError::DeviceNotAvailable); return Err(CreationError::DeviceNotAvailable);
}, },
@ -201,15 +210,15 @@ impl EventLoop {
// Building a `IAudioRenderClient` that will be used to fill the samples buffer. // Building a `IAudioRenderClient` that will be used to fill the samples buffer.
let render_client = { let render_client = {
let mut render_client: *mut winapi::IAudioRenderClient = mem::uninitialized(); let mut render_client: *mut audioclient::IAudioRenderClient = mem::uninitialized();
let hresult = (*audio_client).GetService(&winapi::IID_IAudioRenderClient, let hresult = (*audio_client).GetService(&audioclient::IID_IAudioRenderClient,
&mut render_client as &mut render_client as
*mut *mut winapi::IAudioRenderClient as *mut *mut audioclient::IAudioRenderClient as
*mut _); *mut _);
match check_result(hresult) { match 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(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(CreationError::DeviceNotAvailable); return Err(CreationError::DeviceNotAvailable);
}, },
@ -241,7 +250,7 @@ impl EventLoop {
self.commands.lock().unwrap().push(Command::NewVoice(inner)); self.commands.lock().unwrap().push(Command::NewVoice(inner));
let result = kernel32::SetEvent(self.pending_scheduled_event); let result = synchapi::SetEvent(self.pending_scheduled_event);
assert!(result != 0); assert!(result != 0);
}; };
@ -256,7 +265,7 @@ impl EventLoop {
.lock() .lock()
.unwrap() .unwrap()
.push(Command::DestroyVoice(voice_id)); .push(Command::DestroyVoice(voice_id));
let result = kernel32::SetEvent(self.pending_scheduled_event); let result = synchapi::SetEvent(self.pending_scheduled_event);
assert!(result != 0); assert!(result != 0);
} }
} }
@ -317,16 +326,16 @@ impl EventLoop {
// Wait for any of the handles to be signalled, which means that the corresponding // Wait for any of the handles to be signalled, which means that the corresponding
// sound needs a buffer. // sound needs a buffer.
debug_assert!(run_context.handles.len() <= winapi::MAXIMUM_WAIT_OBJECTS as usize); debug_assert!(run_context.handles.len() <= winnt::MAXIMUM_WAIT_OBJECTS as usize);
let result = kernel32::WaitForMultipleObjectsEx(run_context.handles.len() as u32, let result = synchapi::WaitForMultipleObjectsEx(run_context.handles.len() as u32,
run_context.handles.as_ptr(), run_context.handles.as_ptr(),
winapi::FALSE, FALSE,
winapi::INFINITE, /* TODO: allow setting a timeout */ winbase::INFINITE, /* TODO: allow setting a timeout */
winapi::FALSE /* irrelevant parameter here */); FALSE /* irrelevant parameter here */);
// Notifying the corresponding task handler. // Notifying the corresponding task handler.
debug_assert!(result >= winapi::WAIT_OBJECT_0); debug_assert!(result >= winbase::WAIT_OBJECT_0);
let handle_id = (result - winapi::WAIT_OBJECT_0) as usize; let handle_id = (result - winbase::WAIT_OBJECT_0) as usize;
// If `handle_id` is 0, then it's `pending_scheduled_event` that was signalled in // If `handle_id` is 0, then it's `pending_scheduled_event` that was signalled in
// order for us to pick up the pending commands. // order for us to pick up the pending commands.
@ -350,7 +359,7 @@ impl EventLoop {
// 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 BYTE = mem::uninitialized();
let hresult = (*voice.render_client) let hresult = (*voice.render_client)
.GetBuffer(frames_available, &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`
@ -380,7 +389,7 @@ impl EventLoop {
pub fn play(&self, voice: VoiceId) { pub fn play(&self, voice: VoiceId) {
unsafe { unsafe {
self.commands.lock().unwrap().push(Command::Play(voice)); self.commands.lock().unwrap().push(Command::Play(voice));
let result = kernel32::SetEvent(self.pending_scheduled_event); let result = synchapi::SetEvent(self.pending_scheduled_event);
assert!(result != 0); assert!(result != 0);
} }
} }
@ -389,7 +398,7 @@ impl EventLoop {
pub fn pause(&self, voice: VoiceId) { pub fn pause(&self, voice: VoiceId) {
unsafe { unsafe {
self.commands.lock().unwrap().push(Command::Pause(voice)); self.commands.lock().unwrap().push(Command::Pause(voice));
let result = kernel32::SetEvent(self.pending_scheduled_event); let result = synchapi::SetEvent(self.pending_scheduled_event);
assert!(result != 0); assert!(result != 0);
} }
} }
@ -399,7 +408,7 @@ impl Drop for EventLoop {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
kernel32::CloseHandle(self.pending_scheduled_event); handleapi::CloseHandle(self.pending_scheduled_event);
} }
} }
} }
@ -419,7 +428,7 @@ impl Drop for VoiceInner {
unsafe { unsafe {
(*self.render_client).Release(); (*self.render_client).Release();
(*self.audio_client).Release(); (*self.audio_client).Release();
kernel32::CloseHandle(self.event); handleapi::CloseHandle(self.event);
} }
} }
} }
@ -429,7 +438,7 @@ pub struct Buffer<'a, T: 'a> {
buffer_data: *mut T, buffer_data: *mut T,
buffer_len: usize, buffer_len: usize,
frames: winapi::UINT32, frames: UINT32,
marker: PhantomData<&'a mut [T]>, marker: PhantomData<&'a mut [T]>,
} }
@ -454,7 +463,7 @@ impl<'a, T> Buffer<'a, T> {
let hresult = (*self.voice.render_client).ReleaseBuffer(self.frames as u32, 0); let hresult = (*self.voice.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) if e.raw_os_error() == Some(winapi::AUDCLNT_E_DEVICE_INVALIDATED) => (), Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => (),
e => e.unwrap(), e => e.unwrap(),
}; };
} }
@ -463,53 +472,53 @@ impl<'a, T> Buffer<'a, T> {
// Turns a `Format` into a `WAVEFORMATEXTENSIBLE`. // Turns a `Format` into a `WAVEFORMATEXTENSIBLE`.
fn format_to_waveformatextensible(format: &Format) fn format_to_waveformatextensible(format: &Format)
-> Result<winapi::WAVEFORMATEXTENSIBLE, CreationError> { -> Result<mmreg::WAVEFORMATEXTENSIBLE, CreationError> {
Ok(winapi::WAVEFORMATEXTENSIBLE { Ok(mmreg::WAVEFORMATEXTENSIBLE {
Format: winapi::WAVEFORMATEX { Format: mmreg::WAVEFORMATEX {
wFormatTag: match format.data_type { wFormatTag: match format.data_type {
SampleFormat::I16 => winapi::WAVE_FORMAT_PCM, SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM,
SampleFormat::F32 => winapi::WAVE_FORMAT_EXTENSIBLE, SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE,
SampleFormat::U16 => return Err(CreationError::FormatNotSupported), SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
}, },
nChannels: format.channels as winapi::WORD, nChannels: format.channels as WORD,
nSamplesPerSec: format.sample_rate.0 as winapi::DWORD, nSamplesPerSec: format.sample_rate.0 as DWORD,
nAvgBytesPerSec: format.channels as winapi::DWORD * nAvgBytesPerSec: format.channels as DWORD *
format.sample_rate.0 as winapi::DWORD * format.sample_rate.0 as DWORD *
format.data_type.sample_size() as winapi::DWORD, format.data_type.sample_size() as DWORD,
nBlockAlign: format.channels as winapi::WORD * nBlockAlign: format.channels as WORD *
format.data_type.sample_size() as winapi::WORD, format.data_type.sample_size() as WORD,
wBitsPerSample: 8 * format.data_type.sample_size() as winapi::WORD, wBitsPerSample: 8 * format.data_type.sample_size() as WORD,
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::<mmreg::WAVEFORMATEXTENSIBLE>() -
mem::size_of::<winapi::WAVEFORMATEX>()) as mem::size_of::<mmreg::WAVEFORMATEX>()) as
winapi::WORD, WORD,
SampleFormat::U16 => return Err(CreationError::FormatNotSupported), SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
}, },
}, },
Samples: 8 * format.data_type.sample_size() as winapi::WORD, Samples: 8 * format.data_type.sample_size() as WORD,
dwChannelMask: { dwChannelMask: {
let mut mask = 0; let mut mask = 0;
const CHANNEL_POSITIONS: &'static [winapi::DWORD] = &[ const CHANNEL_POSITIONS: &'static [DWORD] = &[
winapi::SPEAKER_FRONT_LEFT, mmreg::SPEAKER_FRONT_LEFT,
winapi::SPEAKER_FRONT_RIGHT, mmreg::SPEAKER_FRONT_RIGHT,
winapi::SPEAKER_FRONT_CENTER, mmreg::SPEAKER_FRONT_CENTER,
winapi::SPEAKER_LOW_FREQUENCY, mmreg::SPEAKER_LOW_FREQUENCY,
winapi::SPEAKER_BACK_LEFT, mmreg::SPEAKER_BACK_LEFT,
winapi::SPEAKER_BACK_RIGHT, mmreg::SPEAKER_BACK_RIGHT,
winapi::SPEAKER_FRONT_LEFT_OF_CENTER, mmreg::SPEAKER_FRONT_LEFT_OF_CENTER,
winapi::SPEAKER_FRONT_RIGHT_OF_CENTER, mmreg::SPEAKER_FRONT_RIGHT_OF_CENTER,
winapi::SPEAKER_BACK_CENTER, mmreg::SPEAKER_BACK_CENTER,
winapi::SPEAKER_SIDE_LEFT, mmreg::SPEAKER_SIDE_LEFT,
winapi::SPEAKER_SIDE_RIGHT, mmreg::SPEAKER_SIDE_RIGHT,
winapi::SPEAKER_TOP_CENTER, mmreg::SPEAKER_TOP_CENTER,
winapi::SPEAKER_TOP_FRONT_LEFT, mmreg::SPEAKER_TOP_FRONT_LEFT,
winapi::SPEAKER_TOP_FRONT_CENTER, mmreg::SPEAKER_TOP_FRONT_CENTER,
winapi::SPEAKER_TOP_FRONT_RIGHT, mmreg::SPEAKER_TOP_FRONT_RIGHT,
winapi::SPEAKER_TOP_BACK_LEFT, mmreg::SPEAKER_TOP_BACK_LEFT,
winapi::SPEAKER_TOP_BACK_CENTER, mmreg::SPEAKER_TOP_BACK_CENTER,
winapi::SPEAKER_TOP_BACK_RIGHT, mmreg::SPEAKER_TOP_BACK_RIGHT,
]; ];
for i in 0..format.channels { for i in 0..format.channels {
@ -520,8 +529,8 @@ fn format_to_waveformatextensible(format: &Format)
mask mask
}, },
SubFormat: match format.data_type { SubFormat: match format.data_type {
SampleFormat::I16 => winapi::KSDATAFORMAT_SUBTYPE_PCM, SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM,
SampleFormat::F32 => winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
SampleFormat::U16 => return Err(CreationError::FormatNotSupported), SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
}, },
}) })