From 7f6828df0ca89736b08e68c5ff65c779f17db9a8 Mon Sep 17 00:00:00 2001 From: oiupoyt Date: Tue, 29 Sep 2026 21:11:40 +0530 Subject: [PATCH] feat(audio): implement AAudio C-ABI function bindings --- crates/molotov-core/src/audio/c_api.rs | 113 ++++++++++++++++++ crates/molotov-core/src/audio/mod.rs | 1 + .../molotov-core/tests/aaudio_c_api_test.rs | 25 ++++ 3 files changed, 139 insertions(+) create mode 100644 crates/molotov-core/src/audio/c_api.rs create mode 100644 crates/molotov-core/tests/aaudio_c_api_test.rs diff --git a/crates/molotov-core/src/audio/c_api.rs b/crates/molotov-core/src/audio/c_api.rs new file mode 100644 index 0000000..aee0b9f --- /dev/null +++ b/crates/molotov-core/src/audio/c_api.rs @@ -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 + } +} diff --git a/crates/molotov-core/src/audio/mod.rs b/crates/molotov-core/src/audio/mod.rs index 13ad4b2..80a6437 100644 --- a/crates/molotov-core/src/audio/mod.rs +++ b/crates/molotov-core/src/audio/mod.rs @@ -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; diff --git a/crates/molotov-core/tests/aaudio_c_api_test.rs b/crates/molotov-core/tests/aaudio_c_api_test.rs new file mode 100644 index 0000000..a14c071 --- /dev/null +++ b/crates/molotov-core/tests/aaudio_c_api_test.rs @@ -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); + } +}