1 use std;
2 use std::ffi::OsString;
3 use std::io::Error as IoError;
4 use std::mem;
5 use std::ops::{Deref, DerefMut};
6 use std::os::windows::ffi::OsStringExt;
7 use std::ptr;
8 use std::slice;
9 use std::sync::{Arc, Mutex, MutexGuard};
10 
11 use DefaultFormatError;
12 use Format;
13 use FormatsEnumerationError;
14 use SampleFormat;
15 use SampleRate;
16 use SupportedFormat;
17 use COMMON_SAMPLE_RATES;
18 
19 use super::check_result;
20 use super::com;
21 use super::winapi::Interface;
22 use super::winapi::shared::devpkey;
23 use super::winapi::shared::ksmedia;
24 use super::winapi::shared::guiddef::{
25     GUID,
26 };
27 use super::winapi::shared::winerror;
28 use super::winapi::shared::minwindef::{
29     DWORD,
30 };
31 use super::winapi::shared::mmreg;
32 use super::winapi::shared::wtypes;
33 use super::winapi::um::coml2api;
34 use super::winapi::um::audioclient::{
35     IAudioClient,
36     IID_IAudioClient,
37     AUDCLNT_E_DEVICE_INVALIDATED,
38 };
39 use super::winapi::um::audiosessiontypes::{
40     AUDCLNT_SHAREMODE_SHARED,
41 };
42 use super::winapi::um::combaseapi::{
43     CoCreateInstance,
44     CoTaskMemFree,
45     CLSCTX_ALL,
46     PropVariantClear,
47 };
48 use super::winapi::um::mmdeviceapi::{
49     eAll,
50     eCapture,
51     eConsole,
52     eRender,
53     CLSID_MMDeviceEnumerator,
54     DEVICE_STATE_ACTIVE,
55     EDataFlow,
56     IMMDevice,
57     IMMDeviceCollection,
58     IMMDeviceEnumerator,
59     IMMEndpoint,
60 };
61 
62 pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
63 pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
64 
65 /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
66 #[derive(Copy, Clone)]
67 struct IAudioClientWrapper(*mut IAudioClient);
68 unsafe impl Send for IAudioClientWrapper {
69 }
70 unsafe impl Sync for IAudioClientWrapper {
71 }
72 
73 /// An opaque type that identifies an end point.
74 pub struct Device {
75     device: *mut IMMDevice,
76     /// We cache an uninitialized `IAudioClient` so that we can call functions from it without
77     /// having to create/destroy audio clients all the time.
78     future_audio_client: Arc<Mutex<Option<IAudioClientWrapper>>>, // TODO: add NonZero around the ptr
79 }
80 
81 struct Endpoint {
82     endpoint: *mut IMMEndpoint,
83 }
84 
85 enum WaveFormat {
86     Ex(mmreg::WAVEFORMATEX),
87     Extensible(mmreg::WAVEFORMATEXTENSIBLE),
88 }
89 
90 // Use RAII to make sure CoTaskMemFree is called when we are responsible for freeing.
91 struct WaveFormatExPtr(*mut mmreg::WAVEFORMATEX);
92 
93 impl Drop for WaveFormatExPtr {
drop(&mut self)94     fn drop(&mut self) {
95         unsafe {
96             CoTaskMemFree(self.0 as *mut _);
97         }
98     }
99 }
100 
101 
102 impl WaveFormat {
103     // Given a pointer to some format, returns a valid copy of the format.
copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self>104     pub fn copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self> {
105         unsafe {
106             match (*ptr).wFormatTag {
107                 mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => {
108                     Some(WaveFormat::Ex(*ptr))
109                 },
110                 mmreg::WAVE_FORMAT_EXTENSIBLE => {
111                     let extensible_ptr = ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
112                     Some(WaveFormat::Extensible(*extensible_ptr))
113                 },
114                 _ => None,
115             }
116         }
117     }
118 
119     // Get the pointer to the WAVEFORMATEX struct.
as_ptr(&self) -> *const mmreg::WAVEFORMATEX120     pub fn as_ptr(&self) -> *const mmreg::WAVEFORMATEX {
121         self.deref() as *const _
122     }
123 }
124 
125 impl Deref for WaveFormat {
126     type Target = mmreg::WAVEFORMATEX;
deref(&self) -> &Self::Target127     fn deref(&self) -> &Self::Target {
128         match *self {
129             WaveFormat::Ex(ref f) => f,
130             WaveFormat::Extensible(ref f) => &f.Format,
131         }
132     }
133 }
134 
135 impl DerefMut for WaveFormat {
deref_mut(&mut self) -> &mut Self::Target136     fn deref_mut(&mut self) -> &mut Self::Target {
137         match *self {
138             WaveFormat::Ex(ref mut f) => f,
139             WaveFormat::Extensible(ref mut f) => &mut f.Format,
140         }
141     }
142 }
143 
144 
immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint145 unsafe fn immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint {
146     let mut endpoint: *mut IMMEndpoint = mem::uninitialized();
147     check_result((*device).QueryInterface(&IMMEndpoint::uuidof(), &mut endpoint as *mut _ as *mut _))
148         .expect("could not query IMMDevice interface for IMMEndpoint");
149     endpoint
150 }
151 
data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow152 unsafe fn data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow {
153     let mut data_flow = mem::uninitialized();
154     check_result((*endpoint).GetDataFlow(&mut data_flow))
155         .expect("could not get endpoint data_flow");
156     data_flow
157 }
158 
159 // Given the audio client and format, returns whether or not the format is supported.
is_format_supported( client: *const IAudioClient, waveformatex_ptr: *const mmreg::WAVEFORMATEX, ) -> Result<bool, FormatsEnumerationError>160 pub unsafe fn is_format_supported(
161     client: *const IAudioClient,
162     waveformatex_ptr: *const mmreg::WAVEFORMATEX,
163 ) -> Result<bool, FormatsEnumerationError>
164 {
165 
166 
167     /*
168     // `IsFormatSupported` checks whether the format is supported and fills
169     // a `WAVEFORMATEX`
170     let mut dummy_fmt_ptr: *mut mmreg::WAVEFORMATEX = mem::uninitialized();
171     let hresult =
172         (*audio_client)
173             .IsFormatSupported(share_mode, &format_attempt.Format, &mut dummy_fmt_ptr);
174     // we free that `WAVEFORMATEX` immediately after because we don't need it
175     if !dummy_fmt_ptr.is_null() {
176         CoTaskMemFree(dummy_fmt_ptr as *mut _);
177     }
178 
179     // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
180     // has been found) but we also treat this as an error
181     match (hresult, check_result(hresult)) {
182         (_, Err(ref e))
183             if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
184             (*audio_client).Release();
185             return Err(CreationError::DeviceNotAvailable);
186         },
187         (_, Err(e)) => {
188             (*audio_client).Release();
189             panic!("{:?}", e);
190         },
191         (winerror::S_FALSE, _) => {
192             (*audio_client).Release();
193             return Err(CreationError::FormatNotSupported);
194         },
195         (_, Ok(())) => (),
196     };
197     */
198 
199 
200     // Check if the given format is supported.
201     let is_supported = |waveformatex_ptr, mut closest_waveformatex_ptr| {
202         let result = (*client).IsFormatSupported(
203             AUDCLNT_SHAREMODE_SHARED,
204             waveformatex_ptr,
205             &mut closest_waveformatex_ptr,
206         );
207         // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
208         // has been found, but not an exact match) so we also treat this as unsupported.
209         match (result, check_result(result)) {
210             (_, Err(ref e)) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
211                 return Err(FormatsEnumerationError::DeviceNotAvailable);
212             },
213             (_, Err(_)) => {
214                 Ok(false)
215             },
216             (winerror::S_FALSE, _) => {
217                 Ok(false)
218             },
219             (_, Ok(())) => {
220                 Ok(true)
221             },
222         }
223     };
224 
225     // First we want to retrieve a pointer to the `WAVEFORMATEX`.
226     // Although `GetMixFormat` writes the format to a given `WAVEFORMATEX` pointer,
227     // the pointer itself may actually point to a `WAVEFORMATEXTENSIBLE` structure.
228     // We check the wFormatTag to determine this and get a pointer to the correct type.
229     match (*waveformatex_ptr).wFormatTag {
230         mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => {
231             let mut closest_waveformatex = *waveformatex_ptr;
232             let mut closest_waveformatex_ptr = &mut closest_waveformatex as *mut _;
233             is_supported(waveformatex_ptr, closest_waveformatex_ptr)
234         },
235         mmreg::WAVE_FORMAT_EXTENSIBLE => {
236             let waveformatextensible_ptr =
237                 waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
238             let mut closest_waveformatextensible = *waveformatextensible_ptr;
239             let closest_waveformatextensible_ptr =
240                 &mut closest_waveformatextensible as *mut _;
241             let mut closest_waveformatex_ptr =
242                 closest_waveformatextensible_ptr as *mut mmreg::WAVEFORMATEX;
243             is_supported(waveformatex_ptr, closest_waveformatex_ptr)
244         },
245         _ => Ok(false),
246     }
247 }
248 
249 
250 // Get a cpal Format from a WAVEFORMATEX.
format_from_waveformatex_ptr( waveformatex_ptr: *const mmreg::WAVEFORMATEX, ) -> Option<Format>251 unsafe fn format_from_waveformatex_ptr(
252     waveformatex_ptr: *const mmreg::WAVEFORMATEX,
253 ) -> Option<Format>
254 {
255     fn cmp_guid(a: &GUID, b: &GUID) -> bool {
256         a.Data1 == b.Data1
257             && a.Data2 == b.Data2
258             && a.Data3 == b.Data3
259             && a.Data4 == b.Data4
260     }
261     let data_type = match ((*waveformatex_ptr).wBitsPerSample, (*waveformatex_ptr).wFormatTag) {
262         (16, mmreg::WAVE_FORMAT_PCM) => SampleFormat::I16,
263         (32, mmreg::WAVE_FORMAT_IEEE_FLOAT) => SampleFormat::F32,
264         (n_bits, mmreg::WAVE_FORMAT_EXTENSIBLE) => {
265             let waveformatextensible_ptr = waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
266             let sub = (*waveformatextensible_ptr).SubFormat;
267             if n_bits == 16 && cmp_guid(&sub, &ksmedia::KSDATAFORMAT_SUBTYPE_PCM) {
268                 SampleFormat::I16
269             } else if n_bits == 32 && cmp_guid(&sub, &ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
270                 SampleFormat::F32
271             } else {
272                 return None;
273             }
274         },
275         // Unknown data format returned by GetMixFormat.
276         _ => return None,
277     };
278     let format = Format {
279         channels: (*waveformatex_ptr).nChannels as _,
280         sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec),
281         data_type: data_type,
282     };
283     Some(format)
284 }
285 
286 unsafe impl Send for Device {
287 }
288 unsafe impl Sync for Device {
289 }
290 
291 impl Device {
name(&self) -> String292     pub fn name(&self) -> String {
293         unsafe {
294             // Open the device's property store.
295             let mut property_store = ptr::null_mut();
296             (*self.device).OpenPropertyStore(coml2api::STGM_READ, &mut property_store);
297 
298             // Get the endpoint's friendly-name property.
299             let mut property_value = mem::zeroed();
300             check_result(
301                 (*property_store).GetValue(
302                     &devpkey::DEVPKEY_Device_FriendlyName as *const _ as *const _,
303                     &mut property_value
304                 )
305             ).expect("failed to get friendly-name from property store");
306 
307             // Read the friendly-name from the union data field, expecting a *const u16.
308             assert_eq!(property_value.vt, wtypes::VT_LPWSTR as _);
309             let ptr_usize: usize = *(&property_value.data as *const _ as *const usize);
310             let ptr_utf16 = ptr_usize as *const u16;
311 
312             // Find the length of the friendly name.
313             let mut len = 0;
314             while *ptr_utf16.offset(len) != 0 {
315                 len += 1;
316             }
317 
318             // Create the utf16 slice and covert it into a string.
319             let name_slice = slice::from_raw_parts(ptr_utf16, len as usize);
320             let name_os_string: OsString = OsStringExt::from_wide(name_slice);
321             let name_string = name_os_string.into_string().unwrap();
322 
323             // Clean up the property.
324             PropVariantClear(&mut property_value);
325 
326             name_string
327         }
328     }
329 
330     #[inline]
from_immdevice(device: *mut IMMDevice) -> Self331     fn from_immdevice(device: *mut IMMDevice) -> Self {
332         Device {
333             device: device,
334             future_audio_client: Arc::new(Mutex::new(None)),
335         }
336     }
337 
338     /// Ensures that `future_audio_client` contains a `Some` and returns a locked mutex to it.
ensure_future_audio_client(&self) -> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError>339     fn ensure_future_audio_client(&self)
340                                   -> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> {
341         let mut lock = self.future_audio_client.lock().unwrap();
342         if lock.is_some() {
343             return Ok(lock);
344         }
345 
346         let audio_client: *mut IAudioClient = unsafe {
347             let mut audio_client = mem::uninitialized();
348             let hresult = (*self.device).Activate(&IID_IAudioClient,
349                                                   CLSCTX_ALL,
350                                                   ptr::null_mut(),
351                                                   &mut audio_client);
352 
353             // can fail if the device has been disconnected since we enumerated it, or if
354             // the device doesn't support playback for some reason
355             check_result(hresult)?;
356             assert!(!audio_client.is_null());
357             audio_client as *mut _
358         };
359 
360         *lock = Some(IAudioClientWrapper(audio_client));
361         Ok(lock)
362     }
363 
364     /// Returns an uninitialized `IAudioClient`.
365     #[inline]
build_audioclient(&self) -> Result<*mut IAudioClient, IoError>366     pub(crate) fn build_audioclient(&self) -> Result<*mut IAudioClient, IoError> {
367         let mut lock = self.ensure_future_audio_client()?;
368         let client = lock.unwrap().0;
369         *lock = None;
370         Ok(client)
371     }
372 
373     // There is no way to query the list of all formats that are supported by the
374     // audio processor, so instead we just trial some commonly supported formats.
375     //
376     // Common formats are trialed by first getting the default format (returned via
377     // `GetMixFormat`) and then mutating that format with common sample rates and
378     // querying them via `IsFormatSupported`.
379     //
380     // When calling `IsFormatSupported` with the shared-mode audio engine, only the default
381     // number of channels seems to be supported. Any more or less returns an invalid
382     // parameter error. Thus we just assume that the default number of channels is the only
383     // number supported.
supported_formats(&self) -> Result<SupportedInputFormats, FormatsEnumerationError>384     fn supported_formats(&self) -> Result<SupportedInputFormats, FormatsEnumerationError> {
385         // initializing COM because we call `CoTaskMemFree` to release the format.
386         com::com_initialized();
387 
388         // Retrieve the `IAudioClient`.
389         let lock = match self.ensure_future_audio_client() {
390             Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
391                 return Err(FormatsEnumerationError::DeviceNotAvailable),
392             e => e.unwrap(),
393         };
394         let client = lock.unwrap().0;
395 
396         unsafe {
397             // Retrieve the pointer to the default WAVEFORMATEX.
398             let mut default_waveformatex_ptr = WaveFormatExPtr(mem::uninitialized());
399             match check_result((*client).GetMixFormat(&mut default_waveformatex_ptr.0)) {
400                 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
401                     return Err(FormatsEnumerationError::DeviceNotAvailable);
402                 },
403                 Err(e) => panic!("{:?}", e),
404                 Ok(()) => (),
405             };
406 
407             // If the default format can't succeed we have no hope of finding other formats.
408             assert_eq!(try!(is_format_supported(client, default_waveformatex_ptr.0)), true);
409 
410             // Copy the format to use as a test format (as to avoid mutating the original format).
411             let mut test_format = {
412                 match WaveFormat::copy_from_waveformatex_ptr(default_waveformatex_ptr.0) {
413                     Some(f) => f,
414                     // If the format is neither EX or EXTENSIBLE we don't know how to work with it.
415                     None => return Ok(vec![].into_iter()),
416                 }
417             };
418 
419             // Begin testing common sample rates.
420             //
421             // NOTE: We should really be testing for whole ranges here, but it is infeasible to
422             // test every sample rate up to the overflow limit as the `IsFormatSupported` method is
423             // quite slow.
424             let mut supported_sample_rates: Vec<u32> = Vec::new();
425             for &rate in COMMON_SAMPLE_RATES {
426                 let rate = rate.0 as DWORD;
427                 test_format.nSamplesPerSec = rate;
428                 test_format.nAvgBytesPerSec =
429                     rate * (*default_waveformatex_ptr.0).nBlockAlign as DWORD;
430                 if try!(is_format_supported(client, test_format.as_ptr())) {
431                     supported_sample_rates.push(rate);
432                 }
433             }
434 
435             // If the common rates don't include the default one, add the default.
436             let default_sr = (*default_waveformatex_ptr.0).nSamplesPerSec as _;
437             if !supported_sample_rates.iter().any(|&r| r == default_sr) {
438                 supported_sample_rates.push(default_sr);
439             }
440 
441             // Reset the sample rate on the test format now that we're done.
442             test_format.nSamplesPerSec = (*default_waveformatex_ptr.0).nSamplesPerSec;
443             test_format.nAvgBytesPerSec = (*default_waveformatex_ptr.0).nAvgBytesPerSec;
444 
445             // TODO: Test the different sample formats?
446 
447             // Create the supported formats.
448             let mut format = format_from_waveformatex_ptr(default_waveformatex_ptr.0)
449                 .expect("could not create a cpal::Format from a WAVEFORMATEX");
450             let mut supported_formats = Vec::with_capacity(supported_sample_rates.len());
451             for rate in supported_sample_rates {
452                 format.sample_rate = SampleRate(rate as _);
453                 supported_formats.push(SupportedFormat::from(format.clone()));
454             }
455 
456             Ok(supported_formats.into_iter())
457         }
458     }
459 
supported_input_formats(&self) -> Result<SupportedInputFormats, FormatsEnumerationError>460     pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, FormatsEnumerationError> {
461         if self.data_flow() == eCapture {
462             self.supported_formats()
463         // If it's an output device, assume no input formats.
464         } else {
465             Ok(vec![].into_iter())
466         }
467     }
468 
supported_output_formats(&self) -> Result<SupportedOutputFormats, FormatsEnumerationError>469     pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats, FormatsEnumerationError> {
470         if self.data_flow() == eRender {
471             self.supported_formats()
472         // If it's an input device, assume no output formats.
473         } else {
474             Ok(vec![].into_iter())
475         }
476     }
477 
478     // We always create voices in shared mode, therefore all samples go through an audio
479     // processor to mix them together.
480     //
481     // One format is guaranteed to be supported, the one returned by `GetMixFormat`.
default_format(&self) -> Result<Format, DefaultFormatError>482     fn default_format(&self) -> Result<Format, DefaultFormatError> {
483         // initializing COM because we call `CoTaskMemFree`
484         com::com_initialized();
485 
486         let lock = match self.ensure_future_audio_client() {
487             Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
488                 return Err(DefaultFormatError::DeviceNotAvailable),
489             e => e.unwrap(),
490         };
491         let client = lock.unwrap().0;
492 
493         unsafe {
494             let mut format_ptr = WaveFormatExPtr(mem::uninitialized());
495             match check_result((*client).GetMixFormat(&mut format_ptr.0)) {
496                 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
497                     return Err(DefaultFormatError::DeviceNotAvailable);
498                 },
499                 Err(e) => panic!("{:?}", e),
500                 Ok(()) => (),
501             };
502 
503             format_from_waveformatex_ptr(format_ptr.0)
504                 .ok_or(DefaultFormatError::StreamTypeNotSupported)
505         }
506     }
507 
data_flow(&self) -> EDataFlow508     fn data_flow(&self) -> EDataFlow {
509         let endpoint = Endpoint::from(self.device as *const _);
510         endpoint.data_flow()
511     }
512 
default_input_format(&self) -> Result<Format, DefaultFormatError>513     pub fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
514         if self.data_flow() == eCapture {
515             self.default_format()
516         } else {
517             Err(DefaultFormatError::StreamTypeNotSupported)
518         }
519     }
520 
default_output_format(&self) -> Result<Format, DefaultFormatError>521     pub fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
522         let data_flow = self.data_flow();
523         if data_flow == eRender {
524             self.default_format()
525         } else {
526             Err(DefaultFormatError::StreamTypeNotSupported)
527         }
528     }
529 }
530 
531 impl PartialEq for Device {
532     #[inline]
eq(&self, other: &Device) -> bool533     fn eq(&self, other: &Device) -> bool {
534         self.device == other.device
535     }
536 }
537 
538 impl Eq for Device {
539 }
540 
541 impl Clone for Device {
542     #[inline]
clone(&self) -> Device543     fn clone(&self) -> Device {
544         unsafe {
545             (*self.device).AddRef();
546         }
547 
548         Device {
549             device: self.device,
550             future_audio_client: self.future_audio_client.clone(),
551         }
552     }
553 }
554 
555 impl Drop for Device {
556     #[inline]
drop(&mut self)557     fn drop(&mut self) {
558         unsafe {
559             (*self.device).Release();
560         }
561 
562         if let Some(client) = self.future_audio_client.lock().unwrap().take() {
563             unsafe {
564                 (*client.0).Release();
565             }
566         }
567     }
568 }
569 
570 impl Drop for Endpoint {
drop(&mut self)571     fn drop(&mut self) {
572         unsafe {
573             (*self.endpoint).Release();
574         }
575     }
576 }
577 
578 impl From<*const IMMDevice> for Endpoint {
from(device: *const IMMDevice) -> Self579     fn from(device: *const IMMDevice) -> Self {
580         unsafe {
581             let endpoint = immendpoint_from_immdevice(device);
582             Endpoint { endpoint: endpoint }
583         }
584     }
585 }
586 
587 impl Endpoint {
data_flow(&self) -> EDataFlow588     fn data_flow(&self) -> EDataFlow {
589         unsafe {
590             data_flow_from_immendpoint(self.endpoint)
591         }
592     }
593 }
594 
595 lazy_static! {
596     static ref ENUMERATOR: Enumerator = {
597         // COM initialization is thread local, but we only need to have COM initialized in the
598         // thread we create the objects in
599         com::com_initialized();
600 
601         // building the devices enumerator object
602         unsafe {
603             let mut enumerator: *mut IMMDeviceEnumerator = mem::uninitialized();
604 
605             let hresult = CoCreateInstance(
606                 &CLSID_MMDeviceEnumerator,
607                 ptr::null_mut(),
608                 CLSCTX_ALL,
609                 &IMMDeviceEnumerator::uuidof(),
610                 &mut enumerator as *mut *mut IMMDeviceEnumerator as *mut _,
611             );
612 
613             check_result(hresult).unwrap();
614             Enumerator(enumerator)
615         }
616     };
617 }
618 
619 /// RAII object around `IMMDeviceEnumerator`.
620 struct Enumerator(*mut IMMDeviceEnumerator);
621 
622 unsafe impl Send for Enumerator {
623 }
624 unsafe impl Sync for Enumerator {
625 }
626 
627 impl Drop for Enumerator {
628     #[inline]
drop(&mut self)629     fn drop(&mut self) {
630         unsafe {
631             (*self.0).Release();
632         }
633     }
634 }
635 
636 /// WASAPI implementation for `Devices`.
637 pub struct Devices {
638     collection: *mut IMMDeviceCollection,
639     total_count: u32,
640     next_item: u32,
641 }
642 
643 unsafe impl Send for Devices {
644 }
645 unsafe impl Sync for Devices {
646 }
647 
648 impl Drop for Devices {
649     #[inline]
drop(&mut self)650     fn drop(&mut self) {
651         unsafe {
652             (*self.collection).Release();
653         }
654     }
655 }
656 
657 impl Default for Devices {
default() -> Devices658     fn default() -> Devices {
659         unsafe {
660             let mut collection: *mut IMMDeviceCollection = mem::uninitialized();
661             // can fail because of wrong parameters (should never happen) or out of memory
662             check_result(
663                 (*ENUMERATOR.0).EnumAudioEndpoints(
664                     eAll,
665                     DEVICE_STATE_ACTIVE,
666                     &mut collection,
667                 )
668             ).unwrap();
669 
670             let mut count = mem::uninitialized();
671             // can fail if the parameter is null, which should never happen
672             check_result((*collection).GetCount(&mut count)).unwrap();
673 
674             Devices {
675                 collection: collection,
676                 total_count: count,
677                 next_item: 0,
678             }
679         }
680     }
681 }
682 
683 impl Iterator for Devices {
684     type Item = Device;
685 
next(&mut self) -> Option<Device>686     fn next(&mut self) -> Option<Device> {
687         if self.next_item >= self.total_count {
688             return None;
689         }
690 
691         unsafe {
692             let mut device = mem::uninitialized();
693             // can fail if out of range, which we just checked above
694             check_result((*self.collection).Item(self.next_item, &mut device)).unwrap();
695 
696             self.next_item += 1;
697             Some(Device::from_immdevice(device))
698         }
699     }
700 
701     #[inline]
size_hint(&self) -> (usize, Option<usize>)702     fn size_hint(&self) -> (usize, Option<usize>) {
703         let num = self.total_count - self.next_item;
704         let num = num as usize;
705         (num, Some(num))
706     }
707 }
708 
default_device(data_flow: EDataFlow) -> Option<Device>709 fn default_device(data_flow: EDataFlow) -> Option<Device> {
710     unsafe {
711         let mut device = mem::uninitialized();
712         let hres = (*ENUMERATOR.0)
713             .GetDefaultAudioEndpoint(data_flow, eConsole, &mut device);
714         if let Err(_err) = check_result(hres) {
715             return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise
716         }
717         Some(Device::from_immdevice(device))
718     }
719 }
720 
default_input_device() -> Option<Device>721 pub fn default_input_device() -> Option<Device> {
722     default_device(eCapture)
723 }
724 
default_output_device() -> Option<Device>725 pub fn default_output_device() -> Option<Device> {
726     default_device(eRender)
727 }
728