xref: /aosp_15_r20/external/crosvm/win_audio/src/win_audio_impl/async_stream.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::mem::MaybeUninit;
6 use std::sync::atomic::AtomicUsize;
7 use std::sync::atomic::Ordering;
8 
9 use async_trait::async_trait;
10 use audio_streams::capture::AsyncCaptureBuffer;
11 use audio_streams::capture::AsyncCaptureBufferStream;
12 use audio_streams::AsyncBufferCommit;
13 use audio_streams::AsyncPlaybackBufferStream;
14 use audio_streams::AudioStreamsExecutor;
15 use audio_streams::BoxError;
16 use audio_streams::NoopStream;
17 use audio_streams::NoopStreamControl;
18 use audio_streams::SampleFormat;
19 use audio_streams::StreamControl;
20 use audio_streams::StreamSource;
21 use audio_streams::StreamSourceGenerator;
22 use base::error;
23 use base::warn;
24 use metrics::MetricEventType;
25 
26 use super::NoopBufferCommit;
27 use crate::intermediate_resampler_buffer::CaptureResamplerBuffer;
28 use crate::intermediate_resampler_buffer::PlaybackResamplerBuffer;
29 use crate::CaptureError;
30 use crate::CapturerStream;
31 use crate::DeviceCapturerWrapper;
32 use crate::DeviceRenderer;
33 use crate::DeviceRendererWrapper;
34 use crate::RenderError;
35 use crate::RendererStream;
36 use crate::WinAudio;
37 use crate::WinAudioCapturer;
38 use crate::WinAudioError;
39 use crate::WinAudioRenderer;
40 
41 // These global values are used to prevent metrics upload spam.
42 const ERROR_METRICS_LOG_LIMIT: usize = 5;
43 static INIT_ERRORS_LOGGED_COUNT: AtomicUsize = AtomicUsize::new(0);
44 static PLAYBACK_ERRORS_LOGGED_COUNT: AtomicUsize = AtomicUsize::new(0);
45 
46 pub struct WinAudioStreamSourceGenerator {}
47 
48 impl StreamSourceGenerator for WinAudioStreamSourceGenerator {
generate(&self) -> std::result::Result<Box<dyn StreamSource>, BoxError>49     fn generate(&self) -> std::result::Result<Box<dyn StreamSource>, BoxError> {
50         Ok(Box::new(WinAudio::new()?))
51     }
52 }
53 
54 impl WinAudio {
new_async_playback_stream_helper( num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result< ( Box<dyn StreamControl>, Box<dyn audio_streams::AsyncPlaybackBufferStream>, ), BoxError, >55     pub(super) fn new_async_playback_stream_helper(
56         num_channels: usize,
57         format: SampleFormat,
58         frame_rate: u32,
59         buffer_size: usize,
60         ex: &dyn audio_streams::AudioStreamsExecutor,
61     ) -> Result<
62         (
63             Box<dyn StreamControl>,
64             Box<dyn audio_streams::AsyncPlaybackBufferStream>,
65         ),
66         BoxError,
67     > {
68         let hr = WinAudio::co_init_once_per_thread();
69         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
70 
71         let playback_buffer_stream: Box<dyn AsyncPlaybackBufferStream> =
72             match WinAudioRenderer::new_async(
73                 num_channels,
74                 format,
75                 frame_rate,
76                 buffer_size,
77                 ex,
78                 None,
79             ) {
80                 Ok(renderer) => Box::new(renderer),
81                 Err(e) => {
82                     warn!(
83                         "Failed to create WinAudioRenderer. Fallback to NoopStream with error: {}",
84                         e
85                     );
86                     Box::new(NoopStream::new(
87                         num_channels,
88                         SampleFormat::S16LE,
89                         frame_rate,
90                         buffer_size,
91                     ))
92                 }
93             };
94 
95         Ok((Box::new(NoopStreamControl::new()), playback_buffer_stream))
96     }
97 }
98 
99 impl WinAudioRenderer {
100     /// Constructor to allow for async audio backend.
new_async( num_channels: usize, guest_bit_depth: SampleFormat, frame_rate: u32, incoming_buffer_size_in_frames: usize, ex: &dyn audio_streams::AudioStreamsExecutor, audio_client_guid: Option<String>, ) -> Result<Self, RenderError>101     pub fn new_async(
102         num_channels: usize,
103         guest_bit_depth: SampleFormat,
104         frame_rate: u32,
105         incoming_buffer_size_in_frames: usize,
106         ex: &dyn audio_streams::AudioStreamsExecutor,
107         audio_client_guid: Option<String>,
108     ) -> Result<Self, RenderError> {
109         let device = DeviceRendererWrapper::new(
110             num_channels,
111             guest_bit_depth,
112             frame_rate,
113             incoming_buffer_size_in_frames,
114             Some(ex),
115             audio_client_guid.clone(),
116         )
117         .map_err(|e| {
118             match &e {
119                 RenderError::WinAudioError(win_audio_error) => {
120                     log_init_error_with_limit(win_audio_error.into());
121                 }
122                 _ => {
123                     log_init_error_with_limit((&WinAudioError::Unknown).into());
124                     error!(
125                         "Unhandled NoopStream forced error. These errors should not have been \
126                      returned: {}",
127                         e
128                     );
129                 }
130             }
131             e
132         })?;
133 
134         Ok(Self {
135             device,
136             audio_client_guid,
137         })
138     }
139 
unregister_notification_client_and_make_new_device_renderer( &mut self, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<(), BoxError>140     fn unregister_notification_client_and_make_new_device_renderer(
141         &mut self,
142         ex: &dyn audio_streams::AudioStreamsExecutor,
143     ) -> Result<(), BoxError> {
144         base::info!("Device found. Will attempt to make a DeviceRenderer");
145         let device_renderer = DeviceRendererWrapper::create_device_renderer_and_log_time(
146             self.device.num_channels,
147             self.device.guest_frame_rate,
148             self.device.incoming_buffer_size_in_frames,
149             Some(ex),
150             self.audio_client_guid.clone(),
151         )
152         .map_err(|e| {
153             match &e {
154                 RenderError::WinAudioError(win_audio_error) => {
155                     log_playback_error_with_limit(win_audio_error.into())
156                 }
157                 _ => log_playback_error_with_limit((&WinAudioError::Unknown).into()),
158             }
159             Box::new(e)
160         })?;
161 
162         let audio_shared_format = device_renderer.audio_shared_format;
163 
164         let playback_resampler_buffer = PlaybackResamplerBuffer::new(
165             self.device.guest_frame_rate as usize,
166             audio_shared_format.frame_rate,
167             self.device.incoming_buffer_size_in_frames,
168             audio_shared_format.shared_audio_engine_period_in_frames,
169             audio_shared_format.channels,
170             audio_shared_format.channel_mask,
171         )
172         .expect("Failed to create PlaybackResamplerBuffer");
173 
174         self.device.renderer_stream =
175             RendererStream::Device((device_renderer, playback_resampler_buffer));
176 
177         Ok(())
178     }
179 }
180 
181 /// Attach `descriptor` to the event code `AudioNoopStreamForced` and upload to clearcut.
182 ///
183 /// This method will stop uploading after `ERRO_METRICS_LOG_LIMIT` uploads in order to prevent
184 /// metrics upload spam.
log_init_error_with_limit(descriptor: i64)185 pub(crate) fn log_init_error_with_limit(descriptor: i64) {
186     if INIT_ERRORS_LOGGED_COUNT.load(Ordering::SeqCst) <= ERROR_METRICS_LOG_LIMIT {
187         metrics::log_descriptor(MetricEventType::AudioNoopStreamForced, descriptor);
188         INIT_ERRORS_LOGGED_COUNT.fetch_add(1, Ordering::SeqCst);
189     }
190 }
191 
192 #[async_trait(?Send)]
193 impl AsyncPlaybackBufferStream for WinAudioRenderer {
next_playback_buffer<'a>( &'a mut self, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<audio_streams::AsyncPlaybackBuffer<'a>, BoxError>194     async fn next_playback_buffer<'a>(
195         &'a mut self,
196         ex: &dyn audio_streams::AudioStreamsExecutor,
197     ) -> Result<audio_streams::AsyncPlaybackBuffer<'a>, BoxError> {
198         // Check to see if a new device is available, if so, create a new `DeviceRenderer`.
199         if let RendererStream::Noop(noop_renderer) = &self.device.renderer_stream {
200             if noop_renderer
201                 .is_device_available
202                 .fetch_and(false, Ordering::SeqCst)
203             {
204                 match self.unregister_notification_client_and_make_new_device_renderer(ex) {
205                     Ok(()) => {}
206                     Err(e) => warn!(
207                         "Making a new DeviceRenderer failed in the middle of playback. \
208                             Will continue using NoopStream and listening for new devices: {}",
209                         e
210                     ),
211                 };
212             }
213         }
214 
215         if let RendererStream::Device((device_renderer, _)) = &mut self.device.renderer_stream {
216             if device_renderer.should_get_next_win_buffer {
217                 if let Err(e) = device_renderer.async_next_win_buffer().await {
218                     Self::handle_playback_logging_on_error(&e);
219                     // At this point, the `DeviceRenderer` doesn't exist, so we assume that
220                     // there were no available audio devices.
221                     base::info!(
222                         "async_next_win_buffer failed. Starting NoopStream and start \
223                         listening for a new default device"
224                     );
225                     self.device.renderer_stream =
226                         DeviceRendererWrapper::create_noop_stream_with_device_notification(
227                             self.device.num_channels,
228                             self.device.guest_frame_rate,
229                             self.device.incoming_buffer_size_in_frames,
230                         )
231                         .inspect_err(|e| match &e {
232                             RenderError::WinAudioError(win_audio_error) => {
233                                 log_playback_error_with_limit(win_audio_error.into())
234                             }
235                             _ => log_playback_error_with_limit((&WinAudioError::Unknown).into()),
236                         })?;
237                 }
238             }
239         }
240 
241         if let RendererStream::Noop(noop_renderer) = &mut self.device.renderer_stream {
242             // This will trigger the sleep so that virtio sound doesn't write to win_audio too
243             // quickly, which will cause underruns. No audio samples will actually be written to
244             // this buffer, but it doesn't matter becuase those samples are meant to be dropped
245             // anyways.
246             AsyncPlaybackBufferStream::next_playback_buffer(&mut noop_renderer.noop_stream, ex)
247                 .await?;
248         }
249 
250         self.device
251             .get_intermediate_async_buffer()
252             .map_err(|e| Box::new(e) as _)
253     }
254 }
255 
256 #[async_trait(?Send)]
257 impl AsyncBufferCommit for DeviceRendererWrapper {
commit(&mut self, nframes: usize)258     async fn commit(&mut self, nframes: usize) {
259         if nframes != self.incoming_buffer_size_in_frames {
260             warn!(
261                 "AsyncBufferCommit commited {} frames, instead of a full period of {}",
262                 nframes, self.incoming_buffer_size_in_frames
263             );
264         }
265 
266         match &mut self.renderer_stream {
267             RendererStream::Device((device_renderer, playback_resampler_buffer)) => {
268                 // `intermediate_buffer` will contain audio samples from CrosVm's emulated audio
269                 // device (ie. Virtio Sound). First, we will add the audio samples to the resampler
270                 // buffer.
271                 playback_resampler_buffer.convert_and_add(self.intermediate_buffer.as_slice());
272 
273                 if playback_resampler_buffer.is_priming {
274                     if device_renderer.win_buffer.is_null() {
275                         error!("AsyncBufferCommit: win_buffer is null");
276                         return;
277                     }
278 
279                     let format = device_renderer.audio_shared_format;
280                     let shared_audio_engine_period_bytes =
281                         format.get_shared_audio_engine_period_in_bytes();
282                     Self::write_slice_to_wasapi_buffer_and_release_buffer(
283                         device_renderer,
284                         &vec![0; shared_audio_engine_period_bytes],
285                     );
286 
287                     // WASAPI's `GetBuffer` should be called next because we either wrote to the
288                     // Windows endpoint buffer or the audio samples were dropped.
289                     device_renderer.should_get_next_win_buffer = true;
290                     return;
291                 }
292 
293                 if let Some(next_period) = playback_resampler_buffer.get_next_period() {
294                     if device_renderer.win_buffer.is_null() {
295                         error!("AsyncBufferCommit: win_buffer is null");
296                         return;
297                     }
298                     Self::write_slice_to_wasapi_buffer_and_release_buffer(
299                         device_renderer,
300                         next_period,
301                     );
302                     device_renderer.should_get_next_win_buffer = true;
303                 } else {
304                     // Don't call WASAPI's `GetBuffer` because the resampler didn't have enough
305                     // audio samples write a full period in the Windows endpoint buffer.
306                     device_renderer.should_get_next_win_buffer = false;
307                 }
308             }
309             // For the `Noop` case, we can just drop the incoming audio samples.
310             RendererStream::Noop(_) => {}
311         }
312     }
313 }
314 
315 impl DeviceRendererWrapper {
write_slice_to_wasapi_buffer_and_release_buffer( device_renderer: &DeviceRenderer, slice_to_write: &[u8], )316     fn write_slice_to_wasapi_buffer_and_release_buffer(
317         device_renderer: &DeviceRenderer,
318         slice_to_write: &[u8],
319     ) {
320         let format = device_renderer.audio_shared_format;
321         let shared_audio_engine_period_bytes = format.get_shared_audio_engine_period_in_bytes();
322 
323         // SAFETY: win_buffer is a valid pointer to shared_audio_engine_period_bytes of data
324         let win_buffer_slice = unsafe {
325             std::slice::from_raw_parts_mut(
326                 device_renderer.win_buffer,
327                 shared_audio_engine_period_bytes,
328             )
329         };
330 
331         win_buffer_slice.copy_from_slice(slice_to_write);
332         // SAFETY: We own the buffer
333         unsafe {
334             let hr = device_renderer
335                 .audio_render_client
336                 .ReleaseBuffer(format.shared_audio_engine_period_in_frames as u32, 0);
337             if let Err(e) = check_hresult!(
338                 hr,
339                 WinAudioError::ReleaseBufferError(hr),
340                 "Audio Render Client ReleaseBuffer() failed"
341             ) {
342                 log_playback_error_with_limit((&e).into());
343             }
344         }
345     }
346 }
347 
log_playback_error_with_limit(descriptor: i64)348 pub(crate) fn log_playback_error_with_limit(descriptor: i64) {
349     if PLAYBACK_ERRORS_LOGGED_COUNT.load(Ordering::SeqCst) <= ERROR_METRICS_LOG_LIMIT {
350         metrics::log_descriptor(MetricEventType::AudioPlaybackError, descriptor);
351         PLAYBACK_ERRORS_LOGGED_COUNT.fetch_add(1, Ordering::SeqCst);
352     }
353 }
354 
355 impl DeviceRenderer {
356     /// Similiar to `next_win_buffer`, this is the async version that will return a wrapper
357     /// the WASAPI buffer.
358     ///
359     /// Unlike `next_win_buffer`, there is no timeout if `async_ready_to_read_event` doesn't fire.
360     /// This should be fine, since the end result with or without the timeout will be no audio.
async_next_win_buffer(&mut self) -> Result<(), RenderError>361     async fn async_next_win_buffer(&mut self) -> Result<(), RenderError> {
362         self.win_buffer = MaybeUninit::uninit().as_mut_ptr();
363 
364         // We will wait for windows to tell us when it is ready to take in the next set of
365         // audio samples from the guest
366         loop {
367             let async_ready_to_read_event = self
368                 .async_ready_to_read_event
369                 .as_ref()
370                 .ok_or(RenderError::WinAudioError(WinAudioError::MissingEventAsync))?;
371             async_ready_to_read_event.wait().await.map_err(|e| {
372                 RenderError::WinAudioError(WinAudioError::AsyncError(
373                     e,
374                     "Failed to wait for async event to get next playback buffer.".to_string(),
375                 ))
376             })?;
377 
378             if self.enough_available_frames()? {
379                 break;
380             }
381         }
382 
383         self.get_buffer()?;
384 
385         Ok(())
386     }
387 }
388 
389 impl WinAudioCapturer {
new_async( num_channels: usize, guest_bit_depth: SampleFormat, frame_rate: u32, outgoing_buffer_size_in_frames: usize, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<Self, CaptureError>390     pub fn new_async(
391         num_channels: usize,
392         guest_bit_depth: SampleFormat,
393         frame_rate: u32,
394         outgoing_buffer_size_in_frames: usize,
395         ex: &dyn audio_streams::AudioStreamsExecutor,
396     ) -> Result<Self, CaptureError> {
397         let device = DeviceCapturerWrapper::new(
398             num_channels,
399             guest_bit_depth,
400             frame_rate,
401             outgoing_buffer_size_in_frames,
402             Some(ex),
403         )?;
404 
405         Ok(Self { device })
406     }
407 
unregister_notification_client_and_make_new_device_capturer( &mut self, ex: &dyn AudioStreamsExecutor, ) -> Result<(), BoxError>408     fn unregister_notification_client_and_make_new_device_capturer(
409         &mut self,
410         ex: &dyn AudioStreamsExecutor,
411     ) -> Result<(), BoxError> {
412         let device_capturer = DeviceCapturerWrapper::create_device_capturer_and_log_time(
413             self.device.num_channels,
414             self.device.guest_frame_rate,
415             self.device.outgoing_buffer_size_in_frames,
416             Some(ex),
417         )
418         .map_err(Box::new)?;
419 
420         let audio_shared_format = device_capturer.audio_shared_format;
421 
422         let capture_resampler_buffer = CaptureResamplerBuffer::new_input_resampler(
423             audio_shared_format.frame_rate,
424             self.device.guest_frame_rate as usize,
425             self.device.outgoing_buffer_size_in_frames,
426             audio_shared_format.channels,
427             audio_shared_format.channel_mask,
428         )
429         .expect("Failed to create CaptureResamplerBuffer.");
430 
431         self.device.capturer_stream =
432             CapturerStream::Device((device_capturer, capture_resampler_buffer, NoopBufferCommit));
433 
434         Ok(())
435     }
436 }
437 
438 #[async_trait(?Send)]
439 impl AsyncCaptureBufferStream for WinAudioCapturer {
next_capture_buffer<'a>( &'a mut self, ex: &dyn AudioStreamsExecutor, ) -> Result<AsyncCaptureBuffer<'a>, BoxError>440     async fn next_capture_buffer<'a>(
441         &'a mut self,
442         ex: &dyn AudioStreamsExecutor,
443     ) -> Result<AsyncCaptureBuffer<'a>, BoxError> {
444         // In the `Noop` state, check to see if there is a new device connected. If so, create a
445         // `DeviceCapturer`.
446         if let CapturerStream::Noop(noop_capturer) = &self.device.capturer_stream {
447             if noop_capturer
448                 .is_device_available
449                 .fetch_and(false, Ordering::SeqCst)
450             {
451                 match self.unregister_notification_client_and_make_new_device_capturer(ex) {
452                     Ok(()) => {}
453                     Err(e) => warn!(
454                         "Making a new DeviceCapturer failed in the middle of capture \
455                     Will continue using NoopCaptureStream and listening for new devices: {}",
456                         e
457                     ),
458                 }
459             }
460         }
461 
462         // Try to drain bytes from the Windows buffer into the capture resample buffer, which acts
463         // as a sink. If any part fails, the `Noop` state is set.
464         if let CapturerStream::Device((device_capturer, capture_resampler_buffer, _)) =
465             &mut self.device.capturer_stream
466         {
467             match DeviceCapturerWrapper::drain_until_bytes_avaialable(
468                 device_capturer,
469                 capture_resampler_buffer,
470                 self.device.outgoing_buffer_size_in_frames,
471             )
472             .await
473             {
474                 Ok(()) => {}
475                 Err(e) => {
476                     warn!(
477                         "Making a new DeviceCapturer failed in the middle of capture. \
478                         Will continue using NoopStream and listening for new devices: {}",
479                         e
480                     );
481                     self.device.capturer_stream =
482                         DeviceCapturerWrapper::create_noop_capture_stream_with_device_notification(
483                             self.device.num_channels,
484                             self.device.guest_bit_depth,
485                             self.device.guest_frame_rate,
486                             self.device.outgoing_buffer_size_in_frames,
487                         )
488                         .map_err(Box::new)?;
489                 }
490             };
491         }
492 
493         // Return the buffer to be written to shared memory.
494         match &mut self.device.capturer_stream {
495             CapturerStream::Device((_, capture_resampler_buffer, noop_buffer_commit)) => {
496                 DeviceCapturerWrapper::get_async_capture_buffer(
497                     capture_resampler_buffer,
498                     noop_buffer_commit,
499                 )
500                 .map_err(|e| Box::new(e) as _)
501             }
502             CapturerStream::Noop(noop_capturer) => {
503                 AsyncCaptureBufferStream::next_capture_buffer(
504                     &mut noop_capturer.noop_capture_stream,
505                     ex,
506                 )
507                 .await
508             }
509         }
510     }
511 }
512 
513 #[cfg(test)]
514 mod tests {
515     use cros_async::Executor;
516 
517     use super::*;
518     use crate::WinStreamSourceGenerator;
519 
520     // This test is meant to run through the normal audio playback procedure in order to make
521     // debugging easier. The test needs to be ran with a playback device format of 48KHz,
522     // stereo, 16bit. This test might not pass on AMD, since its period is 513 instead of 480.
523     #[ignore]
524     #[test]
test_async()525     fn test_async() {
526         async fn test(ex: &Executor) {
527             let stream_source_generator: Box<dyn StreamSourceGenerator> =
528                 Box::new(WinAudioStreamSourceGenerator {});
529             let mut stream_source = stream_source_generator
530                 .generate()
531                 .expect("Failed to create stream source.");
532 
533             let (_, mut async_pb_stream) = stream_source
534                 .new_async_playback_stream(2, SampleFormat::S16LE, 48000, 480, ex)
535                 .expect("Failed to create async playback stream.");
536 
537             let mut async_pb_buffer = async_pb_stream
538                 .next_playback_buffer(ex)
539                 .await
540                 .expect("Failed to get next playback buffer");
541 
542             // The buffer size is calculated by "period * channels * bit depth". The actual buffer
543             // from `next_playback_buffer` may vary, depending on the device format and the user's
544             // machine.
545             let buffer = [1u8; 480 * 2 * 2];
546 
547             async_pb_buffer
548                 .copy_cb(buffer.len(), |out| out.copy_from_slice(&buffer))
549                 .unwrap();
550 
551             async_pb_buffer.commit().await;
552 
553             let mut async_pb_buffer = async_pb_stream
554                 .next_playback_buffer(ex)
555                 .await
556                 .expect("Failed to get next playback buffer");
557 
558             let buffer = [1u8; 480 * 2 * 2];
559 
560             async_pb_buffer
561                 .copy_cb(buffer.len(), |out| out.copy_from_slice(&buffer))
562                 .expect("Failed to copy samples from buffer to win_buffer");
563 
564             async_pb_buffer.commit().await;
565         }
566 
567         let ex = Executor::new().expect("Failed to create executor.");
568 
569         ex.run_until(test(&ex)).unwrap();
570     }
571 
572     // This test is meant to run through the normal audio capture procedure in order to make
573     // debugging easier.
574     #[ignore]
575     #[test]
test_async_capture()576     fn test_async_capture() {
577         async fn test(ex: &Executor) {
578             let stream_source_generator: Box<dyn WinStreamSourceGenerator> =
579                 Box::new(WinAudioStreamSourceGenerator {});
580             let mut stream_source = stream_source_generator
581                 .generate()
582                 .expect("Failed to create stream source.");
583 
584             let (mut async_cp_stream, _shared_format) = stream_source
585                 .new_async_capture_stream_and_get_shared_format(
586                     2,
587                     SampleFormat::S16LE,
588                     48000,
589                     480,
590                     ex,
591                 )
592                 .expect("Failed to create async capture stream.");
593 
594             let mut async_cp_buffer = async_cp_stream
595                 .next_capture_buffer(ex)
596                 .await
597                 .expect("Failed to get next capture buffer");
598 
599             // Capacity of 480 frames, where there are 2 channels and 2 bytes per sample.
600             let mut buffer_to_send_to_guest = Vec::with_capacity(480 * 2 * 2);
601 
602             async_cp_buffer
603                 .copy_cb(buffer_to_send_to_guest.len(), |win_buffer| {
604                     buffer_to_send_to_guest.copy_from_slice(win_buffer);
605                 })
606                 .expect("Failed to copy samples from win_buffer to buffer");
607         }
608 
609         let ex = Executor::new().expect("Failed to create executor.");
610 
611         ex.run_until(test(&ex)).unwrap();
612     }
613 }
614