Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/android_audio/src/lib.rs
5394 views
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" {
71
fn AAudio_createStreamBuilder(builder: *mut *mut AAudioStreamBuilder) -> AaudioResultT;
72
fn AAudioStreamBuilder_delete(builder: *mut AAudioStreamBuilder) -> AaudioResultT;
73
fn AAudioStreamBuilder_setBufferCapacityInFrames(
74
builder: *mut AAudioStreamBuilder,
75
num_frames: i32,
76
);
77
fn AAudioStreamBuilder_setDirection(builder: *mut AAudioStreamBuilder, direction: u32);
78
fn AAudioStreamBuilder_setFormat(builder: *mut AAudioStreamBuilder, format: AaudioFormatT);
79
fn AAudioStreamBuilder_setSampleRate(builder: *mut AAudioStreamBuilder, sample_rate: i32);
80
fn AAudioStreamBuilder_setChannelCount(builder: *mut AAudioStreamBuilder, channel_count: i32);
81
fn AAudioStreamBuilder_openStream(
82
builder: *mut AAudioStreamBuilder,
83
stream: *mut *mut AAudioStream,
84
) -> AaudioResultT;
85
fn AAudioStream_getBufferSizeInFrames(stream: *mut AAudioStream) -> i32;
86
fn AAudioStream_requestStart(stream: *mut AAudioStream) -> AaudioResultT;
87
fn AAudioStream_read(
88
stream: *mut AAudioStream,
89
buffer: *mut c_void,
90
num_frames: i32,
91
timeout_nanoseconds: i64,
92
) -> AaudioResultT;
93
fn AAudioStream_write(
94
stream: *mut AAudioStream,
95
buffer: *const c_void,
96
num_frames: i32,
97
timeout_nanoseconds: i64,
98
) -> AaudioResultT;
99
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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)]
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)]
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)]
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)]
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 {
421
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 {
429
fn generate(&self) -> Result<Box<dyn StreamSource>, BoxError> {
430
Ok(Box::new(AndroidAudioStreamSource))
431
}
432
}
433
434