xref: /aosp_15_r20/external/crosvm/android_audio/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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