• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, ) -> 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     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
116         unimplemented!()
117     }
118 
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>119     fn new_async_capture_stream_and_get_shared_format(
120         &mut self,
121         _num_channels: usize,
122         _format: SampleFormat,
123         _frame_rate: u32,
124         _buffer_size: usize,
125         _ex: &dyn audio_streams::AudioStreamsExecutor,
126     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
127         unimplemented!()
128     }
129 
130     /// Evict the playback stream cache so that the audio device can be released, thus allowing
131     /// for machines to go to sleep.
evict_playback_stream_cache(&mut self)132     fn evict_playback_stream_cache(&mut self) {
133         unimplemented!()
134     }
135 
136     /// Returns true if audio server is a noop stream. This determine if evicting a cache is worth
137     /// doing
is_noop_stream(&self) -> bool138     fn is_noop_stream(&self) -> bool;
139 }
140 
141 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>142     fn new_playback_stream_and_get_shared_format(
143         &mut self,
144         num_channels: usize,
145         format: SampleFormat,
146         frame_rate: usize,
147         buffer_size: usize,
148     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
149         let hr = WinAudio::co_init_once_per_thread();
150         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
151 
152         // Return the existing stream if we have one.
153         // This is mainly to reduce audio skips caused by a buffer underrun on the guest. An
154         // underrun causes the guest to stop the audio stream, but then start it back up when the
155         // guest buffer is filled again.
156         if let Some((playback_buffer_stream, audio_format)) =
157             self.cached_playback_buffer_stream.as_ref()
158         {
159             info!("Reusing playback_buffer_stream.");
160             return Ok((playback_buffer_stream.clone(), *audio_format));
161         }
162 
163         let (playback_buffer_stream, audio_shared_format): (
164             Arc<Mutex<Box<dyn PlaybackBufferStream>>>,
165             AudioSharedFormat,
166         ) = match win_audio_impl::WinAudioRenderer::new(
167             num_channels,
168             format,
169             frame_rate as u32,
170             buffer_size,
171         ) {
172             Ok(renderer) => {
173                 let audio_shared_format = renderer.get_audio_shared_format();
174                 let renderer_arc = Arc::new(Mutex::new(
175                     Box::new(renderer) as Box<dyn PlaybackBufferStream>
176                 ));
177                 self.cached_playback_buffer_stream =
178                     Some((renderer_arc.clone(), audio_shared_format));
179                 (renderer_arc, audio_shared_format)
180             }
181             Err(e) => {
182                 error!(
183                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
184                      NoopStream with error: {}",
185                     e
186                 );
187                 (
188                     Arc::new(Mutex::new(Box::new(NoopStream::new(
189                         num_channels,
190                         SampleFormat::S16LE,
191                         frame_rate as u32,
192                         buffer_size,
193                     )))),
194                     AudioSharedFormat {
195                         bit_depth: 16,
196                         frame_rate,
197                         channels: 2,
198                         shared_audio_engine_period_in_frames: frame_rate / 100,
199                         channel_mask: None,
200                     },
201                 )
202             }
203         };
204 
205         Ok((playback_buffer_stream, audio_shared_format))
206     }
207 
208     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
209     // 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, ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError>210     fn new_async_playback_stream_and_get_shared_format(
211         &mut self,
212         num_channels: usize,
213         guest_bit_depth: SampleFormat,
214         frame_rate: usize,
215         buffer_size: usize,
216         ex: &dyn audio_streams::AudioStreamsExecutor,
217     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
218         let hr = WinAudio::co_init_once_per_thread();
219         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
220 
221         let (async_playback_buffer_stream, audio_shared_format): (
222             Box<dyn AsyncPlaybackBufferStream>,
223             AudioSharedFormat,
224         ) = match win_audio_impl::WinAudioRenderer::new_async(
225             num_channels,
226             guest_bit_depth,
227             frame_rate as u32,
228             buffer_size,
229             ex,
230         ) {
231             Ok(renderer) => {
232                 let audio_shared_format = renderer.get_audio_shared_format();
233                 let renderer_box = Box::new(renderer) as Box<dyn AsyncPlaybackBufferStream>;
234                 (renderer_box, audio_shared_format)
235             }
236             Err(e) => {
237                 error!(
238                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
239                      NoopStream with error: {}",
240                     e
241                 );
242                 (
243                     Box::new(NoopStream::new(
244                         num_channels,
245                         SampleFormat::S32LE,
246                         frame_rate as u32,
247                         buffer_size,
248                     )),
249                     AudioSharedFormat {
250                         bit_depth: 32,
251                         frame_rate,
252                         channels: 2,
253                         shared_audio_engine_period_in_frames: frame_rate / 100,
254                         channel_mask: None,
255                     },
256                 )
257             }
258         };
259 
260         Ok((async_playback_buffer_stream, audio_shared_format))
261     }
262 
263     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
264     // 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>265     fn new_async_capture_stream_and_get_shared_format(
266         &mut self,
267         num_channels: usize,
268         guest_bit_depth: SampleFormat,
269         frame_rate: u32,
270         buffer_size: usize,
271         ex: &dyn audio_streams::AudioStreamsExecutor,
272     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
273         let hr = WinAudio::co_init_once_per_thread();
274         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
275 
276         let (capturer, audio_shared_format): (
277             Box<dyn AsyncCaptureBufferStream>,
278             AudioSharedFormat,
279         ) = match WinAudioCapturer::new_async(
280             num_channels,
281             guest_bit_depth,
282             frame_rate,
283             buffer_size,
284             ex,
285         ) {
286             Ok(capturer) => {
287                 let audio_shared_format = capturer.get_audio_shared_format();
288                 (Box::new(capturer), audio_shared_format)
289             }
290             Err(e) => {
291                 warn!("Failed to create WinAudioCapturer. Fallback to NoopCaptureStream with error: {}", e);
292                 (
293                     Box::new(NoopCaptureStream::new(
294                         num_channels,
295                         SampleFormat::S32LE,
296                         frame_rate,
297                         buffer_size,
298                     )),
299                     AudioSharedFormat {
300                         bit_depth: 32,
301                         frame_rate: frame_rate as usize,
302                         channels: 2,
303                         shared_audio_engine_period_in_frames: frame_rate as usize / 100,
304                         channel_mask: None,
305                     },
306                 )
307             }
308         };
309 
310         Ok((capturer, audio_shared_format))
311     }
312 
evict_playback_stream_cache(&mut self)313     fn evict_playback_stream_cache(&mut self) {
314         self.cached_playback_buffer_stream = None;
315     }
316 
is_noop_stream(&self) -> bool317     fn is_noop_stream(&self) -> bool {
318         false
319     }
320 }
321 
322 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>323     fn new_playback_stream_and_get_shared_format(
324         &mut self,
325         num_channels: usize,
326         format: SampleFormat,
327         frame_rate: usize,
328         buffer_size: usize,
329     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
330         let (_, playback_buffer_stream) = self
331             .new_playback_stream(num_channels, format, frame_rate as u32, buffer_size)
332             .unwrap();
333         Ok((
334             Arc::new(Mutex::new(playback_buffer_stream)),
335             AudioSharedFormat {
336                 bit_depth: 16,
337                 frame_rate,
338                 channels: 2,
339                 shared_audio_engine_period_in_frames: frame_rate / 100,
340                 channel_mask: None,
341             },
342         ))
343     }
344 
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, ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError>345     fn new_async_playback_stream_and_get_shared_format(
346         &mut self,
347         num_channels: usize,
348         format: SampleFormat,
349         frame_rate: usize,
350         buffer_size: usize,
351         ex: &dyn audio_streams::AudioStreamsExecutor,
352     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
353         let (_, playback_stream) = self
354             .new_async_playback_stream(num_channels, format, frame_rate as u32, buffer_size, ex)
355             .unwrap();
356 
357         // Set shared format to be the same as the incoming audio format.
358         let format = AudioSharedFormat {
359             bit_depth: format.sample_bytes() * 8,
360             frame_rate,
361             channels: num_channels,
362             shared_audio_engine_period_in_frames: buffer_size * format.sample_bytes(),
363             channel_mask: None,
364         };
365         Ok((playback_stream, format))
366     }
367 
is_noop_stream(&self) -> bool368     fn is_noop_stream(&self) -> bool {
369         true
370     }
371 }
372 
create_win_audio_device() -> Result<WinAudio, BoxError>373 pub fn create_win_audio_device() -> Result<WinAudio, BoxError> {
374     WinAudio::new()
375 }
376