use crate::{
audio::SoundBuffer,
ffi::{
audio::*,
system::{sfStdString, sfStdStringVector},
},
system::Time,
SfBox,
};
use std::{ffi::CString, os::raw::c_void, ptr::NonNull};
pub trait SoundRecorder {
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> {
ffi_handle: NonNull<sfSoundRecorder>,
recorder: &'a mut R,
}
unsafe extern "C" fn on_start_callback<R: SoundRecorder>(user_data: *mut c_void) -> bool {
let recorder = user_data as *mut R;
(*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 = user_data as *mut R;
(*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 = user_data as *mut R;
(*recorder).on_stop()
}
impl<'a, R: SoundRecorder> SoundRecorderDriver<'a, R> {
pub fn new(sound_recorder: &'a mut R) -> Self {
let ptr: *mut R = sound_recorder;
Self {
ffi_handle: unsafe {
NonNull::new(sfSoundRecorder_create(
Some(on_start_callback::<R>),
Some(on_process_callback::<R>),
Some(on_stop_callback::<R>),
ptr as *mut _,
))
.expect("Failed to create SoundRecorderDriver")
},
recorder: sound_recorder,
}
}
pub fn start(&mut self, sample_rate: u32) -> bool {
unsafe { sfSoundRecorder_start(self.ffi_handle.as_ptr(), sample_rate) }
}
pub fn stop(&mut self) -> &mut R {
unsafe {
sfSoundRecorder_stop(self.ffi_handle.as_ptr());
}
self.recorder
}
#[must_use]
pub fn sample_rate(&self) -> u32 {
unsafe { sfSoundRecorder_getSampleRate(self.ffi_handle.as_ptr()) }
}
pub fn set_channel_count(&mut self, channel_count: u32) {
unsafe { sfSoundRecorder_setChannelCount(self.ffi_handle.as_ptr(), channel_count) }
}
#[must_use]
pub fn channel_count(&self) -> u32 {
unsafe { sfSoundRecorder_getChannelCount(self.ffi_handle.as_ptr()) }
}
pub fn set_processing_interval(&mut self, interval: Time) {
unsafe { sfSoundRecorder_setProcessingInterval(self.ffi_handle.as_ptr(), interval.raw()) }
}
#[must_use]
pub fn device(&self) -> &sfStdString {
unsafe { &*sfSoundRecorder_getDevice(self.ffi_handle.as_ptr()) }
}
pub fn set_device(&mut self, name: &str) -> Result<(), SetDeviceError> {
let name = CString::new(name).unwrap();
let success = unsafe { sfSoundRecorder_setDevice(self.ffi_handle.as_ptr(), name.as_ptr()) };
if success {
Ok(())
} else {
Err(SetDeviceError)
}
}
}
impl<'a, S> Drop for SoundRecorderDriver<'a, S> {
fn drop(&mut self) {
unsafe {
sfSoundRecorder_stop(self.ffi_handle.as_ptr());
sfSoundRecorder_destroy(self.ffi_handle.as_ptr());
}
}
}
#[derive(Debug)]
pub struct SoundBufferRecorder {
ffi_handle: NonNull<sfSoundBufferRecorder>,
}
#[derive(Debug, Clone, Copy)]
pub struct SetDeviceError;
impl SoundBufferRecorder {
#[must_use]
pub fn new() -> SoundBufferRecorder {
let buffer = unsafe { sfSoundBufferRecorder_create() };
SoundBufferRecorder {
ffi_handle: NonNull::new(buffer).expect("Failed to create SoundBufferRecorder"),
}
}
pub fn start(&mut self, sample_rate: u32) -> bool {
unsafe { sfSoundBufferRecorder_start(self.ffi_handle.as_ptr(), sample_rate) }
}
pub fn stop(&mut self) {
unsafe { sfSoundBufferRecorder_stop(self.ffi_handle.as_ptr()) }
}
#[must_use]
pub fn sample_rate(&self) -> u32 {
unsafe { sfSoundBufferRecorder_getSampleRate(self.ffi_handle.as_ptr()) }
}
#[must_use]
pub fn buffer(&self) -> &SoundBuffer {
let buff = unsafe { sfSoundBufferRecorder_getBuffer(self.ffi_handle.as_ptr()) };
assert!(!buff.is_null(), "sfSoundBufferRecorder_getBuffer failed");
unsafe { &*(buff) }
}
#[must_use]
pub fn device(&self) -> &sfStdString {
unsafe { &*sfSoundBufferRecorder_getDevice(self.ffi_handle.as_ptr()) }
}
pub fn set_device(&mut self, name: &str) -> Result<(), SetDeviceError> {
let name = CString::new(name).unwrap();
let success =
unsafe { sfSoundBufferRecorder_setDevice(self.ffi_handle.as_ptr(), name.as_ptr()) };
if success {
Ok(())
} else {
Err(SetDeviceError)
}
}
}
#[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.into_iter() {
println!("{device}");
}
let mut recorder = SoundBufferRecorder::new();
assert_eq!(*recorder.device(), *default);
if let Some(device) = devices.into_iter().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 {
sfSoundBufferRecorder_destroy(self.ffi_handle.as_ptr());
}
}
}
#[must_use]
pub fn is_available() -> bool {
unsafe { sfSoundRecorder_isAvailable() }
}
#[must_use]
pub fn default_device() -> SfBox<sfStdString> {
unsafe { SfBox::new(sfSoundRecorder_getDefaultDevice()).expect("Failed to create sfStdString") }
}
#[must_use]
pub fn available_devices() -> SfBox<sfStdStringVector> {
unsafe {
SfBox::new(sfSoundRecorder_getAvailableDevices())
.expect("Failed to create sfStdStringVector")
}
}