use super::{
audio::{Audio, AudioStream},
events::{Event, Flags, Recognition, Session, SynthEventResult},
};
use crate::{
error::{AlreadyExists, Other, SpxError},
hr,
properties::Properties,
speech_api::{
synthesizer_async_handle_is_valid, synthesizer_async_handle_release,
synthesizer_canceled_set_callback, synthesizer_completed_set_callback,
synthesizer_disable, synthesizer_enable, synthesizer_get_property_bag,
synthesizer_handle_is_valid, synthesizer_handle_release,
synthesizer_speak_ssml, synthesizer_speak_ssml_async,
synthesizer_speak_text, synthesizer_speak_text_async,
synthesizer_start_speaking_ssml_async,
synthesizer_start_speaking_text_async,
synthesizer_started_set_callback,
synthesizer_synthesizing_set_callback, SPXASYNCHANDLE, SPXEVENTHANDLE,
SPXSYNTHHANDLE,
},
DeriveHandle, FlattenProps, Result, SmartHandle, INVALID_HANDLE,
};
use futures::{
sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
try_ready, Async, Poll, Stream,
};
use std::{
ffi::CString,
os::raw::c_void,
sync::{Arc, Weak},
};
macro_rules! DefCallback {
($name:ident, $flag:expr) => {
#[no_mangle]
unsafe extern "C" fn $name(
_: SPXSYNTHHANDLE,
hevent: SPXEVENTHANDLE,
context: *mut c_void,
) {
fire_on_event($flag, hevent, context);
}
};
}
SmartHandle!(
SynthesizerAsync,
SPXASYNCHANDLE,
synthesizer_async_handle_release,
synthesizer_async_handle_is_valid
);
DeriveHandle!(
Synthesizer,
SPXSYNTHHANDLE,
synthesizer_handle_release,
synthesizer_handle_is_valid
);
pub struct Synthesizer {
handle: SPXSYNTHHANDLE,
flags: Flags,
audio: Audio,
sink: Option<Arc<UnboundedSender<Event>>>,
props: Properties,
}
FlattenProps!(Synthesizer);
impl Synthesizer {
pub fn new(
handle: SPXSYNTHHANDLE,
audio: Audio,
flags: Flags,
) -> Result<Self> {
let mut hprops = INVALID_HANDLE;
hr!(synthesizer_get_property_bag(handle, &mut hprops))?;
Ok(Synthesizer {
handle,
flags,
audio,
sink: None,
props: Properties::new(hprops),
})
}
pub fn synthesize(&mut self, text: &str) -> Result {
let mut hasync = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_speak_text_async(
self.handle,
txt.as_ptr(),
txt_len,
&mut hasync
))?;
SynthesizerAsync::new(hasync);
Ok(())
}
pub fn ssml_synthesis(&mut self, text: &str) -> Result {
let mut hasync = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_speak_ssml_async(
self.handle,
txt.as_ptr(),
txt_len,
&mut hasync
))?;
SynthesizerAsync::new(hasync);
Ok(())
}
pub fn start_synthesize(&mut self, text: &str) -> Result {
let mut hasync = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_start_speaking_text_async(
self.handle,
txt.as_ptr(),
txt_len,
&mut hasync
))?;
SynthesizerAsync::new(hasync);
Ok(())
}
pub fn start_ssml_synthesis(&mut self, text: &str) -> Result {
let mut hasync = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_start_speaking_ssml_async(
self.handle,
txt.as_ptr(),
txt_len,
&mut hasync
))?;
SynthesizerAsync::new(hasync);
Ok(())
}
pub fn synthesis_once(&mut self, text: &str) -> Result<SynthEventResult> {
let mut hres = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_speak_text(
self.handle,
txt.as_ptr(),
txt_len,
&mut hres
))?;
SynthEventResult::new(Flags::empty(), hres)
}
pub fn ssml_synthesis_once(
&mut self,
text: &str,
) -> Result<SynthEventResult> {
let mut hres = INVALID_HANDLE;
let txt_len = text.len() as u32;
let txt = CString::new(text)?;
hr!(synthesizer_speak_ssml(
self.handle,
txt.as_ptr(),
txt_len,
&mut hres
))?;
SynthEventResult::new(Flags::empty(), hres)
}
pub fn write_stream(&mut self, buffer: &mut [u8]) -> Result {
self.audio.write(buffer)
}
pub fn read_stream(&mut self, buffer: &mut [u8]) -> Result<usize> {
self.audio.read(buffer)
}
pub fn close_stream(&mut self) -> Result {
self.audio.close()
}
pub fn pause(&self) -> Result {
hr!(synthesizer_disable(self.handle))
}
pub fn resume(&self) -> Result {
hr!(synthesizer_enable(self.handle))
}
pub fn started(&self) -> bool {
self.sink.is_some()
}
pub fn start(&mut self) -> Result<EventStream> {
self.start_flags(Flags::SessionStarted | Flags::Canceled)
}
pub fn stop(&mut self) -> Result {
self.close_stream()?;
self.sink = None;
Ok(())
}
pub fn start_flags(&mut self, flags: Flags) -> Result<EventStream> {
if self.started() {
return Err(AlreadyExists);
}
let flags = self.flags | flags;
let (s, r) = unbounded::<Event>();
let sink = Arc::new(s);
self.sink = Some(sink.clone());
let reception = EventStream::new(r, flags);
let sk = Box::new(Arc::downgrade(&sink));
let context = Box::into_raw(sk) as *mut c_void;
if flags.contains(Flags::Synthesizing) {
hr!(synthesizer_synthesizing_set_callback(
self.handle,
Some(on_synthesizing),
context,
))?;
}
if flags.contains(Flags::Synthesized) {
hr!(synthesizer_completed_set_callback(
self.handle,
Some(on_synthesized),
context,
))?;
}
if flags.contains(Flags::SessionStarted) {
hr!(synthesizer_started_set_callback(
self.handle,
Some(on_synthesis_started),
context,
))?;
}
if flags.contains(Flags::Canceled) {
hr!(synthesizer_canceled_set_callback(
self.handle,
Some(on_synth_canceled),
context,
))?;
}
Ok(reception)
}
}
pub struct EventStream {
filter: Flags,
source: UnboundedReceiver<Event>,
stopped: bool,
}
impl EventStream {
pub fn new(source: UnboundedReceiver<Event>, filter: Flags) -> Self {
EventStream {
filter,
source,
stopped: false,
}
}
pub fn set_filter(mut self, flags: Flags) -> Self {
self.filter = flags;
self
}
pub fn resulting(
self,
) -> impl Stream<Item = Recognition, Error = SpxError> {
self.then(|res| {
if let Ok(evt) = res {
evt.into_result()
} else {
Err(Other(String::from("streaming is interrupted")))
}
})
}
}
impl Stream for EventStream {
type Item = Event;
type Error = ();
fn poll(&mut self) -> Poll<Option<Event>, ()> {
while !self.stopped {
match try_ready!(self.source.poll()) {
Some(evt) => {
if evt
.flag()
.intersects(Flags::Canceled)
{
self.stopped = true;
}
if evt.flag().intersects(self.filter) {
return Ok(Async::Ready(Some(evt)));
}
}
None => return Ok(Async::Ready(None)),
}
}
Ok(Async::Ready(None))
}
}
DefCallback!(on_synthesizing, Flags::Synthesizing);
DefCallback!(on_synthesized, Flags::Synthesized);
DefCallback!(on_synthesis_started, Flags::SessionStarted);
DefCallback!(on_synth_canceled, Flags::Canceled);
fn fire_on_event(flag: Flags, hevent: SPXEVENTHANDLE, context: *mut c_void) {
log::trace!("Recognition event {:?} fired.", flag);
let evt = Event::new(flag, hevent);
if context.is_null() {
log::error!("Unknown context with NULL pointer.");
return;
}
log::trace!("Event is fired with {:?} and address: {:?}", flag, context);
let ctx =
unsafe { Box::from_raw(context as *mut Weak<UnboundedSender<Event>>) };
let weak_ptr = Weak::clone(&ctx);
Box::into_raw(ctx);
if let Some(mut arc) = weak_ptr.upgrade() {
let sender = Arc::make_mut(&mut arc);
if let Err(err) = sender.unbounded_send(evt) {
log::error!("failed to post {:?} event: {}", flag, err);
}
} else {
log::error!("Recognizer instance is dropped!");
}
}