1 use crate::{
2 BackendSpecificError, BufferSize, Data, DefaultStreamConfigError, DeviceNameError,
3 DevicesError, InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig,
4 SupportedBufferSize, SupportedStreamConfig, SupportedStreamConfigRange,
5 SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
6 };
7 use std;
8 use std::ffi::OsString;
9 use std::fmt;
10 use std::io::Error as IoError;
11 use std::mem;
12 use std::ops::{Deref, DerefMut};
13 use std::os::windows::ffi::OsStringExt;
14 use std::ptr;
15 use std::slice;
16 use std::sync::{Arc, Mutex, MutexGuard};
17
18 use super::check_result;
19 use super::check_result_backend_specific;
20 use super::com;
21 use super::winapi::ctypes::c_void;
22 use super::winapi::shared::devpkey;
23 use super::winapi::shared::guiddef::GUID;
24 use super::winapi::shared::ksmedia;
25 use super::winapi::shared::minwindef::{DWORD, WORD};
26 use super::winapi::shared::mmreg;
27 use super::winapi::shared::winerror;
28 use super::winapi::shared::wtypes;
29 use super::winapi::Interface;
30
31 // https://msdn.microsoft.com/en-us/library/cc230355.aspx
32 use super::winapi::um::audioclient::{
33 self, IAudioClient, IID_IAudioClient, AUDCLNT_E_DEVICE_INVALIDATED,
34 };
35 use super::winapi::um::audiosessiontypes::{
36 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, AUDCLNT_STREAMFLAGS_LOOPBACK,
37 };
38 use super::winapi::um::combaseapi::{
39 CoCreateInstance, CoTaskMemFree, PropVariantClear, CLSCTX_ALL,
40 };
41 use super::winapi::um::coml2api;
42 use super::winapi::um::mmdeviceapi::{
43 eAll, eCapture, eConsole, eRender, CLSID_MMDeviceEnumerator, EDataFlow, IMMDevice,
44 IMMDeviceCollection, IMMDeviceEnumerator, IMMEndpoint, DEVICE_STATE_ACTIVE,
45 };
46 use super::winapi::um::winnt::{LPWSTR, WCHAR};
47
48 use super::{
49 stream::{AudioClientFlow, Stream, StreamInner},
50 winapi::um::synchapi,
51 };
52 use crate::{traits::DeviceTrait, BuildStreamError, StreamError};
53
54 pub type SupportedInputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
55 pub type SupportedOutputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
56
57 /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
58 #[derive(Copy, Clone)]
59 struct IAudioClientWrapper(*mut IAudioClient);
60 unsafe impl Send for IAudioClientWrapper {}
61 unsafe impl Sync for IAudioClientWrapper {}
62
63 /// An opaque type that identifies an end point.
64 pub struct Device {
65 device: *mut IMMDevice,
66 /// We cache an uninitialized `IAudioClient` so that we can call functions from it without
67 /// having to create/destroy audio clients all the time.
68 future_audio_client: Arc<Mutex<Option<IAudioClientWrapper>>>, // TODO: add NonZero around the ptr
69 }
70
71 impl DeviceTrait for Device {
72 type SupportedInputConfigs = SupportedInputConfigs;
73 type SupportedOutputConfigs = SupportedOutputConfigs;
74 type Stream = Stream;
75
name(&self) -> Result<String, DeviceNameError>76 fn name(&self) -> Result<String, DeviceNameError> {
77 Device::name(self)
78 }
79
supported_input_configs( &self, ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError>80 fn supported_input_configs(
81 &self,
82 ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
83 Device::supported_input_configs(self)
84 }
85
supported_output_configs( &self, ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError>86 fn supported_output_configs(
87 &self,
88 ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
89 Device::supported_output_configs(self)
90 }
91
default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>92 fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
93 Device::default_input_config(self)
94 }
95
default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>96 fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
97 Device::default_output_config(self)
98 }
99
build_input_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, data_callback: D, error_callback: E, ) -> Result<Self::Stream, BuildStreamError> where D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,100 fn build_input_stream_raw<D, E>(
101 &self,
102 config: &StreamConfig,
103 sample_format: SampleFormat,
104 data_callback: D,
105 error_callback: E,
106 ) -> Result<Self::Stream, BuildStreamError>
107 where
108 D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
109 E: FnMut(StreamError) + Send + 'static,
110 {
111 let stream_inner = self.build_input_stream_raw_inner(config, sample_format)?;
112 Ok(Stream::new_input(
113 stream_inner,
114 data_callback,
115 error_callback,
116 ))
117 }
118
build_output_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, data_callback: D, error_callback: E, ) -> Result<Self::Stream, BuildStreamError> where D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,119 fn build_output_stream_raw<D, E>(
120 &self,
121 config: &StreamConfig,
122 sample_format: SampleFormat,
123 data_callback: D,
124 error_callback: E,
125 ) -> Result<Self::Stream, BuildStreamError>
126 where
127 D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
128 E: FnMut(StreamError) + Send + 'static,
129 {
130 let stream_inner = self.build_output_stream_raw_inner(config, sample_format)?;
131 Ok(Stream::new_output(
132 stream_inner,
133 data_callback,
134 error_callback,
135 ))
136 }
137 }
138
139 struct Endpoint {
140 endpoint: *mut IMMEndpoint,
141 }
142
143 enum WaveFormat {
144 Ex(mmreg::WAVEFORMATEX),
145 Extensible(mmreg::WAVEFORMATEXTENSIBLE),
146 }
147
148 // Use RAII to make sure CoTaskMemFree is called when we are responsible for freeing.
149 struct WaveFormatExPtr(*mut mmreg::WAVEFORMATEX);
150
151 impl Drop for WaveFormatExPtr {
drop(&mut self)152 fn drop(&mut self) {
153 unsafe {
154 CoTaskMemFree(self.0 as *mut _);
155 }
156 }
157 }
158
159 impl WaveFormat {
160 // Given a pointer to some format, returns a valid copy of the format.
copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self>161 pub fn copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self> {
162 unsafe {
163 match (*ptr).wFormatTag {
164 mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => {
165 Some(WaveFormat::Ex(*ptr))
166 }
167 mmreg::WAVE_FORMAT_EXTENSIBLE => {
168 let extensible_ptr = ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
169 Some(WaveFormat::Extensible(*extensible_ptr))
170 }
171 _ => None,
172 }
173 }
174 }
175
176 // Get the pointer to the WAVEFORMATEX struct.
as_ptr(&self) -> *const mmreg::WAVEFORMATEX177 pub fn as_ptr(&self) -> *const mmreg::WAVEFORMATEX {
178 self.deref() as *const _
179 }
180 }
181
182 impl Deref for WaveFormat {
183 type Target = mmreg::WAVEFORMATEX;
deref(&self) -> &Self::Target184 fn deref(&self) -> &Self::Target {
185 match *self {
186 WaveFormat::Ex(ref f) => f,
187 WaveFormat::Extensible(ref f) => &f.Format,
188 }
189 }
190 }
191
192 impl DerefMut for WaveFormat {
deref_mut(&mut self) -> &mut Self::Target193 fn deref_mut(&mut self) -> &mut Self::Target {
194 match *self {
195 WaveFormat::Ex(ref mut f) => f,
196 WaveFormat::Extensible(ref mut f) => &mut f.Format,
197 }
198 }
199 }
200
immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint201 unsafe fn immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint {
202 let mut endpoint: *mut IMMEndpoint = ptr::null_mut();
203 check_result(
204 (*device).QueryInterface(&IMMEndpoint::uuidof(), &mut endpoint as *mut _ as *mut _),
205 )
206 .expect("could not query IMMDevice interface for IMMEndpoint");
207 endpoint
208 }
209
data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow210 unsafe fn data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow {
211 let mut data_flow = std::mem::MaybeUninit::<EDataFlow>::uninit();
212 check_result((*endpoint).GetDataFlow(data_flow.as_mut_ptr()))
213 .expect("could not get endpoint data_flow");
214 data_flow.assume_init()
215 }
216
217 // 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, SupportedStreamConfigsError>218 pub unsafe fn is_format_supported(
219 client: *const IAudioClient,
220 waveformatex_ptr: *const mmreg::WAVEFORMATEX,
221 ) -> Result<bool, SupportedStreamConfigsError> {
222 /*
223 // `IsFormatSupported` checks whether the format is supported and fills
224 // a `WAVEFORMATEX`
225 let mut dummy_fmt_ptr: *mut mmreg::WAVEFORMATEX = mem::uninitialized();
226 let hresult =
227 (*audio_client)
228 .IsFormatSupported(share_mode, &format_attempt.Format, &mut dummy_fmt_ptr);
229 // we free that `WAVEFORMATEX` immediately after because we don't need it
230 if !dummy_fmt_ptr.is_null() {
231 CoTaskMemFree(dummy_fmt_ptr as *mut _);
232 }
233
234 // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
235 // has been found), but we also treat this as an error
236 match (hresult, check_result(hresult)) {
237 (_, Err(ref e))
238 if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
239 (*audio_client).Release();
240 return Err(BuildStreamError::DeviceNotAvailable);
241 },
242 (_, Err(e)) => {
243 (*audio_client).Release();
244 panic!("{:?}", e);
245 },
246 (winerror::S_FALSE, _) => {
247 (*audio_client).Release();
248 return Err(BuildStreamError::StreamConfigNotSupported);
249 },
250 (_, Ok(())) => (),
251 };
252 */
253
254 // Check if the given format is supported.
255 let is_supported = |waveformatex_ptr, mut closest_waveformatex_ptr| {
256 let result = (*client).IsFormatSupported(
257 AUDCLNT_SHAREMODE_SHARED,
258 waveformatex_ptr,
259 &mut closest_waveformatex_ptr,
260 );
261 // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
262 // has been found, but not an exact match) so we also treat this as unsupported.
263 match (result, check_result(result)) {
264 (_, Err(ref e)) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
265 Err(SupportedStreamConfigsError::DeviceNotAvailable)
266 }
267 (_, Err(_)) => Ok(false),
268 (winerror::S_FALSE, _) => Ok(false),
269 (_, Ok(())) => Ok(true),
270 }
271 };
272
273 // First we want to retrieve a pointer to the `WAVEFORMATEX`.
274 // Although `GetMixFormat` writes the format to a given `WAVEFORMATEX` pointer,
275 // the pointer itself may actually point to a `WAVEFORMATEXTENSIBLE` structure.
276 // We check the wFormatTag to determine this and get a pointer to the correct type.
277 match (*waveformatex_ptr).wFormatTag {
278 mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => {
279 let mut closest_waveformatex = *waveformatex_ptr;
280 let closest_waveformatex_ptr = &mut closest_waveformatex as *mut _;
281 is_supported(waveformatex_ptr, closest_waveformatex_ptr)
282 }
283 mmreg::WAVE_FORMAT_EXTENSIBLE => {
284 let waveformatextensible_ptr = waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
285 let mut closest_waveformatextensible = *waveformatextensible_ptr;
286 let closest_waveformatextensible_ptr = &mut closest_waveformatextensible as *mut _;
287 let closest_waveformatex_ptr =
288 closest_waveformatextensible_ptr as *mut mmreg::WAVEFORMATEX;
289 is_supported(waveformatex_ptr, closest_waveformatex_ptr)
290 }
291 _ => Ok(false),
292 }
293 }
294
295 // Get a cpal Format from a WAVEFORMATEX.
format_from_waveformatex_ptr( waveformatex_ptr: *const mmreg::WAVEFORMATEX, ) -> Option<SupportedStreamConfig>296 unsafe fn format_from_waveformatex_ptr(
297 waveformatex_ptr: *const mmreg::WAVEFORMATEX,
298 ) -> Option<SupportedStreamConfig> {
299 fn cmp_guid(a: &GUID, b: &GUID) -> bool {
300 a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4
301 }
302 let sample_format = match (
303 (*waveformatex_ptr).wBitsPerSample,
304 (*waveformatex_ptr).wFormatTag,
305 ) {
306 (16, mmreg::WAVE_FORMAT_PCM) => SampleFormat::I16,
307 (32, mmreg::WAVE_FORMAT_IEEE_FLOAT) => SampleFormat::F32,
308 (n_bits, mmreg::WAVE_FORMAT_EXTENSIBLE) => {
309 let waveformatextensible_ptr = waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
310 let sub = (*waveformatextensible_ptr).SubFormat;
311 if n_bits == 16 && cmp_guid(&sub, &ksmedia::KSDATAFORMAT_SUBTYPE_PCM) {
312 SampleFormat::I16
313 } else if n_bits == 32 && cmp_guid(&sub, &ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
314 SampleFormat::F32
315 } else {
316 return None;
317 }
318 }
319 // Unknown data format returned by GetMixFormat.
320 _ => return None,
321 };
322
323 let format = SupportedStreamConfig {
324 channels: (*waveformatex_ptr).nChannels as _,
325 sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec),
326 buffer_size: SupportedBufferSize::Unknown,
327 sample_format,
328 };
329 Some(format)
330 }
331
332 unsafe impl Send for Device {}
333 unsafe impl Sync for Device {}
334
335 impl Device {
name(&self) -> Result<String, DeviceNameError>336 pub fn name(&self) -> Result<String, DeviceNameError> {
337 unsafe {
338 // Open the device's property store.
339 let mut property_store = ptr::null_mut();
340 (*self.device).OpenPropertyStore(coml2api::STGM_READ, &mut property_store);
341
342 // Get the endpoint's friendly-name property.
343 let mut property_value = mem::zeroed();
344 if let Err(err) = check_result((*property_store).GetValue(
345 &devpkey::DEVPKEY_Device_FriendlyName as *const _ as *const _,
346 &mut property_value,
347 )) {
348 let description = format!("failed to retrieve name from property store: {}", err);
349 let err = BackendSpecificError { description };
350 return Err(err.into());
351 }
352
353 // Read the friendly-name from the union data field, expecting a *const u16.
354 if property_value.vt != wtypes::VT_LPWSTR as _ {
355 let description = format!(
356 "property store produced invalid data: {:?}",
357 property_value.vt
358 );
359 let err = BackendSpecificError { description };
360 return Err(err.into());
361 }
362 let ptr_utf16 = *(&property_value.data as *const _ as *const *const u16);
363
364 // Find the length of the friendly name.
365 let mut len = 0;
366 while *ptr_utf16.offset(len) != 0 {
367 len += 1;
368 }
369
370 // Create the utf16 slice and covert it into a string.
371 let name_slice = slice::from_raw_parts(ptr_utf16, len as usize);
372 let name_os_string: OsString = OsStringExt::from_wide(name_slice);
373 let name_string = match name_os_string.into_string() {
374 Ok(string) => string,
375 Err(os_string) => os_string.to_string_lossy().into(),
376 };
377
378 // Clean up the property.
379 PropVariantClear(&mut property_value);
380
381 Ok(name_string)
382 }
383 }
384
385 #[inline]
from_immdevice(device: *mut IMMDevice) -> Self386 fn from_immdevice(device: *mut IMMDevice) -> Self {
387 Device {
388 device,
389 future_audio_client: Arc::new(Mutex::new(None)),
390 }
391 }
392
393 /// 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>394 fn ensure_future_audio_client(
395 &self,
396 ) -> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> {
397 let mut lock = self.future_audio_client.lock().unwrap();
398 if lock.is_some() {
399 return Ok(lock);
400 }
401
402 let audio_client: *mut IAudioClient = unsafe {
403 let mut audio_client = ptr::null_mut();
404 let hresult = (*self.device).Activate(
405 &IID_IAudioClient,
406 CLSCTX_ALL,
407 ptr::null_mut(),
408 &mut audio_client,
409 );
410
411 // can fail if the device has been disconnected since we enumerated it, or if
412 // the device doesn't support playback for some reason
413 check_result(hresult)?;
414 assert!(!audio_client.is_null());
415 audio_client as *mut _
416 };
417
418 *lock = Some(IAudioClientWrapper(audio_client));
419 Ok(lock)
420 }
421
422 /// Returns an uninitialized `IAudioClient`.
423 #[inline]
build_audioclient(&self) -> Result<*mut IAudioClient, IoError>424 pub(crate) fn build_audioclient(&self) -> Result<*mut IAudioClient, IoError> {
425 let mut lock = self.ensure_future_audio_client()?;
426 let client = lock.unwrap().0;
427 *lock = None;
428 Ok(client)
429 }
430
431 // There is no way to query the list of all formats that are supported by the
432 // audio processor, so instead we just trial some commonly supported formats.
433 //
434 // Common formats are trialed by first getting the default format (returned via
435 // `GetMixFormat`) and then mutating that format with common sample rates and
436 // querying them via `IsFormatSupported`.
437 //
438 // When calling `IsFormatSupported` with the shared-mode audio engine, only the default
439 // number of channels seems to be supported. Any, more or less returns an invalid
440 // parameter error. Thus, we just assume that the default number of channels is the only
441 // number supported.
supported_formats(&self) -> Result<SupportedInputConfigs, SupportedStreamConfigsError>442 fn supported_formats(&self) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
443 // initializing COM because we call `CoTaskMemFree` to release the format.
444 com::com_initialized();
445
446 // Retrieve the `IAudioClient`.
447 let lock = match self.ensure_future_audio_client() {
448 Ok(lock) => lock,
449 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
450 return Err(SupportedStreamConfigsError::DeviceNotAvailable)
451 }
452 Err(e) => {
453 let description = format!("{}", e);
454 let err = BackendSpecificError { description };
455 return Err(err.into());
456 }
457 };
458 let client = lock.unwrap().0;
459
460 unsafe {
461 // Retrieve the pointer to the default WAVEFORMATEX.
462 let mut default_waveformatex_ptr = WaveFormatExPtr(ptr::null_mut());
463 match check_result((*client).GetMixFormat(&mut default_waveformatex_ptr.0)) {
464 Ok(()) => (),
465 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
466 return Err(SupportedStreamConfigsError::DeviceNotAvailable);
467 }
468 Err(e) => {
469 let description = format!("{}", e);
470 let err = BackendSpecificError { description };
471 return Err(err.into());
472 }
473 };
474
475 // If the default format can't succeed we have no hope of finding other formats.
476 assert_eq!(
477 is_format_supported(client, default_waveformatex_ptr.0)?,
478 true
479 );
480
481 // Copy the format to use as a test format (as to avoid mutating the original format).
482 let mut test_format = {
483 match WaveFormat::copy_from_waveformatex_ptr(default_waveformatex_ptr.0) {
484 Some(f) => f,
485 // If the format is neither EX nor EXTENSIBLE we don't know how to work with it.
486 None => return Ok(vec![].into_iter()),
487 }
488 };
489
490 // Begin testing common sample rates.
491 //
492 // NOTE: We should really be testing for whole ranges here, but it is infeasible to
493 // test every sample rate up to the overflow limit as the `IsFormatSupported` method is
494 // quite slow.
495 let mut supported_sample_rates: Vec<u32> = Vec::new();
496 for &rate in COMMON_SAMPLE_RATES {
497 let rate = rate.0 as DWORD;
498 test_format.nSamplesPerSec = rate;
499 test_format.nAvgBytesPerSec =
500 rate * u32::from((*default_waveformatex_ptr.0).nBlockAlign);
501 if is_format_supported(client, test_format.as_ptr())? {
502 supported_sample_rates.push(rate);
503 }
504 }
505
506 // If the common rates don't include the default one, add the default.
507 let default_sr = (*default_waveformatex_ptr.0).nSamplesPerSec as _;
508 if !supported_sample_rates.iter().any(|&r| r == default_sr) {
509 supported_sample_rates.push(default_sr);
510 }
511
512 // Reset the sample rate on the test format now that we're done.
513 test_format.nSamplesPerSec = (*default_waveformatex_ptr.0).nSamplesPerSec;
514 test_format.nAvgBytesPerSec = (*default_waveformatex_ptr.0).nAvgBytesPerSec;
515
516 // TODO: Test the different sample formats?
517
518 // Create the supported formats.
519 let format = match format_from_waveformatex_ptr(default_waveformatex_ptr.0) {
520 Some(fmt) => fmt,
521 None => {
522 let description =
523 "could not create a `cpal::SupportedStreamConfig` from a `WAVEFORMATEX`"
524 .to_string();
525 let err = BackendSpecificError { description };
526 return Err(err.into());
527 }
528 };
529 let mut supported_formats = Vec::with_capacity(supported_sample_rates.len());
530 for rate in supported_sample_rates {
531 supported_formats.push(SupportedStreamConfigRange {
532 channels: format.channels.clone(),
533 min_sample_rate: SampleRate(rate as _),
534 max_sample_rate: SampleRate(rate as _),
535 buffer_size: format.buffer_size.clone(),
536 sample_format: format.sample_format.clone(),
537 })
538 }
539 Ok(supported_formats.into_iter())
540 }
541 }
542
supported_input_configs( &self, ) -> Result<SupportedInputConfigs, SupportedStreamConfigsError>543 pub fn supported_input_configs(
544 &self,
545 ) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
546 if self.data_flow() == eCapture {
547 self.supported_formats()
548 // If it's an output device, assume no input formats.
549 } else {
550 Ok(vec![].into_iter())
551 }
552 }
553
supported_output_configs( &self, ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError>554 pub fn supported_output_configs(
555 &self,
556 ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
557 if self.data_flow() == eRender {
558 self.supported_formats()
559 // If it's an input device, assume no output formats.
560 } else {
561 Ok(vec![].into_iter())
562 }
563 }
564
565 // We always create voices in shared mode, therefore all samples go through an audio
566 // processor to mix them together.
567 //
568 // One format is guaranteed to be supported, the one returned by `GetMixFormat`.
default_format(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>569 fn default_format(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
570 // initializing COM because we call `CoTaskMemFree`
571 com::com_initialized();
572
573 let lock = match self.ensure_future_audio_client() {
574 Ok(lock) => lock,
575 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
576 return Err(DefaultStreamConfigError::DeviceNotAvailable)
577 }
578 Err(e) => {
579 let description = format!("{}", e);
580 let err = BackendSpecificError { description };
581 return Err(err.into());
582 }
583 };
584 let client = lock.unwrap().0;
585
586 unsafe {
587 let mut format_ptr = WaveFormatExPtr(ptr::null_mut());
588 match check_result((*client).GetMixFormat(&mut format_ptr.0)) {
589 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
590 return Err(DefaultStreamConfigError::DeviceNotAvailable);
591 }
592 Err(e) => {
593 let description = format!("{}", e);
594 let err = BackendSpecificError { description };
595 return Err(err.into());
596 }
597 Ok(()) => (),
598 };
599
600 format_from_waveformatex_ptr(format_ptr.0)
601 .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)
602 }
603 }
604
data_flow(&self) -> EDataFlow605 pub(crate) fn data_flow(&self) -> EDataFlow {
606 let endpoint = Endpoint::from(self.device as *const _);
607 endpoint.data_flow()
608 }
609
default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>610 pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
611 if self.data_flow() == eCapture {
612 self.default_format()
613 } else {
614 Err(DefaultStreamConfigError::StreamTypeNotSupported)
615 }
616 }
617
default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>618 pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
619 let data_flow = self.data_flow();
620 if data_flow == eRender {
621 self.default_format()
622 } else {
623 Err(DefaultStreamConfigError::StreamTypeNotSupported)
624 }
625 }
626
build_input_stream_raw_inner( &self, config: &StreamConfig, sample_format: SampleFormat, ) -> Result<StreamInner, BuildStreamError>627 pub(crate) fn build_input_stream_raw_inner(
628 &self,
629 config: &StreamConfig,
630 sample_format: SampleFormat,
631 ) -> Result<StreamInner, BuildStreamError> {
632 unsafe {
633 // Making sure that COM is initialized.
634 // It's not actually sure that this is required, but when in doubt do it.
635 com::com_initialized();
636
637 // Obtaining a `IAudioClient`.
638 let audio_client = match self.build_audioclient() {
639 Ok(client) => client,
640 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
641 return Err(BuildStreamError::DeviceNotAvailable)
642 }
643 Err(e) => {
644 let description = format!("{}", e);
645 let err = BackendSpecificError { description };
646 return Err(err.into());
647 }
648 };
649
650 match config.buffer_size {
651 BufferSize::Fixed(_) => {
652 // TO DO: We need IAudioClient3 to get buffersize ranges first
653 // Otherwise the supported ranges are unknown. In the meantime
654 // the smallest buffersize is selected and used.
655 return Err(BuildStreamError::StreamConfigNotSupported);
656 }
657 BufferSize::Default => (),
658 };
659
660 let mut stream_flags: DWORD = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
661
662 if self.data_flow() == eRender {
663 stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
664 }
665
666 // Computing the format and initializing the device.
667 let waveformatex = {
668 let format_attempt = config_to_waveformatextensible(config, sample_format)
669 .ok_or(BuildStreamError::StreamConfigNotSupported)?;
670 let share_mode = AUDCLNT_SHAREMODE_SHARED;
671
672 // Ensure the format is supported.
673 match super::device::is_format_supported(audio_client, &format_attempt.Format) {
674 Ok(false) => return Err(BuildStreamError::StreamConfigNotSupported),
675 Err(_) => return Err(BuildStreamError::DeviceNotAvailable),
676 _ => (),
677 }
678
679 // Finally, initializing the audio client
680 let hresult = (*audio_client).Initialize(
681 share_mode,
682 stream_flags,
683 0,
684 0,
685 &format_attempt.Format,
686 ptr::null(),
687 );
688 match check_result(hresult) {
689 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
690 (*audio_client).Release();
691 return Err(BuildStreamError::DeviceNotAvailable);
692 }
693 Err(e) => {
694 (*audio_client).Release();
695 let description = format!("{}", e);
696 let err = BackendSpecificError { description };
697 return Err(err.into());
698 }
699 Ok(()) => (),
700 };
701
702 format_attempt.Format
703 };
704
705 // obtaining the size of the samples buffer in number of frames
706 let max_frames_in_buffer = {
707 let mut max_frames_in_buffer = 0u32;
708 let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
709
710 match check_result(hresult) {
711 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
712 (*audio_client).Release();
713 return Err(BuildStreamError::DeviceNotAvailable);
714 }
715 Err(e) => {
716 (*audio_client).Release();
717 let description = format!("{}", e);
718 let err = BackendSpecificError { description };
719 return Err(err.into());
720 }
721 Ok(()) => (),
722 };
723
724 max_frames_in_buffer
725 };
726
727 // Creating the event that will be signalled whenever we need to submit some samples.
728 let event = {
729 let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
730 if event.is_null() {
731 (*audio_client).Release();
732 let description = "failed to create event".to_string();
733 let err = BackendSpecificError { description };
734 return Err(err.into());
735 }
736
737 if let Err(e) = check_result((*audio_client).SetEventHandle(event)) {
738 (*audio_client).Release();
739 let description = format!("failed to call SetEventHandle: {}", e);
740 let err = BackendSpecificError { description };
741 return Err(err.into());
742 }
743
744 event
745 };
746
747 // Building a `IAudioCaptureClient` that will be used to read captured samples.
748 let capture_client = {
749 let mut capture_client: *mut audioclient::IAudioCaptureClient = ptr::null_mut();
750 let hresult = (*audio_client).GetService(
751 &audioclient::IID_IAudioCaptureClient,
752 &mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _,
753 );
754
755 match check_result(hresult) {
756 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
757 (*audio_client).Release();
758 return Err(BuildStreamError::DeviceNotAvailable);
759 }
760 Err(e) => {
761 (*audio_client).Release();
762 let description = format!("failed to build capture client: {}", e);
763 let err = BackendSpecificError { description };
764 return Err(err.into());
765 }
766 Ok(()) => (),
767 };
768
769 &mut *capture_client
770 };
771
772 // Once we built the `StreamInner`, we add a command that will be picked up by the
773 // `run()` method and added to the `RunContext`.
774 let client_flow = AudioClientFlow::Capture { capture_client };
775
776 let audio_clock = get_audio_clock(audio_client).map_err(|err| {
777 (*audio_client).Release();
778 err
779 })?;
780
781 Ok(StreamInner {
782 audio_client,
783 audio_clock,
784 client_flow,
785 event,
786 playing: false,
787 max_frames_in_buffer,
788 bytes_per_frame: waveformatex.nBlockAlign,
789 config: config.clone(),
790 sample_format,
791 })
792 }
793 }
794
build_output_stream_raw_inner( &self, config: &StreamConfig, sample_format: SampleFormat, ) -> Result<StreamInner, BuildStreamError>795 pub(crate) fn build_output_stream_raw_inner(
796 &self,
797 config: &StreamConfig,
798 sample_format: SampleFormat,
799 ) -> Result<StreamInner, BuildStreamError> {
800 unsafe {
801 // Making sure that COM is initialized.
802 // It's not actually sure that this is required, but when in doubt do it.
803 com::com_initialized();
804
805 // Obtaining a `IAudioClient`.
806 let audio_client = match self.build_audioclient() {
807 Ok(client) => client,
808 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
809 return Err(BuildStreamError::DeviceNotAvailable)
810 }
811 Err(e) => {
812 let description = format!("{}", e);
813 let err = BackendSpecificError { description };
814 return Err(err.into());
815 }
816 };
817
818 match config.buffer_size {
819 BufferSize::Fixed(_) => {
820 // TO DO: We need IAudioClient3 to get buffersize ranges first
821 // Otherwise the supported ranges are unknown. In the meantime
822 // the smallest buffersize is selected and used.
823 return Err(BuildStreamError::StreamConfigNotSupported);
824 }
825 BufferSize::Default => (),
826 };
827
828 // Computing the format and initializing the device.
829 let waveformatex = {
830 let format_attempt = config_to_waveformatextensible(config, sample_format)
831 .ok_or(BuildStreamError::StreamConfigNotSupported)?;
832 let share_mode = AUDCLNT_SHAREMODE_SHARED;
833
834 // Ensure the format is supported.
835 match super::device::is_format_supported(audio_client, &format_attempt.Format) {
836 Ok(false) => return Err(BuildStreamError::StreamConfigNotSupported),
837 Err(_) => return Err(BuildStreamError::DeviceNotAvailable),
838 _ => (),
839 }
840
841 // Finally, initializing the audio client
842 let hresult = (*audio_client).Initialize(
843 share_mode,
844 AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
845 0,
846 0,
847 &format_attempt.Format,
848 ptr::null(),
849 );
850
851 match check_result(hresult) {
852 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
853 (*audio_client).Release();
854 return Err(BuildStreamError::DeviceNotAvailable);
855 }
856 Err(e) => {
857 (*audio_client).Release();
858 let description = format!("{}", e);
859 let err = BackendSpecificError { description };
860 return Err(err.into());
861 }
862 Ok(()) => (),
863 };
864
865 format_attempt.Format
866 };
867
868 // Creating the event that will be signalled whenever we need to submit some samples.
869 let event = {
870 let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
871 if event.is_null() {
872 (*audio_client).Release();
873 let description = "failed to create event".to_string();
874 let err = BackendSpecificError { description };
875 return Err(err.into());
876 }
877
878 if let Err(e) = check_result((*audio_client).SetEventHandle(event)) {
879 (*audio_client).Release();
880 let description = format!("failed to call SetEventHandle: {}", e);
881 let err = BackendSpecificError { description };
882 return Err(err.into());
883 };
884
885 event
886 };
887
888 // obtaining the size of the samples buffer in number of frames
889 let max_frames_in_buffer = {
890 let mut max_frames_in_buffer = 0u32;
891 let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
892
893 match check_result(hresult) {
894 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
895 (*audio_client).Release();
896 return Err(BuildStreamError::DeviceNotAvailable);
897 }
898 Err(e) => {
899 (*audio_client).Release();
900 let description = format!("failed to obtain buffer size: {}", e);
901 let err = BackendSpecificError { description };
902 return Err(err.into());
903 }
904 Ok(()) => (),
905 };
906
907 max_frames_in_buffer
908 };
909
910 // Building a `IAudioRenderClient` that will be used to fill the samples buffer.
911 let render_client = {
912 let mut render_client: *mut audioclient::IAudioRenderClient = ptr::null_mut();
913 let hresult = (*audio_client).GetService(
914 &audioclient::IID_IAudioRenderClient,
915 &mut render_client as *mut *mut audioclient::IAudioRenderClient as *mut _,
916 );
917
918 match check_result(hresult) {
919 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
920 (*audio_client).Release();
921 return Err(BuildStreamError::DeviceNotAvailable);
922 }
923 Err(e) => {
924 (*audio_client).Release();
925 let description = format!("failed to build render client: {}", e);
926 let err = BackendSpecificError { description };
927 return Err(err.into());
928 }
929 Ok(()) => (),
930 };
931
932 &mut *render_client
933 };
934
935 // Once we built the `StreamInner`, we add a command that will be picked up by the
936 // `run()` method and added to the `RunContext`.
937 let client_flow = AudioClientFlow::Render { render_client };
938
939 let audio_clock = get_audio_clock(audio_client).map_err(|err| {
940 (*audio_client).Release();
941 err
942 })?;
943
944 Ok(StreamInner {
945 audio_client,
946 audio_clock,
947 client_flow,
948 event,
949 playing: false,
950 max_frames_in_buffer,
951 bytes_per_frame: waveformatex.nBlockAlign,
952 config: config.clone(),
953 sample_format,
954 })
955 }
956 }
957 }
958
959 impl PartialEq for Device {
960 #[inline]
eq(&self, other: &Device) -> bool961 fn eq(&self, other: &Device) -> bool {
962 // Use case: In oder to check whether the default device has changed
963 // the client code might need to compare the previous default device with the current one.
964 // The pointer comparison (`self.device == other.device`) don't work there,
965 // because the pointers are different even when the default device stays the same.
966 //
967 // In this code section we're trying to use the GetId method for the device comparison, cf.
968 // https://docs.microsoft.com/en-us/windows/desktop/api/mmdeviceapi/nf-mmdeviceapi-immdevice-getid
969 unsafe {
970 struct IdRAII(LPWSTR);
971 /// RAII for device IDs.
972 impl Drop for IdRAII {
973 fn drop(&mut self) {
974 unsafe { CoTaskMemFree(self.0 as *mut c_void) }
975 }
976 }
977 let mut id1: LPWSTR = ptr::null_mut();
978 let rc1 = (*self.device).GetId(&mut id1);
979 // GetId only fails with E_OUTOFMEMORY and if it does, we're probably dead already.
980 // Plus it won't do to change the device comparison logic unexpectedly.
981 if rc1 != winerror::S_OK {
982 panic!("cpal: GetId failure: {}", rc1)
983 }
984 let id1 = IdRAII(id1);
985 let mut id2: LPWSTR = ptr::null_mut();
986 let rc2 = (*other.device).GetId(&mut id2);
987 if rc2 != winerror::S_OK {
988 panic!("cpal: GetId failure: {}", rc1)
989 }
990 let id2 = IdRAII(id2);
991 // 16-bit null-terminated comparison.
992 let mut offset = 0;
993 loop {
994 let w1: WCHAR = *id1.0.offset(offset);
995 let w2: WCHAR = *id2.0.offset(offset);
996 if w1 == 0 && w2 == 0 {
997 return true;
998 }
999 if w1 != w2 {
1000 return false;
1001 }
1002 offset += 1;
1003 }
1004 }
1005 }
1006 }
1007
1008 impl Eq for Device {}
1009
1010 impl Clone for Device {
1011 #[inline]
clone(&self) -> Device1012 fn clone(&self) -> Device {
1013 unsafe {
1014 (*self.device).AddRef();
1015 }
1016
1017 Device {
1018 device: self.device,
1019 future_audio_client: self.future_audio_client.clone(),
1020 }
1021 }
1022 }
1023
1024 impl fmt::Debug for Device {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1025 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1026 f.debug_struct("Device")
1027 .field("device", &self.device)
1028 .field("name", &self.name())
1029 .finish()
1030 }
1031 }
1032
1033 impl Drop for Device {
1034 #[inline]
drop(&mut self)1035 fn drop(&mut self) {
1036 unsafe {
1037 (*self.device).Release();
1038 }
1039
1040 if let Some(client) = self.future_audio_client.lock().unwrap().take() {
1041 unsafe {
1042 (*client.0).Release();
1043 }
1044 }
1045 }
1046 }
1047
1048 impl Drop for Endpoint {
drop(&mut self)1049 fn drop(&mut self) {
1050 unsafe {
1051 (*self.endpoint).Release();
1052 }
1053 }
1054 }
1055
1056 impl From<*const IMMDevice> for Endpoint {
from(device: *const IMMDevice) -> Self1057 fn from(device: *const IMMDevice) -> Self {
1058 unsafe {
1059 let endpoint = immendpoint_from_immdevice(device);
1060 Endpoint { endpoint }
1061 }
1062 }
1063 }
1064
1065 impl Endpoint {
data_flow(&self) -> EDataFlow1066 fn data_flow(&self) -> EDataFlow {
1067 unsafe { data_flow_from_immendpoint(self.endpoint) }
1068 }
1069 }
1070
1071 lazy_static! {
1072 static ref ENUMERATOR: Enumerator = {
1073 // COM initialization is thread local, but we only need to have COM initialized in the
1074 // thread we create the objects in
1075 com::com_initialized();
1076
1077 // building the devices enumerator object
1078 unsafe {
1079 let mut enumerator: *mut IMMDeviceEnumerator = ptr::null_mut();
1080
1081 let hresult = CoCreateInstance(
1082 &CLSID_MMDeviceEnumerator,
1083 ptr::null_mut(),
1084 CLSCTX_ALL,
1085 &IMMDeviceEnumerator::uuidof(),
1086 &mut enumerator as *mut *mut IMMDeviceEnumerator as *mut _,
1087 );
1088
1089 check_result(hresult).unwrap();
1090 Enumerator(enumerator)
1091 }
1092 };
1093 }
1094
1095 /// RAII objects around `IMMDeviceEnumerator`.
1096 struct Enumerator(*mut IMMDeviceEnumerator);
1097
1098 unsafe impl Send for Enumerator {}
1099 unsafe impl Sync for Enumerator {}
1100
1101 impl Drop for Enumerator {
1102 #[inline]
drop(&mut self)1103 fn drop(&mut self) {
1104 unsafe {
1105 (*self.0).Release();
1106 }
1107 }
1108 }
1109
1110 /// WASAPI implementation for `Devices`.
1111 pub struct Devices {
1112 collection: *mut IMMDeviceCollection,
1113 total_count: u32,
1114 next_item: u32,
1115 }
1116
1117 impl Devices {
new() -> Result<Self, DevicesError>1118 pub fn new() -> Result<Self, DevicesError> {
1119 unsafe {
1120 let mut collection: *mut IMMDeviceCollection = ptr::null_mut();
1121 // can fail because of wrong parameters (should never happen) or out of memory
1122 check_result_backend_specific((*ENUMERATOR.0).EnumAudioEndpoints(
1123 eAll,
1124 DEVICE_STATE_ACTIVE,
1125 &mut collection,
1126 ))?;
1127
1128 let count = 0u32;
1129 // can fail if the parameter is null, which should never happen
1130 check_result_backend_specific((*collection).GetCount(&count))?;
1131
1132 Ok(Devices {
1133 collection,
1134 total_count: count,
1135 next_item: 0,
1136 })
1137 }
1138 }
1139 }
1140
1141 unsafe impl Send for Devices {}
1142 unsafe impl Sync for Devices {}
1143
1144 impl Drop for Devices {
1145 #[inline]
drop(&mut self)1146 fn drop(&mut self) {
1147 unsafe {
1148 (*self.collection).Release();
1149 }
1150 }
1151 }
1152
1153 impl Iterator for Devices {
1154 type Item = Device;
1155
next(&mut self) -> Option<Device>1156 fn next(&mut self) -> Option<Device> {
1157 if self.next_item >= self.total_count {
1158 return None;
1159 }
1160
1161 unsafe {
1162 let mut device = ptr::null_mut();
1163 // can fail if out of range, which we just checked above
1164 check_result((*self.collection).Item(self.next_item, &mut device)).unwrap();
1165
1166 self.next_item += 1;
1167 Some(Device::from_immdevice(device))
1168 }
1169 }
1170
1171 #[inline]
size_hint(&self) -> (usize, Option<usize>)1172 fn size_hint(&self) -> (usize, Option<usize>) {
1173 let num = self.total_count - self.next_item;
1174 let num = num as usize;
1175 (num, Some(num))
1176 }
1177 }
1178
default_device(data_flow: EDataFlow) -> Option<Device>1179 fn default_device(data_flow: EDataFlow) -> Option<Device> {
1180 unsafe {
1181 let mut device = ptr::null_mut();
1182 let hres = (*ENUMERATOR.0).GetDefaultAudioEndpoint(data_flow, eConsole, &mut device);
1183 if let Err(_err) = check_result(hres) {
1184 return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise
1185 }
1186 Some(Device::from_immdevice(device))
1187 }
1188 }
1189
default_input_device() -> Option<Device>1190 pub fn default_input_device() -> Option<Device> {
1191 default_device(eCapture)
1192 }
1193
default_output_device() -> Option<Device>1194 pub fn default_output_device() -> Option<Device> {
1195 default_device(eRender)
1196 }
1197
1198 /// Get the audio clock used to produce `StreamInstant`s.
get_audio_clock( audio_client: *mut audioclient::IAudioClient, ) -> Result<*mut audioclient::IAudioClock, BuildStreamError>1199 unsafe fn get_audio_clock(
1200 audio_client: *mut audioclient::IAudioClient,
1201 ) -> Result<*mut audioclient::IAudioClock, BuildStreamError> {
1202 let mut audio_clock: *mut audioclient::IAudioClock = ptr::null_mut();
1203 let hresult = (*audio_client).GetService(
1204 &audioclient::IID_IAudioClock,
1205 &mut audio_clock as *mut *mut audioclient::IAudioClock as *mut _,
1206 );
1207 match check_result(hresult) {
1208 Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
1209 return Err(BuildStreamError::DeviceNotAvailable);
1210 }
1211 Err(e) => {
1212 let description = format!("failed to build audio clock: {}", e);
1213 let err = BackendSpecificError { description };
1214 return Err(err.into());
1215 }
1216 Ok(()) => (),
1217 };
1218 Ok(audio_clock)
1219 }
1220
1221 // Turns a `Format` into a `WAVEFORMATEXTENSIBLE`.
1222 //
1223 // Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format.
config_to_waveformatextensible( config: &StreamConfig, sample_format: SampleFormat, ) -> Option<mmreg::WAVEFORMATEXTENSIBLE>1224 fn config_to_waveformatextensible(
1225 config: &StreamConfig,
1226 sample_format: SampleFormat,
1227 ) -> Option<mmreg::WAVEFORMATEXTENSIBLE> {
1228 let format_tag = match sample_format {
1229 SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM,
1230 SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE,
1231 SampleFormat::U16 => return None,
1232 };
1233 let channels = config.channels as WORD;
1234 let sample_rate = config.sample_rate.0 as DWORD;
1235 let sample_bytes = sample_format.sample_size() as WORD;
1236 let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes);
1237 let block_align = channels * sample_bytes;
1238 let bits_per_sample = 8 * sample_bytes;
1239 let cb_size = match sample_format {
1240 SampleFormat::I16 => 0,
1241 SampleFormat::F32 => {
1242 let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>();
1243 let ex_size = mem::size_of::<mmreg::WAVEFORMATEX>();
1244 (extensible_size - ex_size) as WORD
1245 }
1246 SampleFormat::U16 => return None,
1247 };
1248 let waveformatex = mmreg::WAVEFORMATEX {
1249 wFormatTag: format_tag,
1250 nChannels: channels,
1251 nSamplesPerSec: sample_rate,
1252 nAvgBytesPerSec: avg_bytes_per_sec,
1253 nBlockAlign: block_align,
1254 wBitsPerSample: bits_per_sample,
1255 cbSize: cb_size,
1256 };
1257
1258 // CPAL does not care about speaker positions, so pass audio straight through.
1259 // TODO: This constant should be defined in winapi but is missing.
1260 const KSAUDIO_SPEAKER_DIRECTOUT: DWORD = 0;
1261 let channel_mask = KSAUDIO_SPEAKER_DIRECTOUT;
1262
1263 let sub_format = match sample_format {
1264 SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM,
1265 SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1266 SampleFormat::U16 => return None,
1267 };
1268 let waveformatextensible = mmreg::WAVEFORMATEXTENSIBLE {
1269 Format: waveformatex,
1270 Samples: bits_per_sample as WORD,
1271 dwChannelMask: channel_mask,
1272 SubFormat: sub_format,
1273 };
1274
1275 Some(waveformatextensible)
1276 }
1277