feat(audio): implement AAudio C-ABI function bindings
This commit is contained in:
parent
370a13c422
commit
7f6828df0c
3 changed files with 139 additions and 0 deletions
113
crates/molotov-core/src/audio/c_api.rs
Normal file
113
crates/molotov-core/src/audio/c_api.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use super::builder::AAudioStreamBuilder;
|
||||
use super::pipewire::PipeWireStreamController;
|
||||
use super::types::{AAudioDirection, AAudioResult};
|
||||
|
||||
pub struct AAudioStreamHandle {
|
||||
pub controller: PipeWireStreamController,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudio_createStreamBuilder(
|
||||
builder: *mut *mut AAudioStreamBuilder,
|
||||
) -> i32 {
|
||||
if builder.is_null() {
|
||||
return AAudioResult::ErrorNull as i32;
|
||||
}
|
||||
let b = Box::new(AAudioStreamBuilder::new());
|
||||
*builder = Box::into_raw(b);
|
||||
AAudioResult::Ok as i32
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStreamBuilder_setDirection(
|
||||
builder: *mut AAudioStreamBuilder,
|
||||
direction: i32,
|
||||
) {
|
||||
if let Some(b) = builder.as_mut() {
|
||||
let dir = if direction == 1 {
|
||||
AAudioDirection::Input
|
||||
} else {
|
||||
AAudioDirection::Output
|
||||
};
|
||||
b.set_direction(dir);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStreamBuilder_openStream(
|
||||
builder: *mut AAudioStreamBuilder,
|
||||
stream: *mut *mut AAudioStreamHandle,
|
||||
) -> i32 {
|
||||
if builder.is_null() || stream.is_null() {
|
||||
return AAudioResult::ErrorNull as i32;
|
||||
}
|
||||
|
||||
let b = match builder.as_ref() {
|
||||
Some(val) => val,
|
||||
None => return AAudioResult::ErrorNull as i32,
|
||||
};
|
||||
|
||||
let controller = PipeWireStreamController::new(b.direction(), b.sample_rate(), b.channel_count());
|
||||
let handle = Box::new(AAudioStreamHandle { controller });
|
||||
*stream = Box::into_raw(handle);
|
||||
|
||||
AAudioResult::Ok as i32
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStream_requestStart(stream: *mut AAudioStreamHandle) -> i32 {
|
||||
if let Some(s) = stream.as_mut() {
|
||||
match s.controller.request_start() {
|
||||
Ok(()) => AAudioResult::Ok as i32,
|
||||
Err(e) => e as i32,
|
||||
}
|
||||
} else {
|
||||
AAudioResult::ErrorNull as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStream_requestPause(stream: *mut AAudioStreamHandle) -> i32 {
|
||||
if let Some(s) = stream.as_mut() {
|
||||
match s.controller.request_pause() {
|
||||
Ok(()) => AAudioResult::Ok as i32,
|
||||
Err(e) => e as i32,
|
||||
}
|
||||
} else {
|
||||
AAudioResult::ErrorNull as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStream_requestStop(stream: *mut AAudioStreamHandle) -> i32 {
|
||||
if let Some(s) = stream.as_mut() {
|
||||
match s.controller.request_stop() {
|
||||
Ok(()) => AAudioResult::Ok as i32,
|
||||
Err(e) => e as i32,
|
||||
}
|
||||
} else {
|
||||
AAudioResult::ErrorNull as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStream_close(stream: *mut AAudioStreamHandle) -> i32 {
|
||||
if !stream.is_null() {
|
||||
let mut handle = Box::from_raw(stream);
|
||||
handle.controller.close();
|
||||
AAudioResult::Ok as i32
|
||||
} else {
|
||||
AAudioResult::ErrorNull as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAudioStreamBuilder_delete(builder: *mut AAudioStreamBuilder) -> i32 {
|
||||
if !builder.is_null() {
|
||||
drop(Box::from_raw(builder));
|
||||
AAudioResult::Ok as i32
|
||||
} else {
|
||||
AAudioResult::ErrorNull as i32
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
pub mod builder;
|
||||
pub mod buffer;
|
||||
pub mod c_api;
|
||||
pub mod pipewire;
|
||||
pub mod types;
|
||||
|
|
|
|||
25
crates/molotov-core/tests/aaudio_c_api_test.rs
Normal file
25
crates/molotov-core/tests/aaudio_c_api_test.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use molotov_core::audio::c_api::*;
|
||||
use molotov_core::audio::types::{AAudioDirection, AAudioResult};
|
||||
|
||||
#[test]
|
||||
fn test_c_api_stream_lifecycle() {
|
||||
let mut builder_ptr = std::ptr::null_mut();
|
||||
unsafe {
|
||||
let res = AAudio_createStreamBuilder(&mut builder_ptr);
|
||||
assert_eq!(res, AAudioResult::Ok as i32);
|
||||
assert!(!builder_ptr.is_null());
|
||||
|
||||
AAudioStreamBuilder_setDirection(builder_ptr, AAudioDirection::Input as i32);
|
||||
|
||||
let mut stream_ptr = std::ptr::null_mut();
|
||||
let res = AAudioStreamBuilder_openStream(builder_ptr, &mut stream_ptr);
|
||||
assert_eq!(res, AAudioResult::Ok as i32);
|
||||
assert!(!stream_ptr.is_null());
|
||||
|
||||
assert_eq!(AAudioStream_requestStart(stream_ptr), AAudioResult::Ok as i32);
|
||||
assert_eq!(AAudioStream_requestPause(stream_ptr), AAudioResult::Ok as i32);
|
||||
assert_eq!(AAudioStream_close(stream_ptr), AAudioResult::Ok as i32);
|
||||
assert_eq!(AAudioStreamBuilder_delete(builder_ptr), AAudioResult::Ok as i32);
|
||||
}
|
||||
}
|
||||
Reference in a new issue