xref: /aosp_15_r20/external/crosvm/win_audio/src/lib.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 // Do nothing on unix as win_audio is windows only.
6 #![cfg(windows)]
7 #![allow(non_upper_case_globals)]
8 include!(concat!(
9     env!("CARGO_MANIFEST_DIR"),
10     "/src/r8brain_sys/bindings.rs"
11 ));
12 
13 macro_rules! check_hresult {
14     ($hr: expr, $error: expr, $msg: expr) => {
15         if winapi::shared::winerror::FAILED($hr) {
16             base::warn!("{}: {}", $msg, $hr);
17             Err($error)
18         } else {
19             Ok($hr)
20         }
21     };
22 }
23 
24 pub mod intermediate_resampler_buffer;
25 mod win_audio_impl;
26 use std::error;
27 use std::sync::Arc;
28 
29 use audio_streams::capture::AsyncCaptureBufferStream;
30 use audio_streams::capture::NoopCaptureStream;
31 use audio_streams::AsyncPlaybackBufferStream;
32 use audio_streams::NoopStream;
33 use audio_streams::NoopStreamSource;
34 use audio_streams::NoopStreamSourceGenerator;
35 use audio_streams::PlaybackBufferStream;
36 use audio_streams::SampleFormat;
37 use audio_streams::StreamSource;
38 use audio_util::FileStreamSourceGenerator;
39 use base::error;
40 use base::info;
41 use base::warn;
42 pub use intermediate_resampler_buffer::ANDROID_CAPTURE_FRAME_SIZE_BYTES;
43 pub use intermediate_resampler_buffer::BYTES_PER_32FLOAT;
44 use sync::Mutex;
45 use win_audio_impl::async_stream::WinAudioStreamSourceGenerator;
46 pub use win_audio_impl::*;
47 
48 pub type BoxError = Box<dyn error::Error + Send + Sync>;
49 
50 pub trait WinStreamSourceGenerator: Send + Sync {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>51     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>;
52 }
53 
54 impl WinStreamSourceGenerator for WinAudioStreamSourceGenerator {
generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError>55     fn generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError> {
56         Ok(Box::new(WinAudio::new()?))
57     }
58 }
59 
60 impl WinStreamSourceGenerator for NoopStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>61     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
62         Ok(Box::new(NoopStreamSource))
63     }
64 }
65 
66 impl WinStreamSourceGenerator for FileStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>67     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
68         unimplemented!();
69     }
70 }
71 
72 /// Contains information about the audio engine's properties, such as its audio sample format
73 /// and its period in frames.
74 ///
75 /// This does exclude whether the bit depth is in the form of floats or ints. The bit depth form
76 /// isn't used for sample rate conversion so it's excluded.
77 #[derive(Clone, Copy)]
78 pub struct AudioSharedFormat {
79     pub bit_depth: usize,
80     pub frame_rate: usize,
81     pub shared_audio_engine_period_in_frames: usize,
82     pub channels: usize,
83     // Only available for WAVEFORMATEXTENSIBLE
84     pub channel_mask: Option<u32>,
85 }
86 
87 impl AudioSharedFormat {
get_shared_audio_engine_period_in_bytes(&self) -> usize88     fn get_shared_audio_engine_period_in_bytes(&self) -> usize {
89         let frame_size_bytes = self.bit_depth * self.channels / 8;
90         self.shared_audio_engine_period_in_frames * frame_size_bytes
91     }
92 }
93 
94 /// Implementation of StreamSource which will create the playback stream for the Windows
95 /// audio engine.
96 ///
97 /// Extending the StreamSource trait will allow us to make necessary changes without modifying
98 /// the third party audiostream library.
99 pub trait WinAudioServer: StreamSource {
new_playback_stream_and_get_shared_format( &mut self, num_channels: usize, format: SampleFormat, frame_rate: usize, buffer_size: usize, ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>100     fn new_playback_stream_and_get_shared_format(
101         &mut self,
102         num_channels: usize,
103         format: SampleFormat,
104         frame_rate: usize,
105         buffer_size: usize,
106     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>;
107 
new_async_playback_stream_and_get_shared_format( &mut self, _num_channels: usize, _format: SampleFormat, _frame_rate: usize, _buffer_size: usize, _ex: &dyn audio_streams::AudioStreamsExecutor, _audio_client_guid: Option<String>, ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError>108     fn new_async_playback_stream_and_get_shared_format(
109         &mut self,
110         _num_channels: usize,
111         _format: SampleFormat,
112         _frame_rate: usize,
113         _buffer_size: usize,
114         _ex: &dyn audio_streams::AudioStreamsExecutor,
115         _audio_client_guid: Option<String>,
116     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
117         unimplemented!()
118     }
119 
new_async_capture_stream_and_get_shared_format( &mut self, _num_channels: usize, _format: SampleFormat, _frame_rate: u32, _buffer_size: usize, _ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError>120     fn new_async_capture_stream_and_get_shared_format(
121         &mut self,
122         _num_channels: usize,
123         _format: SampleFormat,
124         _frame_rate: u32,
125         _buffer_size: usize,
126         _ex: &dyn audio_streams::AudioStreamsExecutor,
127     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
128         unimplemented!()
129     }
130 
131     /// Evict the playback stream cache so that the audio device can be released, thus allowing
132     /// for machines to go to sleep.
evict_playback_stream_cache(&mut self)133     fn evict_playback_stream_cache(&mut self) {
134         unimplemented!()
135     }
136 
137     /// Returns true if audio server is a noop stream. This determine if evicting a cache is worth
138     /// doing
is_noop_stream(&self) -> bool139     fn is_noop_stream(&self) -> bool;
140 }
141 
142 impl WinAudioServer for WinAudio {
new_playback_stream_and_get_shared_format( &mut self, num_channels: usize, format: SampleFormat, frame_rate: usize, buffer_size: usize, ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>143     fn new_playback_stream_and_get_shared_format(
144         &mut self,
145         num_channels: usize,
146         format: SampleFormat,
147         frame_rate: usize,
148         buffer_size: usize,
149     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
150         let hr = WinAudio::co_init_once_per_thread();
151         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
152 
153         // Return the existing stream if we have one.
154         // This is mainly to reduce audio skips caused by a buffer underrun on the guest. An
155         // underrun causes the guest to stop the audio stream, but then start it back up when the
156         // guest buffer is filled again.
157         if let Some((playback_buffer_stream, audio_format)) =
158             self.cached_playback_buffer_stream.as_ref()
159         {
160             info!("Reusing playback_buffer_stream.");
161             return Ok((playback_buffer_stream.clone(), *audio_format));
162         }
163 
164         let (playback_buffer_stream, audio_shared_format): (
165             Arc<Mutex<Box<dyn PlaybackBufferStream>>>,
166             AudioSharedFormat,
167         ) = match win_audio_impl::WinAudioRenderer::new(
168             num_channels,
169             format,
170             frame_rate as u32,
171             buffer_size,
172         ) {
173             Ok(renderer) => {
174                 let audio_shared_format = renderer.get_audio_shared_format();
175                 let renderer_arc = Arc::new(Mutex::new(
176                     Box::new(renderer) as Box<dyn PlaybackBufferStream>
177                 ));
178                 self.cached_playback_buffer_stream =
179                     Some((renderer_arc.clone(), audio_shared_format));
180                 (renderer_arc, audio_shared_format)
181             }
182             Err(e) => {
183                 error!(
184                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
185                      NoopStream with error: {}",
186                     e
187                 );
188                 (
189                     Arc::new(Mutex::new(Box::new(NoopStream::new(
190                         num_channels,
191                         SampleFormat::S16LE,
192                         frame_rate as u32,
193                         buffer_size,
194                     )))),
195                     AudioSharedFormat {
196                         bit_depth: 16,
197                         frame_rate,
198                         channels: 2,
199                         shared_audio_engine_period_in_frames: frame_rate / 100,
200                         channel_mask: None,
201                     },
202                 )
203             }
204         };
205 
206         Ok((playback_buffer_stream, audio_shared_format))
207     }
208 
209     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
210     // upstreaming.
new_async_playback_stream_and_get_shared_format( &mut self, num_channels: usize, guest_bit_depth: SampleFormat, frame_rate: usize, buffer_size: usize, ex: &dyn audio_streams::AudioStreamsExecutor, audio_client_guid: Option<String>, ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError>211     fn new_async_playback_stream_and_get_shared_format(
212         &mut self,
213         num_channels: usize,
214         guest_bit_depth: SampleFormat,
215         frame_rate: usize,
216         buffer_size: usize,
217         ex: &dyn audio_streams::AudioStreamsExecutor,
218         audio_client_guid: Option<String>,
219     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
220         let hr = WinAudio::co_init_once_per_thread();
221         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
222 
223         let (async_playback_buffer_stream, audio_shared_format): (
224             Box<dyn AsyncPlaybackBufferStream>,
225             AudioSharedFormat,
226         ) = match win_audio_impl::WinAudioRenderer::new_async(
227             num_channels,
228             guest_bit_depth,
229             frame_rate as u32,
230             buffer_size,
231             ex,
232             audio_client_guid,
233         ) {
234             Ok(renderer) => {
235                 let audio_shared_format = renderer.get_audio_shared_format();
236                 let renderer_box = Box::new(renderer) as Box<dyn AsyncPlaybackBufferStream>;
237                 (renderer_box, audio_shared_format)
238             }
239             Err(e) => {
240                 error!(
241                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
242                      NoopStream with error: {}",
243                     e
244                 );
245                 (
246                     Box::new(NoopStream::new(
247                         num_channels,
248                         SampleFormat::S32LE,
249                         frame_rate as u32,
250                         buffer_size,
251                     )),
252                     AudioSharedFormat {
253                         bit_depth: 32,
254                         frame_rate,
255                         channels: 2,
256                         shared_audio_engine_period_in_frames: frame_rate / 100,
257                         channel_mask: None,
258                     },
259                 )
260             }
261         };
262 
263         Ok((async_playback_buffer_stream, audio_shared_format))
264     }
265 
266     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
267     // upstreaming.
new_async_capture_stream_and_get_shared_format( &mut self, num_channels: usize, guest_bit_depth: SampleFormat, frame_rate: u32, buffer_size: usize, ex: &dyn audio_streams::AudioStreamsExecutor, ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError>268     fn new_async_capture_stream_and_get_shared_format(
269         &mut self,
270         num_channels: usize,
271         guest_bit_depth: SampleFormat,
272         frame_rate: u32,
273         buffer_size: usize,
274         ex: &dyn audio_streams::AudioStreamsExecutor,
275     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
276         let hr = WinAudio::co_init_once_per_thread();
277         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
278 
279         let (capturer, audio_shared_format): (
280             Box<dyn AsyncCaptureBufferStream>,
281             AudioSharedFormat,
282         ) = match WinAudioCapturer::new_async(
283             num_channels,
284             guest_bit_depth,
285             frame_rate,
286             buffer_size,
287             ex,
288         ) {
289             Ok(capturer) => {
290                 let audio_shared_format = capturer.get_audio_shared_format();
291                 (Box::new(capturer), audio_shared_format)
292             }
293             Err(e) => {
294                 warn!("Failed to create WinAudioCapturer. Fallback to NoopCaptureStream with error: {}", e);
295                 (
296                     Box::new(NoopCaptureStream::new(
297                         num_channels,
298                         SampleFormat::S32LE,
299                         frame_rate,
300                         buffer_size,
301                     )),
302                     AudioSharedFormat {
303                         bit_depth: 32,
304                         frame_rate: frame_rate as usize,
305                         channels: 2,
306                         shared_audio_engine_period_in_frames: frame_rate as usize / 100,
307                         channel_mask: None,
308                     },
309                 )
310             }
311         };
312 
313         Ok((capturer, audio_shared_format))
314     }
315 
evict_playback_stream_cache(&mut self)316     fn evict_playback_stream_cache(&mut self) {
317         self.cached_playback_buffer_stream = None;
318     }
319 
is_noop_stream(&self) -> bool320     fn is_noop_stream(&self) -> bool {
321         false
322     }
323 }
324 
325 impl WinAudioServer for NoopStreamSource {
new_playback_stream_and_get_shared_format( &mut self, num_channels: usize, format: SampleFormat, frame_rate: usize, buffer_size: usize, ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>326     fn new_playback_stream_and_get_shared_format(
327         &mut self,
328         num_channels: usize,
329         format: SampleFormat,
330         frame_rate: usize,
331         buffer_size: usize,
332     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
333         let (_, playback_buffer_stream) = self
334             .new_playback_stream(num_channels, format, frame_rate as u32, buffer_size)
335             .unwrap();
336         Ok((
337             Arc::new(Mutex::new(playback_buffer_stream)),
338             AudioSharedFormat {
339                 bit_depth: 16,
340                 frame_rate,
341                 channels: 2,
342                 shared_audio_engine_period_in_frames: frame_rate / 100,
343                 channel_mask: None,
344             },
345         ))
346     }
347 
new_async_playback_stream_and_get_shared_format( &mut self, num_channels: usize, format: SampleFormat, frame_rate: usize, buffer_size: usize, ex: &dyn audio_streams::AudioStreamsExecutor, _audio_client_guid: Option<String>, ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError>348     fn new_async_playback_stream_and_get_shared_format(
349         &mut self,
350         num_channels: usize,
351         format: SampleFormat,
352         frame_rate: usize,
353         buffer_size: usize,
354         ex: &dyn audio_streams::AudioStreamsExecutor,
355         _audio_client_guid: Option<String>,
356     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
357         let (_, playback_stream) = self
358             .new_async_playback_stream(num_channels, format, frame_rate as u32, buffer_size, ex)
359             .unwrap();
360 
361         // Set shared format to be the same as the incoming audio format.
362         let format = AudioSharedFormat {
363             bit_depth: format.sample_bytes() * 8,
364             frame_rate,
365             channels: num_channels,
366             shared_audio_engine_period_in_frames: buffer_size * format.sample_bytes(),
367             channel_mask: None,
368         };
369         Ok((playback_stream, format))
370     }
371 
is_noop_stream(&self) -> bool372     fn is_noop_stream(&self) -> bool {
373         true
374     }
375 }
376 
create_win_audio_device() -> Result<WinAudio, BoxError>377 pub fn create_win_audio_device() -> Result<WinAudio, BoxError> {
378     WinAudio::new()
379 }
380