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