• 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 #![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