use crate::common::{PropertyCollection, StreamStatus};
use crate::error::{convert_err, Error, ErrorRootCause, Result};
use crate::ffi::{
audio_data_stream_can_read_data, audio_data_stream_can_read_data_from_position,
audio_data_stream_create_from_file, audio_data_stream_create_from_result,
audio_data_stream_get_position, audio_data_stream_get_property_bag,
audio_data_stream_get_status, audio_data_stream_read, audio_data_stream_read_from_position,
audio_data_stream_save_to_wave_file, audio_data_stream_set_position, audio_stream_release,
SmartHandle, SPXAUDIOSTREAMHANDLE, SPXPROPERTYBAGHANDLE,
};
use crate::speech::SpeechSynthesisResult;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::raw::c_uint;
#[derive(Debug)]
pub struct AudioDataStream {
pub handle: SmartHandle<SPXAUDIOSTREAMHANDLE>,
pub properties: PropertyCollection,
}
impl AudioDataStream {
fn from_handle(handle: SPXAUDIOSTREAMHANDLE) -> Result<Self> {
unsafe {
let mut prop_bag_handle: SPXPROPERTYBAGHANDLE = MaybeUninit::uninit().assume_init();
let ret = audio_data_stream_get_property_bag(handle, &mut prop_bag_handle);
convert_err(ret, "AudioDataStream::from_handle error")?;
let property_bag = PropertyCollection::from_handle(prop_bag_handle);
Ok(AudioDataStream {
handle: SmartHandle::create("AudioDataStream", handle, audio_stream_release),
properties: property_bag,
})
}
}
pub fn from_wav_file(filename: &str) -> Result<Self> {
unsafe {
let c_filename = CString::new(filename)?;
let mut handle: SPXAUDIOSTREAMHANDLE = MaybeUninit::uninit().assume_init();
let ret = audio_data_stream_create_from_file(&mut handle, c_filename.as_ptr());
convert_err(ret, "AudioDataStream::from_wav_file error")?;
AudioDataStream::from_handle(handle)
}
}
pub fn from_speech_synthesis_result(
speech_synthesis_result: SpeechSynthesisResult,
) -> Result<Self> {
unsafe {
let mut handle: SPXAUDIOSTREAMHANDLE = MaybeUninit::uninit().assume_init();
let ret = audio_data_stream_create_from_result(
&mut handle,
speech_synthesis_result.handle.inner(),
);
convert_err(ret, "AudioDataStream::from_speech_synthesis_result error")?;
AudioDataStream::from_handle(handle)
}
}
pub fn get_status(&self) -> Result<StreamStatus> {
unsafe {
let mut status: c_uint = MaybeUninit::uninit().assume_init();
let ret = audio_data_stream_get_status(self.handle.inner(), &mut status);
convert_err(ret, "AudioDataStream.get_status error")?;
Ok(StreamStatus::from_u32(status))
}
}
pub fn can_read_data(&self, requested_size: u32) -> bool {
unsafe { audio_data_stream_can_read_data(self.handle.inner(), requested_size) }
}
pub fn can_read_data_at(&self, requested_size: u32, offset: u32) -> bool {
unsafe {
audio_data_stream_can_read_data_from_position(
self.handle.inner(),
requested_size,
offset,
)
}
}
pub fn read(&self, buffer: &mut [u8]) -> Result<u32> {
unsafe {
#[allow(clippy::len_zero)]
if buffer.len() == 0 {
let rootc = ErrorRootCause::ApiError(0x005);
return Err(Error::new(Error::api_error_desc(&rootc).unwrap(), rootc));
}
let mut filled_size: u32 = MaybeUninit::uninit().assume_init();
let c_buffer = buffer.as_mut_ptr();
let ret = audio_data_stream_read(
self.handle.inner(),
c_buffer,
buffer.len() as u32,
&mut filled_size,
);
convert_err(ret, "AudioDataStream.read error")?;
Ok(filled_size)
}
}
pub fn read_at(&self, buffer: &mut [u8], offset: u32) -> Result<u32> {
unsafe {
#[allow(clippy::len_zero)]
if buffer.len() == 0 {
let rootc = ErrorRootCause::ApiError(0x005);
return Err(Error::new(Error::api_error_desc(&rootc).unwrap(), rootc));
}
let mut filled_size: u32 = MaybeUninit::uninit().assume_init();
let c_buffer = buffer.as_mut_ptr();
let ret = audio_data_stream_read_from_position(
self.handle.inner(),
c_buffer,
buffer.len() as u32,
offset,
&mut filled_size,
);
convert_err(ret, "AudioDataStream.read_at error")?;
Ok(filled_size)
}
}
pub async fn save_wav_file_async(&self, filename: &str) -> Result<()> {
unsafe {
let c_filename = CString::new(filename)?;
let ret = audio_data_stream_save_to_wave_file(self.handle.inner(), c_filename.as_ptr());
convert_err(ret, "AudioDataStream.save_wav_file_async error")?;
Ok(())
}
}
pub fn get_offset(&self) -> Result<u32> {
unsafe {
let mut offset: u32 = MaybeUninit::uninit().assume_init();
let ret = audio_data_stream_get_position(self.handle.inner(), &mut offset);
convert_err(ret, "AudioDataStream.get_offset error")?;
Ok(offset)
}
}
pub fn set_offset(&self, offset: u32) -> Result<()> {
unsafe {
let ret = audio_data_stream_set_position(self.handle.inner(), offset);
convert_err(ret, "AudioDataStream.set_offset error")?;
Ok(())
}
}
}