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