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