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