use {
crate::{
IntoSfResult, SfResult,
audio::SoundBuffer,
cpp::{CppString, CppVector, FBox},
ffi::audio as ffi,
system::Time,
},
std::{ffi::CString, os::raw::c_void, ptr::NonNull},
};
pub trait SoundRecorder: Send {
fn on_start(&mut self) -> bool {
true
}
fn on_process_samples(&mut self, samples: &[i16]) -> bool;
fn on_stop(&mut self) {}
}
#[derive(Debug)]
pub struct SoundRecorderDriver<'a, R: 'a> {
handle: NonNull<ffi::sfCustomSoundRecorder>,
recorder: &'a mut R,
}
unsafe impl<R: Send> Send for SoundRecorderDriver<'_, R> {}
unsafe impl<R: Sync> Sync for SoundRecorderDriver<'_, R> {}
unsafe extern "C" fn on_start_callback<R: SoundRecorder>(user_data: *mut c_void) -> bool {
let recorder: *mut R = user_data.cast();
unsafe { (*recorder).on_start() }
}
unsafe extern "C" fn on_process_callback<R: SoundRecorder>(
data: *const i16,
len: usize,
user_data: *mut c_void,
) -> bool {
let recorder: *mut R = user_data.cast();
unsafe { (*recorder).on_process_samples(std::slice::from_raw_parts(data, len)) }
}
unsafe extern "C" fn on_stop_callback<R: SoundRecorder>(user_data: *mut c_void) {
let recorder: *mut R = user_data.cast();
unsafe { (*recorder).on_stop() }
}
impl<'a, R: SoundRecorder> SoundRecorderDriver<'a, R> {
pub fn new(sound_recorder: &'a mut R) -> Self {
Self {
handle: unsafe {
let ptr: *mut R = sound_recorder;
NonNull::new(ffi::sfCustomSoundRecorder_new(
Some(on_start_callback::<R>),
Some(on_process_callback::<R>),
Some(on_stop_callback::<R>),
ptr.cast(),
))
.expect("Failed to create SoundRecorderDriver")
},
recorder: sound_recorder,
}
}
pub fn start(&mut self, sample_rate: u32) -> SfResult<()> {
unsafe { ffi::sfCustomSoundRecorder_start(self.handle.as_ptr(), sample_rate) }
.into_sf_result()
}
pub fn stop(&mut self) -> &mut R {
unsafe {
ffi::sfCustomSoundRecorder_stop(self.handle.as_ptr());
}
self.recorder
}
#[must_use]
pub fn sample_rate(&self) -> u32 {
unsafe { ffi::sfCustomSoundRecorder_getSampleRate(self.handle.as_ptr()) }
}
pub fn set_channel_count(&mut self, channel_count: u32) {
unsafe { ffi::sfCustomSoundRecorder_setChannelCount(self.handle.as_ptr(), channel_count) }
}
#[must_use]
pub fn channel_count(&self) -> u32 {
unsafe { ffi::sfCustomSoundRecorder_getChannelCount(self.handle.as_ptr()) }
}
pub fn set_processing_interval(&mut self, interval: Time) {
unsafe {
ffi::sfCustomSoundRecorder_setProcessingInterval(self.handle.as_ptr(), interval.raw())
}
}
#[must_use]
pub fn device(&self) -> &CppString {
unsafe { &*ffi::sfCustomSoundRecorder_getDevice(self.handle.as_ptr()) }
}
pub fn set_device(&mut self, name: &str) -> SfResult<()> {
let name = CString::new(name)?;
let success =
unsafe { ffi::sfCustomSoundRecorder_setDevice(self.handle.as_ptr(), name.as_ptr()) };
success.into_sf_result()
}
}
impl<S> Drop for SoundRecorderDriver<'_, S> {
fn drop(&mut self) {
unsafe {
ffi::sfCustomSoundRecorder_stop(self.handle.as_ptr());
ffi::sfCustomSoundRecorder_del(self.handle.as_ptr());
}
}
}
#[derive(Debug)]
pub struct SoundBufferRecorder {
handle: NonNull<ffi::sfSoundBufferRecorder>,
}
unsafe impl Send for SoundBufferRecorder {}
unsafe impl Sync for SoundBufferRecorder {}
impl SoundBufferRecorder {
#[must_use]
pub fn new() -> SoundBufferRecorder {
let buffer = unsafe { ffi::sfSoundBufferRecorder_new() };
SoundBufferRecorder {
handle: NonNull::new(buffer).expect("Failed to create SoundBufferRecorder"),
}
}
pub fn start(&mut self, sample_rate: u32) -> SfResult<()> {
unsafe { ffi::sfSoundBufferRecorder_start(self.handle.as_ptr(), sample_rate) }
.into_sf_result()
}
pub fn stop(&mut self) {
unsafe { ffi::sfSoundBufferRecorder_stop(self.handle.as_ptr()) }
}
#[must_use]
pub fn sample_rate(&self) -> u32 {
unsafe { ffi::sfSoundBufferRecorder_getSampleRate(self.handle.as_ptr()) }
}
#[must_use]
pub fn buffer(&self) -> &SoundBuffer {
let buff = unsafe { ffi::sfSoundBufferRecorder_getBuffer(self.handle.as_ptr()) };
unsafe { &*(buff) }
}
#[must_use]
pub fn device(&self) -> &CppString {
unsafe { &*ffi::sfSoundBufferRecorder_getDevice(self.handle.as_ptr()) }
}
pub fn set_device(&mut self, name: &str) -> SfResult<()> {
let name = CString::new(name)?;
let success =
unsafe { ffi::sfSoundBufferRecorder_setDevice(self.handle.as_ptr(), name.as_ptr()) };
success.into_sf_result()
}
}
#[cfg_attr(not(feature = "ci-headless"), test)]
fn test_devices() {
let default = default_device();
println!("Default device: {}", *default);
println!("Available devices:");
let devices = available_devices();
for device in devices.iter() {
println!("{device}");
}
let mut recorder = SoundBufferRecorder::new();
assert_eq!(*recorder.device(), *default);
if let Some(device) = devices.last() {
recorder.set_device(device.to_str().unwrap()).unwrap();
assert_eq!(recorder.device().to_str().unwrap(), device);
}
}
impl Default for SoundBufferRecorder {
fn default() -> Self {
Self::new()
}
}
impl Drop for SoundBufferRecorder {
fn drop(&mut self) {
unsafe {
ffi::sfSoundBufferRecorder_del(self.handle.as_ptr());
}
}
}
#[must_use]
pub fn is_available() -> bool {
unsafe { ffi::sfSoundRecorder_isAvailable() }
}
#[must_use]
pub fn default_device() -> FBox<CppString> {
unsafe {
FBox::new(ffi::sfSoundRecorder_getDefaultDevice()).expect("Failed to create sfStdString")
}
}
#[must_use]
pub fn available_devices() -> FBox<CppVector<CppString>> {
unsafe {
FBox::new(ffi::sfSoundRecorder_getAvailableDevices())
.expect("Failed to create sfStdStringVector")
}
}