1 // Copyright 2024 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 #[cfg(feature = "libaaudio_stub")] 6 mod libaaudio_stub; 7 8 use std::os::raw::c_void; 9 use std::time::Duration; 10 use std::time::Instant; 11 12 use async_trait::async_trait; 13 use audio_streams::capture::AsyncCaptureBuffer; 14 use audio_streams::capture::AsyncCaptureBufferStream; 15 use audio_streams::capture::CaptureBuffer; 16 use audio_streams::capture::CaptureBufferStream; 17 use audio_streams::AsyncBufferCommit; 18 use audio_streams::AsyncPlaybackBuffer; 19 use audio_streams::AsyncPlaybackBufferStream; 20 use audio_streams::AudioStreamsExecutor; 21 use audio_streams::BoxError; 22 use audio_streams::BufferCommit; 23 use audio_streams::NoopStreamControl; 24 use audio_streams::PlaybackBuffer; 25 use audio_streams::PlaybackBufferStream; 26 use audio_streams::SampleFormat; 27 use audio_streams::StreamControl; 28 use audio_streams::StreamEffect; 29 use audio_streams::StreamSource; 30 use audio_streams::StreamSourceGenerator; 31 use base::warn; 32 use thiserror::Error; 33 34 #[derive(Clone, Copy)] 35 enum AndroidAudioStreamDirection { 36 Input = 1, 37 Output = 0, 38 } 39 40 #[derive(Error, Debug)] 41 pub enum AAudioError { 42 #[error("Failed to create stream builder")] 43 StreamBuilderCreation, 44 #[error("Failed to open stream")] 45 StreamOpen, 46 #[error("Failed to start stream")] 47 StreamStart, 48 #[error("Failed to delete stream builder")] 49 StreamBuilderDelete, 50 } 51 52 // Opaque blob 53 #[repr(C)] 54 struct AAudioStream { 55 _data: [u8; 0], 56 _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, 57 } 58 59 // Opaque blob 60 #[repr(C)] 61 struct AAudioStreamBuilder { 62 _data: [u8; 0], 63 _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, 64 } 65 66 type AaudioFormatT = i32; 67 type AaudioResultT = i32; 68 const AAUDIO_OK: AaudioResultT = 0; 69 70 extern "C" { AAudio_createStreamBuilder(builder: *mut *mut AAudioStreamBuilder) -> AaudioResultT71 fn AAudio_createStreamBuilder(builder: *mut *mut AAudioStreamBuilder) -> AaudioResultT; AAudioStreamBuilder_delete(builder: *mut AAudioStreamBuilder) -> AaudioResultT72 fn AAudioStreamBuilder_delete(builder: *mut AAudioStreamBuilder) -> AaudioResultT; AAudioStreamBuilder_setBufferCapacityInFrames( builder: *mut AAudioStreamBuilder, num_frames: i32, )73 fn AAudioStreamBuilder_setBufferCapacityInFrames( 74 builder: *mut AAudioStreamBuilder, 75 num_frames: i32, 76 ); AAudioStreamBuilder_setDirection(builder: *mut AAudioStreamBuilder, direction: u32)77 fn AAudioStreamBuilder_setDirection(builder: *mut AAudioStreamBuilder, direction: u32); AAudioStreamBuilder_setFormat(builder: *mut AAudioStreamBuilder, format: AaudioFormatT)78 fn AAudioStreamBuilder_setFormat(builder: *mut AAudioStreamBuilder, format: AaudioFormatT); AAudioStreamBuilder_setSampleRate(builder: *mut AAudioStreamBuilder, sample_rate: i32)79 fn AAudioStreamBuilder_setSampleRate(builder: *mut AAudioStreamBuilder, sample_rate: i32); AAudioStreamBuilder_setChannelCount(builder: *mut AAudioStreamBuilder, channel_count: i32)80 fn AAudioStreamBuilder_setChannelCount(builder: *mut AAudioStreamBuilder, channel_count: i32); AAudioStreamBuilder_openStream( builder: *mut AAudioStreamBuilder, stream: *mut *mut AAudioStream, ) -> AaudioResultT81 fn AAudioStreamBuilder_openStream( 82 builder: *mut AAudioStreamBuilder, 83 stream: *mut *mut AAudioStream, 84 ) -> AaudioResultT; AAudioStream_getBufferSizeInFrames(stream: *mut AAudioStream) -> i3285 fn AAudioStream_getBufferSizeInFrames(stream: *mut AAudioStream) -> i32; AAudioStream_requestStart(stream: *mut AAudioStream) -> AaudioResultT86 fn AAudioStream_requestStart(stream: *mut AAudioStream) -> AaudioResultT; AAudioStream_read( stream: *mut AAudioStream, buffer: *mut c_void, num_frames: i32, timeout_nanoseconds: i64, ) -> AaudioResultT87 fn AAudioStream_read( 88 stream: *mut AAudioStream, 89 buffer: *mut c_void, 90 num_frames: i32, 91 timeout_nanoseconds: i64, 92 ) -> AaudioResultT; AAudioStream_write( stream: *mut AAudioStream, buffer: *const c_void, num_frames: i32, timeout_nanoseconds: i64, ) -> AaudioResultT93 fn AAudioStream_write( 94 stream: *mut AAudioStream, 95 buffer: *const c_void, 96 num_frames: i32, 97 timeout_nanoseconds: i64, 98 ) -> AaudioResultT; AAudioStream_close(stream: *mut AAudioStream) -> AaudioResultT99 fn AAudioStream_close(stream: *mut AAudioStream) -> AaudioResultT; 100 } 101 102 struct AAudioStreamPtr { 103 // TODO: Use callback function to avoid possible thread preemption and glitches cause by 104 // using AAudio APIs in different threads. 105 stream_ptr: *mut AAudioStream, 106 } 107 108 // SAFETY: 109 // AudioStream.drop.buffer_ptr: *const u8 points to AudioStream.buffer, which would be alive 110 // whenever AudioStream.drop.buffer_ptr is alive. 111 unsafe impl Send for AndroidAudioStreamCommit {} 112 113 struct AudioStream { 114 buffer: Box<[u8]>, 115 frame_size: usize, 116 frame_rate: u32, 117 next_frame: Instant, 118 start_time: Option<Instant>, 119 total_frames: i32, 120 buffer_drop: AndroidAudioStreamCommit, 121 read_count: i32, 122 aaudio_buffer_size: usize, 123 } 124 125 struct AndroidAudioStreamCommit { 126 buffer_ptr: *const u8, 127 stream: AAudioStreamPtr, 128 direction: AndroidAudioStreamDirection, 129 } 130 131 impl BufferCommit for AndroidAudioStreamCommit { commit(&mut self, _nwritten: usize)132 fn commit(&mut self, _nwritten: usize) { 133 // This traits function is never called. 134 unimplemented!(); 135 } 136 } 137 138 #[async_trait(?Send)] 139 impl AsyncBufferCommit for AndroidAudioStreamCommit { commit(&mut self, nwritten: usize)140 async fn commit(&mut self, nwritten: usize) { 141 match self.direction { 142 AndroidAudioStreamDirection::Input => {} 143 AndroidAudioStreamDirection::Output => { 144 // SAFETY: 145 // The AAudioStream_write reads buffer for nwritten * frame_size bytes 146 // It is safe since nwritten < buffer_size and the buffer.len() == buffer_size * 147 // frame_size 148 let frames_written: i32 = unsafe { 149 AAudioStream_write( 150 self.stream.stream_ptr, 151 self.buffer_ptr as *const c_void, 152 nwritten as i32, 153 0, // this call will not wait. 154 ) 155 }; 156 if frames_written < 0 { 157 warn!("AAudio stream write failed."); 158 } else if (frames_written as usize) < nwritten { 159 // Currently, the frames unable to write by the AAudio API are dropped. 160 warn!( 161 "Android Audio Stream: Drop {} frames", 162 nwritten - (frames_written as usize) 163 ); 164 } 165 } 166 } 167 } 168 } 169 170 impl AudioStream { new( num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, direction: AndroidAudioStreamDirection, ) -> Result<Self, BoxError>171 pub fn new( 172 num_channels: usize, 173 format: SampleFormat, 174 frame_rate: u32, 175 buffer_size: usize, 176 direction: AndroidAudioStreamDirection, 177 ) -> Result<Self, BoxError> { 178 let frame_size = format.sample_bytes() * num_channels; 179 180 let mut stream_ptr: *mut AAudioStream = std::ptr::null_mut(); 181 let mut builder: *mut AAudioStreamBuilder = std::ptr::null_mut(); 182 // SAFETY: 183 // Interfacing with the AAudio C API. Assumes correct linking 184 // and `builder` and `stream_ptr` pointers are valid and properly initialized. 185 unsafe { 186 if AAudio_createStreamBuilder(&mut builder) != AAUDIO_OK { 187 return Err(Box::new(AAudioError::StreamBuilderCreation)); 188 } 189 AAudioStreamBuilder_setDirection(builder, direction as u32); 190 AAudioStreamBuilder_setBufferCapacityInFrames(builder, buffer_size as i32 * 2); 191 AAudioStreamBuilder_setFormat(builder, format as AaudioFormatT); 192 AAudioStreamBuilder_setSampleRate(builder, frame_rate as i32); 193 AAudioStreamBuilder_setChannelCount(builder, num_channels as i32); 194 if AAudioStreamBuilder_openStream(builder, &mut stream_ptr) != AAUDIO_OK { 195 return Err(Box::new(AAudioError::StreamOpen)); 196 } 197 if AAudioStreamBuilder_delete(builder) != AAUDIO_OK { 198 return Err(Box::new(AAudioError::StreamBuilderDelete)); 199 } 200 if AAudioStream_requestStart(stream_ptr) != AAUDIO_OK { 201 return Err(Box::new(AAudioError::StreamStart)); 202 } 203 } 204 // SAFETY: 205 // Interfacing with the AAudio C API. Assumes correct linking 206 // and `stream_ptr` pointers are valid and properly initialized. 207 let aaudio_buffer_size = unsafe { AAudioStream_getBufferSizeInFrames(stream_ptr) } as usize; 208 let buffer = vec![0; buffer_size * frame_size].into_boxed_slice(); 209 let stream = AAudioStreamPtr { stream_ptr }; 210 let buffer_drop = AndroidAudioStreamCommit { 211 stream, 212 buffer_ptr: buffer.as_ptr(), 213 direction, 214 }; 215 Ok(AudioStream { 216 buffer, 217 frame_size, 218 frame_rate, 219 next_frame: Instant::now(), 220 start_time: None, 221 total_frames: 0, 222 buffer_drop, 223 read_count: 0, 224 aaudio_buffer_size, 225 }) 226 } 227 } 228 229 impl PlaybackBufferStream for AudioStream { next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError>230 fn next_playback_buffer<'b, 's: 'b>(&'s mut self) -> Result<PlaybackBuffer<'b>, BoxError> { 231 // This traits function is never called. 232 unimplemented!(); 233 } 234 } 235 236 #[async_trait(?Send)] 237 impl AsyncPlaybackBufferStream for AudioStream { next_playback_buffer<'a>( &'a mut self, ex: &dyn AudioStreamsExecutor, ) -> Result<AsyncPlaybackBuffer<'a>, BoxError>238 async fn next_playback_buffer<'a>( 239 &'a mut self, 240 ex: &dyn AudioStreamsExecutor, 241 ) -> Result<AsyncPlaybackBuffer<'a>, BoxError> { 242 self.total_frames += (self.buffer.len() / self.frame_size) as i32; 243 let start_time = match self.start_time { 244 Some(time) => { 245 ex.delay(self.next_frame.saturating_duration_since(Instant::now())) 246 .await?; 247 time 248 } 249 None => { 250 let now = Instant::now(); 251 self.start_time = Some(now); 252 now 253 } 254 }; 255 self.next_frame = start_time 256 + Duration::from_millis(self.total_frames as u64 * 1000 / self.frame_rate as u64); 257 Ok( 258 AsyncPlaybackBuffer::new(self.frame_size, self.buffer.as_mut(), &mut self.buffer_drop) 259 .map_err(Box::new)?, 260 ) 261 } 262 } 263 264 #[async_trait(?Send)] 265 impl CaptureBufferStream for AudioStream { next_capture_buffer<'b, 's: 'b>(&'s mut self) -> Result<CaptureBuffer<'b>, BoxError>266 fn next_capture_buffer<'b, 's: 'b>(&'s mut self) -> Result<CaptureBuffer<'b>, BoxError> { 267 // This traits function is never called. 268 unimplemented!() 269 } 270 } 271 272 #[async_trait(?Send)] 273 impl AsyncCaptureBufferStream for AudioStream { next_capture_buffer<'a>( &'a mut self, ex: &dyn AudioStreamsExecutor, ) -> Result<AsyncCaptureBuffer<'a>, BoxError>274 async fn next_capture_buffer<'a>( 275 &'a mut self, 276 ex: &dyn AudioStreamsExecutor, 277 ) -> Result<AsyncCaptureBuffer<'a>, BoxError> { 278 let buffer_size = self.buffer.len() / self.frame_size; 279 self.read_count += 1; 280 self.total_frames += buffer_size as i32; 281 let start_time = match self.start_time { 282 Some(time) => { 283 ex.delay(self.next_frame.saturating_duration_since(Instant::now())) 284 .await?; 285 time 286 } 287 None => { 288 let now = Instant::now(); 289 self.start_time = Some(now); 290 now 291 } 292 }; 293 self.next_frame = start_time 294 + Duration::from_millis(self.total_frames as u64 * 1000 / self.frame_rate as u64); 295 296 // Skip for at least (1.5x aaudio buffer size - buffer_size) to ensure there is always a 297 // aaudio buffer available for read. 298 if self.read_count < (self.aaudio_buffer_size * 3 / 2 / buffer_size) as i32 + 1 { 299 self.buffer.fill(0); 300 return Ok(AsyncCaptureBuffer::new( 301 buffer_size, 302 self.buffer.as_mut(), 303 &mut self.buffer_drop, 304 ) 305 .map_err(Box::new)?); 306 } 307 308 // SAFETY: 309 // The AAudioStream_read writes buffer for buffer.len() / frame_size * frame_size bytes 310 let frames_read = unsafe { 311 AAudioStream_read( 312 self.buffer_drop.stream.stream_ptr, 313 self.buffer.as_mut_ptr() as *mut c_void, 314 (buffer_size) as i32, 315 0, 316 ) 317 }; 318 319 if frames_read < 0 { 320 warn!("AAudio stream read failed: {frames_read}"); 321 self.buffer.fill(0); 322 } else if (frames_read as usize) < buffer_size { 323 warn!( 324 "AAudio stream read data not enough. frames read: {frames_read}, buffer size: {buffer_size}", 325 ); 326 self.buffer[frames_read as usize * self.frame_size..].fill(0); 327 } 328 329 Ok( 330 AsyncCaptureBuffer::new(buffer_size, self.buffer.as_mut(), &mut self.buffer_drop) 331 .map_err(Box::new)?, 332 ) 333 } 334 } 335 336 impl Drop for AAudioStreamPtr { drop(&mut self)337 fn drop(&mut self) { 338 // SAFETY: 339 // Interfacing with the AAudio C API. Assumes correct linking 340 // and `stream_ptr` are valid and properly initialized. 341 if unsafe { AAudioStream_close(self.stream_ptr) } != AAUDIO_OK { 342 warn!("AAudio stream close failed."); 343 } 344 } 345 } 346 347 #[derive(Default)] 348 struct AndroidAudioStreamSource; 349 350 impl StreamSource for AndroidAudioStreamSource { 351 #[allow(clippy::type_complexity)] new_playback_stream( &mut self, _num_channels: usize, _format: SampleFormat, _frame_rate: u32, _buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>352 fn new_playback_stream( 353 &mut self, 354 _num_channels: usize, 355 _format: SampleFormat, 356 _frame_rate: u32, 357 _buffer_size: usize, 358 ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError> { 359 // This traits function is never called. 360 unimplemented!(); 361 } 362 363 #[allow(clippy::type_complexity)] new_async_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, _ex: &dyn AudioStreamsExecutor, ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError>364 fn new_async_playback_stream( 365 &mut self, 366 num_channels: usize, 367 format: SampleFormat, 368 frame_rate: u32, 369 buffer_size: usize, 370 _ex: &dyn AudioStreamsExecutor, 371 ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError> { 372 let audio_stream = AudioStream::new( 373 num_channels, 374 format, 375 frame_rate, 376 buffer_size, 377 AndroidAudioStreamDirection::Output, 378 )?; 379 Ok((Box::new(NoopStreamControl::new()), Box::new(audio_stream))) 380 } 381 382 #[allow(clippy::type_complexity)] new_capture_stream( &mut self, _num_channels: usize, _format: SampleFormat, _frame_rate: u32, _buffer_size: usize, _effects: &[StreamEffect], ) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), BoxError>383 fn new_capture_stream( 384 &mut self, 385 _num_channels: usize, 386 _format: SampleFormat, 387 _frame_rate: u32, 388 _buffer_size: usize, 389 _effects: &[StreamEffect], 390 ) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), BoxError> { 391 // This traits function is never called. 392 unimplemented!(); 393 } 394 395 #[allow(clippy::type_complexity)] new_async_capture_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, _effects: &[StreamEffect], _ex: &dyn AudioStreamsExecutor, ) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn AsyncCaptureBufferStream>), BoxError>396 fn new_async_capture_stream( 397 &mut self, 398 num_channels: usize, 399 format: SampleFormat, 400 frame_rate: u32, 401 buffer_size: usize, 402 _effects: &[StreamEffect], 403 _ex: &dyn AudioStreamsExecutor, 404 ) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn AsyncCaptureBufferStream>), BoxError> 405 { 406 let audio_stream = AudioStream::new( 407 num_channels, 408 format, 409 frame_rate, 410 buffer_size, 411 AndroidAudioStreamDirection::Input, 412 )?; 413 Ok((Box::new(NoopStreamControl::new()), Box::new(audio_stream))) 414 } 415 } 416 417 #[derive(Default)] 418 pub struct AndroidAudioStreamSourceGenerator; 419 420 impl AndroidAudioStreamSourceGenerator { new() -> Self421 pub fn new() -> Self { 422 AndroidAudioStreamSourceGenerator {} 423 } 424 } 425 426 /// `AndroidAudioStreamSourceGenerator` is a struct that implements [`StreamSourceGenerator`] 427 /// for `AndroidAudioStreamSource`. 428 impl StreamSourceGenerator for AndroidAudioStreamSourceGenerator { generate(&self) -> Result<Box<dyn StreamSource>, BoxError>429 fn generate(&self) -> Result<Box<dyn StreamSource>, BoxError> { 430 Ok(Box::new(AndroidAudioStreamSource)) 431 } 432 } 433