xref: /aosp_15_r20/external/crosvm/win_audio/src/win_audio_impl/mod.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 // TODO(b/301630330): Address comments from CL once this is sync'd with downstream.
6 
7 pub mod async_stream;
8 mod completion_handler;
9 mod device_notification;
10 mod wave_format;
11 
12 use std::convert::From;
13 use std::fmt::Debug;
14 use std::num::ParseIntError;
15 use std::os::raw::c_void;
16 use std::ptr::null_mut;
17 use std::sync::atomic::AtomicBool;
18 use std::sync::Arc;
19 use std::sync::Once;
20 use std::thread_local;
21 use std::time::Duration;
22 
23 use async_trait::async_trait;
24 use audio_streams::async_api::EventAsyncWrapper;
25 use audio_streams::capture::AsyncCaptureBuffer;
26 use audio_streams::capture::CaptureBufferError;
27 use audio_streams::capture::NoopCaptureStream;
28 use audio_streams::AsyncBufferCommit;
29 use audio_streams::AsyncPlaybackBuffer;
30 use audio_streams::AsyncPlaybackBufferStream;
31 use audio_streams::AudioStreamsExecutor;
32 use audio_streams::BoxError;
33 use audio_streams::BufferCommit;
34 use audio_streams::NoopStream;
35 use audio_streams::NoopStreamControl;
36 use audio_streams::PlaybackBuffer;
37 use audio_streams::PlaybackBufferError;
38 use audio_streams::PlaybackBufferStream;
39 use audio_streams::SampleFormat;
40 use audio_streams::StreamControl;
41 use audio_streams::StreamSource;
42 use base::error;
43 use base::info;
44 use base::warn;
45 use base::AsRawDescriptor;
46 use base::Error;
47 use base::Event;
48 use base::EventExt;
49 use base::EventWaitResult;
50 use base::IntoRawDescriptor;
51 use completion_handler::WinAudioActivateAudioInterfaceCompletionHandler;
52 use sync::Mutex;
53 use thiserror::Error as ThisError;
54 use wave_format::*;
55 use winapi::shared::guiddef::GUID;
56 use winapi::shared::guiddef::REFCLSID;
57 use winapi::um::audioclient::*;
58 use winapi::um::audiosessiontypes::AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED;
59 use winapi::um::audiosessiontypes::AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED;
60 use winapi::um::audiosessiontypes::AUDCLNT_SHAREMODE_SHARED;
61 use winapi::um::audiosessiontypes::AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
62 use winapi::um::combaseapi::*;
63 use winapi::um::coml2api::STGM_READ;
64 use winapi::um::functiondiscoverykeys_devpkey::PKEY_Device_FriendlyName;
65 use winapi::um::mmdeviceapi::*;
66 use winapi::um::objbase::COINIT_APARTMENTTHREADED;
67 use winapi::um::propidl::PropVariantClear;
68 use winapi::um::propidl::PROPVARIANT;
69 use winapi::um::propsys::IPropertyStore;
70 use winapi::um::synchapi::WaitForSingleObject;
71 use winapi::um::unknwnbase::IUnknown;
72 use winapi::um::winbase::WAIT_OBJECT_0;
73 use winapi::Interface;
74 use wio::com::ComPtr;
75 
76 use crate::async_stream::log_init_error_with_limit;
77 use crate::async_stream::log_playback_error_with_limit;
78 use crate::intermediate_resampler_buffer::CaptureResamplerBuffer;
79 use crate::intermediate_resampler_buffer::PlaybackResamplerBuffer;
80 use crate::win_audio_impl::device_notification::WinIMMNotificationClient;
81 use crate::AudioSharedFormat;
82 use crate::ANDROID_CAPTURE_FRAME_SIZE_BYTES;
83 use crate::BYTES_PER_32FLOAT;
84 
85 const READY_TO_READ_TIMEOUT_MS: u32 = 2000;
86 pub const STEREO_CHANNEL_COUNT: u16 = 2;
87 pub const MONO_CHANNEL_COUNT: u16 = 1;
88 
89 // from msdn: https://docs.microsoft.com/en-us/windows/win32/coreaudio/audclnt-streamflags-xxx-constants
90 // these don't currently exist in winapi
91 const AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM: u32 = 0x80000000;
92 const AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY: u32 = 0x08000000;
93 
94 thread_local!(static THREAD_ONCE_INIT: Once = const { Once::new() });
95 
96 // Used to differentiate between S_FALSE and S_OK. This means `CoInitializeEx` did not get called.
97 // Mainly used for testing.
98 const S_SKIPPED_COINIT: i32 = 2;
99 
100 const ACTIVATE_AUDIO_EVENT_TIMEOUT: Duration = Duration::from_secs(5);
101 
102 pub struct WinAudio {
103     pub cached_playback_buffer_stream:
104         Option<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat)>,
105 }
106 impl WinAudio {
new() -> Result<Self, BoxError>107     pub fn new() -> Result<Self, BoxError> {
108         Ok(WinAudio {
109             cached_playback_buffer_stream: None,
110         })
111     }
112 
co_init_once_per_thread() -> i32113     pub(crate) fn co_init_once_per_thread() -> i32 {
114         let mut hr = S_SKIPPED_COINIT;
115         THREAD_ONCE_INIT.with(|once| {
116             once.call_once(|| {
117                 // SAFETY: All variables passed into `CoInitializeEx` are hardcoded
118                 unsafe {
119                     // Initializes the COM library for use by the calling thread. Needed so that
120                     // `CoCreateInstance` can be called to create a device
121                     // enumerator object.
122                     //
123                     // TODO(b/217413370): `CoUninitialize` is never called at any point in KiwiVm.
124                     // It might make sense for all VCPU threads to call `CoInitializeEx` when
125                     // starting and `CoUninitialize` when the thread ends. However when switching to
126                     // virtio-snd, we need to make sure cros_async threads get `Co(Un)Initialize`
127                     // support if needed.
128                     hr = CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED);
129                 };
130             })
131         });
132 
133         hr
134     }
135 }
136 
137 impl StreamSource for WinAudio {
138     /// Returns a stream control and a buffer generator object. The stream control object is not
139     /// used. The buffer generator object is a wrapper around WASAPI's objects that will create a
140     /// 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>141     fn new_playback_stream(
142         &mut self,
143         num_channels: usize,
144         format: SampleFormat,
145         frame_rate: u32,
146         buffer_size: usize, //number of frames;
147     ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError> {
148         let hr = WinAudio::co_init_once_per_thread();
149         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
150 
151         let playback_buffer_stream: Box<dyn PlaybackBufferStream> =
152             match WinAudioRenderer::new(num_channels, format, frame_rate, buffer_size) {
153                 Ok(renderer) => Box::new(renderer),
154                 Err(e) => {
155                     warn!(
156                         "Failed to create WinAudioRenderer. Fallback to NoopStream with error: {}",
157                         e
158                     );
159                     Box::new(NoopStream::new(
160                         num_channels,
161                         SampleFormat::S16LE,
162                         frame_rate,
163                         buffer_size,
164                     ))
165                 }
166             };
167 
168         Ok((Box::new(NoopStreamControl::new()), playback_buffer_stream))
169     }
170 
171     /// Similar to `new_playback_stream, but will return an `AsyncPlaybackBufferStream` that can
172     /// run async operations.
new_async_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ex: &dyn AudioStreamsExecutor, ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError>173     fn new_async_playback_stream(
174         &mut self,
175         num_channels: usize,
176         format: SampleFormat,
177         frame_rate: u32,
178         buffer_size: usize,
179         ex: &dyn AudioStreamsExecutor,
180     ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError> {
181         WinAudio::new_async_playback_stream_helper(
182             num_channels,
183             format,
184             frame_rate,
185             buffer_size,
186             ex,
187         )
188     }
189 }
190 
191 /// Proxy for a `DeviceRenderer` that handles device invalidated errors by switching to a new
192 /// `DeviceRenderer` on a new device.
193 pub(crate) struct WinAudioRenderer {
194     pub device: DeviceRendererWrapper,
195     audio_client_guid: Option<String>,
196 }
197 
198 impl WinAudioRenderer {
199     /// Initializes WASAPI objects needed for audio. Only used for the Ac97 device.
new( num_channels: usize, format: SampleFormat, frame_rate: u32, incoming_buffer_size_in_frames: usize, ) -> Result<Self, RenderError>200     pub fn new(
201         num_channels: usize,
202         format: SampleFormat,
203         frame_rate: u32,
204         incoming_buffer_size_in_frames: usize,
205     ) -> Result<Self, RenderError> {
206         let device = DeviceRendererWrapper::new(
207             num_channels,
208             format,
209             frame_rate,
210             incoming_buffer_size_in_frames,
211             None,
212             None,
213         )?;
214         Ok(Self {
215             device,
216             audio_client_guid: None,
217         })
218     }
219 
handle_playback_logging_on_error(e: &RenderError)220     fn handle_playback_logging_on_error(e: &RenderError) {
221         match &e {
222             RenderError::WinAudioError(win_audio_error) => {
223                 log_playback_error_with_limit(win_audio_error.into());
224                 match win_audio_error {
225                     WinAudioError::GetCurrentPaddingError(hr)
226                     | WinAudioError::GetBufferError(hr) => {
227                         if *hr == AUDCLNT_E_DEVICE_INVALIDATED {
228                             info!(
229                                 "Recieved AUDLNT_E_DEVICE_INVALIDATED error. No devices \
230                              attached, so will start listening for one."
231                             );
232                         } else {
233                             warn!(
234                                 "Unknown HResult: {} from GetCurrentPadding or GetBufferError. \
235                              Will still start listening for a new device",
236                                 hr
237                             );
238                         }
239                     }
240                     _ => warn!(
241                         "Unexpected errors. Will still listen for a new device: {}",
242                         win_audio_error
243                     ),
244                 }
245             }
246             _ => {
247                 log_playback_error_with_limit((&WinAudioError::Unknown).into());
248                 warn!(
249                     "Unexpected non WinAudioError. Will stil start listening for a new device: {}",
250                     e
251                 );
252             }
253         }
254     }
255 
256     /// Get the audio format used by the endpoint buffer, whether it be the `NoopStream` buffer
257     /// or the WASAPI endpoint buffer.
get_audio_shared_format(&self) -> AudioSharedFormat258     pub(crate) fn get_audio_shared_format(&self) -> AudioSharedFormat {
259         match &self.device.renderer_stream {
260             RendererStream::Device((device_renderer, _)) => device_renderer.audio_shared_format,
261             RendererStream::Noop(_) => AudioSharedFormat {
262                 bit_depth: 32,
263                 frame_rate: self.device.guest_frame_rate as usize,
264                 channels: self.device.num_channels,
265                 shared_audio_engine_period_in_frames: self.device.incoming_buffer_size_in_frames,
266                 channel_mask: None,
267             },
268         }
269     }
270 }
271 
272 /// This is only used by the Ac97 device, so this impl is deprecated.
273 impl PlaybackBufferStream for WinAudioRenderer {
274     /// Returns a wrapper around the WASAPI buffer.
next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError>275     fn next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError> {
276         match &mut self.device.renderer_stream {
277             RendererStream::Device((device_renderer, _)) => {
278                 match device_renderer.next_win_buffer() {
279                     Ok(_) => {
280                         return device_renderer
281                             .playback_buffer()
282                             .map_err(|e| Box::new(e) as _)
283                     }
284                     Err(e) => Err(Box::new(e)),
285                 }
286             }
287             RendererStream::Noop(_) => {
288                 error!("Unable to attach to a working audio device, giving up");
289                 Err(Box::new(WinAudioError::DeviceInvalidated))
290             }
291         }
292     }
293 }
294 
295 /// Used to help listen for device related events.
296 struct DeviceNotifier {
297     // Used to register the `IMMNotificationClient`.
298     device_enumerator: ComPtr<IMMDeviceEnumerator>,
299     // Used to help detect when a new audio device has been attached.
300     imm_notification_client: ComPtr<IMMNotificationClient>,
301 }
302 
303 impl DeviceNotifier {
304     /// Create the notification client that will listen to audio device events.
create_imm_device_notification( is_device_available: Arc<AtomicBool>, dataflow: EDataFlow, ) -> Result<Self, WinAudioError>305     pub(crate) fn create_imm_device_notification(
306         is_device_available: Arc<AtomicBool>,
307         dataflow: EDataFlow,
308     ) -> Result<Self, WinAudioError> {
309         let mut device_enumerator: *mut c_void = null_mut();
310 
311         // Creates a device enumerator in order to select our default audio device.
312         //
313         // SAFETY: Only `device_enumerator` is being modified and we own it.
314         let hr = unsafe {
315             CoCreateInstance(
316                 &CLSID_MMDeviceEnumerator as REFCLSID,
317                 null_mut(),
318                 CLSCTX_ALL,
319                 &IMMDeviceEnumerator::uuidof(),
320                 &mut device_enumerator,
321             )
322         };
323 
324         check_hresult!(
325             hr,
326             WinAudioError::GetDeviceEnumeratorError(hr),
327             "Win audio create client CoCreateInstance() failed when trying to set up the \
328              IMMNotificationClient."
329         )?;
330 
331         let device_enumerator =
332             // SAFETY: We know `device_enumerator` is a valid pointer, otherwise, we would've
333             // returned with an error earlier.
334             unsafe { ComPtr::from_raw(device_enumerator as *mut IMMDeviceEnumerator) };
335 
336         let imm_notification_client =
337             WinIMMNotificationClient::create_com_ptr(is_device_available, dataflow);
338 
339         // SAFETY: The creation of `imm_notification_client` is always valid.
340         let hr = unsafe {
341             device_enumerator.RegisterEndpointNotificationCallback(imm_notification_client.as_raw())
342         };
343         check_hresult!(
344             hr,
345             WinAudioError::RegisterEndpointNotifError(hr),
346             "Win audio errored on RegisterEndpointNotificationCallback."
347         )?;
348 
349         Ok(DeviceNotifier {
350             device_enumerator,
351             imm_notification_client,
352         })
353     }
354 }
355 
356 impl Drop for DeviceNotifier {
357     // `device_enumerator` and `imm_notification_client` will call `Release` when they are dropped
358     // since they are `ComPtr`s.
drop(&mut self)359     fn drop(&mut self) {
360         // SAFETY: The `notification_client` is a valid `IMMNotificationClient`.
361         unsafe {
362             self.device_enumerator
363                 .UnregisterEndpointNotificationCallback(self.imm_notification_client.as_raw());
364         }
365     }
366 }
367 
368 pub(crate) struct NoopRenderer {
369     // Playback stream that helps with sleeping in the playback loop when no devices are available.
370     // Audio bytes coming from the guest will be dropped.
371     noop_stream: NoopStream,
372     // Help listen for device related events, so that a new audio device can be detected.
373     _device_notifier: DeviceNotifier,
374     // True if a new device is available.
375     is_device_available: Arc<AtomicBool>,
376 }
377 
378 pub(crate) enum RendererStream {
379     Device(
380         (
381             DeviceRenderer,
382             // Buffer that contains a sample rate converter and also helps with managing differing
383             // periods between the guest and the host.
384             PlaybackResamplerBuffer,
385         ),
386     ),
387     Noop(NoopRenderer),
388 }
389 
390 /// Wraps the `DeviceRenderer` and `NoopStream` so that they can easily be interchanged in the
391 /// middle of audio playback. This also contains fields that helps with creating the aforementioned
392 /// objects and helps with detecting a new audio device being connected.
393 pub(crate) struct DeviceRendererWrapper {
394     // Helps manage a playback stream.
395     pub(crate) renderer_stream: RendererStream,
396     // Buffer sent to the CrosVm audio device (ie. Virtio Sound) for it to write to.
397     intermediate_buffer: Vec<u8>,
398     // guest channel count.
399     num_channels: usize,
400     // guest bit depth.
401     guest_bit_depth: SampleFormat,
402     // guest frame rate.
403     guest_frame_rate: u32,
404     // incoming buffer size from the guest per period.
405     incoming_buffer_size_in_frames: usize,
406 }
407 
408 impl DeviceRendererWrapper {
409     /// If no audio device are detected, then the creation of `DeviceRenderer` will fail. In this
410     /// case, a `NoopStream` will be created as well as the set up of the `IMMNotificationClient`.
new( num_channels: usize, guest_bit_depth: SampleFormat, guest_frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: Option<&dyn AudioStreamsExecutor>, audio_client_guid: Option<String>, ) -> Result<Self, RenderError>411     fn new(
412         num_channels: usize,
413         guest_bit_depth: SampleFormat,
414         guest_frame_rate: u32,
415         incoming_buffer_size_in_frames: usize,
416         ex: Option<&dyn AudioStreamsExecutor>,
417         audio_client_guid: Option<String>,
418     ) -> Result<Self, RenderError> {
419         let renderer_stream = match Self::create_device_renderer_and_log_time(
420             num_channels,
421             guest_frame_rate,
422             incoming_buffer_size_in_frames,
423             ex,
424             audio_client_guid,
425         ) {
426             Ok(device) => {
427                 let audio_shared_format = device.audio_shared_format;
428                 let playback_resampler_buffer = PlaybackResamplerBuffer::new(
429                     guest_frame_rate as usize,
430                     audio_shared_format.frame_rate,
431                     incoming_buffer_size_in_frames,
432                     audio_shared_format.shared_audio_engine_period_in_frames,
433                     audio_shared_format.channels,
434                     audio_shared_format.channel_mask,
435                 )
436                 .expect("Failed to create PlaybackResamplerBuffer");
437 
438                 RendererStream::Device((device, playback_resampler_buffer))
439             }
440 
441             Err(e) => {
442                 Self::handle_init_logging_on_error(&e);
443                 Self::create_noop_stream_with_device_notification(
444                     num_channels,
445                     guest_frame_rate,
446                     incoming_buffer_size_in_frames,
447                 )?
448             }
449         };
450 
451         Ok(Self {
452             renderer_stream,
453             intermediate_buffer: vec![
454                 0;
455                 incoming_buffer_size_in_frames
456                     * num_channels
457                     * guest_bit_depth.sample_bytes()
458             ],
459             num_channels,
460             guest_bit_depth,
461             guest_frame_rate,
462             incoming_buffer_size_in_frames,
463         })
464     }
465 
handle_init_logging_on_error(e: &RenderError)466     fn handle_init_logging_on_error(e: &RenderError) {
467         match &e {
468             RenderError::WinAudioError(win_audio_error) => {
469                 match win_audio_error {
470                     WinAudioError::MissingDeviceError(_) => {
471                         info!(
472                             "No audio playback devices were found. Will start listening for new \
473                          devices"
474                         );
475                     }
476                     _ => {
477                         warn!(
478                             "Unexpected WinAudioError on initialization. Will still listen for \
479                         new devices: {}",
480                             e
481                         );
482                     }
483                 }
484                 log_init_error_with_limit(win_audio_error.into());
485             }
486             _ => {
487                 log_init_error_with_limit((&WinAudioError::Unknown).into());
488                 error!(
489                     "Unhandled NoopStream forced error. These errors should not have been \
490                  returned. WIll still listen for new devices: {}",
491                     e
492                 );
493             }
494         }
495     }
496 
create_noop_stream_with_device_notification( num_channels: usize, guest_frame_rate: u32, incoming_buffer_size_in_frames: usize, ) -> Result<RendererStream, RenderError>497     fn create_noop_stream_with_device_notification(
498         num_channels: usize,
499         guest_frame_rate: u32,
500         incoming_buffer_size_in_frames: usize,
501     ) -> Result<RendererStream, RenderError> {
502         let is_device_available = Arc::new(AtomicBool::new(false));
503         let noop_renderer = NoopRenderer {
504             noop_stream: NoopStream::new(
505                 num_channels,
506                 SampleFormat::S32LE,
507                 guest_frame_rate,
508                 incoming_buffer_size_in_frames,
509             ),
510             _device_notifier: DeviceNotifier::create_imm_device_notification(
511                 is_device_available.clone(),
512                 eRender,
513             )
514             .map_err(RenderError::WinAudioError)?,
515             is_device_available,
516         };
517 
518         Ok(RendererStream::Noop(noop_renderer))
519     }
520 
create_device_renderer_and_log_time( num_channels: usize, frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: Option<&dyn AudioStreamsExecutor>, audio_client_guid: Option<String>, ) -> Result<DeviceRenderer, RenderError>521     fn create_device_renderer_and_log_time(
522         num_channels: usize,
523         frame_rate: u32,
524         incoming_buffer_size_in_frames: usize,
525         ex: Option<&dyn AudioStreamsExecutor>,
526         audio_client_guid: Option<String>,
527     ) -> Result<DeviceRenderer, RenderError> {
528         let start = std::time::Instant::now();
529         let device = DeviceRenderer::new(
530             num_channels,
531             frame_rate,
532             incoming_buffer_size_in_frames,
533             ex,
534             audio_client_guid,
535         )?;
536         // This can give us insights to how other long other machines take to initialize audio.
537         // Eventually this should be a histogram metric.
538         info!(
539             "DeviceRenderer took {}ms to initialize audio.",
540             start.elapsed().as_millis()
541         );
542         Ok(device)
543     }
544 
get_intermediate_async_buffer(&mut self) -> Result<AsyncPlaybackBuffer, RenderError>545     fn get_intermediate_async_buffer(&mut self) -> Result<AsyncPlaybackBuffer, RenderError> {
546         let guest_frame_size = self.num_channels * self.guest_bit_depth.sample_bytes();
547         // SAFETY: `intermediate_buffer` doesn't get mutated by `Self` after this slice is
548         // created.
549         let slice = unsafe {
550             std::slice::from_raw_parts_mut(
551                 self.intermediate_buffer.as_mut_ptr(),
552                 self.intermediate_buffer.len(),
553             )
554         };
555         AsyncPlaybackBuffer::new(guest_frame_size, slice, self).map_err(RenderError::PlaybackBuffer)
556     }
557 }
558 
559 // SAFETY: DeviceRendererWrapper is safe to send between threads
560 unsafe impl Send for DeviceRendererWrapper {}
561 
562 // Implementation of buffer generator object. Used to get a buffer from WASAPI for crosvm to copy
563 // audio bytes from the guest memory into.
564 pub(crate) struct DeviceRenderer {
565     audio_render_client: ComPtr<IAudioRenderClient>,
566     audio_client: ComPtr<IAudioClient>,
567     win_buffer: *mut u8,
568     pub audio_shared_format: AudioSharedFormat,
569     audio_render_client_buffer_frame_count: u32,
570     ready_to_read_event: Event,
571     async_ready_to_read_event: Option<Box<dyn EventAsyncWrapper>>,
572     // Set to true if we should call WASAPI's `GetBuffer`. This should be false if there aren't
573     // enough bytes in `playback_resampler_buffer` to write a full Windows endpoint buffer period.
574     should_get_next_win_buffer: bool,
575 }
576 
577 impl DeviceRenderer {
578     // Initializes WASAPI objects needed for audio
new( num_channels: usize, guest_frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: Option<&dyn AudioStreamsExecutor>, audio_client_guid: Option<String>, ) -> Result<Self, RenderError>579     fn new(
580         num_channels: usize,
581         guest_frame_rate: u32,
582         incoming_buffer_size_in_frames: usize,
583         ex: Option<&dyn AudioStreamsExecutor>,
584         audio_client_guid: Option<String>,
585     ) -> Result<Self, RenderError> {
586         if num_channels > 2 {
587             return Err(RenderError::WinAudioError(
588                 WinAudioError::InvalidChannelCount(num_channels),
589             ));
590         }
591 
592         info!("Render guest frame rate: {}", guest_frame_rate);
593 
594         let audio_client = create_audio_client(eRender).map_err(RenderError::WinAudioError)?;
595 
596         let format = get_valid_mix_format(&audio_client).map_err(RenderError::WinAudioError)?;
597 
598         let res = if let Some(audio_client_guid) = audio_client_guid {
599             info!(
600                 "IAudioClient initializing with GUID: {:?}",
601                 audio_client_guid
602             );
603             Some(Self::convert_session_string_to_guid(audio_client_guid)?)
604         } else {
605             None
606         };
607 
608         // SAFETY: `audio_client` is initialized
609         let hr = unsafe {
610             // Intializes the audio client by setting the buffer size in 100-nanoseconds and
611             // specifying the format the audio bytes will be passed in as.
612             // Setting `hnsBufferDuration` (in miilisecond units) to 0 will let the audio engine to
613             // pick the size that will minimize latency.
614             // `hnsPeriodicity` sets the device period and should always be 0 for shared mode.
615             audio_client.Initialize(
616                 AUDCLNT_SHAREMODE_SHARED,
617                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
618                     | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
619                     | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
620                     | AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
621                     | AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED,
622                 0, /* hnsBufferDuration */
623                 0, /* hnsPeriodicity */
624                 format.as_ptr(),
625                 match res {
626                     Some(guid) => &guid as *const GUID,
627                     None => null_mut(),
628                 },
629             )
630         };
631         check_hresult!(
632             hr,
633             WinAudioError::AudioClientInitializationError(hr),
634             "Audio Client Initialize() failed."
635         )
636         .map_err(RenderError::WinAudioError)?;
637 
638         let (ready_to_read_event, async_ready_to_read_event) =
639             create_and_set_audio_client_event(&audio_client, &ex)
640                 .map_err(RenderError::WinAudioError)?;
641 
642         let audio_render_client = DeviceRenderer::create_audio_render_client(&audio_client)?;
643 
644         let shared_audio_engine_period_in_frames =
645             get_device_period_in_frames(&audio_client, &format);
646 
647         let audio_render_client_buffer_frame_count =
648             check_endpoint_buffer_size(&audio_client, shared_audio_engine_period_in_frames)
649                 .map_err(RenderError::WinAudioError)?;
650         if incoming_buffer_size_in_frames % shared_audio_engine_period_in_frames != 0 {
651             warn!(
652                 "Rendering: Guest period size: `{}` not divisible by shared audio engine period size: `{}`. \
653                  Audio glitches may occur if sample rate conversion isn't on.",
654                 incoming_buffer_size_in_frames, shared_audio_engine_period_in_frames
655             );
656         }
657 
658         // SAFETY: `audio_client` is initialized
659         let hr = unsafe {
660             // Starts the audio stream for playback
661             audio_client.Start()
662         };
663         check_hresult!(
664             hr,
665             WinAudioError::AudioClientStartError(hr),
666             "Audio Render Client Start() failed."
667         )
668         .map_err(RenderError::WinAudioError)?;
669 
670         let audio_shared_format =
671             format.create_audio_shared_format(shared_audio_engine_period_in_frames);
672         Ok(Self {
673             audio_render_client,
674             audio_client,
675             win_buffer: std::ptr::null_mut(),
676             audio_shared_format,
677             audio_render_client_buffer_frame_count,
678             ready_to_read_event,
679             async_ready_to_read_event,
680             should_get_next_win_buffer: true,
681         })
682     }
683 
create_audio_render_client( audio_client: &IAudioClient, ) -> Result<ComPtr<IAudioRenderClient>, RenderError>684     fn create_audio_render_client(
685         audio_client: &IAudioClient,
686     ) -> Result<ComPtr<IAudioRenderClient>, RenderError> {
687         let mut audio_render_client: *mut c_void = null_mut();
688 
689         // SAFETY: `audio_client` is initialized
690         let hr = unsafe {
691             audio_client.GetService(
692                 &IID_IAudioRenderClient as *const GUID,
693                 &mut audio_render_client,
694             )
695         };
696         check_hresult!(
697             hr,
698             WinAudioError::GetRenderClientError(hr),
699             "Audio Client GetService() failed."
700         )
701         .map_err(RenderError::WinAudioError)?;
702 
703         // SAFETY: `audio_render_client` is guaranteed to be initialized
704         unsafe {
705             Ok(ComPtr::from_raw(
706                 audio_render_client as *mut IAudioRenderClient,
707             ))
708         }
709     }
710 
711     // Returns a wraper around the WASAPI buffer
next_win_buffer(&mut self) -> Result<(), RenderError>712     fn next_win_buffer(&mut self) -> Result<(), RenderError> {
713         // We will wait for windows to tell us when it is ready to take in the next set of
714         // audio samples from the guest
715         loop {
716             // SAFETY: `ready_to_read_event` is guaranteed to be properly initialized
717             // and `num_frames_padding` is property initliazed as an empty pointer.
718             unsafe {
719                 let res = WaitForSingleObject(
720                     self.ready_to_read_event.as_raw_descriptor(),
721                     READY_TO_READ_TIMEOUT_MS,
722                 );
723                 if res != WAIT_OBJECT_0 {
724                     warn!(
725                         "Waiting for ready_to_read_event timed out after {} ms",
726                         READY_TO_READ_TIMEOUT_MS
727                     );
728                     break;
729                 }
730                 if self.enough_available_frames()? {
731                     break;
732                 }
733             }
734         }
735 
736         self.get_buffer()?;
737 
738         Ok(())
739     }
740 
741     /// Returns true if the number of frames avaialble in the Windows playback buffer is at least
742     /// the size of one full period worth of audio samples.
enough_available_frames(&mut self) -> Result<bool, RenderError>743     fn enough_available_frames(&mut self) -> Result<bool, RenderError> {
744         let mut num_frames_padding = 0u32;
745         // SAFETY: `num_frames_padding` is an u32 and `GetCurrentPadding` is a simple
746         // Windows function that shouldn't fail.
747         let hr = unsafe { self.audio_client.GetCurrentPadding(&mut num_frames_padding) };
748         check_hresult!(
749             hr,
750             WinAudioError::GetCurrentPaddingError(hr),
751             "Audio Client GetCurrentPadding() failed."
752         )
753         .map_err(RenderError::WinAudioError)?;
754 
755         // If the available free frames is less than the frames that are being sent over from the
756         // guest, then we want to only grab the number of frames available.
757         let num_frames_available =
758             (self.audio_render_client_buffer_frame_count - num_frames_padding) as usize;
759 
760         Ok(num_frames_available
761             >= self
762                 .audio_shared_format
763                 .shared_audio_engine_period_in_frames)
764     }
765 
get_buffer(&mut self) -> Result<(), RenderError>766     fn get_buffer(&mut self) -> Result<(), RenderError> {
767         self.win_buffer = std::ptr::null_mut();
768 
769         // This unsafe block will get the playback buffer and return the size of the buffer
770         //
771         // SAFETY:
772         // This is safe because the contents of `win_buffer` will be
773         // released when `ReleaseBuffer` is called in the `BufferCommit` implementation.
774         unsafe {
775             let hr = self.audio_render_client.GetBuffer(
776                 self.audio_shared_format
777                     .shared_audio_engine_period_in_frames as u32,
778                 &mut self.win_buffer,
779             );
780             check_hresult!(
781                 hr,
782                 WinAudioError::GetBufferError(hr),
783                 "Audio Render Client GetBuffer failed."
784             )
785             .map_err(RenderError::WinAudioError)?;
786         }
787 
788         Ok(())
789     }
790 
playback_buffer(&mut self) -> Result<PlaybackBuffer, RenderError>791     fn playback_buffer(&mut self) -> Result<PlaybackBuffer, RenderError> {
792         // SAFETY: `win_buffer` is allocated and retrieved from WASAPI. The size requested,
793         // which we specified in `next_win_buffer` is exactly
794         // `shared_audio_engine_period_in_frames`, so the size parameter should be valid.
795         let (frame_size_bytes, buffer_slice) = unsafe {
796             Self::get_frame_size_and_buffer_slice(
797                 self.audio_shared_format.bit_depth,
798                 self.audio_shared_format.channels,
799                 self.win_buffer,
800                 self.audio_shared_format
801                     .shared_audio_engine_period_in_frames,
802             )?
803         };
804 
805         PlaybackBuffer::new(frame_size_bytes, buffer_slice, self)
806             .map_err(RenderError::PlaybackBuffer)
807     }
808 
809     /// # Safety
810     ///
811     /// Safe only if:
812     ///   1. `win_buffer` is pointing to a valid buffer used for holding audio bytes.
813     ///   2. `bit_depth`, `channels`, and `shared_audio_engine_period_in_frames` are accurate with
814     ///      respect to `win_buffer`, so that a valid slice can be made.
815     ///   3. The variables mentioned in reason "2." must calculate a size no greater than the size
816     ///      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>817     unsafe fn get_frame_size_and_buffer_slice<'a>(
818         bit_depth: usize,
819         channels: usize,
820         win_buffer: *mut u8,
821         shared_audio_engine_period_in_frames: usize,
822     ) -> Result<(usize, &'a mut [u8]), RenderError> {
823         if win_buffer.is_null() {
824             return Err(RenderError::InvalidBuffer);
825         }
826 
827         let frame_size_bytes = bit_depth * channels / 8;
828 
829         Ok((
830             frame_size_bytes,
831             std::slice::from_raw_parts_mut(
832                 win_buffer,
833                 shared_audio_engine_period_in_frames * frame_size_bytes,
834             ),
835         ))
836     }
837 
convert_session_string_to_guid(audio_client_guid: String) -> Result<GUID, RenderError>838     fn convert_session_string_to_guid(audio_client_guid: String) -> Result<GUID, RenderError> {
839         let split_guid: Vec<&str> = audio_client_guid.split('-').collect();
840         if split_guid.len() != 5 {
841             return Err(RenderError::WinAudioError(
842                 WinAudioError::GuidSplitWrongSize(split_guid.len()),
843             ));
844         }
845 
846         let first = u32::from_str_radix(split_guid[0], 16)
847             .map_err(|e| RenderError::WinAudioError(WinAudioError::GuidParseIntError(e)))?;
848         let second = u16::from_str_radix(split_guid[1], 16)
849             .map_err(|e| RenderError::WinAudioError(WinAudioError::GuidParseIntError(e)))?;
850         let third = u16::from_str_radix(split_guid[2], 16)
851             .map_err(|e| RenderError::WinAudioError(WinAudioError::GuidParseIntError(e)))?;
852 
853         let combined = split_guid[3].to_owned() + split_guid[4];
854         let fourth_vec: Vec<String> = combined
855             .chars()
856             .collect::<Vec<char>>()
857             .chunks(2)
858             .map(|chunk| chunk.iter().collect())
859             .collect();
860         let fourth: Vec<u8> = fourth_vec
861             .into_iter()
862             .map(|byte_str| {
863                 u8::from_str_radix(&byte_str, 16)
864                     .map_err(|e| RenderError::WinAudioError(WinAudioError::GuidParseIntError(e)))
865             })
866             .collect::<Result<Vec<u8>, RenderError>>()?;
867 
868         Ok(GUID {
869             Data1: first,
870             Data2: second,
871             Data3: third,
872             Data4: fourth
873                 .try_into()
874                 .map_err(|_| RenderError::WinAudioError(WinAudioError::GuidVecConversionError))?,
875         })
876     }
877 }
878 
879 impl BufferCommit for DeviceRenderer {
880     // Called after buffer from WASAPI is filled. This will allow the audio bytes to be played as
881     // sound.
commit(&mut self, nframes: usize)882     fn commit(&mut self, nframes: usize) {
883         // SAFETY: `audio_render_client` is initialized and parameters passed
884         // into `ReleaseBuffer()` are valid
885         unsafe {
886             let hr = self.audio_render_client.ReleaseBuffer(nframes as u32, 0);
887             let _ = check_hresult!(
888                 hr,
889                 WinAudioError::from(hr),
890                 "Audio Render Client ReleaseBuffer() failed"
891             );
892         }
893     }
894 }
895 
896 impl Drop for DeviceRenderer {
drop(&mut self)897     fn drop(&mut self) {
898         // SAFETY:
899         // audio_client and audio_render_client will be released by ComPtr when dropped. Most likely
900         // safe to Release() if audio_client fails to stop. The MSDN doc does not mention that it
901         // will crash and this should be done anyways to prevent memory leaks
902         unsafe {
903             let hr = self.audio_client.Stop();
904             let _ = check_hresult!(
905                 hr,
906                 WinAudioError::from(hr),
907                 "Audio Render Client Stop() failed."
908             );
909         }
910     }
911 }
912 
913 // SAFETY: DeviceRenderer is safe to send between threads
914 unsafe impl Send for DeviceRenderer {}
915 
916 pub(crate) struct WinAudioCapturer {
917     pub device: DeviceCapturerWrapper,
918 }
919 
920 impl WinAudioCapturer {
get_audio_shared_format(&self) -> AudioSharedFormat921     pub(crate) fn get_audio_shared_format(&self) -> AudioSharedFormat {
922         match &self.device.capturer_stream {
923             CapturerStream::Device((device_capturer, _, _)) => device_capturer.audio_shared_format,
924             CapturerStream::Noop(_) => AudioSharedFormat {
925                 bit_depth: 16,
926                 frame_rate: self.device.guest_frame_rate as usize,
927                 channels: self.device.num_channels,
928                 shared_audio_engine_period_in_frames: self.device.guest_frame_rate as usize / 100,
929                 channel_mask: None,
930             },
931         }
932     }
933 }
934 
935 pub(crate) struct NoopBufferCommit;
936 
937 #[async_trait(?Send)]
938 impl AsyncBufferCommit for NoopBufferCommit {
939     // For capture, we don't need to `commit`, hence we no-op
commit(&mut self, _nframes: usize)940     async fn commit(&mut self, _nframes: usize) {
941         // No-op
942     }
943 }
944 
945 pub(crate) struct NoopCapturer {
946     // Capture stream that helps with sleeping in the capture loop when no devices are available.
947     // This will send 0's to the guest.
948     noop_capture_stream: NoopCaptureStream,
949     // Help listen for device related events, so that a new audio device can be detected.
950     _device_notifier: DeviceNotifier,
951     // True if a new device is available.
952     is_device_available: Arc<AtomicBool>,
953 }
954 
955 pub(crate) enum CapturerStream {
956     Device(
957         (
958             DeviceCapturer,
959             // Buffer that contains a sample rate converter and also helps with managing differing
960             // periods between the guest and the host.
961             CaptureResamplerBuffer,
962             // The `AsyncCaptureBuffer` requires an `AsyncBufferCommit` trait, but Windows doesn't
963             // need it.
964             NoopBufferCommit,
965         ),
966     ),
967     Noop(NoopCapturer),
968 }
969 
970 pub(crate) struct DeviceCapturerWrapper {
971     // Playback stream when an audio device is available.
972     pub(crate) capturer_stream: CapturerStream,
973     // guest channel count.
974     num_channels: usize,
975     // guest bit depth.
976     guest_bit_depth: SampleFormat,
977     // guest frame rate.
978     guest_frame_rate: u32,
979     // incoming buffer size from the guest per period.
980     outgoing_buffer_size_in_frames: usize,
981 }
982 
983 impl DeviceCapturerWrapper {
new( num_channels: usize, guest_bit_depth: SampleFormat, guest_frame_rate: u32, outgoing_buffer_size_in_frames: usize, ex: Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<Self, CaptureError>984     fn new(
985         num_channels: usize,
986         guest_bit_depth: SampleFormat,
987         guest_frame_rate: u32,
988         outgoing_buffer_size_in_frames: usize,
989         ex: Option<&dyn audio_streams::AudioStreamsExecutor>,
990     ) -> Result<Self, CaptureError> {
991         let capturer_stream = match Self::create_device_capturer_and_log_time(
992             num_channels,
993             guest_frame_rate,
994             outgoing_buffer_size_in_frames,
995             ex,
996         ) {
997             Ok(device) => {
998                 let audio_shared_format = device.audio_shared_format;
999                 let capture_resampler_buffer = CaptureResamplerBuffer::new_input_resampler(
1000                     audio_shared_format.frame_rate,
1001                     guest_frame_rate as usize,
1002                     outgoing_buffer_size_in_frames,
1003                     audio_shared_format.channels,
1004                     audio_shared_format.channel_mask,
1005                 )
1006                 .expect("Failed to create CaptureResamplerBuffer");
1007 
1008                 CapturerStream::Device((device, capture_resampler_buffer, NoopBufferCommit))
1009             }
1010             Err(e) => {
1011                 base::warn!("Creating DeviceCapturer failed: {}", e);
1012                 Self::create_noop_capture_stream_with_device_notification(
1013                     num_channels,
1014                     guest_bit_depth,
1015                     guest_frame_rate,
1016                     outgoing_buffer_size_in_frames,
1017                 )?
1018             }
1019         };
1020         Ok(Self {
1021             capturer_stream,
1022             num_channels,
1023             guest_bit_depth,
1024             guest_frame_rate,
1025             outgoing_buffer_size_in_frames,
1026         })
1027     }
1028 
create_device_capturer_and_log_time( num_channels: usize, frame_rate: u32, outgoing_buffer_size_in_frames: usize, ex: Option<&dyn AudioStreamsExecutor>, ) -> Result<DeviceCapturer, CaptureError>1029     fn create_device_capturer_and_log_time(
1030         num_channels: usize,
1031         frame_rate: u32,
1032         outgoing_buffer_size_in_frames: usize,
1033         ex: Option<&dyn AudioStreamsExecutor>,
1034     ) -> Result<DeviceCapturer, CaptureError> {
1035         let start = std::time::Instant::now();
1036         let device =
1037             DeviceCapturer::new(num_channels, frame_rate, outgoing_buffer_size_in_frames, ex)?;
1038         // This can give us insights to how other long other machines take to initialize audio.
1039         // Eventually this should be a histogram metric.
1040         info!(
1041             "DeviceRenderer took {}ms to initialize audio.",
1042             start.elapsed().as_millis()
1043         );
1044         Ok(device)
1045     }
1046 
1047     /// Read from the Windows capture buffer into the resampler until the resampler has bytes
1048     /// available to be written to the guest.
drain_until_bytes_avaialable( device_capturer: &mut DeviceCapturer, capture_resampler_buffer: &mut CaptureResamplerBuffer, outgoing_buffer_size_in_frames: usize, ) -> Result<(), CaptureError>1049     async fn drain_until_bytes_avaialable(
1050         device_capturer: &mut DeviceCapturer,
1051         capture_resampler_buffer: &mut CaptureResamplerBuffer,
1052         outgoing_buffer_size_in_frames: usize,
1053     ) -> Result<(), CaptureError> {
1054         while !capture_resampler_buffer.is_next_period_available() {
1055             device_capturer.async_next_win_buffer().await?;
1056             Self::drain_to_resampler(
1057                 device_capturer,
1058                 capture_resampler_buffer,
1059                 outgoing_buffer_size_in_frames,
1060             )?;
1061         }
1062         Ok(())
1063     }
1064 
1065     /// Gets a slice of sample rate converted audio frames and return an `AsyncCaptureBuffer`
1066     /// with these audio frames to be used by the emulated audio device.
1067     ///
1068     /// This assumes the precondition that `capture_resmapler_buffer` has at least a period worth
1069     /// of audio frames available.
get_async_capture_buffer<'a>( capture_resampler_buffer: &mut CaptureResamplerBuffer, noop_buffer_commit: &'a mut NoopBufferCommit, ) -> Result<AsyncCaptureBuffer<'a>, CaptureError>1070     fn get_async_capture_buffer<'a>(
1071         capture_resampler_buffer: &mut CaptureResamplerBuffer,
1072         noop_buffer_commit: &'a mut NoopBufferCommit,
1073     ) -> Result<AsyncCaptureBuffer<'a>, CaptureError> {
1074         match capture_resampler_buffer.get_next_period() {
1075             Some(next_period) => {
1076                 // SAFETY: `next_period`'s buffer is owned by `capture_resampler_buffer`,
1077                 // and the buffer won't be cleared until
1078                 // `capture_resampler_buffer.get_next_period` is called again. That means the
1079                 // clearing won't happen until `next_slice` has been written into the rx queue.
1080                 let next_slice = unsafe {
1081                     std::slice::from_raw_parts_mut(next_period.as_mut_ptr(), next_period.len())
1082                 };
1083                 return AsyncCaptureBuffer::new(
1084                     ANDROID_CAPTURE_FRAME_SIZE_BYTES,
1085                     next_slice,
1086                     noop_buffer_commit,
1087                 )
1088                 .map_err(CaptureError::CaptureBuffer);
1089             }
1090             None => Err(CaptureError::ResamplerNoSamplesAvailable),
1091         }
1092     }
1093 
1094     /// Copy all the bytes from the Windows capture buffer into `CaptureResamplerBuffer`.
1095     ///
1096     /// This has a precondition that `win_buffer` is not null because `GetBuffer` has been called
1097     /// to get the next round of capture audio frames.
drain_to_resampler( device_capturer: &mut DeviceCapturer, capture_resampler_buffer: &mut CaptureResamplerBuffer, outgoing_buffer_size_in_frames: usize, ) -> Result<(), CaptureError>1098     fn drain_to_resampler(
1099         device_capturer: &mut DeviceCapturer,
1100         capture_resampler_buffer: &mut CaptureResamplerBuffer,
1101         outgoing_buffer_size_in_frames: usize,
1102     ) -> Result<(), CaptureError> {
1103         let mut slice = device_capturer.win_buffer.as_mut_slice();
1104         let audio_shared_format = device_capturer.audio_shared_format;
1105         // Guest period in buffer with the audio format provided by WASAPI.
1106         let guest_period_in_bytes =
1107             outgoing_buffer_size_in_frames * audio_shared_format.channels * BYTES_PER_32FLOAT;
1108 
1109         while !slice.is_empty() {
1110             if slice.len() >= guest_period_in_bytes {
1111                 capture_resampler_buffer.convert_and_add(&slice[..guest_period_in_bytes]);
1112                 slice = &mut slice[guest_period_in_bytes..];
1113             } else {
1114                 capture_resampler_buffer.convert_and_add(slice);
1115                 slice = &mut [];
1116             }
1117         }
1118         Ok(())
1119     }
1120 
1121     /// Set up a stream that write 0's and set up a listener for new audio capture devices.
1122     ///
1123     /// This call assumes that the last capture device has been disconnected and the
1124     /// `DeviceCapturer` no longer functions properly.
create_noop_capture_stream_with_device_notification( num_channels: usize, guest_bit_depth: SampleFormat, guest_frame_rate: u32, outgoing_buffer_size_in_frames: usize, ) -> Result<CapturerStream, CaptureError>1125     fn create_noop_capture_stream_with_device_notification(
1126         num_channels: usize,
1127         guest_bit_depth: SampleFormat,
1128         guest_frame_rate: u32,
1129         outgoing_buffer_size_in_frames: usize,
1130     ) -> Result<CapturerStream, CaptureError> {
1131         let is_device_available = Arc::new(AtomicBool::new(false));
1132         let noop_renderer = NoopCapturer {
1133             noop_capture_stream: NoopCaptureStream::new(
1134                 num_channels,
1135                 guest_bit_depth,
1136                 guest_frame_rate,
1137                 outgoing_buffer_size_in_frames,
1138             ),
1139             _device_notifier: DeviceNotifier::create_imm_device_notification(
1140                 is_device_available.clone(),
1141                 eCapture,
1142             )
1143             .map_err(CaptureError::WinAudioError)?,
1144             is_device_available,
1145         };
1146 
1147         Ok(CapturerStream::Noop(noop_renderer))
1148     }
1149 }
1150 
1151 // SAFETY: DeviceCapturerWrapper can be sent between threads safely
1152 unsafe impl Send for DeviceCapturerWrapper {}
1153 
1154 pub(crate) struct DeviceCapturer {
1155     audio_capture_client: ComPtr<IAudioCaptureClient>,
1156     _audio_client: ComPtr<IAudioClient>,
1157     win_buffer: Vec<u8>,
1158     pub audio_shared_format: AudioSharedFormat,
1159     _ready_to_write_event: Event,
1160     async_ready_to_write_event: Option<Box<dyn EventAsyncWrapper>>,
1161     last_buffer_flags: u32,
1162 }
1163 
1164 impl DeviceCapturer {
new( num_channels: usize, guest_frame_rate: u32, outgoing_buffer_size_in_frames: usize, ex: Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<Self, CaptureError>1165     fn new(
1166         num_channels: usize,
1167         guest_frame_rate: u32,
1168         outgoing_buffer_size_in_frames: usize,
1169         ex: Option<&dyn audio_streams::AudioStreamsExecutor>,
1170     ) -> Result<Self, CaptureError> {
1171         if num_channels > 2 {
1172             return Err(CaptureError::WinAudioError(
1173                 WinAudioError::InvalidChannelCount(num_channels),
1174             ));
1175         }
1176 
1177         info!("Capture guest frame rate: {}", guest_frame_rate);
1178 
1179         let audio_client = create_audio_client(eCapture).map_err(CaptureError::WinAudioError)?;
1180 
1181         let format = get_valid_mix_format(&audio_client).map_err(CaptureError::WinAudioError)?;
1182 
1183         // SAFETY: `audio_client` is initialized
1184         let hr = unsafe {
1185             // Intializes the audio client by setting the buffer size in 100-nanoseconds and
1186             // specifying the format the audio bytes will be passed in as.
1187             // Setting `hnsBufferDuration` (in miilisecond units) to 0 will let the audio engine to
1188             // pick the size that will minimize latency.
1189             // `hnsPeriodicity` sets the device period and should always be 0 for shared mode.
1190             audio_client.Initialize(
1191                 AUDCLNT_SHAREMODE_SHARED,
1192                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
1193                     | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
1194                     | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
1195                     | AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
1196                     | AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED,
1197                 0, /* hnsBufferDuration */
1198                 0, /* hnsPeriodicity */
1199                 format.as_ptr(),
1200                 null_mut(),
1201             )
1202         };
1203         check_hresult!(
1204             hr,
1205             WinAudioError::from(hr),
1206             "Audio Client Initialize() failed."
1207         )
1208         .map_err(CaptureError::WinAudioError)?;
1209 
1210         let (_ready_to_write_event, async_ready_to_write_event) =
1211             create_and_set_audio_client_event(&audio_client, &ex)
1212                 .map_err(CaptureError::WinAudioError)?;
1213 
1214         let audio_capture_client = Self::create_audio_capture_client(&audio_client)?;
1215 
1216         let shared_audio_engine_period_in_frames =
1217             get_device_period_in_frames(&audio_client, &format);
1218 
1219         if outgoing_buffer_size_in_frames % shared_audio_engine_period_in_frames != 0 {
1220             warn!(
1221                 "Capture: Guest period size: `{}` not divisible by shared audio engine period size: `{}`. \
1222                  Audio glitches may occur if sample rate conversion isn't on.",
1223                 outgoing_buffer_size_in_frames, shared_audio_engine_period_in_frames
1224             );
1225         }
1226 
1227         check_endpoint_buffer_size(&audio_client, shared_audio_engine_period_in_frames)
1228             .map_err(CaptureError::WinAudioError)?;
1229 
1230         // SAFETY: `audio_client` is initialized
1231         let hr = unsafe {
1232             // Starts the audio stream for capture
1233             audio_client.Start()
1234         };
1235         check_hresult!(
1236             hr,
1237             WinAudioError::from(hr),
1238             "Audio Render Client Start() failed."
1239         )
1240         .map_err(CaptureError::WinAudioError)?;
1241 
1242         Ok(Self {
1243             audio_capture_client,
1244             _audio_client: audio_client,
1245             win_buffer: Vec::new(),
1246             audio_shared_format: format
1247                 .create_audio_shared_format(shared_audio_engine_period_in_frames),
1248             _ready_to_write_event,
1249             async_ready_to_write_event,
1250             last_buffer_flags: 0,
1251         })
1252     }
1253 
create_audio_capture_client( audio_client: &IAudioClient, ) -> Result<ComPtr<IAudioCaptureClient>, CaptureError>1254     fn create_audio_capture_client(
1255         audio_client: &IAudioClient,
1256     ) -> Result<ComPtr<IAudioCaptureClient>, CaptureError> {
1257         let mut audio_capture_client: *mut c_void = null_mut();
1258 
1259         // SAFETY: `audio_client` is initialized
1260         let hr = unsafe {
1261             audio_client.GetService(
1262                 &IID_IAudioCaptureClient as *const GUID,
1263                 &mut audio_capture_client,
1264             )
1265         };
1266         check_hresult!(
1267             hr,
1268             WinAudioError::from(hr),
1269             "Audio Client GetService() failed."
1270         )
1271         .map_err(CaptureError::WinAudioError)?;
1272 
1273         // SAFETY: `audio_capture_client` is guaranteed to be initialized
1274         unsafe {
1275             Ok(ComPtr::from_raw(
1276                 audio_capture_client as *mut IAudioCaptureClient,
1277             ))
1278         }
1279     }
1280 
1281     // Returns a wrapper around the WASAPI buffer
async_next_win_buffer(&mut self) -> Result<(), CaptureError>1282     async fn async_next_win_buffer(&mut self) -> Result<(), CaptureError> {
1283         self.win_buffer.clear();
1284 
1285         // We will wait for windows to tell us when it is ready to take in the next set of
1286         // audio samples from the guest
1287         let async_ready_to_write_event =
1288             self.async_ready_to_write_event
1289                 .as_ref()
1290                 .ok_or(CaptureError::WinAudioError(
1291                     WinAudioError::MissingEventAsync,
1292                 ))?;
1293 
1294         // Unlike the sync version, there is no timeout anymore. So we could get stuck here,
1295         // although it is unlikely.
1296         async_ready_to_write_event.wait().await.map_err(|e| {
1297             CaptureError::WinAudioError(WinAudioError::AsyncError(
1298                 e,
1299                 "Failed to wait for async event to get next capture buffer.".to_string(),
1300             ))
1301         })?;
1302 
1303         // TODO(b/253506231): Might need to check for a full period of bytes before returning from
1304         // this function on AMD. For playback, there was a bug caused from us not doing this.
1305 
1306         self.get_buffer()?;
1307 
1308         Ok(())
1309     }
1310 
1311     // Drain the capture buffer and store the bytes in `win_buffer`.
get_buffer(&mut self) -> Result<(), CaptureError>1312     fn get_buffer(&mut self) -> Result<(), CaptureError> {
1313         // SAFETY:
1314         //   - `GetBuffer` only take output parameters that are all defined in this unsafe block.
1315         //   - `ReleaseBuffer` is called after the audio bytes are copied to `win_buffer`, so the
1316         //     audio bytes from `GetBuffer` will remain valid long enough.
1317         unsafe {
1318             let mut packet_length = self.next_packet_size()?;
1319 
1320             // The Windows documentation recommends calling `GetBuffer` until `GetNextPacketSize`
1321             // returns 0.
1322             while packet_length != 0 {
1323                 let mut buffer = std::ptr::null_mut();
1324                 let mut num_frames_available = 0;
1325                 let mut flags = 0;
1326 
1327                 // Position variables unused for now, but may be useful for debugging.
1328                 let mut device_position = 0;
1329                 let mut qpc_position = 0;
1330                 let hr = self.audio_capture_client.GetBuffer(
1331                     &mut buffer,
1332                     &mut num_frames_available,
1333                     &mut flags,
1334                     &mut device_position,
1335                     &mut qpc_position,
1336                 );
1337                 check_hresult!(
1338                     hr,
1339                     WinAudioError::from(hr),
1340                     "Audio Capture Client GetBuffer failed."
1341                 )
1342                 .map_err(CaptureError::WinAudioError)?;
1343 
1344                 let buffer_slice = std::slice::from_raw_parts_mut(
1345                     buffer,
1346                     num_frames_available as usize
1347                         * self.audio_shared_format.channels
1348                         * self.audio_shared_format.bit_depth
1349                         / 8,
1350                 );
1351 
1352                 if flags != 0 && self.last_buffer_flags != flags {
1353                     warn!(
1354                         "Audio Cature Client GetBuffer flags were not 0: {}",
1355                         Self::get_buffer_flags_to_string(flags)
1356                     );
1357 
1358                     self.last_buffer_flags = flags;
1359                 }
1360 
1361                 if flags & AUDCLNT_BUFFERFLAGS_SILENT == 0 {
1362                     self.win_buffer.extend_from_slice(buffer_slice);
1363                 } else {
1364                     self.win_buffer
1365                         .resize(self.win_buffer.len() + buffer_slice.len(), 0);
1366                 }
1367 
1368                 let hr = self
1369                     .audio_capture_client
1370                     .ReleaseBuffer(num_frames_available);
1371                 check_hresult!(
1372                     hr,
1373                     WinAudioError::from(hr),
1374                     "Audio Capture Client ReleaseBuffer() failed"
1375                 )
1376                 .map_err(CaptureError::WinAudioError)?;
1377 
1378                 packet_length = self.next_packet_size()?;
1379             }
1380         }
1381 
1382         Ok(())
1383     }
1384 
next_packet_size(&self) -> Result<u32, CaptureError>1385     fn next_packet_size(&self) -> Result<u32, CaptureError> {
1386         let mut len = 0;
1387         // SAFETY: `len` is a valid u32.
1388         let hr = unsafe { self.audio_capture_client.GetNextPacketSize(&mut len) };
1389         check_hresult!(
1390             hr,
1391             WinAudioError::from(hr),
1392             "Capture GetNextPacketSize() failed."
1393         )
1394         .map_err(CaptureError::WinAudioError)?;
1395         Ok(len)
1396     }
1397 
get_buffer_flags_to_string(flags: u32) -> String1398     fn get_buffer_flags_to_string(flags: u32) -> String {
1399         let mut result = Vec::new();
1400         if flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY != 0 {
1401             result.push("AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY".to_string());
1402         }
1403         if flags & AUDCLNT_BUFFERFLAGS_SILENT != 0 {
1404             result.push("AUDCLNT_BUFFERFLAGS_SILENT".to_string());
1405         }
1406         if flags & AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR != 0 {
1407             result.push("AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR".to_string());
1408         }
1409         result.join(" | ")
1410     }
1411 }
1412 
1413 // SAFETY: DeviceCapturer can be sent between threads safely
1414 unsafe impl Send for DeviceCapturer {}
1415 
1416 // Create the `IAudioClient` which is used to create `IAudioRenderClient`, which is used for
1417 // audio playback, or used to create `IAudioCaptureClient`, which is used for audio capture.
create_audio_client(dataflow: EDataFlow) -> Result<ComPtr<IAudioClient>, WinAudioError>1418 fn create_audio_client(dataflow: EDataFlow) -> Result<ComPtr<IAudioClient>, WinAudioError> {
1419     let mut device_enumerator: *mut c_void = null_mut();
1420 
1421     // Creates a device enumerator in order to select our default audio device.
1422     //
1423     // SAFETY: Only `device_enumerator` is being modified and we own it.
1424     let hr = unsafe {
1425         CoCreateInstance(
1426             &CLSID_MMDeviceEnumerator as REFCLSID,
1427             null_mut(),
1428             CLSCTX_ALL,
1429             &IMMDeviceEnumerator::uuidof(),
1430             &mut device_enumerator,
1431         )
1432     };
1433     check_hresult!(
1434         hr,
1435         WinAudioError::GetDeviceEnumeratorError(hr),
1436         "Win audio create client CoCreateInstance() failed."
1437     )?;
1438 
1439     let device_enumerator =
1440         // SAFETY: `device_enumerator` is guaranteed to be initialized
1441         unsafe { ComPtr::from_raw(device_enumerator as *mut IMMDeviceEnumerator) };
1442 
1443     let mut device: *mut IMMDevice = null_mut();
1444     // SAFETY: `device_enumerator` is guaranteed to be initialized otherwise this method
1445     // would've exited
1446     let hr = unsafe { device_enumerator.GetDefaultAudioEndpoint(dataflow, eConsole, &mut device) };
1447     check_hresult!(
1448         hr,
1449         WinAudioError::MissingDeviceError(hr),
1450         "Device Enumerator GetDefaultAudioEndpoint() failed."
1451     )?;
1452 
1453     // SAFETY: `device` is guaranteed to be initialized
1454     let device = unsafe { ComPtr::from_raw(device) };
1455     print_device_info(&device)?;
1456 
1457     let is_render = if dataflow == eRender { true } else { false };
1458 
1459     // Call Windows API functions to get the `async_op` which will be used to retrieve the
1460     // AudioClient. More details above function definition.
1461     let async_op = enable_auto_stream_routing_and_wait(is_render)?;
1462 
1463     let mut factory: *mut IUnknown = null_mut();
1464 
1465     // SAFETY: `async_op` should be initialized at this point.
1466     let activate_result_hr = unsafe {
1467         let mut activate_result_hr = 0;
1468         let hr = (*async_op).GetActivateResult(&mut activate_result_hr, &mut factory);
1469 
1470         check_hresult!(
1471             hr,
1472             WinAudioError::GetActivateResultError(hr),
1473             "GetActivateResult failed. Cannot retrieve factory to create the Audio Client."
1474         )?;
1475 
1476         activate_result_hr
1477     };
1478     check_hresult!(
1479         activate_result_hr,
1480         WinAudioError::ActivateResultRunningError(activate_result_hr),
1481         "activateResult is an error. Cannot retrieve factory to create the Audio Client."
1482     )?;
1483 
1484     // SAFETY: `factory` is guaranteed to be initialized.
1485     let factory = unsafe { ComPtr::from_raw(factory) };
1486 
1487     factory.cast().map_err(WinAudioError::from)
1488 }
1489 
1490 // Enables automatic audio device routing (only will work for Windows 10, version 1607+).
1491 // This will return IActivateAudioInterfaceAsyncOperation that can be used to retrive the
1492 // AudioClient.
1493 //
1494 // This function will pretty much works as follows:
1495 // 1. Create the parameters to pass into `ActivateAudioInterfaceAsync`
1496 // 2. Call `ActivateAudioInterfaceAsync` which will run asynchrnously and will call a callback when
1497 //    completed.
1498 // 3. Wait on an event that will be notified when that callback is triggered.
1499 // 4. Return an IActivateAudioInterfaceAsyncOperation which can be used to retrived the AudioClient.
enable_auto_stream_routing_and_wait( is_render: bool, ) -> Result<ComPtr<IActivateAudioInterfaceAsyncOperation>, WinAudioError>1500 fn enable_auto_stream_routing_and_wait(
1501     is_render: bool,
1502 ) -> Result<ComPtr<IActivateAudioInterfaceAsyncOperation>, WinAudioError> {
1503     // Event that fires when callback is called.
1504     let activate_audio_interface_complete_event =
1505         Event::new_auto_reset().map_err(WinAudioError::CreateActivateAudioEventError)?;
1506 
1507     let cloned_activate_event = activate_audio_interface_complete_event
1508         .try_clone()
1509         .map_err(WinAudioError::CloneEvent)?;
1510 
1511     // Create the callback that is called when `ActivateAudioInterfaceAsync` is finished.
1512     // The field `parent` is irrelevant and is only there to fill in the struct so that
1513     // this code will run. `ActivateCompleted` is the callback.
1514     let completion_handler =
1515         WinAudioActivateAudioInterfaceCompletionHandler::create_com_ptr(cloned_activate_event);
1516 
1517     // Retrieve GUID that represents the default audio device.
1518     let mut audio_direction_guid_string: *mut u16 = std::ptr::null_mut();
1519 
1520     // This will get the GUID that represents the device we want `ActivateAudioInterfaceAsync`
1521     // to activate. `DEVINTERFACE_AUDIO_RENDER` represents the users default audio render device, so
1522     // as a result Windows will always route sound to the default device. Likewise,
1523     // `DEVINTERFACE_AUDIO_CAPTURE` represents the default audio capture device.
1524     //
1525     // SAFETY: We own `audio_direction_guid_string`.
1526     let hr = unsafe {
1527         if is_render {
1528             StringFromIID(
1529                 &DEVINTERFACE_AUDIO_RENDER as *const winapi::shared::guiddef::GUID,
1530                 &mut audio_direction_guid_string,
1531             )
1532         } else {
1533             StringFromIID(
1534                 &DEVINTERFACE_AUDIO_CAPTURE as *const winapi::shared::guiddef::GUID,
1535                 &mut audio_direction_guid_string,
1536             )
1537         }
1538     };
1539     check_hresult!(
1540         hr,
1541         WinAudioError::from(hr),
1542         format!(
1543             "Failed to retrive DEVINTERFACE_AUDIO GUID for {}",
1544             if is_render { "rendering" } else { "capturing" }
1545         )
1546     )?;
1547 
1548     let mut async_op: *mut IActivateAudioInterfaceAsyncOperation = std::ptr::null_mut();
1549 
1550     // This will asynchronously run and when completed, it will trigger the
1551     // `IActivateINterfaceCompletetionHandler` callback.
1552     // The callback is where the AudioClient can be retrived. This would be easier in C/C++,
1553     // but since in rust the callback is an extern function, it would be difficult to get the
1554     // `IAudioClient` from the callback to the scope here, so we use an
1555     // event to wait for the callback.
1556     //
1557     // SAFETY: We own async_op and the completion handler.
1558     let hr = unsafe {
1559         ActivateAudioInterfaceAsync(
1560             audio_direction_guid_string,
1561             &IAudioClient::uuidof(),
1562             /* activateParams= */ std::ptr::null_mut(),
1563             completion_handler.as_raw(),
1564             &mut async_op,
1565         )
1566     };
1567 
1568     // We want to free memory before error checking for `ActivateAudioInterfaceAsync` to prevent
1569     // a memory leak.
1570     //
1571     // SAFETY: `audio_direction_guid_string` should have valid memory
1572     // and we are freeing up memory here.
1573     unsafe {
1574         CoTaskMemFree(audio_direction_guid_string as *mut std::ffi::c_void);
1575     }
1576 
1577     check_hresult!(
1578         hr,
1579         WinAudioError::from(hr),
1580         "`Activate AudioInterfaceAsync failed."
1581     )?;
1582 
1583     // Wait for `ActivateAudioInterfaceAsync` to finish. `ActivateAudioInterfaceAsync` should
1584     // never hang, but added a long timeout just incase.
1585     match activate_audio_interface_complete_event.wait_timeout(ACTIVATE_AUDIO_EVENT_TIMEOUT) {
1586         Ok(event_result) => match event_result {
1587             EventWaitResult::Signaled => {}
1588             EventWaitResult::TimedOut => {
1589                 return Err(WinAudioError::ActivateAudioEventTimeoutError);
1590             }
1591         },
1592         Err(e) => {
1593             return Err(WinAudioError::ActivateAudioEventError(e));
1594         }
1595     }
1596 
1597     // SAFETY: We own `async_op` and it shouldn't be null if the activate audio event
1598     // fired.
1599     unsafe { Ok(ComPtr::from_raw(async_op)) }
1600 }
1601 
1602 /// Wrapper for dropping `PROPVARIANT` when out of scope.
1603 ///
1604 /// Safe when `prop_variant` is set to a valid `PROPVARIANT`
1605 struct SafePropVariant {
1606     prop_variant: PROPVARIANT,
1607 }
1608 
1609 impl Drop for SafePropVariant {
drop(&mut self)1610     fn drop(&mut self) {
1611         // SAFETY: `prop_variant` is set to a valid `PROPVARIANT` and won't be dropped elsewhere.
1612         unsafe {
1613             PropVariantClear(&mut self.prop_variant);
1614         }
1615     }
1616 }
1617 
1618 // Prints the friendly name for audio `device` to the log.
1619 // Safe when `device` is guaranteed to be successfully initialized.
print_device_info(device: &IMMDevice) -> Result<(), WinAudioError>1620 fn print_device_info(device: &IMMDevice) -> Result<(), WinAudioError> {
1621     let mut props: *mut IPropertyStore = null_mut();
1622     // SAFETY: `device` is guaranteed to be initialized
1623     let hr = unsafe { device.OpenPropertyStore(STGM_READ, &mut props) };
1624     check_hresult!(
1625         hr,
1626         WinAudioError::from(hr),
1627         "Win audio OpenPropertyStore failed."
1628     )?;
1629 
1630     // SAFETY: `props` is guaranteed to be initialized
1631     let props = unsafe { ComPtr::from_raw(props) };
1632 
1633     let mut prop_variant: PROPVARIANT = Default::default();
1634     // SAFETY: `props` is guaranteed to be initialized
1635     let hr = unsafe { props.GetValue(&PKEY_Device_FriendlyName, &mut prop_variant) };
1636     check_hresult!(
1637         hr,
1638         WinAudioError::from(hr),
1639         "Win audio property store GetValue failed."
1640     )?;
1641     let safe_prop_variant = SafePropVariant { prop_variant };
1642 
1643     // SAFETY: `val` was populated by a successful GetValue call that returns a pwszVal
1644     if unsafe { safe_prop_variant.prop_variant.data.pwszVal().is_null() } {
1645         warn!("Win audio property store GetValue returned a null string");
1646         return Err(WinAudioError::GenericError);
1647     }
1648     // SAFETY: `val` was populated by a successful GetValue call that returned a non-null
1649     // null-terminated pwszVal
1650     let device_name = unsafe {
1651         win_util::from_ptr_win32_wide_string(*(safe_prop_variant.prop_variant).data.pwszVal())
1652     };
1653     info!("Creating audio client: {}", device_name);
1654 
1655     Ok(())
1656 }
1657 
1658 // TODO(b/259476096): Once Ac97 is deprecated, we won't need to return a regular `Event`.
create_and_set_audio_client_event( audio_client: &IAudioClient, ex: &Option<&dyn audio_streams::AudioStreamsExecutor>, ) -> Result<(Event, Option<Box<dyn EventAsyncWrapper>>), WinAudioError>1659 fn create_and_set_audio_client_event(
1660     audio_client: &IAudioClient,
1661     ex: &Option<&dyn audio_streams::AudioStreamsExecutor>,
1662 ) -> Result<(Event, Option<Box<dyn EventAsyncWrapper>>), WinAudioError> {
1663     let ready_event = Event::new_auto_reset().unwrap();
1664     // SAFETY: `ready_event` will be initialized and also it will have the same
1665     // lifetime as `audio_client` because they are owned by DeviceRenderer or DeviceCapturer on
1666     // return.
1667     let hr = unsafe { audio_client.SetEventHandle(ready_event.as_raw_descriptor()) };
1668     check_hresult!(
1669         hr,
1670         WinAudioError::SetEventHandleError(hr),
1671         "SetEventHandle() failed."
1672     )?;
1673 
1674     let async_ready_event = if let Some(ex) = ex {
1675         let ready_event = ready_event.try_clone().map_err(WinAudioError::CloneEvent)?;
1676         // SAFETY: ready_event is cloned from an Event. Its RawDescriptor must be also an Event.
1677         Some(unsafe {
1678             ex.async_event(ready_event.into_raw_descriptor())
1679                 .map_err(|e| {
1680                     WinAudioError::AsyncError(e, "Failed to create async event".to_string())
1681                 })?
1682         })
1683     } else {
1684         None
1685     };
1686     Ok((ready_event, async_ready_event))
1687 }
1688 
get_device_period_in_frames(audio_client: &IAudioClient, format: &WaveAudioFormat) -> usize1689 fn get_device_period_in_frames(audio_client: &IAudioClient, format: &WaveAudioFormat) -> usize {
1690     let mut shared_default_size_in_100nanoseconds: i64 = 0;
1691     let mut exclusive_min: i64 = 0;
1692     // SAFETY: `GetDevicePeriod` is taking in intialized valid i64's on the stack created above.
1693     unsafe {
1694         audio_client.GetDevicePeriod(
1695             &mut shared_default_size_in_100nanoseconds,
1696             &mut exclusive_min,
1697         );
1698     };
1699 
1700     format.get_shared_audio_engine_period_in_frames(shared_default_size_in_100nanoseconds as f64)
1701 }
1702 
check_endpoint_buffer_size( audio_client: &IAudioClient, shared_audio_engine_period_in_frames: usize, ) -> Result<u32, WinAudioError>1703 fn check_endpoint_buffer_size(
1704     audio_client: &IAudioClient,
1705     shared_audio_engine_period_in_frames: usize,
1706 ) -> Result<u32, WinAudioError> {
1707     let mut audio_client_buffer_frame_count: u32 = 0;
1708     // SAFETY: audio_client_buffer_frame_count is created above.
1709     let hr = unsafe { audio_client.GetBufferSize(&mut audio_client_buffer_frame_count) };
1710     check_hresult!(
1711         hr,
1712         WinAudioError::GetBufferSizeError(hr),
1713         "Audio Client GetBufferSize() failed."
1714     )?;
1715 
1716     if audio_client_buffer_frame_count < shared_audio_engine_period_in_frames as u32 {
1717         warn!(
1718             "The Windows audio engine period size in frames: {} /
1719             is bigger than the Audio Client's buffer size in frames: {}",
1720             shared_audio_engine_period_in_frames, audio_client_buffer_frame_count
1721         );
1722         return Err(WinAudioError::InvalidIncomingBufferSize);
1723     }
1724     Ok(audio_client_buffer_frame_count)
1725 }
1726 
1727 // TODO(b/253509368): Rename error so it is more generic for rendering and capturing.
1728 #[derive(Debug, ThisError)]
1729 pub enum WinAudioError {
1730     #[error("An unknown error has occurred.")]
1731     Unknown,
1732     /// The audio device was unplugged or became unavailable.
1733     #[error("win audio device invalidated")]
1734     DeviceInvalidated,
1735     /// A Windows API error occurred.
1736     /// "unknown win audio error HResult: {}, error code: {}"
1737     #[error("unknown win audio error HResult: {0}, error code: {1}")]
1738     WindowsError(i32, Error),
1739     #[error("buffer pointer is null")]
1740     InvalidBuffer,
1741     #[error("playback buffer error: {0}")]
1742     PlaybackBuffer(PlaybackBufferError),
1743     #[error("Incoming buffer size invalid")]
1744     InvalidIncomingBufferSize,
1745     #[error("Failed to wait for Activate Audio Event callback: {0}")]
1746     ActivateAudioEventError(Error),
1747     #[error("Failed to create Activate Audio Event: {0}")]
1748     CreateActivateAudioEventError(Error),
1749     #[error("Timed out waiting for Activate Audio Event callback.")]
1750     ActivateAudioEventTimeoutError,
1751     #[error("Something went wrong in windows audio.")]
1752     GenericError,
1753     #[error("Invalid guest channel count {0} is > than 2")]
1754     InvalidChannelCount(usize),
1755     #[error("Async related error: {0}: {1}")]
1756     AsyncError(std::io::Error, String),
1757     #[error("Ready to read async event was not set during win_audio initialization.")]
1758     MissingEventAsync,
1759     #[error("Failed to clone an event: {0}")]
1760     CloneEvent(Error),
1761     #[error("Failed to retrieve device enumerator. HResult: {0}")]
1762     GetDeviceEnumeratorError(i32),
1763     #[error("No audio device available. HResult: {0}")]
1764     MissingDeviceError(i32),
1765     #[error("Failed to run GetActivateResult. HResult: {0}")]
1766     GetActivateResultError(i32),
1767     #[error("Error while running GetActivateResult. HResult: {0}")]
1768     ActivateResultRunningError(i32),
1769     #[error("The AudioClient failed to initialize. HResult: {0}")]
1770     AudioClientInitializationError(i32),
1771     #[error("The AudioClient failed to set the event handle. HResult: {0}")]
1772     SetEventHandleError(i32),
1773     #[error("Failed to retrieve the rendering client. HResult: {0}")]
1774     GetRenderClientError(i32),
1775     #[error("The AudioClient failed to get the buffer size. HResult: {0}")]
1776     GetBufferSizeError(i32),
1777     #[error("The AudioClient failed to start. HResult: {0}")]
1778     AudioClientStartError(i32),
1779     #[error("GetCurrentPadding failed. This could mean the user disconnected their last audio device. HResult: {0}")]
1780     GetCurrentPaddingError(i32),
1781     #[error("GetBuffer failed during playback. HResult: {0}")]
1782     GetBufferError(i32),
1783     #[error("Failed to register IMMNotificationClient. HResult: {0}")]
1784     RegisterEndpointNotifError(i32),
1785     #[error("ReleaseBuffer failed. HResult: {0}")]
1786     ReleaseBufferError(i32),
1787     #[error("Failed to parse part of a guid: {0}")]
1788     GuidParseIntError(ParseIntError),
1789     #[error("Guid split size is not len 5. It is: {0}")]
1790     GuidSplitWrongSize(usize),
1791     #[error("Failed to convert Vector to a slice")]
1792     GuidVecConversionError,
1793 }
1794 
1795 impl From<&WinAudioError> for i64 {
from(error: &WinAudioError) -> i641796     fn from(error: &WinAudioError) -> i64 {
1797         let (err_type, hr) = match error {
1798             WinAudioError::Unknown => (0, 0),
1799             WinAudioError::GetDeviceEnumeratorError(hr) => (1, *hr),
1800             WinAudioError::MissingDeviceError(hr) => (2, *hr),
1801             WinAudioError::GetActivateResultError(hr) => (3, *hr),
1802             WinAudioError::ActivateResultRunningError(hr) => (4, *hr),
1803             WinAudioError::AudioClientInitializationError(hr) => (5, *hr),
1804             WinAudioError::SetEventHandleError(hr) => (6, *hr),
1805             WinAudioError::GetRenderClientError(hr) => (7, *hr),
1806             WinAudioError::GetBufferSizeError(hr) => (8, *hr),
1807             WinAudioError::AudioClientStartError(hr) => (9, *hr),
1808             WinAudioError::DeviceInvalidated => (10, 0),
1809             WinAudioError::WindowsError(hr, _) => (11, *hr),
1810             WinAudioError::InvalidBuffer => (12, 0),
1811             WinAudioError::PlaybackBuffer(_) => (13, 0),
1812             WinAudioError::InvalidIncomingBufferSize => (14, 0),
1813             WinAudioError::ActivateAudioEventError(_) => (15, 0),
1814             WinAudioError::CreateActivateAudioEventError(_) => (16, 0),
1815             WinAudioError::ActivateAudioEventTimeoutError => (17, 0),
1816             WinAudioError::GenericError => (18, 0),
1817             WinAudioError::InvalidChannelCount(_) => (19, 0),
1818             WinAudioError::AsyncError(_, _) => (20, 0),
1819             WinAudioError::MissingEventAsync => (21, 0),
1820             WinAudioError::CloneEvent(_) => (22, 0),
1821             WinAudioError::GetCurrentPaddingError(hr) => (23, *hr),
1822             WinAudioError::GetBufferError(hr) => (24, *hr),
1823             WinAudioError::RegisterEndpointNotifError(hr) => (25, *hr),
1824             WinAudioError::ReleaseBufferError(hr) => (26, *hr),
1825             WinAudioError::GuidParseIntError(_) => (27, 0),
1826             WinAudioError::GuidSplitWrongSize(_) => (28, 0),
1827             WinAudioError::GuidVecConversionError => (29, 0),
1828         };
1829         ((err_type as u64) << 32 | ((hr as u32) as u64)) as i64
1830     }
1831 }
1832 
1833 impl From<i32> for WinAudioError {
from(winapi_error_code: i32) -> Self1834     fn from(winapi_error_code: i32) -> Self {
1835         match winapi_error_code {
1836             AUDCLNT_E_DEVICE_INVALIDATED => Self::DeviceInvalidated,
1837             _ => Self::WindowsError(winapi_error_code, Error::last()),
1838         }
1839     }
1840 }
1841 
1842 #[derive(Debug, ThisError)]
1843 pub enum RenderError {
1844     #[error("RenderError: {0}")]
1845     WinAudioError(WinAudioError),
1846     #[error("AudioStream RenderBufferError error: {0}")]
1847     PlaybackBuffer(PlaybackBufferError),
1848     #[error("buffer pointer is null")]
1849     InvalidBuffer,
1850 }
1851 
1852 #[derive(Debug, ThisError)]
1853 pub enum CaptureError {
1854     #[error("CaptureError: {0}")]
1855     WinAudioError(WinAudioError),
1856     #[error("AudioStream CaptureBufferError error: {0}")]
1857     CaptureBuffer(CaptureBufferError),
1858     #[error("CaptureResamplerBuffer has no samples available.")]
1859     ResamplerNoSamplesAvailable,
1860     #[error("CaptureResamplerBuffer is missing.")]
1861     ResamplerMissing,
1862 }
1863 
1864 // Unfortunately, Kokoro's VM tests will fail on `GetDefaultAudioEndpoint` most likely because there
1865 // are no audio endpoints on the VMs running the test. These tests can be ran on a windows machine
1866 // with an audio device though.
1867 //
1868 // Thus these test are ignored, but are good for local testing. To run, just use the command:
1869 //
1870 //   $: cargo test -p win_audio win_audio_impl::tests:: -- --ignored
1871 //
1872 // Also, if a STATUS_DLL_NOT_FOUND exception happens, this is because the r8brain.dll can't be
1873 // be found. Just put it in the appropriate spot in the `target` directory.
1874 #[cfg(test)]
1875 mod tests {
1876     use std::thread;
1877 
1878     use cros_async::Executor;
1879     use metrics::sys::WaveFormatDetails;
1880     use winapi::shared::ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1881     use winapi::shared::mmreg::WAVEFORMATEX;
1882     use winapi::shared::mmreg::WAVEFORMATEXTENSIBLE;
1883     use winapi::shared::mmreg::WAVE_FORMAT_EXTENSIBLE;
1884     use winapi::shared::winerror::S_OK;
1885 
1886     use super::*;
1887     // These tests needs to be ran serially because there is a chance that two different tests
1888     // running on different threads could open the same event named
1889     // ACTIVATE_AUDIO_INTERFACE_COMPLETION_EVENT.
1890     // So the first test thread could trigger it correctly, but the second test thread could open
1891     // the same triggered event even though the `ActivateAudioInterfaceAsync` operation hasn't
1892     // completed, thus causing an error.
1893     //
1894     // TODO(b/217768491): Randomizing events should resolve the need for serialized tests.
1895     static SERIALIZE_LOCK: Mutex<()> = Mutex::new(());
1896 
1897     struct SafeCoInit;
1898     impl SafeCoInit {
new_coinitialize() -> Self1899         fn new_coinitialize() -> Self {
1900             // SAFETY: We pass valid parameters to CoInitializeEx.
1901             unsafe {
1902                 CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED);
1903             }
1904             SafeCoInit {}
1905         }
1906     }
1907 
1908     impl Drop for SafeCoInit {
drop(&mut self)1909         fn drop(&mut self) {
1910             // SAFETY: We initialized COM, so it is safe to uninitialize it here.
1911             unsafe {
1912                 CoUninitialize();
1913             }
1914         }
1915     }
1916 
1917     #[test]
test_win_audio_error_to_descriptor_for_no_device()1918     fn test_win_audio_error_to_descriptor_for_no_device() {
1919         let err = WinAudioError::MissingDeviceError(-2147023728);
1920         let result: i64 = (&err).into();
1921 
1922         // 2 << 32 | (-2147023728)
1923         assert_eq!(result, 10737878160);
1924     }
1925 
1926     #[test]
test_win_audio_error_to_descriptor_for_failed_initialization()1927     fn test_win_audio_error_to_descriptor_for_failed_initialization() {
1928         let err = WinAudioError::AudioClientInitializationError(-2004287484);
1929         let result: i64 = (&err).into();
1930 
1931         // 5 << 32 | (-2004287484)
1932         assert_eq!(result, 23765516292);
1933     }
1934 
1935     #[test]
test_win_audio_error_to_descriptor_for_getcurrentpadding_error()1936     fn test_win_audio_error_to_descriptor_for_getcurrentpadding_error() {
1937         let err = WinAudioError::GetCurrentPaddingError(-2147023728);
1938         let result: i64 = (&err).into();
1939 
1940         // 23 << 32 | (-2004287484)
1941         assert_eq!(result, 100932191376);
1942     }
1943 
1944     #[test]
test_device_renderer_convert_string_to_guid()1945     fn test_device_renderer_convert_string_to_guid() {
1946         let guid_string = "465c4ed4-cda1-4d65-b412-641299a39c2c";
1947         let result_guid =
1948             DeviceRenderer::convert_session_string_to_guid(guid_string.to_string()).unwrap();
1949         assert_eq!(result_guid.Data1, 0x465c4ed4);
1950         assert_eq!(result_guid.Data2, 0xcda1);
1951         assert_eq!(result_guid.Data3, 0x4d65);
1952 
1953         let data_4 = result_guid.Data4;
1954         assert_eq!(data_4[0], 0xb4);
1955         assert_eq!(data_4[1], 0x12);
1956         assert_eq!(data_4[2], 0x64);
1957         assert_eq!(data_4[3], 0x12);
1958         assert_eq!(data_4[4], 0x99);
1959         assert_eq!(data_4[5], 0xa3);
1960         assert_eq!(data_4[6], 0x9c);
1961         assert_eq!(data_4[7], 0x2c);
1962     }
1963 
1964     #[ignore]
1965     #[test]
test_create_win_audio_renderer_no_co_initliazed()1966     fn test_create_win_audio_renderer_no_co_initliazed() {
1967         let _shared = SERIALIZE_LOCK.lock();
1968         let win_audio_renderer = DeviceRenderer::new(2, 48000, 720, None, None);
1969         assert!(win_audio_renderer.is_err());
1970     }
1971 
1972     #[ignore]
1973     #[test]
test_create_win_audio_capturer_no_co_initliazed()1974     fn test_create_win_audio_capturer_no_co_initliazed() {
1975         let _shared = SERIALIZE_LOCK.lock();
1976         let win_audio_renderer = DeviceCapturer::new(2, 48000, 720, None);
1977         assert!(win_audio_renderer.is_err());
1978     }
1979 
1980     #[ignore]
1981     #[test]
test_create_win_audio_renderer()1982     fn test_create_win_audio_renderer() {
1983         let _shared = SERIALIZE_LOCK.lock();
1984         let _co_init = SafeCoInit::new_coinitialize();
1985         let win_audio_renderer_result = DeviceRenderer::new(2, 48000, 480, None, None);
1986         assert!(win_audio_renderer_result.is_ok());
1987         let win_audio_renderer = win_audio_renderer_result.unwrap();
1988         // This test is dependent on device format settings and machine. Ie. this will probably
1989         // fail on AMD since its period is normally 513 for 48kHz.
1990         assert_eq!(
1991             win_audio_renderer
1992                 .audio_shared_format
1993                 .shared_audio_engine_period_in_frames,
1994             480
1995         );
1996     }
1997 
1998     #[ignore]
1999     #[test]
test_create_win_audio_capturer()2000     fn test_create_win_audio_capturer() {
2001         let _shared = SERIALIZE_LOCK.lock();
2002         let _co_init = SafeCoInit::new_coinitialize();
2003         let win_audio_capturer_result = DeviceCapturer::new(2, 48000, 480, None);
2004         assert!(win_audio_capturer_result.is_ok());
2005         let win_audio_capturer = win_audio_capturer_result.unwrap();
2006         // This test is dependent on device format settings and machine. Ie. this will probably
2007         // fail on AMD since its period is normally 513 for 48kHz.
2008         assert_eq!(
2009             win_audio_capturer
2010                 .audio_shared_format
2011                 .shared_audio_engine_period_in_frames,
2012             480
2013         );
2014     }
2015 
2016     #[ignore]
2017     #[test]
test_create_playback_stream()2018     fn test_create_playback_stream() {
2019         let _shared = SERIALIZE_LOCK.lock();
2020         let mut win_audio: WinAudio = WinAudio::new().unwrap();
2021         let (_, mut stream_source) = win_audio
2022             .new_playback_stream(2, SampleFormat::S16LE, 48000, 480)
2023             .unwrap();
2024         let playback_buffer = stream_source.next_playback_buffer().unwrap();
2025 
2026         assert_eq!(playback_buffer.frame_capacity(), 480);
2027     }
2028 
2029     #[ignore]
2030     #[test]
2031     // If the guest buffer is too big, then
2032     // there is no way to copy audio samples over succiently.
test_guest_buffer_size_bigger_than_audio_render_client_buffer_size()2033     fn test_guest_buffer_size_bigger_than_audio_render_client_buffer_size() {
2034         let _shared = SERIALIZE_LOCK.lock();
2035         let win_audio_renderer = DeviceRenderer::new(2, 48000, 100000, None, None);
2036 
2037         assert!(win_audio_renderer.is_err());
2038     }
2039 
2040     #[ignore]
2041     #[test]
test_co_init_called_once_per_thread()2042     fn test_co_init_called_once_per_thread() {
2043         let _shared = SERIALIZE_LOCK.lock();
2044         // Call co init in a background thread
2045         let join_handle = thread::spawn(move || {
2046             assert_eq!(WinAudio::co_init_once_per_thread(), S_OK);
2047         });
2048 
2049         // Wait for thread to finish
2050         join_handle
2051             .join()
2052             .expect("Thread calling co_init_once_per_thread panicked");
2053 
2054         // Call co init twice on the main thread.
2055         assert_eq!(WinAudio::co_init_once_per_thread(), S_OK);
2056         // Without thread local once_only this should fail
2057         assert_eq!(WinAudio::co_init_once_per_thread(), S_SKIPPED_COINIT);
2058         // SAFETY: We initialized COM, so it is safe to uninitialize it here.
2059         unsafe {
2060             CoUninitialize();
2061         }
2062     }
2063 
2064     #[ignore]
2065     #[test]
test_device_renderer_wrapper_noop_stream_proper_set()2066     fn test_device_renderer_wrapper_noop_stream_proper_set() {
2067         let _shared = SERIALIZE_LOCK.lock();
2068         let _co_init = SafeCoInit::new_coinitialize();
2069 
2070         let ex = Executor::new().expect("Failed to create executor.");
2071         let mut renderer_wrapper =
2072             DeviceRendererWrapper::new(2, SampleFormat::S16LE, 48000, 480, Some(&ex), None)
2073                 .unwrap();
2074         assert!(matches!(
2075             renderer_wrapper.renderer_stream,
2076             RendererStream::Device(_)
2077         ));
2078 
2079         renderer_wrapper.renderer_stream =
2080             DeviceRendererWrapper::create_noop_stream_with_device_notification(2, 48000, 480)
2081                 .unwrap();
2082         assert!(matches!(
2083             renderer_wrapper.renderer_stream,
2084             RendererStream::Noop(_)
2085         ));
2086     }
2087 
2088     #[ignore]
2089     #[test]
test_device_capturer_wrapper_noop_stream_proper_set()2090     fn test_device_capturer_wrapper_noop_stream_proper_set() {
2091         let _shared = SERIALIZE_LOCK.lock();
2092         let _co_init = SafeCoInit::new_coinitialize();
2093 
2094         let ex = Executor::new().expect("Failed to create executor.");
2095         let mut capturer_wrapper =
2096             DeviceCapturerWrapper::new(2, SampleFormat::S16LE, 48000, 480, Some(&ex)).unwrap();
2097         assert!(matches!(
2098             capturer_wrapper.capturer_stream,
2099             CapturerStream::Device(_)
2100         ));
2101 
2102         capturer_wrapper.capturer_stream =
2103             DeviceCapturerWrapper::create_noop_capture_stream_with_device_notification(
2104                 2,
2105                 SampleFormat::S16LE,
2106                 48000,
2107                 480,
2108             )
2109             .unwrap();
2110         assert!(matches!(
2111             capturer_wrapper.capturer_stream,
2112             CapturerStream::Noop(_)
2113         ));
2114     }
2115 
2116     // Test may be flakey because other tests will be creating an AudioClient. Putting all tests
2117     // in one so we can run this individually to prevent the flakiness. This test may fail
2118     // depending on your selected default audio device.
2119     #[ignore]
2120     #[test]
test_check_format_get_mix_format_success()2121     fn test_check_format_get_mix_format_success() {
2122         let _shared = SERIALIZE_LOCK.lock();
2123 
2124         let _co_init = SafeCoInit::new_coinitialize();
2125         let audio_client = create_audio_client(eRender).unwrap();
2126         let mut format_ptr: *mut WAVEFORMATEX = std::ptr::null_mut();
2127         // SAFETY: `&mut format_ptr` is valid.
2128         let _hr = unsafe { audio_client.GetMixFormat(&mut format_ptr) };
2129 
2130         // SAFETY: `format_ptr` is not a null pointer, since it is set by `GetMixFormat`.
2131         let format = unsafe { WaveAudioFormat::new(format_ptr) };
2132 
2133         // Test format from `GetMixFormat`. This should ALWAYS be valid.
2134         assert!(check_format(
2135             &audio_client,
2136             &format,
2137             WaveFormatDetails::default(),
2138             AudioFormatEventType::RequestOk,
2139         )
2140         .is_ok());
2141 
2142         let format = WAVEFORMATEXTENSIBLE {
2143             Format: WAVEFORMATEX {
2144                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
2145                 nChannels: 2,
2146                 nSamplesPerSec: 48000,
2147                 nAvgBytesPerSec: 8 * 48000,
2148                 nBlockAlign: 8,
2149                 wBitsPerSample: 32,
2150                 cbSize: 22,
2151             },
2152             Samples: 32,
2153             dwChannelMask: 3,
2154             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
2155         };
2156 
2157         // SAFETY: `GetMixFormat` casts `WAVEFORMATEXTENSIBLE` into a `WAVEFORMATEX` like so.
2158         // Also this is casting from a bigger to a smaller struct, so it shouldn't be possible for
2159         // this contructor to access memory it shouldn't.
2160         let format = unsafe { WaveAudioFormat::new((&format) as *const _ as *mut WAVEFORMATEX) };
2161 
2162         // Test valid custom format.
2163         assert!(check_format(
2164             &audio_client,
2165             &format,
2166             WaveFormatDetails::default(),
2167             AudioFormatEventType::RequestOk,
2168         )
2169         .is_ok());
2170 
2171         let format = WAVEFORMATEXTENSIBLE {
2172             Format: WAVEFORMATEX {
2173                 wFormatTag: WAVE_FORMAT_EXTENSIBLE,
2174                 nChannels: 2,
2175                 nSamplesPerSec: 48000,
2176                 nAvgBytesPerSec: 8 * 48000,
2177                 nBlockAlign: 8,
2178                 wBitsPerSample: 3, // This value will cause failure, since bitdepth of 3
2179                 // doesn't make sense
2180                 cbSize: 22,
2181             },
2182             Samples: 32,
2183             dwChannelMask: 3,
2184             SubFormat: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
2185         };
2186 
2187         // SAFETY: `GetMixFormat` casts `WAVEFORMATEXTENSIBLE` into a `WAVEFORMATEX` like so.
2188         // Also this is casting from a bigger to a smaller struct, so it shouldn't be possible for
2189         // this contructor to access memory it shouldn't.
2190         let format = unsafe { WaveAudioFormat::new((&format) as *const _ as *mut WAVEFORMATEX) };
2191 
2192         // Test invalid format
2193         assert!(check_format(
2194             &audio_client,
2195             &format,
2196             WaveFormatDetails::default(),
2197             AudioFormatEventType::RequestOk,
2198         )
2199         .is_err());
2200     }
2201 }
2202