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