1
0
mirror of https://github.com/ndarilek/tts-rs.git synced 2024-11-22 14:29:37 +00:00

AVFoundation: add ability to get the currently used voice

This commit is contained in:
Lee Baker 2022-06-19 18:41:41 -05:00
parent 5feb8e3186
commit f8fa89ed05

View File

@ -13,6 +13,28 @@ use unic_langid::LanguageIdentifier;
use crate::{Backend, BackendId, Error, Features, Gender, UtteranceId, Voice, CALLBACKS}; use crate::{Backend, BackendId, Error, Features, Gender, UtteranceId, Voice, CALLBACKS};
impl Voice {
pub fn from_av_speech_synthesis_voice(voice: id) -> Voice {
let id: CFString = unsafe { msg_send![voice, identifier] };
let name: CFString = unsafe { msg_send![voice, name] };
let gender: i64 = unsafe { msg_send![voice, gender] };
let gender = match gender {
1 => Some(Gender::Male),
2 => Some(Gender::Female),
_ => None,
};
let language: CFString = unsafe { msg_send![voice, language] };
let language = language.to_string();
let language = LanguageIdentifier::from_str(&language).unwrap();
Voice {
id: id.to_string(),
name: name.to_string(),
gender,
language,
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct AvFoundation { pub(crate) struct AvFoundation {
id: BackendId, id: BackendId,
@ -152,6 +174,13 @@ impl AvFoundation {
*backend_id += 1; *backend_id += 1;
Ok(rv) Ok(rv)
} }
fn default_voice(&self) -> Result<Voice, Error> {
unsafe {
let v: id = msg_send![class!(AVSpeechSynthesisVoice), voiceWithLanguage: nil];
Ok(Voice::from_av_speech_synthesis_voice(v))
}
}
} }
impl Backend for AvFoundation { impl Backend for AvFoundation {
@ -167,7 +196,7 @@ impl Backend for AvFoundation {
volume: true, volume: true,
is_speaking: true, is_speaking: true,
voice: true, voice: true,
get_voice: false, get_voice: true,
utterance_callbacks: true, utterance_callbacks: true,
} }
} }
@ -286,32 +315,18 @@ impl Backend for AvFoundation {
} }
fn voice(&self) -> Result<Option<Voice>, Error> { fn voice(&self) -> Result<Option<Voice>, Error> {
unimplemented!() if let Some(voice) = self.voice.clone() {
Ok(Some(voice))
} else {
Ok(Some(self.default_voice()?))
}
} }
fn voices(&self) -> Result<Vec<Voice>, Error> { fn voices(&self) -> Result<Vec<Voice>, Error> {
let voices: CFArray = unsafe { msg_send![class!(AVSpeechSynthesisVoice), speechVoices] }; let voices: CFArray = unsafe { msg_send![class!(AVSpeechSynthesisVoice), speechVoices] };
let rv = voices let rv = voices
.iter() .iter()
.map(|v| { .map(|v| Voice::from_av_speech_synthesis_voice(*v as *mut objc::runtime::Object))
let id: CFString = unsafe { msg_send![*v as *const Object, identifier] };
let name: CFString = unsafe { msg_send![*v as *const Object, name] };
let gender: i64 = unsafe { msg_send![*v as *const Object, gender] };
let gender = match gender {
1 => Some(Gender::Male),
2 => Some(Gender::Female),
_ => None,
};
let language: CFString = unsafe { msg_send![*v as *const Object, language] };
let language = language.to_string();
let language = LanguageIdentifier::from_str(&language).unwrap();
Voice {
id: id.to_string(),
name: name.to_string(),
gender,
language,
}
})
.collect(); .collect();
Ok(rv) Ok(rv)
} }