mirror of
https://github.com/ndarilek/tts-rs.git
synced 2024-11-22 08:09:38 +00:00
AVFoundation: add ability to get the currently used voice
This commit is contained in:
parent
5feb8e3186
commit
f8fa89ed05
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user