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