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 #![allow(non_upper_case_globals)]
6 include!(concat!(
7 env!("CARGO_MANIFEST_DIR"),
8 "/src/r8brain_sys/bindings.rs"
9 ));
10
11 macro_rules! check_hresult {
12 ($hr: expr, $error: expr, $msg: expr) => {
13 if winapi::shared::winerror::FAILED($hr) {
14 base::warn!("{}", $msg);
15 Err($error)
16 } else {
17 Ok($hr)
18 }
19 };
20 }
21
22 pub mod intermediate_resampler_buffer;
23 mod win_audio_impl;
24 use std::error;
25 use std::sync::Arc;
26
27 use audio_streams::AsyncPlaybackBufferStream;
28 use audio_streams::NoopStream;
29 use audio_streams::NoopStreamSource;
30 use audio_streams::NoopStreamSourceGenerator;
31 use audio_streams::PlaybackBufferStream;
32 use audio_streams::SampleFormat;
33 use audio_streams::StreamSource;
34 use audio_util::FileStreamSourceGenerator;
35 use base::info;
36 use base::warn;
37 use sync::Mutex;
38 use win_audio_impl::async_stream::WinAudioStreamSourceGenerator;
39 pub use win_audio_impl::*;
40
41 pub type BoxError = Box<dyn error::Error + Send + Sync>;
42
43 pub trait WinStreamSourceGenerator: Send + Sync {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>44 fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>;
45 }
46
47 impl WinStreamSourceGenerator for WinAudioStreamSourceGenerator {
generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError>48 fn generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError> {
49 Ok(Box::new(WinAudio::new()?))
50 }
51 }
52
53 impl WinStreamSourceGenerator for NoopStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>54 fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
55 Ok(Box::new(NoopStreamSource))
56 }
57 }
58
59 impl WinStreamSourceGenerator for FileStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>60 fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
61 unimplemented!();
62 }
63 }
64
65 /// Contains information about the audio engine's properties, such as its audio sample format
66 /// and its period in frames.
67 ///
68 /// This does exclude whether the bit depth is in the form of floats or ints. The bit depth form
69 /// isn't used for sample rate conversion so it's excluded.
70 #[derive(Clone, Copy)]
71 pub struct AudioSharedFormat {
72 pub bit_depth: usize,
73 pub frame_rate: usize,
74 pub shared_audio_engine_period_in_frames: usize,
75 pub channels: usize,
76 // Only available for WAVEFORMATEXTENSIBLE
77 pub channel_mask: Option<u32>,
78 }
79
80 /// Implementation of StreamSource which will create the playback stream for the Windows
81 /// audio engine.
82 ///
83 /// Extending the StreamSource trait will allow us to make necessary changes without modifying
84 /// the third party audiostream library.
85 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>86 fn new_playback_stream_and_get_shared_format(
87 &mut self,
88 num_channels: usize,
89 format: SampleFormat,
90 frame_rate: usize,
91 buffer_size: usize,
92 ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>;
93
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>94 fn new_async_playback_stream_and_get_shared_format(
95 &mut self,
96 _num_channels: usize,
97 _format: SampleFormat,
98 _frame_rate: usize,
99 _buffer_size: usize,
100 _ex: &dyn audio_streams::AudioStreamsExecutor,
101 ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
102 unimplemented!()
103 }
104
105 /// Evict the playback stream cache so that the audio device can be released, thus allowing
106 /// for machines to go to sleep.
evict_playback_stream_cache(&mut self)107 fn evict_playback_stream_cache(&mut self) {
108 unimplemented!()
109 }
110
111 /// Returns true if audio server is a noop stream. This determine if evicting a cache is worth
112 /// doing
is_noop_stream(&self) -> bool113 fn is_noop_stream(&self) -> bool;
114 }
115
116 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>117 fn new_playback_stream_and_get_shared_format(
118 &mut self,
119 num_channels: usize,
120 _format: SampleFormat,
121 frame_rate: usize,
122 buffer_size: usize,
123 ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
124 let hr = WinAudio::co_init_once_per_thread();
125 let _ = check_hresult!(hr, RenderError::from(hr), "Co Initialized failed");
126
127 // Return the existing stream if we have one.
128 // This is mainly to reduce audio skips caused by a buffer underrun on the guest. An
129 // underrun causes the guest to stop the audio stream, but then start it back up when the
130 // guest buffer is filled again.
131 if let Some((playback_buffer_stream, audio_format)) =
132 self.cached_playback_buffer_stream.as_ref()
133 {
134 info!("Reusing playback_buffer_stream.");
135 return Ok((playback_buffer_stream.clone(), *audio_format));
136 }
137
138 let (playback_buffer_stream, audio_shared_format): (
139 Arc<Mutex<Box<dyn PlaybackBufferStream>>>,
140 AudioSharedFormat,
141 ) = match win_audio_impl::WinAudioRenderer::new(
142 num_channels,
143 frame_rate as u32,
144 buffer_size,
145 ) {
146 Ok(renderer) => {
147 let audio_shared_format = renderer.device.audio_shared_format;
148 let renderer_arc = Arc::new(Mutex::new(
149 Box::new(renderer) as Box<dyn PlaybackBufferStream>
150 ));
151 self.cached_playback_buffer_stream =
152 Some((renderer_arc.clone(), audio_shared_format));
153 (renderer_arc, audio_shared_format)
154 }
155 Err(e) => {
156 warn!(
157 "Failed to create WinAudioRenderer. Fallback to NoopStream with error: {}",
158 e
159 );
160 (
161 Arc::new(Mutex::new(Box::new(NoopStream::new(
162 num_channels,
163 SampleFormat::S16LE,
164 frame_rate as u32,
165 buffer_size,
166 )))),
167 AudioSharedFormat {
168 bit_depth: 16,
169 frame_rate,
170 channels: 2,
171 shared_audio_engine_period_in_frames: frame_rate / 100,
172 channel_mask: None,
173 },
174 )
175 }
176 };
177
178 Ok((playback_buffer_stream, audio_shared_format))
179 }
180
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>181 fn new_async_playback_stream_and_get_shared_format(
182 &mut self,
183 num_channels: usize,
184 _format: SampleFormat,
185 frame_rate: usize,
186 buffer_size: usize,
187 ex: &dyn audio_streams::AudioStreamsExecutor,
188 ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
189 let hr = WinAudio::co_init_once_per_thread();
190 let _ = check_hresult!(hr, RenderError::from(hr), "Co Initialized failed");
191
192 let (async_playback_buffer_stream, audio_shared_format): (
193 Box<dyn AsyncPlaybackBufferStream>,
194 AudioSharedFormat,
195 ) = match win_audio_impl::WinAudioRenderer::new_async(
196 num_channels,
197 frame_rate as u32,
198 buffer_size,
199 ex,
200 ) {
201 Ok(renderer) => {
202 let audio_shared_format = renderer.device.audio_shared_format;
203 let renderer_box = Box::new(renderer) as Box<dyn AsyncPlaybackBufferStream>;
204 (renderer_box, audio_shared_format)
205 }
206 Err(e) => {
207 warn!(
208 "Failed to create WinAudioRenderer. Fallback to NoopStream with error: {}",
209 e
210 );
211 (
212 Box::new(NoopStream::new(
213 num_channels,
214 SampleFormat::S16LE,
215 frame_rate as u32,
216 buffer_size,
217 )),
218 AudioSharedFormat {
219 bit_depth: 16,
220 frame_rate,
221 channels: 2,
222 shared_audio_engine_period_in_frames: frame_rate / 100,
223 channel_mask: None,
224 },
225 )
226 }
227 };
228
229 Ok((async_playback_buffer_stream, audio_shared_format))
230 }
231
evict_playback_stream_cache(&mut self)232 fn evict_playback_stream_cache(&mut self) {
233 self.cached_playback_buffer_stream = None;
234 }
235
is_noop_stream(&self) -> bool236 fn is_noop_stream(&self) -> bool {
237 false
238 }
239 }
240
241 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>242 fn new_playback_stream_and_get_shared_format(
243 &mut self,
244 num_channels: usize,
245 format: SampleFormat,
246 frame_rate: usize,
247 buffer_size: usize,
248 ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
249 let (_, playback_buffer_stream) = self
250 .new_playback_stream(num_channels, format, frame_rate as u32, buffer_size)
251 .unwrap();
252 Ok((
253 Arc::new(Mutex::new(playback_buffer_stream)),
254 AudioSharedFormat {
255 bit_depth: 16,
256 frame_rate,
257 channels: 2,
258 shared_audio_engine_period_in_frames: frame_rate / 100,
259 channel_mask: None,
260 },
261 ))
262 }
263
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>264 fn new_async_playback_stream_and_get_shared_format(
265 &mut self,
266 num_channels: usize,
267 format: SampleFormat,
268 frame_rate: usize,
269 buffer_size: usize,
270 ex: &dyn audio_streams::AudioStreamsExecutor,
271 ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
272 let (_, playback_stream) = self
273 .new_async_playback_stream(num_channels, format, frame_rate as u32, buffer_size, ex)
274 .unwrap();
275
276 // Set shared format to be the same as the incoming audio format.
277 let format = AudioSharedFormat {
278 bit_depth: format.sample_bytes() * 8,
279 frame_rate,
280 channels: num_channels,
281 shared_audio_engine_period_in_frames: buffer_size * format.sample_bytes(),
282 channel_mask: None,
283 };
284 Ok((playback_stream, format))
285 }
286
is_noop_stream(&self) -> bool287 fn is_noop_stream(&self) -> bool {
288 true
289 }
290 }
291
create_win_audio_device() -> Result<WinAudio, BoxError>292 pub fn create_win_audio_device() -> Result<WinAudio, BoxError> {
293 WinAudio::new()
294 }
295