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