xref: /aosp_15_r20/external/crosvm/win_audio/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker // Do nothing on unix as win_audio is windows only.
6*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(windows)]
7*bb4ee6a4SAndroid Build Coastguard Worker #![allow(non_upper_case_globals)]
8*bb4ee6a4SAndroid Build Coastguard Worker include!(concat!(
9*bb4ee6a4SAndroid Build Coastguard Worker     env!("CARGO_MANIFEST_DIR"),
10*bb4ee6a4SAndroid Build Coastguard Worker     "/src/r8brain_sys/bindings.rs"
11*bb4ee6a4SAndroid Build Coastguard Worker ));
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! check_hresult {
14*bb4ee6a4SAndroid Build Coastguard Worker     ($hr: expr, $error: expr, $msg: expr) => {
15*bb4ee6a4SAndroid Build Coastguard Worker         if winapi::shared::winerror::FAILED($hr) {
16*bb4ee6a4SAndroid Build Coastguard Worker             base::warn!("{}: {}", $msg, $hr);
17*bb4ee6a4SAndroid Build Coastguard Worker             Err($error)
18*bb4ee6a4SAndroid Build Coastguard Worker         } else {
19*bb4ee6a4SAndroid Build Coastguard Worker             Ok($hr)
20*bb4ee6a4SAndroid Build Coastguard Worker         }
21*bb4ee6a4SAndroid Build Coastguard Worker     };
22*bb4ee6a4SAndroid Build Coastguard Worker }
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker pub mod intermediate_resampler_buffer;
25*bb4ee6a4SAndroid Build Coastguard Worker mod win_audio_impl;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::error;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::capture::AsyncCaptureBufferStream;
30*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::capture::NoopCaptureStream;
31*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::AsyncPlaybackBufferStream;
32*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::NoopStream;
33*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::NoopStreamSource;
34*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::NoopStreamSourceGenerator;
35*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::PlaybackBufferStream;
36*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::SampleFormat;
37*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::StreamSource;
38*bb4ee6a4SAndroid Build Coastguard Worker use audio_util::FileStreamSourceGenerator;
39*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
40*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
41*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
42*bb4ee6a4SAndroid Build Coastguard Worker pub use intermediate_resampler_buffer::ANDROID_CAPTURE_FRAME_SIZE_BYTES;
43*bb4ee6a4SAndroid Build Coastguard Worker pub use intermediate_resampler_buffer::BYTES_PER_32FLOAT;
44*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
45*bb4ee6a4SAndroid Build Coastguard Worker use win_audio_impl::async_stream::WinAudioStreamSourceGenerator;
46*bb4ee6a4SAndroid Build Coastguard Worker pub use win_audio_impl::*;
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker pub type BoxError = Box<dyn error::Error + Send + Sync>;
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker pub trait WinStreamSourceGenerator: Send + Sync {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>51*bb4ee6a4SAndroid Build Coastguard Worker     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>;
52*bb4ee6a4SAndroid Build Coastguard Worker }
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker impl WinStreamSourceGenerator for WinAudioStreamSourceGenerator {
generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError>55*bb4ee6a4SAndroid Build Coastguard Worker     fn generate(&self) -> std::result::Result<Box<dyn WinAudioServer>, BoxError> {
56*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(WinAudio::new()?))
57*bb4ee6a4SAndroid Build Coastguard Worker     }
58*bb4ee6a4SAndroid Build Coastguard Worker }
59*bb4ee6a4SAndroid Build Coastguard Worker 
60*bb4ee6a4SAndroid Build Coastguard Worker impl WinStreamSourceGenerator for NoopStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>61*bb4ee6a4SAndroid Build Coastguard Worker     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
62*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(NoopStreamSource))
63*bb4ee6a4SAndroid Build Coastguard Worker     }
64*bb4ee6a4SAndroid Build Coastguard Worker }
65*bb4ee6a4SAndroid Build Coastguard Worker 
66*bb4ee6a4SAndroid Build Coastguard Worker impl WinStreamSourceGenerator for FileStreamSourceGenerator {
generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError>67*bb4ee6a4SAndroid Build Coastguard Worker     fn generate(&self) -> Result<Box<dyn WinAudioServer>, BoxError> {
68*bb4ee6a4SAndroid Build Coastguard Worker         unimplemented!();
69*bb4ee6a4SAndroid Build Coastguard Worker     }
70*bb4ee6a4SAndroid Build Coastguard Worker }
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker /// Contains information about the audio engine's properties, such as its audio sample format
73*bb4ee6a4SAndroid Build Coastguard Worker /// and its period in frames.
74*bb4ee6a4SAndroid Build Coastguard Worker ///
75*bb4ee6a4SAndroid Build Coastguard Worker /// This does exclude whether the bit depth is in the form of floats or ints. The bit depth form
76*bb4ee6a4SAndroid Build Coastguard Worker /// isn't used for sample rate conversion so it's excluded.
77*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)]
78*bb4ee6a4SAndroid Build Coastguard Worker pub struct AudioSharedFormat {
79*bb4ee6a4SAndroid Build Coastguard Worker     pub bit_depth: usize,
80*bb4ee6a4SAndroid Build Coastguard Worker     pub frame_rate: usize,
81*bb4ee6a4SAndroid Build Coastguard Worker     pub shared_audio_engine_period_in_frames: usize,
82*bb4ee6a4SAndroid Build Coastguard Worker     pub channels: usize,
83*bb4ee6a4SAndroid Build Coastguard Worker     // Only available for WAVEFORMATEXTENSIBLE
84*bb4ee6a4SAndroid Build Coastguard Worker     pub channel_mask: Option<u32>,
85*bb4ee6a4SAndroid Build Coastguard Worker }
86*bb4ee6a4SAndroid Build Coastguard Worker 
87*bb4ee6a4SAndroid Build Coastguard Worker impl AudioSharedFormat {
get_shared_audio_engine_period_in_bytes(&self) -> usize88*bb4ee6a4SAndroid Build Coastguard Worker     fn get_shared_audio_engine_period_in_bytes(&self) -> usize {
89*bb4ee6a4SAndroid Build Coastguard Worker         let frame_size_bytes = self.bit_depth * self.channels / 8;
90*bb4ee6a4SAndroid Build Coastguard Worker         self.shared_audio_engine_period_in_frames * frame_size_bytes
91*bb4ee6a4SAndroid Build Coastguard Worker     }
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker 
94*bb4ee6a4SAndroid Build Coastguard Worker /// Implementation of StreamSource which will create the playback stream for the Windows
95*bb4ee6a4SAndroid Build Coastguard Worker /// audio engine.
96*bb4ee6a4SAndroid Build Coastguard Worker ///
97*bb4ee6a4SAndroid Build Coastguard Worker /// Extending the StreamSource trait will allow us to make necessary changes without modifying
98*bb4ee6a4SAndroid Build Coastguard Worker /// the third party audiostream library.
99*bb4ee6a4SAndroid Build Coastguard Worker 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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_playback_stream_and_get_shared_format(
101*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
102*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
103*bb4ee6a4SAndroid Build Coastguard Worker         format: SampleFormat,
104*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: usize,
105*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
106*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError>;
107*bb4ee6a4SAndroid Build Coastguard Worker 
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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_playback_stream_and_get_shared_format(
109*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
110*bb4ee6a4SAndroid Build Coastguard Worker         _num_channels: usize,
111*bb4ee6a4SAndroid Build Coastguard Worker         _format: SampleFormat,
112*bb4ee6a4SAndroid Build Coastguard Worker         _frame_rate: usize,
113*bb4ee6a4SAndroid Build Coastguard Worker         _buffer_size: usize,
114*bb4ee6a4SAndroid Build Coastguard Worker         _ex: &dyn audio_streams::AudioStreamsExecutor,
115*bb4ee6a4SAndroid Build Coastguard Worker         _audio_client_guid: Option<String>,
116*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
117*bb4ee6a4SAndroid Build Coastguard Worker         unimplemented!()
118*bb4ee6a4SAndroid Build Coastguard Worker     }
119*bb4ee6a4SAndroid Build Coastguard Worker 
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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_capture_stream_and_get_shared_format(
121*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
122*bb4ee6a4SAndroid Build Coastguard Worker         _num_channels: usize,
123*bb4ee6a4SAndroid Build Coastguard Worker         _format: SampleFormat,
124*bb4ee6a4SAndroid Build Coastguard Worker         _frame_rate: u32,
125*bb4ee6a4SAndroid Build Coastguard Worker         _buffer_size: usize,
126*bb4ee6a4SAndroid Build Coastguard Worker         _ex: &dyn audio_streams::AudioStreamsExecutor,
127*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
128*bb4ee6a4SAndroid Build Coastguard Worker         unimplemented!()
129*bb4ee6a4SAndroid Build Coastguard Worker     }
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker     /// Evict the playback stream cache so that the audio device can be released, thus allowing
132*bb4ee6a4SAndroid Build Coastguard Worker     /// for machines to go to sleep.
evict_playback_stream_cache(&mut self)133*bb4ee6a4SAndroid Build Coastguard Worker     fn evict_playback_stream_cache(&mut self) {
134*bb4ee6a4SAndroid Build Coastguard Worker         unimplemented!()
135*bb4ee6a4SAndroid Build Coastguard Worker     }
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns true if audio server is a noop stream. This determine if evicting a cache is worth
138*bb4ee6a4SAndroid Build Coastguard Worker     /// doing
is_noop_stream(&self) -> bool139*bb4ee6a4SAndroid Build Coastguard Worker     fn is_noop_stream(&self) -> bool;
140*bb4ee6a4SAndroid Build Coastguard Worker }
141*bb4ee6a4SAndroid Build Coastguard Worker 
142*bb4ee6a4SAndroid Build Coastguard Worker 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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_playback_stream_and_get_shared_format(
144*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
145*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
146*bb4ee6a4SAndroid Build Coastguard Worker         format: SampleFormat,
147*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: usize,
148*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
149*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
150*bb4ee6a4SAndroid Build Coastguard Worker         let hr = WinAudio::co_init_once_per_thread();
151*bb4ee6a4SAndroid Build Coastguard Worker         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
152*bb4ee6a4SAndroid Build Coastguard Worker 
153*bb4ee6a4SAndroid Build Coastguard Worker         // Return the existing stream if we have one.
154*bb4ee6a4SAndroid Build Coastguard Worker         // This is mainly to reduce audio skips caused by a buffer underrun on the guest. An
155*bb4ee6a4SAndroid Build Coastguard Worker         // underrun causes the guest to stop the audio stream, but then start it back up when the
156*bb4ee6a4SAndroid Build Coastguard Worker         // guest buffer is filled again.
157*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((playback_buffer_stream, audio_format)) =
158*bb4ee6a4SAndroid Build Coastguard Worker             self.cached_playback_buffer_stream.as_ref()
159*bb4ee6a4SAndroid Build Coastguard Worker         {
160*bb4ee6a4SAndroid Build Coastguard Worker             info!("Reusing playback_buffer_stream.");
161*bb4ee6a4SAndroid Build Coastguard Worker             return Ok((playback_buffer_stream.clone(), *audio_format));
162*bb4ee6a4SAndroid Build Coastguard Worker         }
163*bb4ee6a4SAndroid Build Coastguard Worker 
164*bb4ee6a4SAndroid Build Coastguard Worker         let (playback_buffer_stream, audio_shared_format): (
165*bb4ee6a4SAndroid Build Coastguard Worker             Arc<Mutex<Box<dyn PlaybackBufferStream>>>,
166*bb4ee6a4SAndroid Build Coastguard Worker             AudioSharedFormat,
167*bb4ee6a4SAndroid Build Coastguard Worker         ) = match win_audio_impl::WinAudioRenderer::new(
168*bb4ee6a4SAndroid Build Coastguard Worker             num_channels,
169*bb4ee6a4SAndroid Build Coastguard Worker             format,
170*bb4ee6a4SAndroid Build Coastguard Worker             frame_rate as u32,
171*bb4ee6a4SAndroid Build Coastguard Worker             buffer_size,
172*bb4ee6a4SAndroid Build Coastguard Worker         ) {
173*bb4ee6a4SAndroid Build Coastguard Worker             Ok(renderer) => {
174*bb4ee6a4SAndroid Build Coastguard Worker                 let audio_shared_format = renderer.get_audio_shared_format();
175*bb4ee6a4SAndroid Build Coastguard Worker                 let renderer_arc = Arc::new(Mutex::new(
176*bb4ee6a4SAndroid Build Coastguard Worker                     Box::new(renderer) as Box<dyn PlaybackBufferStream>
177*bb4ee6a4SAndroid Build Coastguard Worker                 ));
178*bb4ee6a4SAndroid Build Coastguard Worker                 self.cached_playback_buffer_stream =
179*bb4ee6a4SAndroid Build Coastguard Worker                     Some((renderer_arc.clone(), audio_shared_format));
180*bb4ee6a4SAndroid Build Coastguard Worker                 (renderer_arc, audio_shared_format)
181*bb4ee6a4SAndroid Build Coastguard Worker             }
182*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
183*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
184*bb4ee6a4SAndroid Build Coastguard Worker                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
185*bb4ee6a4SAndroid Build Coastguard Worker                      NoopStream with error: {}",
186*bb4ee6a4SAndroid Build Coastguard Worker                     e
187*bb4ee6a4SAndroid Build Coastguard Worker                 );
188*bb4ee6a4SAndroid Build Coastguard Worker                 (
189*bb4ee6a4SAndroid Build Coastguard Worker                     Arc::new(Mutex::new(Box::new(NoopStream::new(
190*bb4ee6a4SAndroid Build Coastguard Worker                         num_channels,
191*bb4ee6a4SAndroid Build Coastguard Worker                         SampleFormat::S16LE,
192*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate as u32,
193*bb4ee6a4SAndroid Build Coastguard Worker                         buffer_size,
194*bb4ee6a4SAndroid Build Coastguard Worker                     )))),
195*bb4ee6a4SAndroid Build Coastguard Worker                     AudioSharedFormat {
196*bb4ee6a4SAndroid Build Coastguard Worker                         bit_depth: 16,
197*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate,
198*bb4ee6a4SAndroid Build Coastguard Worker                         channels: 2,
199*bb4ee6a4SAndroid Build Coastguard Worker                         shared_audio_engine_period_in_frames: frame_rate / 100,
200*bb4ee6a4SAndroid Build Coastguard Worker                         channel_mask: None,
201*bb4ee6a4SAndroid Build Coastguard Worker                     },
202*bb4ee6a4SAndroid Build Coastguard Worker                 )
203*bb4ee6a4SAndroid Build Coastguard Worker             }
204*bb4ee6a4SAndroid Build Coastguard Worker         };
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker         Ok((playback_buffer_stream, audio_shared_format))
207*bb4ee6a4SAndroid Build Coastguard Worker     }
208*bb4ee6a4SAndroid Build Coastguard Worker 
209*bb4ee6a4SAndroid Build Coastguard Worker     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
210*bb4ee6a4SAndroid Build Coastguard Worker     // 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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_playback_stream_and_get_shared_format(
212*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
213*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
214*bb4ee6a4SAndroid Build Coastguard Worker         guest_bit_depth: SampleFormat,
215*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: usize,
216*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
217*bb4ee6a4SAndroid Build Coastguard Worker         ex: &dyn audio_streams::AudioStreamsExecutor,
218*bb4ee6a4SAndroid Build Coastguard Worker         audio_client_guid: Option<String>,
219*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
220*bb4ee6a4SAndroid Build Coastguard Worker         let hr = WinAudio::co_init_once_per_thread();
221*bb4ee6a4SAndroid Build Coastguard Worker         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
222*bb4ee6a4SAndroid Build Coastguard Worker 
223*bb4ee6a4SAndroid Build Coastguard Worker         let (async_playback_buffer_stream, audio_shared_format): (
224*bb4ee6a4SAndroid Build Coastguard Worker             Box<dyn AsyncPlaybackBufferStream>,
225*bb4ee6a4SAndroid Build Coastguard Worker             AudioSharedFormat,
226*bb4ee6a4SAndroid Build Coastguard Worker         ) = match win_audio_impl::WinAudioRenderer::new_async(
227*bb4ee6a4SAndroid Build Coastguard Worker             num_channels,
228*bb4ee6a4SAndroid Build Coastguard Worker             guest_bit_depth,
229*bb4ee6a4SAndroid Build Coastguard Worker             frame_rate as u32,
230*bb4ee6a4SAndroid Build Coastguard Worker             buffer_size,
231*bb4ee6a4SAndroid Build Coastguard Worker             ex,
232*bb4ee6a4SAndroid Build Coastguard Worker             audio_client_guid,
233*bb4ee6a4SAndroid Build Coastguard Worker         ) {
234*bb4ee6a4SAndroid Build Coastguard Worker             Ok(renderer) => {
235*bb4ee6a4SAndroid Build Coastguard Worker                 let audio_shared_format = renderer.get_audio_shared_format();
236*bb4ee6a4SAndroid Build Coastguard Worker                 let renderer_box = Box::new(renderer) as Box<dyn AsyncPlaybackBufferStream>;
237*bb4ee6a4SAndroid Build Coastguard Worker                 (renderer_box, audio_shared_format)
238*bb4ee6a4SAndroid Build Coastguard Worker             }
239*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
240*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
241*bb4ee6a4SAndroid Build Coastguard Worker                     "Failed to create WinAudioRenderer and in an unrecoverable state. Fallback to \
242*bb4ee6a4SAndroid Build Coastguard Worker                      NoopStream with error: {}",
243*bb4ee6a4SAndroid Build Coastguard Worker                     e
244*bb4ee6a4SAndroid Build Coastguard Worker                 );
245*bb4ee6a4SAndroid Build Coastguard Worker                 (
246*bb4ee6a4SAndroid Build Coastguard Worker                     Box::new(NoopStream::new(
247*bb4ee6a4SAndroid Build Coastguard Worker                         num_channels,
248*bb4ee6a4SAndroid Build Coastguard Worker                         SampleFormat::S32LE,
249*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate as u32,
250*bb4ee6a4SAndroid Build Coastguard Worker                         buffer_size,
251*bb4ee6a4SAndroid Build Coastguard Worker                     )),
252*bb4ee6a4SAndroid Build Coastguard Worker                     AudioSharedFormat {
253*bb4ee6a4SAndroid Build Coastguard Worker                         bit_depth: 32,
254*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate,
255*bb4ee6a4SAndroid Build Coastguard Worker                         channels: 2,
256*bb4ee6a4SAndroid Build Coastguard Worker                         shared_audio_engine_period_in_frames: frame_rate / 100,
257*bb4ee6a4SAndroid Build Coastguard Worker                         channel_mask: None,
258*bb4ee6a4SAndroid Build Coastguard Worker                     },
259*bb4ee6a4SAndroid Build Coastguard Worker                 )
260*bb4ee6a4SAndroid Build Coastguard Worker             }
261*bb4ee6a4SAndroid Build Coastguard Worker         };
262*bb4ee6a4SAndroid Build Coastguard Worker 
263*bb4ee6a4SAndroid Build Coastguard Worker         Ok((async_playback_buffer_stream, audio_shared_format))
264*bb4ee6a4SAndroid Build Coastguard Worker     }
265*bb4ee6a4SAndroid Build Coastguard Worker 
266*bb4ee6a4SAndroid Build Coastguard Worker     // TODO(b/275406212): AudioSharedFormat not used outside of this crate anymore. Clean up before
267*bb4ee6a4SAndroid Build Coastguard Worker     // 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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_capture_stream_and_get_shared_format(
269*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
270*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
271*bb4ee6a4SAndroid Build Coastguard Worker         guest_bit_depth: SampleFormat,
272*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: u32,
273*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
274*bb4ee6a4SAndroid Build Coastguard Worker         ex: &dyn audio_streams::AudioStreamsExecutor,
275*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn AsyncCaptureBufferStream>, AudioSharedFormat), BoxError> {
276*bb4ee6a4SAndroid Build Coastguard Worker         let hr = WinAudio::co_init_once_per_thread();
277*bb4ee6a4SAndroid Build Coastguard Worker         let _ = check_hresult!(hr, WinAudioError::from(hr), "Co Initialized failed");
278*bb4ee6a4SAndroid Build Coastguard Worker 
279*bb4ee6a4SAndroid Build Coastguard Worker         let (capturer, audio_shared_format): (
280*bb4ee6a4SAndroid Build Coastguard Worker             Box<dyn AsyncCaptureBufferStream>,
281*bb4ee6a4SAndroid Build Coastguard Worker             AudioSharedFormat,
282*bb4ee6a4SAndroid Build Coastguard Worker         ) = match WinAudioCapturer::new_async(
283*bb4ee6a4SAndroid Build Coastguard Worker             num_channels,
284*bb4ee6a4SAndroid Build Coastguard Worker             guest_bit_depth,
285*bb4ee6a4SAndroid Build Coastguard Worker             frame_rate,
286*bb4ee6a4SAndroid Build Coastguard Worker             buffer_size,
287*bb4ee6a4SAndroid Build Coastguard Worker             ex,
288*bb4ee6a4SAndroid Build Coastguard Worker         ) {
289*bb4ee6a4SAndroid Build Coastguard Worker             Ok(capturer) => {
290*bb4ee6a4SAndroid Build Coastguard Worker                 let audio_shared_format = capturer.get_audio_shared_format();
291*bb4ee6a4SAndroid Build Coastguard Worker                 (Box::new(capturer), audio_shared_format)
292*bb4ee6a4SAndroid Build Coastguard Worker             }
293*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
294*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("Failed to create WinAudioCapturer. Fallback to NoopCaptureStream with error: {}", e);
295*bb4ee6a4SAndroid Build Coastguard Worker                 (
296*bb4ee6a4SAndroid Build Coastguard Worker                     Box::new(NoopCaptureStream::new(
297*bb4ee6a4SAndroid Build Coastguard Worker                         num_channels,
298*bb4ee6a4SAndroid Build Coastguard Worker                         SampleFormat::S32LE,
299*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate,
300*bb4ee6a4SAndroid Build Coastguard Worker                         buffer_size,
301*bb4ee6a4SAndroid Build Coastguard Worker                     )),
302*bb4ee6a4SAndroid Build Coastguard Worker                     AudioSharedFormat {
303*bb4ee6a4SAndroid Build Coastguard Worker                         bit_depth: 32,
304*bb4ee6a4SAndroid Build Coastguard Worker                         frame_rate: frame_rate as usize,
305*bb4ee6a4SAndroid Build Coastguard Worker                         channels: 2,
306*bb4ee6a4SAndroid Build Coastguard Worker                         shared_audio_engine_period_in_frames: frame_rate as usize / 100,
307*bb4ee6a4SAndroid Build Coastguard Worker                         channel_mask: None,
308*bb4ee6a4SAndroid Build Coastguard Worker                     },
309*bb4ee6a4SAndroid Build Coastguard Worker                 )
310*bb4ee6a4SAndroid Build Coastguard Worker             }
311*bb4ee6a4SAndroid Build Coastguard Worker         };
312*bb4ee6a4SAndroid Build Coastguard Worker 
313*bb4ee6a4SAndroid Build Coastguard Worker         Ok((capturer, audio_shared_format))
314*bb4ee6a4SAndroid Build Coastguard Worker     }
315*bb4ee6a4SAndroid Build Coastguard Worker 
evict_playback_stream_cache(&mut self)316*bb4ee6a4SAndroid Build Coastguard Worker     fn evict_playback_stream_cache(&mut self) {
317*bb4ee6a4SAndroid Build Coastguard Worker         self.cached_playback_buffer_stream = None;
318*bb4ee6a4SAndroid Build Coastguard Worker     }
319*bb4ee6a4SAndroid Build Coastguard Worker 
is_noop_stream(&self) -> bool320*bb4ee6a4SAndroid Build Coastguard Worker     fn is_noop_stream(&self) -> bool {
321*bb4ee6a4SAndroid Build Coastguard Worker         false
322*bb4ee6a4SAndroid Build Coastguard Worker     }
323*bb4ee6a4SAndroid Build Coastguard Worker }
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker 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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_playback_stream_and_get_shared_format(
327*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
328*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
329*bb4ee6a4SAndroid Build Coastguard Worker         format: SampleFormat,
330*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: usize,
331*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
332*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Arc<Mutex<Box<dyn PlaybackBufferStream>>>, AudioSharedFormat), BoxError> {
333*bb4ee6a4SAndroid Build Coastguard Worker         let (_, playback_buffer_stream) = self
334*bb4ee6a4SAndroid Build Coastguard Worker             .new_playback_stream(num_channels, format, frame_rate as u32, buffer_size)
335*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
336*bb4ee6a4SAndroid Build Coastguard Worker         Ok((
337*bb4ee6a4SAndroid Build Coastguard Worker             Arc::new(Mutex::new(playback_buffer_stream)),
338*bb4ee6a4SAndroid Build Coastguard Worker             AudioSharedFormat {
339*bb4ee6a4SAndroid Build Coastguard Worker                 bit_depth: 16,
340*bb4ee6a4SAndroid Build Coastguard Worker                 frame_rate,
341*bb4ee6a4SAndroid Build Coastguard Worker                 channels: 2,
342*bb4ee6a4SAndroid Build Coastguard Worker                 shared_audio_engine_period_in_frames: frame_rate / 100,
343*bb4ee6a4SAndroid Build Coastguard Worker                 channel_mask: None,
344*bb4ee6a4SAndroid Build Coastguard Worker             },
345*bb4ee6a4SAndroid Build Coastguard Worker         ))
346*bb4ee6a4SAndroid Build Coastguard Worker     }
347*bb4ee6a4SAndroid Build Coastguard Worker 
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*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_playback_stream_and_get_shared_format(
349*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
350*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
351*bb4ee6a4SAndroid Build Coastguard Worker         format: SampleFormat,
352*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: usize,
353*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
354*bb4ee6a4SAndroid Build Coastguard Worker         ex: &dyn audio_streams::AudioStreamsExecutor,
355*bb4ee6a4SAndroid Build Coastguard Worker         _audio_client_guid: Option<String>,
356*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn AsyncPlaybackBufferStream>, AudioSharedFormat), BoxError> {
357*bb4ee6a4SAndroid Build Coastguard Worker         let (_, playback_stream) = self
358*bb4ee6a4SAndroid Build Coastguard Worker             .new_async_playback_stream(num_channels, format, frame_rate as u32, buffer_size, ex)
359*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
360*bb4ee6a4SAndroid Build Coastguard Worker 
361*bb4ee6a4SAndroid Build Coastguard Worker         // Set shared format to be the same as the incoming audio format.
362*bb4ee6a4SAndroid Build Coastguard Worker         let format = AudioSharedFormat {
363*bb4ee6a4SAndroid Build Coastguard Worker             bit_depth: format.sample_bytes() * 8,
364*bb4ee6a4SAndroid Build Coastguard Worker             frame_rate,
365*bb4ee6a4SAndroid Build Coastguard Worker             channels: num_channels,
366*bb4ee6a4SAndroid Build Coastguard Worker             shared_audio_engine_period_in_frames: buffer_size * format.sample_bytes(),
367*bb4ee6a4SAndroid Build Coastguard Worker             channel_mask: None,
368*bb4ee6a4SAndroid Build Coastguard Worker         };
369*bb4ee6a4SAndroid Build Coastguard Worker         Ok((playback_stream, format))
370*bb4ee6a4SAndroid Build Coastguard Worker     }
371*bb4ee6a4SAndroid Build Coastguard Worker 
is_noop_stream(&self) -> bool372*bb4ee6a4SAndroid Build Coastguard Worker     fn is_noop_stream(&self) -> bool {
373*bb4ee6a4SAndroid Build Coastguard Worker         true
374*bb4ee6a4SAndroid Build Coastguard Worker     }
375*bb4ee6a4SAndroid Build Coastguard Worker }
376*bb4ee6a4SAndroid Build Coastguard Worker 
create_win_audio_device() -> Result<WinAudio, BoxError>377*bb4ee6a4SAndroid Build Coastguard Worker pub fn create_win_audio_device() -> Result<WinAudio, BoxError> {
378*bb4ee6a4SAndroid Build Coastguard Worker     WinAudio::new()
379*bb4ee6a4SAndroid Build Coastguard Worker }
380