• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::convert::TryInto;
6 use std::fmt;
7 use std::fmt::Debug;
8 use std::fmt::Formatter;
9 
10 use base::error;
11 use base::info;
12 use base::warn;
13 use base::Error;
14 use metrics::protos::event_details::RecordDetails;
15 use metrics::protos::event_details::WaveFormat;
16 use metrics::protos::event_details::WaveFormatDetails;
17 use metrics::protos::event_details::WaveFormat_WaveFormatSubFormat;
18 use metrics::MetricEventType;
19 use winapi::shared::guiddef::IsEqualGUID;
20 use winapi::shared::guiddef::GUID;
21 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_ADPCM;
22 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_ALAW;
23 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_ANALOG;
24 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_DRM;
25 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
26 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_MPEG;
27 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_MULAW;
28 use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_PCM;
29 use winapi::shared::mmreg::SPEAKER_FRONT_CENTER;
30 use winapi::shared::mmreg::SPEAKER_FRONT_LEFT;
31 use winapi::shared::mmreg::SPEAKER_FRONT_RIGHT;
32 use winapi::shared::mmreg::WAVEFORMATEX;
33 use winapi::shared::mmreg::WAVEFORMATEXTENSIBLE;
34 use winapi::shared::mmreg::WAVE_FORMAT_EXTENSIBLE;
35 use winapi::shared::mmreg::WAVE_FORMAT_IEEE_FLOAT;
36 use winapi::shared::winerror::S_FALSE;
37 use winapi::shared::winerror::S_OK;
38 use winapi::um::audioclient::IAudioClient;
39 use winapi::um::audiosessiontypes::AUDCLNT_SHAREMODE_SHARED;
40 #[cfg(not(test))]
41 use winapi::um::combaseapi::CoTaskMemFree;
42 use wio::com::ComPtr;
43 
44 use crate::AudioSharedFormat;
45 use crate::RenderError;
46 use crate::MONO_CHANNEL_COUNT;
47 use crate::STEREO_CHANNEL_COUNT;
48 
49 pub type WaveFormatDetailsProto = WaveFormatDetails;
50 pub type WaveFormatProto = WaveFormat;
51 pub type SubFormatProto = WaveFormat_WaveFormatSubFormat;
52 
53 /// Wrapper around `WAVEFORMATEX` and `WAVEFORMATEXTENSIBLE` to hide some of the unsafe calls
54 /// that could be made.
55 pub enum WaveAudioFormat {
56     /// Format where channels are capped at 2.
57     WaveFormat(WAVEFORMATEX),
58     /// Format where channels can be >2. (It can still have <=2 channels)
59     WaveFormatExtensible(WAVEFORMATEXTENSIBLE),
60 }
61 
62 impl WaveAudioFormat {
63     /// Wraps a WAVEFORMATEX pointer to make it's use more safe.
64     ///
65     /// # Safety
66     /// Unsafe if `wave_format_ptr` is pointing to null. This function will assume it's not null
67     /// and dereference it.
68     /// Also `format_ptr` will be deallocated after this function completes, so it cannot be used.
69     #[allow(clippy::let_and_return)]
new(format_ptr: *mut WAVEFORMATEX) -> Self70     pub unsafe fn new(format_ptr: *mut WAVEFORMATEX) -> Self {
71         let format_tag = { (*format_ptr).wFormatTag };
72         let result = if format_tag != WAVE_FORMAT_EXTENSIBLE {
73             warn!(
74                 "Default Mix Format does not have format_tag WAVE_FORMAT_EXTENSIBLE. It is: {}",
75                 format_tag
76             );
77             WaveAudioFormat::WaveFormat(*format_ptr)
78         } else {
79             WaveAudioFormat::WaveFormatExtensible(*(format_ptr as *const WAVEFORMATEXTENSIBLE))
80         };
81 
82         // WAVEFORMATEX and WAVEFORMATEXTENSIBLE both implement the Copy trait, so they have been
83         // copied to the WaveAudioFormat enum. Therefore, it is safe to free the memory
84         // `format_ptr` is pointing to.
85         // In a test, WAVEFORMATEX is initiated by us, not by Windows, so calling this function
86         // could cause a STATUS_HEAP_CORRUPTION exception.
87         #[cfg(not(test))]
88         CoTaskMemFree(format_ptr as *mut std::ffi::c_void);
89 
90         result
91     }
92 
get_num_channels(&self) -> u1693     pub fn get_num_channels(&self) -> u16 {
94         match self {
95             WaveAudioFormat::WaveFormat(wave_format) => wave_format.nChannels,
96             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
97                 wave_format_extensible.Format.nChannels
98             }
99         }
100     }
101 
102     // Modifies `WAVEFORMATEXTENSIBLE` to have the values passed into the function params.
103     // Currently it should only modify the bit_depth if it's != 32 and the data format if it's not
104     // float.
modify_mix_format(&mut self, target_bit_depth: usize, ks_data_format: GUID)105     pub fn modify_mix_format(&mut self, target_bit_depth: usize, ks_data_format: GUID) {
106         let default_num_channels = self.get_num_channels();
107 
108         fn calc_avg_bytes_per_sec(num_channels: u16, bit_depth: u16, samples_per_sec: u32) -> u32 {
109             num_channels as u32 * (bit_depth as u32 / 8) * samples_per_sec
110         }
111 
112         fn calc_block_align(num_channels: u16, bit_depth: u16) -> u16 {
113             (bit_depth / 8) * num_channels
114         }
115 
116         match self {
117             WaveAudioFormat::WaveFormat(wave_format) => {
118                 if default_num_channels > STEREO_CHANNEL_COUNT {
119                     warn!("WAVEFORMATEX shouldn't have >2 channels.");
120                 }
121 
122                 // Force the format to be the only supported format (32 bit float)
123                 if wave_format.wBitsPerSample != target_bit_depth as u16
124                     || wave_format.wFormatTag != WAVE_FORMAT_IEEE_FLOAT
125                 {
126                     wave_format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
127                     wave_format.nChannels =
128                         std::cmp::min(STEREO_CHANNEL_COUNT as u16, default_num_channels);
129                     wave_format.wBitsPerSample = target_bit_depth as u16;
130                     wave_format.nAvgBytesPerSec = calc_avg_bytes_per_sec(
131                         wave_format.nChannels,
132                         wave_format.wBitsPerSample,
133                         wave_format.nSamplesPerSec,
134                     );
135                     wave_format.nBlockAlign =
136                         calc_block_align(wave_format.nChannels, wave_format.wBitsPerSample);
137                 }
138             }
139             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
140                 // WAVE_FORMAT_EXTENSIBLE uses the #[repr(packed)] flag so the compiler might
141                 // unalign the fields. Thus, the fields will be copied to a local variable to
142                 // prevent segfaults. For more information:
143                 // https://github.com/rust-lang/rust/issues/46043
144                 let sub_format = wave_format_extensible.SubFormat;
145 
146                 if wave_format_extensible.Format.wBitsPerSample != target_bit_depth as u16
147                     || !IsEqualGUID(&sub_format, &ks_data_format)
148                 {
149                     // wFormatTag won't be changed
150                     wave_format_extensible.Format.nChannels = default_num_channels;
151                     wave_format_extensible.Format.wBitsPerSample = target_bit_depth as u16;
152                     // nSamplesPerSec should stay the same
153                     // Calculated with a bit depth of 32bits
154                     wave_format_extensible.Format.nAvgBytesPerSec = calc_avg_bytes_per_sec(
155                         wave_format_extensible.Format.nChannels,
156                         wave_format_extensible.Format.wBitsPerSample,
157                         wave_format_extensible.Format.nSamplesPerSec,
158                     );
159                     wave_format_extensible.Format.nBlockAlign = calc_block_align(
160                         wave_format_extensible.Format.nChannels,
161                         wave_format_extensible.Format.wBitsPerSample,
162                     );
163                     // 22 is the size typically used when the format tag is WAVE_FORMAT_EXTENSIBLE.
164                     // Since the `Initialize` syscall takes in a WAVEFORMATEX, this tells Windows
165                     // how many bytes are left after the `Format` field
166                     // (ie. Samples, dwChannelMask, SubFormat) so that it can cast to
167                     // WAVEFORMATEXTENSIBLE safely.
168                     wave_format_extensible.Format.cbSize = 22;
169                     wave_format_extensible.Samples = target_bit_depth as u16;
170                     let n_channels = wave_format_extensible.Format.nChannels;
171                     // The channel masks are defined here:
172                     // https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible#remarks
173                     wave_format_extensible.dwChannelMask = match n_channels {
174                         STEREO_CHANNEL_COUNT => SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
175                         MONO_CHANNEL_COUNT => SPEAKER_FRONT_CENTER,
176                         _ => {
177                             // Don't change channel mask if it's >2 channels.
178                             wave_format_extensible.dwChannelMask
179                         }
180                     };
181                     wave_format_extensible.SubFormat = ks_data_format;
182                 }
183             }
184         }
185     }
186 
as_ptr(&self) -> *const WAVEFORMATEX187     pub fn as_ptr(&self) -> *const WAVEFORMATEX {
188         match self {
189             WaveAudioFormat::WaveFormat(wave_format) => wave_format as *const WAVEFORMATEX,
190             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
191                 wave_format_extensible as *const _ as *const WAVEFORMATEX
192             }
193         }
194     }
195 
get_shared_audio_engine_period_in_frames( &self, shared_default_size_in_100nanoseconds: f64, ) -> usize196     pub fn get_shared_audio_engine_period_in_frames(
197         &self,
198         shared_default_size_in_100nanoseconds: f64,
199     ) -> usize {
200         // a 100 nanosecond unit is 1 * 10^-7 seconds
201         //
202         // To convert a 100nanoseconds value to # of frames in a period, we multiple by the
203         // frame rate (nSamplesPerSec. Sample rate == Frame rate) and then divide by 10000000
204         // in order to convert 100nanoseconds to seconds.
205         let samples_per_sec = match self {
206             WaveAudioFormat::WaveFormat(wave_format) => wave_format.nSamplesPerSec,
207             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
208                 wave_format_extensible.Format.nSamplesPerSec
209             }
210         };
211 
212         ((samples_per_sec as f64 * shared_default_size_in_100nanoseconds as f64) / 10000000.0)
213             .ceil() as usize
214     }
215 
create_audio_shared_format( &self, shared_audio_engine_period_in_frames: usize, ) -> AudioSharedFormat216     pub fn create_audio_shared_format(
217         &self,
218         shared_audio_engine_period_in_frames: usize,
219     ) -> AudioSharedFormat {
220         match self {
221             WaveAudioFormat::WaveFormat(wave_format) => AudioSharedFormat {
222                 bit_depth: wave_format.wBitsPerSample as usize,
223                 frame_rate: wave_format.nSamplesPerSec as usize,
224                 shared_audio_engine_period_in_frames,
225                 channels: wave_format.nChannels as usize,
226                 channel_mask: None,
227             },
228             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => AudioSharedFormat {
229                 bit_depth: wave_format_extensible.Format.wBitsPerSample as usize,
230                 frame_rate: wave_format_extensible.Format.nSamplesPerSec as usize,
231                 shared_audio_engine_period_in_frames,
232                 channels: wave_format_extensible.Format.nChannels as usize,
233                 channel_mask: Some(wave_format_extensible.dwChannelMask),
234             },
235         }
236     }
237 
238     #[cfg(test)]
take_waveformatex(self) -> WAVEFORMATEX239     fn take_waveformatex(self) -> WAVEFORMATEX {
240         match self {
241             WaveAudioFormat::WaveFormat(wave_format) => wave_format,
242             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
243                 // Safe because `wave_format_extensible` can't be a null pointer, otherwise the
244                 // constructor would've failed. This will also give the caller ownership of this
245                 // struct.
246                 unsafe { *(&wave_format_extensible as *const _ as *const WAVEFORMATEX) }
247             }
248         }
249     }
250 
251     #[cfg(test)]
take_waveformatextensible(self) -> WAVEFORMATEXTENSIBLE252     fn take_waveformatextensible(self) -> WAVEFORMATEXTENSIBLE {
253         match self {
254             WaveAudioFormat::WaveFormat(_wave_format) => {
255                 panic!("Format is WAVEFORMATEX. Can't convert to WAVEFORMATEXTENSBILE.")
256             }
257             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => wave_format_extensible,
258         }
259     }
260 }
261 
262 impl Debug for WaveAudioFormat {
fmt(&self, f: &mut Formatter) -> fmt::Result263     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
264         let res = match self {
265             WaveAudioFormat::WaveFormat(wave_format) => {
266                 format!(
267                     "wFormatTag: {}, \nnChannels: {}, \nnSamplesPerSec: {}, \nnAvgBytesPerSec: \
268                     {}, \nnBlockAlign: {}, \nwBitsPerSample: {}, \ncbSize: {}",
269                     { wave_format.wFormatTag },
270                     { wave_format.nChannels },
271                     { wave_format.nSamplesPerSec },
272                     { wave_format.nAvgBytesPerSec },
273                     { wave_format.nBlockAlign },
274                     { wave_format.wBitsPerSample },
275                     { wave_format.cbSize },
276                 )
277             }
278             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
279                 let audio_engine_format = format!(
280                     "wFormatTag: {}, \nnChannels: {}, \nnSamplesPerSec: {}, \nnAvgBytesPerSec: \
281                     {}, \nnBlockAlign: {}, \nwBitsPerSample: {}, \ncbSize: {}",
282                     { wave_format_extensible.Format.wFormatTag },
283                     { wave_format_extensible.Format.nChannels },
284                     { wave_format_extensible.Format.nSamplesPerSec },
285                     { wave_format_extensible.Format.nAvgBytesPerSec },
286                     { wave_format_extensible.Format.nBlockAlign },
287                     { wave_format_extensible.Format.wBitsPerSample },
288                     { wave_format_extensible.Format.cbSize },
289                 );
290 
291                 let subformat = wave_format_extensible.SubFormat;
292 
293                 // TODO(b/240186720): Passing in `KSDATAFORMAT_SUBTYPE_PCM` will cause a
294                 // freeze. IsEqualGUID is unsafe even though it isn't marked as such. Look into
295                 // fixing or possibily write our own, that works.
296                 //
297                 // This check would be a nice to have, but not necessary. Right now, the subformat
298                 // used will always be `IEEE_FLOAT`, so this check will be useless if nothing
299                 // changes.
300                 //
301                 // if !IsEqualGUID(
302                 //     &{ wave_format_extensible.SubFormat },
303                 //     &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
304                 // ) {
305                 //     warn!("Audio Engine format is NOT IEEE FLOAT");
306                 // }
307 
308                 let audio_engine_extensible_format = format!(
309                     "\nSamples: {}, \ndwChannelMask: {}, \nSubFormat: {}-{}-{}-{:?}",
310                     { wave_format_extensible.Samples },
311                     { wave_format_extensible.dwChannelMask },
312                     subformat.Data1,
313                     subformat.Data2,
314                     subformat.Data3,
315                     subformat.Data4,
316                 );
317 
318                 format!("{}{}", audio_engine_format, audio_engine_extensible_format)
319             }
320         };
321         write!(f, "{}", res)
322     }
323 }
324 
325 #[cfg(test)]
326 impl PartialEq for WaveAudioFormat {
eq(&self, other: &Self) -> bool327     fn eq(&self, other: &Self) -> bool {
328         if std::mem::discriminant(self) != std::mem::discriminant(other) {
329             return false;
330         }
331 
332         fn are_formats_same(
333             wave_format_pointer: *const u8,
334             other_format_pointer: *const u8,
335             cb_size: usize,
336         ) -> bool {
337             let wave_format_bytes: &[u8] = unsafe {
338                 std::slice::from_raw_parts(
339                     wave_format_pointer,
340                     std::mem::size_of::<WAVEFORMATEX>() + cb_size,
341                 )
342             };
343             let other_bytes: &[u8] = unsafe {
344                 std::slice::from_raw_parts(
345                     other_format_pointer,
346                     std::mem::size_of::<WAVEFORMATEX>() + cb_size,
347                 )
348             };
349 
350             !wave_format_bytes
351                 .iter()
352                 .zip(other_bytes)
353                 .map(|(x, y)| x.cmp(y))
354                 .any(|ord| ord != std::cmp::Ordering::Equal)
355         }
356 
357         match self {
358             WaveAudioFormat::WaveFormat(wave_format) => match other {
359                 WaveAudioFormat::WaveFormat(other_wave_format) => {
360                     if wave_format.cbSize != other_wave_format.cbSize {
361                         return false;
362                     }
363                     are_formats_same(
364                         wave_format as *const _ as *const u8,
365                         other_wave_format as *const _ as *const u8,
366                         wave_format.cbSize as usize,
367                     )
368                 }
369                 WaveAudioFormat::WaveFormatExtensible(_) => unreachable!(),
370             },
371             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => match other {
372                 WaveAudioFormat::WaveFormatExtensible(other_wave_format_extensible) => {
373                     if wave_format_extensible.Format.cbSize
374                         != other_wave_format_extensible.Format.cbSize
375                     {
376                         return false;
377                     }
378                     are_formats_same(
379                         wave_format_extensible as *const _ as *const u8,
380                         other_wave_format_extensible as *const _ as *const u8,
381                         wave_format_extensible.Format.cbSize as usize,
382                     )
383                 }
384                 WaveAudioFormat::WaveFormat(_) => unreachable!(),
385             },
386         }
387     }
388 }
389 
390 impl From<&WaveAudioFormat> for WaveFormatProto {
from(format: &WaveAudioFormat) -> WaveFormatProto391     fn from(format: &WaveAudioFormat) -> WaveFormatProto {
392         let mut wave_format_proto = WaveFormatProto::new();
393 
394         match format {
395             WaveAudioFormat::WaveFormat(wave_format) => {
396                 wave_format_proto.set_format_tag(wave_format.wFormatTag.into());
397                 wave_format_proto.set_channels(wave_format.nChannels.into());
398                 wave_format_proto.set_samples_per_sec(
399                     wave_format
400                         .nSamplesPerSec
401                         .try_into()
402                         .expect("Failed to cast nSamplesPerSec to i32"),
403                 );
404                 wave_format_proto.set_avg_bytes_per_sec(
405                     wave_format
406                         .nAvgBytesPerSec
407                         .try_into()
408                         .expect("Failed to cast nAvgBytesPerSec"),
409                 );
410                 wave_format_proto.set_block_align(wave_format.nBlockAlign.into());
411                 wave_format_proto.set_bits_per_sample(wave_format.wBitsPerSample.into());
412                 wave_format_proto.set_size_bytes(wave_format.cbSize.into());
413             }
414             WaveAudioFormat::WaveFormatExtensible(wave_format_extensible) => {
415                 wave_format_proto.set_format_tag(wave_format_extensible.Format.wFormatTag.into());
416                 wave_format_proto.set_channels(wave_format_extensible.Format.nChannels.into());
417                 wave_format_proto.set_samples_per_sec(
418                     wave_format_extensible
419                         .Format
420                         .nSamplesPerSec
421                         .try_into()
422                         .expect("Failed to cast nSamplesPerSec to i32"),
423                 );
424                 wave_format_proto.set_avg_bytes_per_sec(
425                     wave_format_extensible
426                         .Format
427                         .nAvgBytesPerSec
428                         .try_into()
429                         .expect("Failed to cast nAvgBytesPerSec"),
430                 );
431                 wave_format_proto.set_block_align(wave_format_extensible.Format.nBlockAlign.into());
432                 wave_format_proto
433                     .set_bits_per_sample(wave_format_extensible.Format.wBitsPerSample.into());
434                 wave_format_proto.set_size_bytes(wave_format_extensible.Format.cbSize.into());
435                 wave_format_proto.set_samples(wave_format_extensible.Samples.into());
436                 wave_format_proto.set_channel_mask(wave_format_extensible.dwChannelMask.into());
437                 let sub_format = wave_format_extensible.SubFormat;
438                 wave_format_proto.set_sub_format(GuidWrapper(&sub_format).into());
439             }
440         }
441 
442         wave_format_proto
443     }
444 }
445 
446 /// Get an audio format that will be accepted by the audio client. In terms of bit depth, the goal
447 /// is to always get a 32bit float format.
get_valid_mix_format( audio_client: &ComPtr<IAudioClient>, ) -> Result<WaveAudioFormat, RenderError>448 pub(crate) fn get_valid_mix_format(
449     audio_client: &ComPtr<IAudioClient>,
450 ) -> Result<WaveAudioFormat, RenderError> {
451     // Safe because `format_ptr` is owned by this unsafe block. `format_ptr` is guarenteed to
452     // be not null by the time it reached `WaveAudioFormat::new` (check_hresult! should make
453     // sure of that), which is also release the pointer passed in.
454     let mut format = unsafe {
455         let mut format_ptr: *mut WAVEFORMATEX = std::ptr::null_mut();
456         let hr = audio_client.GetMixFormat(&mut format_ptr);
457         check_hresult!(
458             hr,
459             RenderError::from(hr),
460             "Failed to retrieve audio engine's shared format"
461         )?;
462 
463         WaveAudioFormat::new(format_ptr)
464     };
465 
466     let mut wave_format_details = WaveFormatDetailsProto::new();
467     let mut event_code = MetricEventType::AudioFormatRequestOk;
468     wave_format_details.set_requested(WaveFormatProto::from(&format));
469 
470     info!("Printing mix format from `GetMixFormat`:\n{:?}", format);
471     const BIT_DEPTH: usize = 32;
472     format.modify_mix_format(BIT_DEPTH, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
473 
474     let modified_wave_format = WaveFormatProto::from(&format);
475     if &modified_wave_format != wave_format_details.get_requested() {
476         wave_format_details.set_modified(modified_wave_format);
477         event_code = MetricEventType::AudioFormatModifiedOk;
478     }
479 
480     info!("Audio Engine Mix Format Used: \n{:?}", format);
481     check_format(audio_client, &format, wave_format_details, event_code)?;
482 
483     Ok(format)
484 }
485 
486 /// Checks to see if `format` is accepted by the audio client.
487 ///
488 /// Exposed as crate public for testing.
check_format( audio_client: &IAudioClient, format: &WaveAudioFormat, mut wave_format_details: WaveFormatDetailsProto, event_code: MetricEventType, ) -> Result<(), RenderError>489 pub(crate) fn check_format(
490     audio_client: &IAudioClient,
491     format: &WaveAudioFormat,
492     mut wave_format_details: WaveFormatDetailsProto,
493     event_code: MetricEventType,
494 ) -> Result<(), RenderError> {
495     let mut closest_match_format: *mut WAVEFORMATEX = std::ptr::null_mut();
496     // Safe because all values passed into `IsFormatSupport` is owned by us and we will
497     // guarentee they won't be dropped and are valid.
498     let hr = unsafe {
499         audio_client.IsFormatSupported(
500             AUDCLNT_SHAREMODE_SHARED,
501             format.as_ptr(),
502             &mut closest_match_format,
503         )
504     };
505 
506     // If the audio engine does not support the format.
507     if hr != S_OK {
508         if hr == S_FALSE {
509             // Safe because if the `hr` value is `S_FALSE`, then `IsFormatSupported` must've
510             // given us a closest match.
511             let closest_match_enum = unsafe { WaveAudioFormat::new(closest_match_format) };
512             wave_format_details.set_closest_matched(WaveFormatProto::from(&closest_match_enum));
513 
514             error!(
515                 "Current audio format not supported, the closest format is:\n{:?}",
516                 closest_match_enum
517             );
518         } else {
519             error!("IsFormatSupported failed with hr: {}", hr);
520         }
521 
522         // Get last error here just incase `upload_metrics` causes an error.
523         let last_error = Error::last();
524         // TODO:(b/253509368): Only upload for audio rendering, since these metrics can't
525         // differentiate between rendering and capture.
526         upload_metrics(wave_format_details, MetricEventType::AudioFormatFailed);
527 
528         Err(RenderError::WindowsError(hr, last_error))
529     } else {
530         upload_metrics(wave_format_details, event_code);
531 
532         Ok(())
533     }
534 }
535 
upload_metrics( wave_format_details: WaveFormatDetailsProto, metrics_event_code: MetricEventType, )536 fn upload_metrics(
537     wave_format_details: WaveFormatDetailsProto,
538     metrics_event_code: MetricEventType,
539 ) {
540     let mut details = RecordDetails::new();
541     details.set_wave_format_details(wave_format_details);
542     metrics::log_event_with_details(metrics_event_code, &details);
543 }
544 
545 struct GuidWrapper<'a>(&'a GUID);
546 
547 impl<'a> From<GuidWrapper<'a>> for SubFormatProto {
from(guid: GuidWrapper) -> SubFormatProto548     fn from(guid: GuidWrapper) -> SubFormatProto {
549         let guid = guid.0;
550         if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_ANALOG) {
551             SubFormatProto::KSDATAFORMAT_SUBTYPE_ANALOG
552         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_PCM) {
553             SubFormatProto::KSDATAFORMAT_SUBTYPE_PCM
554         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
555             SubFormatProto::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
556         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_DRM) {
557             SubFormatProto::KSDATAFORMAT_SUBTYPE_DRM
558         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_ALAW) {
559             SubFormatProto::KSDATAFORMAT_SUBTYPE_ALAW
560         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_MULAW) {
561             SubFormatProto::KSDATAFORMAT_SUBTYPE_MULAW
562         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_ADPCM) {
563             SubFormatProto::KSDATAFORMAT_SUBTYPE_ADPCM
564         } else if IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_MPEG) {
565             SubFormatProto::KSDATAFORMAT_SUBTYPE_MPEG
566         } else {
567             SubFormatProto::KSDATAFORMAT_SUBTYPE_INVALID
568         }
569     }
570 }
571 
572 #[cfg(test)]
573 mod tests {
574     use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_PCM;
575     use winapi::shared::mmreg::SPEAKER_BACK_LEFT;
576     use winapi::shared::mmreg::SPEAKER_BACK_RIGHT;
577     use winapi::shared::mmreg::SPEAKER_LOW_FREQUENCY;
578     use winapi::shared::mmreg::SPEAKER_SIDE_LEFT;
579     use winapi::shared::mmreg::SPEAKER_SIDE_RIGHT;
580     use winapi::shared::mmreg::WAVE_FORMAT_PCM;
581 
582     use super::*;
583 
584     #[test]
test_modify_mix_format()585     fn test_modify_mix_format() {
586         // A typical 7.1 surround sound channel mask.
587         const channel_mask_7_1: u32 = SPEAKER_FRONT_LEFT
588             | SPEAKER_FRONT_RIGHT
589             | SPEAKER_FRONT_CENTER
590             | SPEAKER_LOW_FREQUENCY
591             | SPEAKER_BACK_LEFT
592             | SPEAKER_BACK_RIGHT
593             | SPEAKER_SIDE_LEFT
594             | SPEAKER_SIDE_RIGHT;
595 
596         let surround_sound_format = WAVEFORMATEXTENSIBLE {
597             Format: WAVEFORMATEX {
598                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
599                 nChannels: 8,
600                 nSamplesPerSec: 44100,
601                 nAvgBytesPerSec: 1411200,
602                 nBlockAlign: 32,
603                 wBitsPerSample: 32,
604                 cbSize: 22,
605             },
606             Samples: 32,
607             dwChannelMask: channel_mask_7_1,
608             SubFormat: KSDATAFORMAT_SUBTYPE_PCM,
609         };
610 
611         // Safe because `GetMixFormat` casts `WAVEFORMATEXTENSIBLE` into a `WAVEFORMATEX` like so.
612         // Also this is casting from a bigger to a smaller struct, so it shouldn't be possible for
613         // this contructor to access memory it shouldn't.
614         let mut format = unsafe {
615             WaveAudioFormat::new((&surround_sound_format) as *const _ as *mut WAVEFORMATEX)
616         };
617 
618         format.modify_mix_format(
619             /* bit_depth= */ 32,
620             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
621         );
622 
623         // Safe because we know the format is originally a `WAVEFORMATEXTENSIBLE`.
624         let surround_sound_format = format.take_waveformatextensible();
625 
626         // WAVE_FORMAT_EXTENSIBLE uses the #[repr(packed)] flag so the compiler might unalign
627         // the fields. Thus, the fields will be copied to a local variable to prevent segfaults.
628         // For more information: https://github.com/rust-lang/rust/issues/46043
629         let format_tag = surround_sound_format.Format.wFormatTag;
630         // We expect `SubFormat` to be IEEE float instead of PCM.
631         // Everything else should remain the same.
632         assert_eq!(format_tag, WAVE_FORMAT_EXTENSIBLE);
633         let channels = surround_sound_format.Format.nChannels;
634         assert_eq!(channels, 8);
635         let samples_per_sec = surround_sound_format.Format.nSamplesPerSec;
636         assert_eq!(samples_per_sec, 44100);
637         let avg_bytes_per_sec = surround_sound_format.Format.nAvgBytesPerSec;
638         assert_eq!(avg_bytes_per_sec, 1411200);
639         let block_align = surround_sound_format.Format.nBlockAlign;
640         assert_eq!(block_align, 32);
641         let bits_per_samples = surround_sound_format.Format.wBitsPerSample;
642         assert_eq!(bits_per_samples, 32);
643         let size = surround_sound_format.Format.cbSize;
644         assert_eq!(size, 22);
645         let samples = surround_sound_format.Samples;
646         assert_eq!(samples, 32);
647         let channel_mask = surround_sound_format.dwChannelMask;
648         assert_eq!(channel_mask, channel_mask_7_1);
649         let sub_format = surround_sound_format.SubFormat;
650         assert!(IsEqualGUID(&sub_format, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT));
651     }
652 
653     #[test]
test_waveformatex_ieee_modify_same_format()654     fn test_waveformatex_ieee_modify_same_format() {
655         let format = WAVEFORMATEX {
656             wFormatTag: WAVE_FORMAT_IEEE_FLOAT,
657             nChannels: 2,
658             nSamplesPerSec: 48000,
659             nAvgBytesPerSec: 384000,
660             nBlockAlign: 8,
661             wBitsPerSample: 32,
662             cbSize: 0,
663         };
664 
665         // Safe because we can convert a struct to a pointer declared above. Also that means the
666         // pointer can be safely deferenced.
667         let mut format =
668             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
669 
670         format.modify_mix_format(
671             /* bit_depth= */ 32,
672             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
673         );
674 
675         let result_format = format.take_waveformatex();
676 
677         assert_waveformatex_ieee(&result_format);
678     }
679 
680     #[test]
test_waveformatex_ieee_modify_different_format()681     fn test_waveformatex_ieee_modify_different_format() {
682         // I don't expect this format to show up ever, but it's possible so it's good to test.
683         let format = WAVEFORMATEX {
684             wFormatTag: WAVE_FORMAT_IEEE_FLOAT,
685             nChannels: 2,
686             nSamplesPerSec: 48000,
687             nAvgBytesPerSec: 192000,
688             nBlockAlign: 4,
689             wBitsPerSample: 16,
690             cbSize: 0,
691         };
692 
693         // Safe because we can convert a struct to a pointer declared above. Also that means the
694         // pointer can be safely deferenced.
695         let mut format =
696             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
697 
698         format.modify_mix_format(
699             /* bit_depth= */ 32,
700             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
701         );
702 
703         let result_format = format.take_waveformatex();
704 
705         assert_waveformatex_ieee(&result_format);
706     }
707 
708     #[test]
test_format_comparison_waveformatex_pass()709     fn test_format_comparison_waveformatex_pass() {
710         let format = WAVEFORMATEX {
711             wFormatTag: WAVE_FORMAT_PCM,
712             nChannels: 1,
713             nSamplesPerSec: 48000,
714             nAvgBytesPerSec: 4 * 48000,
715             nBlockAlign: 4,
716             wBitsPerSample: 16,
717             cbSize: 0,
718         };
719 
720         // Safe because we can convert a struct to a pointer declared above. Also that means the
721         // pointer can be safely deferenced.
722         let format =
723             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
724 
725         let expected = WAVEFORMATEX {
726             wFormatTag: WAVE_FORMAT_PCM,
727             nChannels: 1,
728             nSamplesPerSec: 48000,
729             nAvgBytesPerSec: 4 * 48000,
730             nBlockAlign: 4,
731             wBitsPerSample: 16,
732             cbSize: 0,
733         };
734 
735         let expected = unsafe {
736             WaveAudioFormat::new((&expected) as *const WAVEFORMATEX as *mut WAVEFORMATEX)
737         };
738 
739         assert_eq!(expected, format);
740     }
741 
742     #[test]
test_format_comparison_waveformatextensible_pass()743     fn test_format_comparison_waveformatextensible_pass() {
744         let format = WAVEFORMATEXTENSIBLE {
745             Format: WAVEFORMATEX {
746                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
747                 nChannels: 1,
748                 nSamplesPerSec: 48000,
749                 nAvgBytesPerSec: 4 * 48000,
750                 nBlockAlign: 4,
751                 wBitsPerSample: 16,
752                 cbSize: 22,
753             },
754             Samples: 16,
755             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
756             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
757         };
758 
759         // Safe because we can convert a struct to a pointer declared above. Also that means the
760         // pointer can be safely deferenced.
761         let format = unsafe {
762             WaveAudioFormat::new((&format) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
763         };
764 
765         let expected = WAVEFORMATEXTENSIBLE {
766             Format: WAVEFORMATEX {
767                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
768                 nChannels: 1,
769                 nSamplesPerSec: 48000,
770                 nAvgBytesPerSec: 4 * 48000,
771                 nBlockAlign: 4,
772                 wBitsPerSample: 16,
773                 cbSize: 22,
774             },
775             Samples: 16,
776             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
777             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
778         };
779 
780         let expected = unsafe {
781             WaveAudioFormat::new((&expected) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
782         };
783 
784         assert_eq!(expected, format);
785     }
786 
787     #[test]
test_format_comparison_waveformatex_fail()788     fn test_format_comparison_waveformatex_fail() {
789         let format = WAVEFORMATEX {
790             wFormatTag: WAVE_FORMAT_PCM,
791             nChannels: 1,
792             nSamplesPerSec: 48000,
793             nAvgBytesPerSec: 4 * 48000,
794             nBlockAlign: 4,
795             wBitsPerSample: 16,
796             cbSize: 0,
797         };
798 
799         // Safe because we can convert a struct to a pointer declared above. Also that means the
800         // pointer can be safely deferenced.
801         let format =
802             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
803 
804         let expected = WAVEFORMATEX {
805             wFormatTag: WAVE_FORMAT_PCM,
806             // The field below is the difference
807             nChannels: 6,
808             nSamplesPerSec: 48000,
809             nAvgBytesPerSec: 4 * 48000,
810             nBlockAlign: 4,
811             wBitsPerSample: 16,
812             cbSize: 0,
813         };
814 
815         let expected = unsafe {
816             WaveAudioFormat::new((&expected) as *const WAVEFORMATEX as *mut WAVEFORMATEX)
817         };
818 
819         assert_ne!(expected, format);
820     }
821 
822     #[test]
test_format_comparison_waveformatextensible_fail()823     fn test_format_comparison_waveformatextensible_fail() {
824         let format = WAVEFORMATEXTENSIBLE {
825             Format: WAVEFORMATEX {
826                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
827                 nChannels: 1,
828                 nSamplesPerSec: 48000,
829                 nAvgBytesPerSec: 4 * 48000,
830                 nBlockAlign: 4,
831                 wBitsPerSample: 16,
832                 cbSize: 22,
833             },
834             Samples: 16,
835             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
836             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
837         };
838 
839         // Safe because we can convert a struct to a pointer declared above. Also that means the
840         // pointer can be safely deferenced.
841         let format = unsafe {
842             WaveAudioFormat::new((&format) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
843         };
844 
845         let expected = WAVEFORMATEXTENSIBLE {
846             Format: WAVEFORMATEX {
847                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
848                 nChannels: 1,
849                 nSamplesPerSec: 48000,
850                 nAvgBytesPerSec: 4 * 48000,
851                 nBlockAlign: 4,
852                 wBitsPerSample: 16,
853                 cbSize: 22,
854             },
855             Samples: 16,
856             // The field below is the difference.
857             dwChannelMask: SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT,
858             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
859         };
860 
861         let expected = unsafe {
862             WaveAudioFormat::new((&expected) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
863         };
864 
865         assert_ne!(expected, format);
866     }
867 
868     #[test]
test_modify_mix_mono_channel_different_bit_depth_wave_format_extensible()869     fn test_modify_mix_mono_channel_different_bit_depth_wave_format_extensible() {
870         // Start with a mono channel and 16 bit depth format.
871         let format = WAVEFORMATEXTENSIBLE {
872             Format: WAVEFORMATEX {
873                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
874                 nChannels: 1,
875                 nSamplesPerSec: 48000,
876                 nAvgBytesPerSec: 2 * 48000,
877                 nBlockAlign: 2,
878                 wBitsPerSample: 16,
879                 cbSize: 22,
880             },
881             Samples: 16,
882             // Probably will never see a mask like this for two channels, but this is just testing
883             // that it will get changed.
884             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
885             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
886         };
887 
888         // Safe because we can convert a struct to a pointer declared above. Also that means the
889         // pointer can be safely deferenced.
890         let mut format = unsafe {
891             WaveAudioFormat::new((&format) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
892         };
893 
894         format.modify_mix_format(
895             /* bit_depth= */ 32,
896             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
897         );
898 
899         // The format should be converted to 32 bit depth and retain mono channel.
900         let expected = WAVEFORMATEXTENSIBLE {
901             Format: WAVEFORMATEX {
902                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
903                 nChannels: 1,
904                 nSamplesPerSec: 48000,
905                 nAvgBytesPerSec: 4 * 48000, // Changed
906                 nBlockAlign: 4,             // Changed
907                 wBitsPerSample: 32,         // Changed
908                 cbSize: 22,
909             },
910             Samples: 32,
911             dwChannelMask: SPEAKER_FRONT_CENTER, // Changed
912             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
913         };
914 
915         let expected = unsafe {
916             WaveAudioFormat::new((&expected) as *const WAVEFORMATEXTENSIBLE as *mut WAVEFORMATEX)
917         };
918 
919         assert_eq!(format, expected);
920     }
921 
922     #[test]
test_modify_mix_mono_channel_different_bit_depth_wave_format()923     fn test_modify_mix_mono_channel_different_bit_depth_wave_format() {
924         // Start with a mono channel and 16 bit depth format.
925         let format = WAVEFORMATEX {
926             wFormatTag: WAVE_FORMAT_PCM,
927             nChannels: 1,
928             nSamplesPerSec: 48000,
929             nAvgBytesPerSec: 2 * 48000,
930             nBlockAlign: 2,
931             wBitsPerSample: 16,
932             cbSize: 0,
933         };
934 
935         // Safe because we can convert a struct to a pointer declared above. Also that means the
936         // pointer can be safely deferenced.
937         let mut format =
938             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
939 
940         format.modify_mix_format(
941             /* bit_depth= */ 32,
942             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
943         );
944 
945         // The format should be converted to 32 bit depth and retain mono channel.
946         let expected = WAVEFORMATEX {
947             wFormatTag: WAVE_FORMAT_IEEE_FLOAT, // Changed
948             nChannels: 1,
949             nSamplesPerSec: 48000,
950             nAvgBytesPerSec: 4 * 48000, // Changed
951             nBlockAlign: 4,             // Changed
952             wBitsPerSample: 32,         // Changed
953             cbSize: 0,
954         };
955 
956         let expected = unsafe {
957             WaveAudioFormat::new((&expected) as *const WAVEFORMATEX as *mut WAVEFORMATEX)
958         };
959 
960         assert_eq!(format, expected);
961     }
962 
963     #[test]
test_waveformatex_non_ieee_modify_format()964     fn test_waveformatex_non_ieee_modify_format() {
965         let format = WAVEFORMATEX {
966             wFormatTag: WAVE_FORMAT_PCM,
967             nChannels: 2,
968             nSamplesPerSec: 48000,
969             nAvgBytesPerSec: 192000,
970             nBlockAlign: 4,
971             wBitsPerSample: 16,
972             cbSize: 0,
973         };
974 
975         // Safe because we can convert a struct to a pointer declared above. Also that means the
976         // pointer can be safely deferenced.
977         let mut format =
978             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
979 
980         format.modify_mix_format(
981             /* bit_depth= */ 32,
982             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
983         );
984 
985         let result_format = format.take_waveformatex();
986 
987         assert_waveformatex_ieee(&result_format);
988     }
989 
990     #[test]
test_waveformatex_non_ieee_32_bit_modify_format()991     fn test_waveformatex_non_ieee_32_bit_modify_format() {
992         let format = WAVEFORMATEX {
993             wFormatTag: WAVE_FORMAT_PCM,
994             nChannels: 2,
995             nSamplesPerSec: 48000,
996             nAvgBytesPerSec: 384000,
997             nBlockAlign: 8,
998             wBitsPerSample: 32,
999             cbSize: 0,
1000         };
1001 
1002         // Safe because we can convert a struct to a pointer declared above. Also that means the
1003         // pointer can be safely deferenced.
1004         let mut format =
1005             unsafe { WaveAudioFormat::new((&format) as *const WAVEFORMATEX as *mut WAVEFORMATEX) };
1006 
1007         format.modify_mix_format(
1008             /* bit_depth= */ 32,
1009             /* ks_data_format= */ KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1010         );
1011 
1012         let result_format = format.take_waveformatex();
1013 
1014         assert_waveformatex_ieee(&result_format);
1015     }
1016 
assert_waveformatex_ieee(result_format: &WAVEFORMATEX)1017     fn assert_waveformatex_ieee(result_format: &WAVEFORMATEX) {
1018         let format_tag = result_format.wFormatTag;
1019         assert_eq!(format_tag, WAVE_FORMAT_IEEE_FLOAT);
1020         let channels = result_format.nChannels;
1021         assert_eq!(channels, 2);
1022         let samples_per_sec = result_format.nSamplesPerSec;
1023         assert_eq!(samples_per_sec, 48000);
1024         let avg_bytes_per_sec = result_format.nAvgBytesPerSec;
1025         assert_eq!(avg_bytes_per_sec, 384000);
1026         let block_align = result_format.nBlockAlign;
1027         assert_eq!(block_align, 8);
1028         let bits_per_samples = result_format.wBitsPerSample;
1029         assert_eq!(bits_per_samples, 32);
1030         let size = result_format.cbSize;
1031         assert_eq!(size, 0);
1032     }
1033 
1034     #[test]
test_create_audio_shared_format_wave_format_ex()1035     fn test_create_audio_shared_format_wave_format_ex() {
1036         let wave_format = WAVEFORMATEX {
1037             wFormatTag: WAVE_FORMAT_PCM,
1038             nChannels: 2,
1039             nSamplesPerSec: 48000,
1040             nAvgBytesPerSec: 192000,
1041             nBlockAlign: 4,
1042             wBitsPerSample: 16,
1043             cbSize: 0,
1044         };
1045 
1046         // Safe because we can convert a struct to a pointer declared above. Also that means the
1047         // pointer can be safely deferenced.
1048         let format = unsafe {
1049             WaveAudioFormat::new((&wave_format) as *const WAVEFORMATEX as *mut WAVEFORMATEX)
1050         };
1051 
1052         // The period will most likely never be 123, but this is ok for testing.
1053         let audio_shared_format =
1054             format.create_audio_shared_format(/* shared_audio_engine_period_in_frames= */ 123);
1055 
1056         assert_eq!(
1057             audio_shared_format.bit_depth,
1058             wave_format.wBitsPerSample as usize
1059         );
1060         assert_eq!(audio_shared_format.channels, wave_format.nChannels as usize);
1061         assert_eq!(
1062             audio_shared_format.frame_rate,
1063             wave_format.nSamplesPerSec as usize
1064         );
1065         assert_eq!(
1066             audio_shared_format.shared_audio_engine_period_in_frames,
1067             123
1068         );
1069     }
1070 
1071     #[test]
test_create_audio_shared_format_wave_format_extensible()1072     fn test_create_audio_shared_format_wave_format_extensible() {
1073         let wave_format_extensible = WAVEFORMATEXTENSIBLE {
1074             Format: WAVEFORMATEX {
1075                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
1076                 nChannels: 2,
1077                 nSamplesPerSec: 48000,
1078                 nAvgBytesPerSec: 8 * 48000,
1079                 nBlockAlign: 8,
1080                 wBitsPerSample: 32,
1081                 cbSize: 22,
1082             },
1083             Samples: 32,
1084             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
1085             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1086         };
1087 
1088         // Safe because we can convert a struct to a pointer declared above. Also that means the
1089         // pointer can be safely deferenced.
1090         let format = unsafe {
1091             WaveAudioFormat::new((&wave_format_extensible) as *const _ as *mut WAVEFORMATEX)
1092         };
1093 
1094         // The period will most likely never be 123, but this is ok for testing.
1095         let audio_shared_format =
1096             format.create_audio_shared_format(/* shared_audio_engine_period_in_frames= */ 123);
1097 
1098         assert_eq!(
1099             audio_shared_format.bit_depth,
1100             wave_format_extensible.Format.wBitsPerSample as usize
1101         );
1102         assert_eq!(
1103             audio_shared_format.channels,
1104             wave_format_extensible.Format.nChannels as usize
1105         );
1106         assert_eq!(
1107             audio_shared_format.frame_rate,
1108             wave_format_extensible.Format.nSamplesPerSec as usize
1109         );
1110         assert_eq!(
1111             audio_shared_format.shared_audio_engine_period_in_frames,
1112             123
1113         );
1114         assert_eq!(
1115             audio_shared_format.channel_mask,
1116             Some(SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
1117         );
1118     }
1119 
1120     #[test]
test_wave_format_to_proto_convertion()1121     fn test_wave_format_to_proto_convertion() {
1122         let wave_format = WAVEFORMATEX {
1123             wFormatTag: WAVE_FORMAT_PCM,
1124             nChannels: 2,
1125             nSamplesPerSec: 48000,
1126             nAvgBytesPerSec: 192000,
1127             nBlockAlign: 4,
1128             wBitsPerSample: 16,
1129             cbSize: 0,
1130         };
1131 
1132         // Safe because we can convert a struct to a pointer declared above. Also that means the
1133         // pointer can be safely deferenced.
1134         let wave_audio_format =
1135             unsafe { WaveAudioFormat::new((&wave_format) as *const _ as *mut WAVEFORMATEX) };
1136 
1137         // Testing the `into`.
1138         let wave_format_proto = WaveFormatProto::from(&wave_audio_format);
1139 
1140         let mut expected = WaveFormatProto::new();
1141         expected.set_format_tag(WAVE_FORMAT_PCM.into());
1142         expected.set_channels(2);
1143         expected.set_samples_per_sec(48000);
1144         expected.set_avg_bytes_per_sec(192000);
1145         expected.set_block_align(4);
1146         expected.set_bits_per_sample(16);
1147         expected.set_size_bytes(0);
1148 
1149         assert_eq!(wave_format_proto, expected);
1150     }
1151 
1152     #[test]
test_wave_format_extensible_to_proto_convertion()1153     fn test_wave_format_extensible_to_proto_convertion() {
1154         let wave_format_extensible = WAVEFORMATEXTENSIBLE {
1155             Format: WAVEFORMATEX {
1156                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
1157                 nChannels: 2,
1158                 nSamplesPerSec: 48000,
1159                 nAvgBytesPerSec: 8 * 48000,
1160                 nBlockAlign: 8,
1161                 wBitsPerSample: 32,
1162                 cbSize: 22,
1163             },
1164             Samples: 32,
1165             dwChannelMask: SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
1166             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1167         };
1168 
1169         // Safe because we can convert a struct to a pointer declared above. Also that means the
1170         // pointer can be safely deferenced.
1171         let wave_audio_format = unsafe {
1172             WaveAudioFormat::new((&wave_format_extensible) as *const _ as *mut WAVEFORMATEX)
1173         };
1174 
1175         // Testing the `into`.
1176         let wave_format_proto = WaveFormatProto::from(&wave_audio_format);
1177 
1178         let mut expected = WaveFormatProto::new();
1179         expected.set_format_tag(WAVE_FORMAT_EXTENSIBLE.into());
1180         expected.set_channels(2);
1181         expected.set_samples_per_sec(48000);
1182         expected.set_avg_bytes_per_sec(8 * 48000);
1183         expected.set_block_align(8);
1184         expected.set_bits_per_sample(32);
1185         expected.set_size_bytes(22);
1186         expected.set_samples(32);
1187         expected.set_channel_mask((SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT) as i64);
1188         expected.set_sub_format(GuidWrapper(&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT).into());
1189 
1190         assert_eq!(wave_format_proto, expected);
1191     }
1192 }
1193