use anyhow::Context as _;
use windows::Win32::System::Com::VARIANT;
mod com;
pub mod error;
mod initialize;
mod variant_ext;
use com::ComObject;
use initialize::Initialize;
use variant_ext::VariantExt;
pub struct CeVIO {
_init: Initialize,
talker: ComObject,
controller: ComObject,
}
fn make_error_message(method_name: &str, fn_name: &str) -> String {
format!("Failed to call `{method_name}` in fn `{fn_name}`")
}
impl CeVIO {
pub fn new() -> error::Result<Self> {
Ok(Self {
_init: Initialize::new().map_err(error::CeVIOError)?,
talker: ComObject::new("CeVIO.Talk.RemoteService2.Talker2")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
controller: ComObject::new("CeVIO.Talk.RemoteService2.ServiceControl2")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
})
}
pub fn new_cevio() -> error::Result<Self> {
Ok(Self {
_init: Initialize::new().map_err(error::CeVIOError)?,
talker: ComObject::new("CeVIO.Talk.RemoteService.Talker")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
controller: ComObject::new("CeVIO.Talk.RemoteService.ServiceControl")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
})
}
pub fn new_cevio_ai() -> error::Result<Self> {
Ok(Self {
_init: Initialize::new().map_err(error::CeVIOError)?,
talker: ComObject::new("CeVIO.Talk.RemoteService2.Talker2")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
controller: ComObject::new("CeVIO.Talk.RemoteService2.ServiceControl2")
.map_err(|e| e.into())
.map_err(error::CeVIOError)?,
})
}
pub fn start_host(&self, no_wait: bool) -> error::Result<i32> {
self.controller
.invoke_method("StartHost", vec![VARIANT::from_bool(no_wait)])
.with_context(|| make_error_message("invoke_method", "start_host"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "start_host"))
.map_err(error::CeVIOError)
}
pub fn close_host(&self, mode: i32) -> error::Result<()> {
self.controller
.invoke_method("CloseHost", vec![VARIANT::from_i32(mode)])
.with_context(|| make_error_message("invoke_method", "close_host"))
.map_err(error::CeVIOError)?;
Ok(())
}
pub fn get_host_version(&self) -> error::Result<String> {
self.controller
.get_property("HostVersion", None)
.with_context(|| make_error_message("get_property", "get_host_version"))
.map_err(error::CeVIOError)?
.to_string()
.with_context(|| make_error_message("to_string", "get_host_version"))
.map_err(error::CeVIOError)
}
pub fn get_interface_version(&self) -> error::Result<String> {
self.controller
.get_property("InterfaceVersion", None)
.with_context(|| make_error_message("get_property", "get_interface_version"))
.map_err(error::CeVIOError)?
.to_string()
.with_context(|| make_error_message("to_string", "get_interface_version"))
.map_err(error::CeVIOError)
}
pub fn get_is_host_started(&self) -> error::Result<bool> {
self.controller
.get_property("InterfaceVersion", None)
.with_context(|| make_error_message("get_property", "get_is_host_started"))
.map_err(error::CeVIOError)?
.to_bool()
.with_context(|| make_error_message("to_bool", "get_is_host_started"))
.map_err(error::CeVIOError)
}
pub fn get_volume(&self) -> error::Result<i32> {
self.talker
.get_property("Volume", None)
.with_context(|| make_error_message("get_property", "get_volume"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "get_volume"))
.map_err(error::CeVIOError)
}
pub fn set_volume(&self, volume: i32) -> error::Result<()> {
self.talker
.set_property("Volume", None, VARIANT::from_i32(volume))
.with_context(|| make_error_message("set_property", "set_volume"))
.map_err(error::CeVIOError)
}
pub fn get_speed(&self) -> error::Result<i32> {
self.talker
.get_property("Speed", None)
.with_context(|| make_error_message("get_property", "get_speed"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "get_speed"))
.map_err(error::CeVIOError)
}
pub fn set_speed(&self, speed: i32) -> error::Result<()> {
self.talker
.set_property("Speed", None, VARIANT::from_i32(speed))
.with_context(|| make_error_message("set_property", "set_speed"))
.map_err(error::CeVIOError)
}
pub fn get_tone(&self) -> error::Result<i32> {
self.talker
.get_property("Tone", None)
.with_context(|| make_error_message("get_property", "get_tone"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "get_tone"))
.map_err(error::CeVIOError)
}
pub fn set_tone(&self, tone: i32) -> error::Result<()> {
self.talker
.set_property("Tone", None, VARIANT::from_i32(tone))
.with_context(|| make_error_message("set_property", "set_tone"))
.map_err(error::CeVIOError)
}
pub fn get_tone_scale(&self) -> error::Result<i32> {
self.talker
.get_property("ToneScale", None)
.with_context(|| make_error_message("get_property", "get_tone_scale"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "get_tone_scale"))
.map_err(error::CeVIOError)
}
pub fn set_tone_scale(&self, tone_scale: i32) -> error::Result<()> {
self.talker
.set_property("ToneScale", None, VARIANT::from_i32(tone_scale))
.with_context(|| make_error_message("set_property", "set_tone_scale"))
.map_err(error::CeVIOError)
}
pub fn get_alpha(&self) -> error::Result<i32> {
self.talker
.get_property("Alpha", None)
.with_context(|| make_error_message("get_property", "get_alpha"))
.map_err(error::CeVIOError)?
.to_i32()
.with_context(|| make_error_message("to_i32", "get_alpha"))
.map_err(error::CeVIOError)
}
pub fn set_alpha(&self, alpha: i32) -> error::Result<()> {
self.talker
.set_property("Alpha", None, VARIANT::from_i32(alpha))
.with_context(|| make_error_message("set_property", "set_alpha"))
.map_err(error::CeVIOError)
}
pub fn get_cast(&self) -> error::Result<String> {
self.talker
.get_property("Cast", None)
.with_context(|| make_error_message("get_property", "get_cast"))
.map_err(error::CeVIOError)?
.to_string()
.with_context(|| make_error_message("to_string", "get_cast"))
.map_err(error::CeVIOError)
}
pub fn set_cast(&self, cast: &str) -> error::Result<()> {
self.talker
.set_property("Cast", None, VARIANT::from_str(cast))
.with_context(|| make_error_message("set_property", "set_cast"))
.map_err(error::CeVIOError)
}
pub fn get_available_casts(&self) -> error::Result<String> {
self.talker
.get_property("AvailableCasts", None)
.with_context(|| make_error_message("get_property", "get_available_casts"))
.map_err(error::CeVIOError)?
.to_string()
.with_context(|| make_error_message("to_string", "get_available_casts"))
.map_err(error::CeVIOError)
}
pub fn speak(&self, text: &str) -> error::Result<()> {
self.talker
.invoke_method("Speak", vec![VARIANT::from_str(text)])
.with_context(|| make_error_message("invoke_method", "speak"))
.map_err(error::CeVIOError)?;
Ok(())
}
pub fn get_phonemes(&self, text: &str) -> error::Result<()> {
self.talker
.invoke_method("GetPhonemes", vec![VARIANT::from_str(text)])
.with_context(|| make_error_message("invoke_method", "get_phonemes"))
.map_err(error::CeVIOError)?;
Ok(())
}
pub fn output_wave_to_file(&self, text: &str, path: &str) -> error::Result<()> {
self.talker
.invoke_method(
"OutputWaveToFile",
vec![VARIANT::from_str(text), VARIANT::from_str(path)],
)
.with_context(|| make_error_message("invoke_method", "speak"))
.map_err(error::CeVIOError)?;
Ok(())
}
}