• 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 pub mod async_stream;
6 mod completion_handler;
7 mod wave_format;
8 
9 use std::convert::From;
10 use std::fmt::Debug;
11 use std::os::raw::c_void;
12 use std::ptr::null_mut;
13 use std::sync::Arc;
14 use std::sync::Once;
15 use std::thread_local;
16 use std::time::Duration;
17 
18 use audio_streams::async_api::EventAsyncWrapper;
19 use audio_streams::AsyncPlaybackBufferStream;
20 use audio_streams::BoxError;
21 use audio_streams::BufferCommit;
22 use audio_streams::NoopStream;
23 use audio_streams::NoopStreamControl;
24 use audio_streams::PlaybackBuffer;
25 use audio_streams::PlaybackBufferError;
26 use audio_streams::PlaybackBufferStream;
27 use audio_streams::SampleFormat;
28 use audio_streams::StreamControl;
29 use audio_streams::StreamSource;
30 use base::error;
31 use base::info;
32 use base::warn;
33 use base::AsRawDescriptor;
34 use base::Error;
35 use base::Event;
36 use base::EventExt;
37 use base::EventWaitResult;
38 use completion_handler::WinAudioActivateAudioInterfaceCompletionHandler;
39 use sync::Mutex;
40 use thiserror::Error as ThisError;
41 use wave_format::*;
42 use winapi::shared::guiddef::GUID;
43 use winapi::shared::guiddef::REFCLSID;
44 use winapi::um::audioclient::*;
45 use winapi::um::audiosessiontypes::AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED;
46 use winapi::um::audiosessiontypes::AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED;
47 use winapi::um::audiosessiontypes::AUDCLNT_SHAREMODE_SHARED;
48 use winapi::um::audiosessiontypes::AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
49 use winapi::um::combaseapi::*;
50 use winapi::um::coml2api::STGM_READ;
51 use winapi::um::functiondiscoverykeys_devpkey::PKEY_Device_FriendlyName;
52 use winapi::um::mmdeviceapi::*;
53 use winapi::um::objbase::COINIT_APARTMENTTHREADED;
54 use winapi::um::propidl::PropVariantClear;
55 use winapi::um::propidl::PROPVARIANT;
56 use winapi::um::propsys::IPropertyStore;
57 use winapi::um::synchapi::WaitForSingleObject;
58 use winapi::um::unknwnbase::IUnknown;
59 use winapi::um::winbase::WAIT_OBJECT_0;
60 use winapi::Interface;
61 use wio::com::ComPtr;
62 
63 use crate::AudioSharedFormat;
64 
65 const READY_TO_READ_TIMEOUT_MS: u32 = 2000;
66 pub const STEREO_CHANNEL_COUNT: u16 = 2;
67 pub const MONO_CHANNEL_COUNT: u16 = 1;
68 
69 // from msdn: https://docs.microsoft.com/en-us/windows/win32/coreaudio/audclnt-streamflags-xxx-constants
70 // these don't currently exist in winapi
71 const AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM: u32 = 0x80000000;
72 const AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY: u32 = 0x08000000;
73 
74 thread_local!(static THREAD_ONCE_INIT: Once = Once::new());
75 
76 // Used to differentiate between S_FALSE and S_OK. This means `CoInitializeEx` did not get called. Mainly used for testing.
77 const S_SKIPPED_COINIT: i32 = 2;
78 
79 const ACTIVATE_AUDIO_EVENT_TIMEOUT: Duration = Duration::from_secs(5);
80 
81 pub struct WinAudio {
82     pub cached_playback_buffer_stream:
83         Option<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat)>,
84 }
85 impl WinAudio {
new() -> Result<Self, BoxError>86     pub fn new() -> Result<Self, BoxError> {
87         Ok(WinAudio {
88             cached_playback_buffer_stream: None,
89         })
90     }
91 
co_init_once_per_thread() -> i3292     pub(crate) fn co_init_once_per_thread() -> i32 {
93         let mut hr = S_SKIPPED_COINIT;
94         THREAD_ONCE_INIT.with(|once| {
95             once.call_once(|| {
96                 // Safe because all variables passed into `CoInitializeEx` are hardcoded
97                 unsafe {
98                     // Initializes the COM library for use by the calling thread. Needed so that `CoCreateInstance`
99                     // can be called to create a device enumerator object.
100                     //
101                     // TODO(b/217413370): `CoUninitialize` is never called at any point in KiwiVm.
102                     // It might make sense for all VCPU threads to call `CoInitializeEx` when
103                     // starting and `CoUninitialize` when the thread ends. However when switching to
104                     // virtio-snd, we need to make sure cros_async threads get `Co(Un)Initialize`
105                     // support if needed.
106                     hr = CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED);
107                 };
108             })
109         });
110 
111         hr
112     }
113 }
114 
115 impl StreamSource for WinAudio {
116     /// Returns a stream control and a buffer generator object. The stream control object is not
117     /// used. The buffer generator object is a wrapper around WASAPI's objects that will create a
118     /// buffer for crosvm to copy audio bytes into.
new_playback_stream( &mut self, num_channels: usize, _format: SampleFormat, frame_rate: u32, buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>119     fn new_playback_stream(
120         &mut self,
121         num_channels: usize,
122         _format: SampleFormat,
123         frame_rate: u32,
124         buffer_size: usize, //number of frames;
125     ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError> {
126         let hr = WinAudio::co_init_once_per_thread();
127         let _ = check_hresult!(hr, RenderError::from(hr), "Co Initialized failed");
128 
129         let playback_buffer_stream: Box<dyn PlaybackBufferStream> =
130             match WinAudioRenderer::new(num_channels, frame_rate, buffer_size) {
131                 Ok(renderer) => Box::new(renderer),
132                 Err(e) => {
133                     warn!(
134                         "Failed to create WinAudioRenderer. Fallback to NoopStream with error: {}",
135                         e
136                     );
137                     Box::new(NoopStream::new(
138                         num_channels,
139                         SampleFormat::S16LE,
140                         frame_rate,
141                         buffer_size,
142                     ))
143                 }
144             };
145 
146         Ok((Box::new(NoopStreamControl::new()), playback_buffer_stream))
147     }
148 
149     /// Similar to `new_playback_stream, but will return an `AsyncPlaybackBufferStream` that can
150     /// run async operations.
new_async_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError>151     fn new_async_playback_stream(
152         &mut self,
153         num_channels: usize,
154         format: SampleFormat,
155         frame_rate: u32,
156         buffer_size: usize,
157         ex: &dyn audio_streams::AudioStreamsExecutor,
158     ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError> {
159         WinAudio::new_async_playback_stream_helper(
160             num_channels,
161             format,
162             frame_rate,
163             buffer_size,
164             ex,
165         )
166     }
167 }
168 
169 /// Proxy for a `DeviceRenderer` that handles device invalidated errors by switching to a new
170 /// `DeviceRenderer` on a new device.
171 pub(crate) struct WinAudioRenderer {
172     pub device: DeviceRenderer,
173     num_channels: usize,
174     frame_rate: u32,
175     incoming_buffer_size_in_frames: usize,
176 }
177 
178 impl WinAudioRenderer {
179     const MAX_REATTACH_TRIES: usize = 50;
180 
181     // Initializes WASAPI objects needed for audio.
new( num_channels: usize, frame_rate: u32, incoming_buffer_size_in_frames: usize, ) -> Result<Self, RenderError>182     pub fn new(
183         num_channels: usize,
184         frame_rate: u32,
185         incoming_buffer_size_in_frames: usize,
186     ) -> Result<Self, RenderError> {
187         let device = Self::create_device_renderer_and_log_time(
188             num_channels,
189             frame_rate,
190             incoming_buffer_size_in_frames,
191             None,
192         )?;
193 
194         Ok(Self {
195             device,
196             num_channels,
197             frame_rate,                     // guest frame rate
198             incoming_buffer_size_in_frames, // from the guest`
199         })
200     }
201 
create_device_renderer_and_log_time( num_channels: usize, frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<DeviceRenderer, RenderError>202     fn create_device_renderer_and_log_time(
203         num_channels: usize,
204         frame_rate: u32,
205         incoming_buffer_size_in_frames: usize,
206         ex: Option<&dyn audio_streams::AudioStreamsExecutor>,
207     ) -> Result<DeviceRenderer, RenderError> {
208         let start = std::time::Instant::now();
209         let device =
210             DeviceRenderer::new(num_channels, frame_rate, incoming_buffer_size_in_frames, ex)?;
211         // This can give us insights to how other long other machines take to initialize audio.
212         // Eventually this should be a histogram metric.
213         info!(
214             "DeviceRenderer took {}ms to initialize audio.",
215             start.elapsed().as_millis()
216         );
217         Ok(device)
218     }
219 
220     // Drops the existing DeviceRenderer and initializes a new DeviceRenderer for the default
221     // device.
reattach_device(&mut self) -> Result<(), RenderError>222     fn reattach_device(&mut self) -> Result<(), RenderError> {
223         self.device = DeviceRenderer::new(
224             self.num_channels,
225             self.frame_rate,
226             self.incoming_buffer_size_in_frames,
227             None,
228         )?;
229         Ok(())
230     }
231 }
232 
233 impl PlaybackBufferStream for WinAudioRenderer {
234     /// Returns a wrapper around the WASAPI buffer.
next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError>235     fn next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError> {
236         for _ in 0..Self::MAX_REATTACH_TRIES {
237             match self.device.next_win_buffer() {
238                 Ok(_) => return self.device.playback_buffer().map_err(|e| Box::new(e) as _),
239                 // If the audio device was disconnected, set up whatever is now the default device
240                 // and loop to try again.
241                 Err(RenderError::DeviceInvalidated) => {
242                     warn!("Audio device disconnected, switching to new default device");
243                     self.reattach_device()?;
244                 }
245                 Err(e) => return Err(Box::new(e)),
246             }
247         }
248         error!("Unable to attach to a working audio device, giving up");
249         Err(Box::new(RenderError::DeviceInvalidated))
250     }
251 }
252 
253 // Implementation of buffer generator object. Used to get a buffer from WASAPI for crosvm to copy audio
254 // bytes from the guest memory into.
255 pub(crate) struct DeviceRenderer {
256     audio_render_client: ComPtr<IAudioRenderClient>,
257     audio_client: ComPtr<IAudioClient>,
258     win_buffer: *mut u8,
259     pub audio_shared_format: AudioSharedFormat,
260     audio_render_client_buffer_frame_count: u32,
261     ready_to_read_event: Event,
262     async_ready_to_read_event: Option<Box<dyn EventAsyncWrapper>>,
263 }
264 
265 impl DeviceRenderer {
266     // Initializes WASAPI objects needed for audio
new( num_channels: usize, _guest_frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<Self, RenderError>267     fn new(
268         num_channels: usize,
269         _guest_frame_rate: u32,
270         incoming_buffer_size_in_frames: usize,
271         ex: Option<&dyn audio_streams::AudioStreamsExecutor>,
272     ) -> Result<Self, RenderError> {
273         if num_channels > 2 {
274             return Err(RenderError::InvalidChannelCount(num_channels));
275         }
276 
277         let audio_client = create_audio_client(eRender)?;
278 
279         let format = get_valid_mix_format(&audio_client)?;
280 
281         // Safe because `audio_client` is initialized
282         let hr = unsafe {
283             // Intializes the audio client by setting the buffer size in 100-nanoseconds and
284             // specifying the format the audio bytes will be passed in as.
285             // Setting `hnsBufferDuration` (in miilisecond units) to 0 will let the audio engine to
286             // pick the size that will minimize latency.
287             // `hnsPeriodicity` sets the device period and should always be 0 for shared mode.
288             audio_client.Initialize(
289                 AUDCLNT_SHAREMODE_SHARED,
290                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
291                     | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
292                     | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
293                     | AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
294                     | AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED,
295                 0, /* hnsBufferDuration */
296                 0, /* hnsPeriodicity */
297                 format.as_ptr(),
298                 null_mut(),
299             )
300         };
301         check_hresult!(
302             hr,
303             RenderError::from(hr),
304             "Audio Client Initialize() failed."
305         )?;
306 
307         let (ready_to_read_event, async_ready_to_read_event) =
308             create_and_set_audio_client_event(&audio_client, &ex)?;
309 
310         let audio_render_client = DeviceRenderer::create_audio_render_client(&audio_client)?;
311 
312         let shared_audio_engine_period_in_frames =
313             get_device_period_in_frames(&audio_client, &format);
314 
315         let audio_render_client_buffer_frame_count =
316             check_endpoint_buffer_size(&audio_client, shared_audio_engine_period_in_frames)?;
317         if incoming_buffer_size_in_frames % shared_audio_engine_period_in_frames != 0 {
318             warn!(
319                 "Guest period size: `{}` not divisible by shared audio engine period size: `{}`. \
320                  Audio glitches may occur if sample rate conversion isn't on.",
321                 incoming_buffer_size_in_frames, shared_audio_engine_period_in_frames
322             );
323         }
324 
325         // Safe because `audio_client` is initialized
326         let hr = unsafe {
327             // Starts the audio stream for playback
328             audio_client.Start()
329         };
330         check_hresult!(
331             hr,
332             RenderError::from(hr),
333             "Audio Render Client Start() failed."
334         )?;
335 
336         Ok(Self {
337             audio_render_client,
338             audio_client,
339             win_buffer: std::ptr::null_mut(),
340             audio_shared_format: format
341                 .create_audio_shared_format(shared_audio_engine_period_in_frames),
342             audio_render_client_buffer_frame_count,
343             ready_to_read_event,
344             async_ready_to_read_event,
345         })
346     }
347 
create_audio_render_client( audio_client: &IAudioClient, ) -> Result<ComPtr<IAudioRenderClient>, RenderError>348     fn create_audio_render_client(
349         audio_client: &IAudioClient,
350     ) -> Result<ComPtr<IAudioRenderClient>, RenderError> {
351         let mut audio_render_client: *mut c_void = null_mut();
352 
353         // Safe because `audio_client` is initialized
354         let hr = unsafe {
355             audio_client.GetService(
356                 &IID_IAudioRenderClient as *const GUID,
357                 &mut audio_render_client,
358             )
359         };
360         check_hresult!(
361             hr,
362             RenderError::from(hr),
363             "Audio Client GetService() failed."
364         )?;
365 
366         // Safe because `audio_render_client` is guaranteed to be initialized
367         unsafe {
368             Ok(ComPtr::from_raw(
369                 audio_render_client as *mut IAudioRenderClient,
370             ))
371         }
372     }
373 
374     // Returns a wraper around the WASAPI buffer
next_win_buffer(&mut self) -> Result<(), RenderError>375     fn next_win_buffer(&mut self) -> Result<(), RenderError> {
376         // We will wait for windows to tell us when it is ready to take in the next set of
377         // audio samples from the guest
378         loop {
379             // Safe because `ready_to_read_event` is guarenteed to be properly initialized
380             // and `num_frames_padding` is property initliazed as an empty pointer.
381             unsafe {
382                 let res = WaitForSingleObject(
383                     self.ready_to_read_event.as_raw_descriptor(),
384                     READY_TO_READ_TIMEOUT_MS,
385                 );
386                 if res != WAIT_OBJECT_0 {
387                     warn!(
388                         "Waiting for ready_to_read_event timed out after {} ms",
389                         READY_TO_READ_TIMEOUT_MS
390                     );
391                     break;
392                 }
393                 if self.enough_available_frames()? {
394                     break;
395                 }
396             }
397         }
398 
399         self.get_buffer()?;
400 
401         Ok(())
402     }
403 
404     /// Returns true if the number of frames avaialble in the Windows playback buffer is at least
405     /// the size of one full period worth of audio samples.
enough_available_frames(&mut self) -> Result<bool, RenderError>406     fn enough_available_frames(&mut self) -> Result<bool, RenderError> {
407         // Safe because `num_frames_padding` is an u32 and `GetCurrentPadding` is a simple
408         // Windows function that shouldn't fail.
409         let mut num_frames_padding = 0u32;
410         let hr = unsafe { self.audio_client.GetCurrentPadding(&mut num_frames_padding) };
411         check_hresult!(
412             hr,
413             RenderError::from(hr),
414             "Audio Client GetCurrentPadding() failed."
415         )?;
416 
417         // If the available free frames is less than the frames that are being sent over from the
418         // guest, then we want to only grab the number of frames available.
419         let num_frames_available =
420             (self.audio_render_client_buffer_frame_count - num_frames_padding) as usize;
421 
422         Ok(num_frames_available
423             >= self
424                 .audio_shared_format
425                 .shared_audio_engine_period_in_frames)
426     }
427 
get_buffer(&mut self) -> Result<(), RenderError>428     fn get_buffer(&mut self) -> Result<(), RenderError> {
429         self.win_buffer = std::ptr::null_mut();
430 
431         // This unsafe block will get the playback buffer and return the size of the buffer
432         //
433         // This is safe because the contents of `win_buffer` will be
434         // released when `ReleaseBuffer` is called in the `BufferCommit` implementation.
435         unsafe {
436             let hr = self.audio_render_client.GetBuffer(
437                 self.audio_shared_format
438                     .shared_audio_engine_period_in_frames as u32,
439                 &mut self.win_buffer,
440             );
441             check_hresult!(
442                 hr,
443                 RenderError::from(hr),
444                 "Audio Render Client GetBuffer failed."
445             )?;
446         }
447 
448         Ok(())
449     }
450 
playback_buffer(&mut self) -> Result<PlaybackBuffer, RenderError>451     fn playback_buffer(&mut self) -> Result<PlaybackBuffer, RenderError> {
452         // Safe because `win_buffer` is allocated and retrieved from WASAPI. The size requested,
453         // which we specified in `next_win_buffer` is exactly
454         // `shared_audio_engine_period_in_frames`, so the size parameter should be valid.
455         let (frame_size_bytes, buffer_slice) = unsafe {
456             Self::get_frame_size_and_buffer_slice(
457                 self.audio_shared_format.bit_depth as usize,
458                 self.audio_shared_format.channels as usize,
459                 self.win_buffer,
460                 self.audio_shared_format
461                     .shared_audio_engine_period_in_frames,
462             )?
463         };
464 
465         PlaybackBuffer::new(frame_size_bytes, buffer_slice, self)
466             .map_err(RenderError::PlaybackBuffer)
467     }
468 
469     /// # Safety
470     ///
471     /// Safe only if:
472     ///   1. `win_buffer` is pointing to a valid buffer used for holding audio bytes.
473     ///   2. `bit_depth`, `channels`, and `shared_audio_engine_period_in_frames` are accurate with
474     ///      respect to `win_buffer`, so that a valid slice can be made.
475     ///   3. The variables mentioned in reason "2." must calculate a size no greater than the size
476     ///      of the buffer pointed to by `win_buffer`.
get_frame_size_and_buffer_slice<'a>( bit_depth: usize, channels: usize, win_buffer: *mut u8, shared_audio_engine_period_in_frames: usize, ) -> Result<(usize, &'a mut [u8]), RenderError>477     unsafe fn get_frame_size_and_buffer_slice<'a>(
478         bit_depth: usize,
479         channels: usize,
480         win_buffer: *mut u8,
481         shared_audio_engine_period_in_frames: usize,
482     ) -> Result<(usize, &'a mut [u8]), RenderError> {
483         if win_buffer.is_null() {
484             return Err(RenderError::InvalidBuffer);
485         }
486 
487         let frame_size_bytes = bit_depth * channels / 8;
488 
489         Ok((
490             frame_size_bytes,
491             std::slice::from_raw_parts_mut(
492                 win_buffer,
493                 shared_audio_engine_period_in_frames * frame_size_bytes,
494             ),
495         ))
496     }
497 }
498 
499 impl BufferCommit for DeviceRenderer {
500     // Called after buffer from WASAPI is filled. This will allow the audio bytes to be played as sound.
commit(&mut self, nframes: usize)501     fn commit(&mut self, nframes: usize) {
502         // Safe because `audio_render_client` is initialized and parameters passed
503         // into `ReleaseBuffer()` are valid
504         unsafe {
505             let hr = self.audio_render_client.ReleaseBuffer(nframes as u32, 0);
506             let _ = check_hresult!(
507                 hr,
508                 RenderError::from(hr),
509                 "Audio Render Client ReleaseBuffer() failed"
510             );
511         }
512     }
513 }
514 
515 impl Drop for DeviceRenderer {
drop(&mut self)516     fn drop(&mut self) {
517         unsafe {
518             let hr = self.audio_client.Stop();
519             let _ = check_hresult!(
520                 hr,
521                 RenderError::from(hr),
522                 "Audio Render Client Stop() failed."
523             );
524             // audio_client and audio_render_client will be released by ComPtr when dropped. Most
525             // likely safe to Release() if audio_client fails to stop. The MSDN doc does not mention
526             // that it will crash and this should be done anyways to prevent memory leaks
527         }
528     }
529 }
530 
531 unsafe impl Send for DeviceRenderer {}
532 
533 // Create the `IAudioClient` which is used to create `IAudioRenderClient`, which is used for
534 // audio playback, or used to create `IAudioCaptureClient`, which is used for audio capture.
create_audio_client(dataflow: EDataFlow) -> Result<ComPtr<IAudioClient>, RenderError>535 fn create_audio_client(dataflow: EDataFlow) -> Result<ComPtr<IAudioClient>, RenderError> {
536     let mut device_enumerator: *mut c_void = null_mut();
537 
538     // Creates a device enumerator in order to select our default audio device.
539     //
540     // Safe because only `device_enumerator` is being modified and we own it.
541     let hr = unsafe {
542         CoCreateInstance(
543             &CLSID_MMDeviceEnumerator as REFCLSID,
544             null_mut(),
545             CLSCTX_ALL,
546             &IMMDeviceEnumerator::uuidof(),
547             &mut device_enumerator,
548         )
549     };
550     check_hresult!(
551         hr,
552         RenderError::from(hr),
553         "Win audio create client CoCreateInstance() failed."
554     )?;
555 
556     // Safe because `device_enumerator` is guaranteed to be initialized
557     let device_enumerator =
558         unsafe { ComPtr::from_raw(device_enumerator as *mut IMMDeviceEnumerator) };
559 
560     let mut device: *mut IMMDevice = null_mut();
561     // Safe because `device_enumerator` is guaranteed to be initialized otherwise this method would've
562     // exited
563     let hr = unsafe { device_enumerator.GetDefaultAudioEndpoint(dataflow, eConsole, &mut device) };
564     check_hresult!(
565         hr,
566         RenderError::from(hr),
567         "Device Enumerator GetDefaultAudioEndpoint() failed."
568     )?;
569 
570     // Safe because `device` is guaranteed to be initialized
571     let device = unsafe { ComPtr::from_raw(device) };
572     print_device_info(&device)?;
573 
574     let is_render = if dataflow == eRender { true } else { false };
575 
576     // Call Windows API functions to get the `async_op` which will be used to retrieve the
577     // AudioClient. More details above function definition.
578     let async_op = enable_auto_stream_routing_and_wait(is_render)?;
579 
580     let mut factory: *mut IUnknown = null_mut();
581 
582     // Safe because `async_op` should be initialized at this point.
583     let activate_result_hr = unsafe {
584         let mut activate_result_hr = 0;
585         let hr = (*async_op).GetActivateResult(&mut activate_result_hr, &mut factory);
586 
587         check_hresult!(
588             hr,
589             RenderError::from(hr),
590             "GetActivateResult failed. Cannot retrieve factory to create the Audio Client."
591         )?;
592 
593         activate_result_hr
594     };
595     check_hresult!(
596         activate_result_hr,
597         RenderError::from(activate_result_hr),
598         "activateResult is an error. Cannot retrieve factory to create the Audio Client."
599     )?;
600 
601     // Safe because `factory` is guaranteed to be initialized.
602     let factory = unsafe { ComPtr::from_raw(factory) };
603 
604     factory.cast().map_err(RenderError::from)
605 }
606 
607 // Enables automatic audio device routing (only will work for Windows 10, version 1607+).
608 // This will return IActivateAudioInterfaceAsyncOperation that can be used to retrive the
609 // AudioClient.
610 //
611 // This function will pretty much works as follows:
612 // 1. Create the parameters to pass into `ActivateAudioInterfaceAsync`
613 // 2. Call `ActivateAudioInterfaceAsync` which will run asynchrnously and will call
614 //    a callback when completed.
615 // 3. Wait on an event that will be notified when that callback is triggered.
616 // 4. Return an IActivateAudioInterfaceAsyncOperation which can be used to retrived the
617 //    AudioClient.
enable_auto_stream_routing_and_wait( is_render: bool, ) -> Result<ComPtr<IActivateAudioInterfaceAsyncOperation>, RenderError>618 fn enable_auto_stream_routing_and_wait(
619     is_render: bool,
620 ) -> Result<ComPtr<IActivateAudioInterfaceAsyncOperation>, RenderError> {
621     // Event that fires when callback is called.
622     let activate_audio_interface_complete_event =
623         Event::new_auto_reset().map_err(RenderError::CreateActivateAudioEventError)?;
624 
625     let cloned_activate_event = activate_audio_interface_complete_event
626         .try_clone()
627         .map_err(RenderError::CloneEvent)?;
628 
629     // Create the callback that is called when `ActivateAudioInterfaceAsync` is finished.
630     // The field `parent` is irrelevant and is only there to fill in the struct so that
631     // this code will run. `ActivateCompleted` is the callback.
632     let completion_handler =
633         WinAudioActivateAudioInterfaceCompletionHandler::create_com_ptr(cloned_activate_event);
634 
635     // Retrieve GUID that represents the default audio device.
636     let mut audio_direction_guid_string: *mut u16 = std::ptr::null_mut();
637 
638     // This will get the GUID that represents the device we want `ActivateAudioInterfaceAsync`
639     // to activate. `DEVINTERFACE_AUDIO_RENDER` represents the users default audio render device, so
640     // as a result Windows will always route sound to the default device. Likewise,
641     // `DEVINTERFACE_AUDIO_CAPTURE` represents the default audio capture device.
642     //
643     // Safe because we own `audio_direction_guid_string`.
644     let hr = unsafe {
645         if is_render {
646             StringFromIID(
647                 &DEVINTERFACE_AUDIO_RENDER as *const winapi::shared::guiddef::GUID,
648                 &mut audio_direction_guid_string,
649             )
650         } else {
651             StringFromIID(
652                 &DEVINTERFACE_AUDIO_CAPTURE as *const winapi::shared::guiddef::GUID,
653                 &mut audio_direction_guid_string,
654             )
655         }
656     };
657     check_hresult!(
658         hr,
659         RenderError::from(hr),
660         format!(
661             "Failed to retrive DEVINTERFACE_AUDIO GUID for {}",
662             if is_render { "rendering" } else { "capturing" }
663         )
664     )?;
665 
666     let mut async_op: *mut IActivateAudioInterfaceAsyncOperation = std::ptr::null_mut();
667 
668     // This will asynchronously run and when completed, it will trigger the
669     // `IActivateINterfaceCompletetionHandler` callback.
670     // The callback is where the AudioClient can be retrived. This would be easier in C/C++,
671     // but since in rust the callback is an extern function, it would be difficult to get the
672     // `IAudioClient` from the callback to the scope here, so we use an
673     // event to wait for the callback.
674     //
675     // Safe because we own async_op and the completion handler.
676     let hr = unsafe {
677         ActivateAudioInterfaceAsync(
678             audio_direction_guid_string,
679             &IAudioClient::uuidof(),
680             /* activateParams= */ std::ptr::null_mut(),
681             completion_handler.as_raw(),
682             &mut async_op,
683         )
684     };
685 
686     // We want to free memory before error checking for `ActivateAudioInterfaceAsync` to prevent
687     // a memory leak.
688     //
689     // Safe because `audio_direction_guid_string` should have valid memory
690     // and we are freeing up memory here.
691     unsafe {
692         CoTaskMemFree(audio_direction_guid_string as *mut std::ffi::c_void);
693     }
694 
695     check_hresult!(
696         hr,
697         RenderError::from(hr),
698         "`Activate AudioInterfaceAsync failed."
699     )?;
700 
701     // Wait for `ActivateAudioInterfaceAsync` to finish. `ActivateAudioInterfaceAsync` should
702     // never hang, but added a long timeout just incase.
703     match activate_audio_interface_complete_event.wait_timeout(ACTIVATE_AUDIO_EVENT_TIMEOUT) {
704         Ok(event_result) => match event_result {
705             EventWaitResult::Signaled => {}
706             EventWaitResult::TimedOut => {
707                 return Err(RenderError::ActivateAudioEventTimeoutError);
708             }
709         },
710         Err(e) => {
711             return Err(RenderError::ActivateAudioEventError(e));
712         }
713     }
714 
715     // Safe because we own `async_op` and it shouldn't be null if the activate audio event
716     // fired.
717     unsafe { Ok(ComPtr::from_raw(async_op)) }
718 }
719 
720 // Prints the friendly name for audio `device` to the log.
721 // Safe when `device` is guaranteed to be successfully initialized.
print_device_info(device: &IMMDevice) -> Result<(), RenderError>722 fn print_device_info(device: &IMMDevice) -> Result<(), RenderError> {
723     let mut props: *mut IPropertyStore = null_mut();
724     // Safe because `device` is guaranteed to be initialized
725     let hr = unsafe { device.OpenPropertyStore(STGM_READ, &mut props) };
726     check_hresult!(
727         hr,
728         RenderError::from(hr),
729         "Win audio OpenPropertyStore failed."
730     )?;
731 
732     // Safe because `props` is guaranteed to be initialized
733     let props = unsafe { ComPtr::from_raw(props) };
734 
735     let mut val: PROPVARIANT = Default::default();
736     // Safe because `props` is guaranteed to be initialized
737     let hr = unsafe { props.GetValue(&PKEY_Device_FriendlyName, &mut val) };
738     check_hresult!(
739         hr,
740         RenderError::from(hr),
741         "Win audio property store GetValue failed."
742     )?;
743 
744     // Safe because `val` was populated by a successful GetValue call that returns a pwszVal
745     if unsafe { val.data.pwszVal().is_null() } {
746         warn!("Win audio property store GetValue returned a null string");
747         return Err(RenderError::GenericError);
748     }
749     // Safe because `val` was populated by a successful GetValue call that returned a non-null
750     // null-terminated pwszVal
751     let device_name = unsafe { win_util::from_ptr_win32_wide_string(*val.data.pwszVal()) };
752     info!("Creating audio client: {}", device_name);
753     // Safe because `val` was populated by a successful GetValue call
754     unsafe {
755         // TODO(b/256244007): `PropVariantClear` doesn't get called if this function errors or
756         // returns early.
757         PropVariantClear(&mut val);
758     }
759 
760     Ok(())
761 }
762 
create_and_set_audio_client_event( audio_client: &IAudioClient, ex: &Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<(Event, Option<Box<dyn EventAsyncWrapper>>), RenderError>763 fn create_and_set_audio_client_event(
764     audio_client: &IAudioClient,
765     ex: &Option<&dyn audio_streams::AudioStreamsExecutor>,
766 ) -> Result<(Event, Option<Box<dyn EventAsyncWrapper>>), RenderError> {
767     let ready_event = Event::new_auto_reset().unwrap();
768     // Safe because `ready_event` will be initialized and also it will have the same
769     // lifetime as `audio_client` because they are owned by DeviceRenderer or DeviceCapturer on
770     // return.
771     let hr = unsafe { audio_client.SetEventHandle(ready_event.as_raw_descriptor()) };
772     check_hresult!(hr, RenderError::from(hr), "SetEventHandle() failed.")?;
773 
774     let async_ready_event = if let Some(ex) = ex {
775         // Unsafe if `ready_event` and `async_ready_event` have different
776         // lifetimes because both can close the underlying `RawDescriptor`. However, both
777         // will be stored in the `DeviceRenderer` or `DeviceCapturer` fields, so this should be
778         // safe.
779         Some(unsafe {
780             ex.async_event(ready_event.as_raw_descriptor())
781                 .map_err(|e| {
782                     RenderError::AsyncError(e, "Failed to create async event".to_string())
783                 })?
784         })
785     } else {
786         None
787     };
788     Ok((ready_event, async_ready_event))
789 }
790 
get_device_period_in_frames(audio_client: &IAudioClient, format: &WaveAudioFormat) -> usize791 fn get_device_period_in_frames(audio_client: &IAudioClient, format: &WaveAudioFormat) -> usize {
792     let mut shared_default_size_in_100nanoseconds: i64 = 0;
793     let mut exclusive_min: i64 = 0;
794     // Safe because `GetDevicePeriod` are taking in intialized valid i64's on the stack created above.
795     unsafe {
796         audio_client.GetDevicePeriod(
797             &mut shared_default_size_in_100nanoseconds,
798             &mut exclusive_min,
799         );
800     };
801 
802     format.get_shared_audio_engine_period_in_frames(shared_default_size_in_100nanoseconds as f64)
803 }
804 
check_endpoint_buffer_size( audio_client: &IAudioClient, shared_audio_engine_period_in_frames: usize, ) -> Result<u32, RenderError>805 fn check_endpoint_buffer_size(
806     audio_client: &IAudioClient,
807     shared_audio_engine_period_in_frames: usize,
808 ) -> Result<u32, RenderError> {
809     let mut audio_client_buffer_frame_count: u32 = 0;
810     // Safe because audio_client_buffer_frame_count is created above.
811     let hr = unsafe { audio_client.GetBufferSize(&mut audio_client_buffer_frame_count) };
812     check_hresult!(
813         hr,
814         RenderError::from(hr),
815         "Audio Client GetBufferSize() failed."
816     )?;
817 
818     if audio_client_buffer_frame_count < shared_audio_engine_period_in_frames as u32 {
819         warn!(
820             "The Windows audio engine period size in frames: {} /
821             is bigger than the Audio Client's buffer size in frames: {}",
822             shared_audio_engine_period_in_frames, audio_client_buffer_frame_count
823         );
824         return Err(RenderError::InvalidIncomingBufferSize);
825     }
826     Ok(audio_client_buffer_frame_count)
827 }
828 
829 // TODO(b/253509368): Rename error so it is more generic for rendering and capturing.
830 #[derive(Debug, ThisError)]
831 pub enum RenderError {
832     /// The audio device was unplugged or became unavailable.
833     #[error("win audio device invalidated")]
834     DeviceInvalidated,
835     /// A Windows API error occurred.
836     /// "unknown win audio error HResult: {}, error code: {}"
837     #[error("unknown win audio error HResult: {0}, error code: {1}")]
838     WindowsError(i32, Error),
839     #[error("buffer pointer is null")]
840     InvalidBuffer,
841     #[error("playback buffer error: {0}")]
842     PlaybackBuffer(PlaybackBufferError),
843     #[error("Incoming buffer size invalid")]
844     InvalidIncomingBufferSize,
845     #[error("Failed to wait for Activate Audio Event callback: {0}")]
846     ActivateAudioEventError(Error),
847     #[error("Failed to create Activate Audio Event: {0}")]
848     CreateActivateAudioEventError(Error),
849     #[error("Timed out waiting for Activate Audio Event callback.")]
850     ActivateAudioEventTimeoutError,
851     #[error("Something went wrong in windows audio.")]
852     GenericError,
853     #[error("Invalid guest channel count {0} is > than 2")]
854     InvalidChannelCount(usize),
855     #[error("Async related error: {0}: {1}")]
856     AsyncError(std::io::Error, String),
857     #[error("Ready to read async event was not set during win_audio initialization.")]
858     MissingEventAsync,
859     #[error("Failed to clone an event: {0}")]
860     CloneEvent(Error),
861 }
862 
863 impl From<i32> for RenderError {
from(winapi_error_code: i32) -> Self864     fn from(winapi_error_code: i32) -> Self {
865         match winapi_error_code {
866             AUDCLNT_E_DEVICE_INVALIDATED => Self::DeviceInvalidated,
867             _ => Self::WindowsError(winapi_error_code, Error::last()),
868         }
869     }
870 }
871 
872 // Unfortunately, Kokoro's VM tests will fail on `GetDefaultAudioEndpoint` most likely because there
873 // are no audio endpoints on the VMs running the test. These tests can be ran on a windows machine
874 // with an audio device though.
875 //
876 // Thus these test are ignored, but are good for local testing. To run, just use the command:
877 //
878 //   $: cargo test -p win_audio win_audio_impl::tests:: -- --ignored
879 //
880 // Also, if a STATUS_DLL_NOT_FOUND exception happens, this is because the r8brain.dll can't be
881 // be found. Just put it in the appropriate spot in the `target` directory.
882 #[cfg(test)]
883 mod tests {
884     use std::thread;
885 
886     use metrics::MetricEventType;
887     use once_cell::sync::Lazy;
888     use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
889     use winapi::shared::mmreg::WAVEFORMATEX;
890     use winapi::shared::mmreg::WAVEFORMATEXTENSIBLE;
891     use winapi::shared::mmreg::WAVE_FORMAT_EXTENSIBLE;
892     use winapi::shared::winerror::S_OK;
893 
894     use super::*;
895     // These tests needs to be ran serially because there is a chance that two different tests
896     // running on different threads could open the same event named
897     // ACTIVATE_AUDIO_INTERFACE_COMPLETION_EVENT.
898     // So the first test thread could trigger it correctly, but the second test thread could open
899     // the same triggered event even though the `ActivateAudioInterfaceAsync` operation hasn't
900     // completed, thus causing an error.
901     //
902     // TODO(b/217768491): Randomizing events should resolve the need for serialized tests.
903     static SERIALIZE_LOCK: Lazy<Mutex<()>> = Lazy::new(Mutex::default);
904 
905     struct SafeCoInit;
906     impl SafeCoInit {
new_coinitialize() -> Self907         fn new_coinitialize() -> Self {
908             unsafe {
909                 CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED);
910             }
911             SafeCoInit {}
912         }
913     }
914 
915     impl Drop for SafeCoInit {
drop(&mut self)916         fn drop(&mut self) {
917             unsafe {
918                 CoUninitialize();
919             }
920         }
921     }
922 
923     #[ignore]
924     #[test]
test_create_win_audio_renderer_no_co_initliazed()925     fn test_create_win_audio_renderer_no_co_initliazed() {
926         let _shared = SERIALIZE_LOCK.lock();
927         let win_audio_renderer = DeviceRenderer::new(2, 48000, 720, None);
928         assert!(win_audio_renderer.is_err());
929     }
930 
931     #[ignore]
932     #[test]
test_create_win_audio_renderer()933     fn test_create_win_audio_renderer() {
934         let _shared = SERIALIZE_LOCK.lock();
935         let _co_init = SafeCoInit::new_coinitialize();
936         let win_audio_renderer_result = DeviceRenderer::new(2, 48000, 480, None);
937         assert!(win_audio_renderer_result.is_ok());
938         let win_audio_renderer = win_audio_renderer_result.unwrap();
939         assert_eq!(
940             win_audio_renderer
941                 .audio_shared_format
942                 .shared_audio_engine_period_in_frames,
943             480
944         );
945     }
946 
947     #[ignore]
948     #[test]
test_create_playback_stream()949     fn test_create_playback_stream() {
950         let _shared = SERIALIZE_LOCK.lock();
951         let mut win_audio: WinAudio = WinAudio::new().unwrap();
952         let (_, mut stream_source) = win_audio
953             .new_playback_stream(2, SampleFormat::S16LE, 48000, 480)
954             .unwrap();
955         let playback_buffer = stream_source.next_playback_buffer().unwrap();
956 
957         assert_eq!(playback_buffer.frame_capacity(), 480);
958     }
959 
960     #[ignore]
961     #[test]
962     // If the guest buffer is too big, then
963     // there is no way to copy audio samples over succiently.
test_guest_buffer_size_bigger_than_audio_render_client_buffer_size()964     fn test_guest_buffer_size_bigger_than_audio_render_client_buffer_size() {
965         let _shared = SERIALIZE_LOCK.lock();
966         let win_audio_renderer = DeviceRenderer::new(2, 48000, 100000, None);
967 
968         assert!(win_audio_renderer.is_err());
969     }
970 
971     #[ignore]
972     #[test]
test_co_init_called_once_per_thread()973     fn test_co_init_called_once_per_thread() {
974         let _shared = SERIALIZE_LOCK.lock();
975         // Call co init in a background thread
976         let join_handle = thread::spawn(move || {
977             assert_eq!(WinAudio::co_init_once_per_thread(), S_OK);
978         });
979 
980         // Wait for thread to finish
981         join_handle
982             .join()
983             .expect("Thread calling co_init_once_per_thread panicked");
984 
985         // Call co init twice on the main thread.
986         assert_eq!(WinAudio::co_init_once_per_thread(), S_OK);
987         // Without thread local once_only this should fail
988         assert_eq!(WinAudio::co_init_once_per_thread(), S_SKIPPED_COINIT);
989         unsafe {
990             CoUninitialize();
991         }
992     }
993 
994     // Test may be flakey because other tests will be creating an AudioClient. Putting all tests
995     // in one so we can run this individually to prevent the flakiness. This test may fail
996     // depending on your selected default audio device.
997     #[ignore]
998     #[test]
test_check_format_get_mix_format_success()999     fn test_check_format_get_mix_format_success() {
1000         let _shared = SERIALIZE_LOCK.lock();
1001 
1002         let _co_init = SafeCoInit::new_coinitialize();
1003         let audio_client = create_audio_client(eRender).unwrap();
1004         let mut format_ptr: *mut WAVEFORMATEX = std::ptr::null_mut();
1005         let _hr = unsafe { audio_client.GetMixFormat(&mut format_ptr) };
1006 
1007         // Safe because `format_ptr` is not a null pointer, since it is set by `GetMixFormat`.
1008         let format = unsafe { WaveAudioFormat::new(format_ptr) };
1009 
1010         // Test format from `GetMixFormat`. This should ALWAYS be valid.
1011         assert!(check_format(
1012             &*audio_client,
1013             &format,
1014             WaveFormatDetailsProto::new(),
1015             MetricEventType::AudioFormatRequestOk,
1016         )
1017         .is_ok());
1018 
1019         let format = WAVEFORMATEXTENSIBLE {
1020             Format: WAVEFORMATEX {
1021                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
1022                 nChannels: 2,
1023                 nSamplesPerSec: 48000,
1024                 nAvgBytesPerSec: 8 * 48000,
1025                 nBlockAlign: 8,
1026                 wBitsPerSample: 32,
1027                 cbSize: 22,
1028             },
1029             Samples: 32,
1030             dwChannelMask: 3,
1031             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1032         };
1033 
1034         // Safe because `GetMixFormat` casts `WAVEFORMATEXTENSIBLE` into a `WAVEFORMATEX` like so.
1035         // Also this is casting from a bigger to a smaller struct, so it shouldn't be possible for
1036         // this contructor to access memory it shouldn't.
1037         let format = unsafe { WaveAudioFormat::new((&format) as *const _ as *mut WAVEFORMATEX) };
1038 
1039         // Test valid custom format.
1040         assert!(check_format(
1041             &*audio_client,
1042             &format,
1043             WaveFormatDetailsProto::new(),
1044             MetricEventType::AudioFormatRequestOk,
1045         )
1046         .is_ok());
1047 
1048         let format = WAVEFORMATEXTENSIBLE {
1049             Format: WAVEFORMATEX {
1050                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
1051                 nChannels: 2,
1052                 nSamplesPerSec: 48000,
1053                 nAvgBytesPerSec: 8 * 48000,
1054                 nBlockAlign: 8,
1055                 wBitsPerSample: 3, // This value will cause failure, since bitdepth of 3
1056                 // doesn't make sense
1057                 cbSize: 22,
1058             },
1059             Samples: 32,
1060             dwChannelMask: 3,
1061             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
1062         };
1063 
1064         // Safe because `GetMixFormat` casts `WAVEFORMATEXTENSIBLE` into a `WAVEFORMATEX` like so.
1065         // Also this is casting from a bigger to a smaller struct, so it shouldn't be possible for
1066         // this contructor to access memory it shouldn't.
1067         let format = unsafe { WaveAudioFormat::new((&format) as *const _ as *mut WAVEFORMATEX) };
1068 
1069         // Test invalid format
1070         assert!(check_format(
1071             &*audio_client,
1072             &format,
1073             WaveFormatDetailsProto::new(),
1074             MetricEventType::AudioFormatRequestOk,
1075         )
1076         .is_err());
1077     }
1078 }
1079