Implement callbacks on AVFoundation.

This commit is contained in:
Nolan Darilek 2020-09-23 12:21:05 -05:00
parent bd57075d53
commit 251fb8d8c1
1 changed files with 65 additions and 3 deletions

View File

@ -6,13 +6,14 @@ use cocoa_foundation::base::{id, nil};
use cocoa_foundation::foundation::NSString;
use lazy_static::lazy_static;
use log::{info, trace};
use objc::runtime::*;
use objc::*;
use objc::runtime::{Object, Sel};
use objc::{class, declare::ClassDecl, msg_send, sel, sel_impl};
use crate::{Backend, BackendId, Error, Features, UtteranceId};
use crate::{Backend, BackendId, Error, Features, UtteranceId, CALLBACKS};
pub(crate) struct AvFoundation {
id: BackendId,
delegate: *mut Object,
synth: *mut Object,
rate: f32,
volume: f32,
@ -26,11 +27,71 @@ lazy_static! {
impl AvFoundation {
pub(crate) fn new() -> Self {
info!("Initializing AVFoundation backend");
let mut decl = ClassDecl::new("MyNSSpeechSynthesizerDelegate", class!(NSObject)).unwrap();
decl.add_ivar::<u64>("backend_id");
extern "C" fn speech_synthesizer_did_start_speech_utterance(
this: &Object,
_: Sel,
synth: *const Object,
utterance: id,
) {
unsafe {
let backend_id: u64 = *this.get_ivar("backend_id");
let backend_id = BackendId::AvFoundation(backend_id);
let callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get(&backend_id).unwrap();
if let Some(callback) = callbacks.utterance_begin {
let utterance_id = UtteranceId::AvFoundation(utterance);
callback(utterance_id);
}
}
}
extern "C" fn speech_synthesizer_did_finish_speech_utterance(
this: &Object,
_: Sel,
synth: *const Object,
utterance: id,
) {
unsafe {
let backend_id: u64 = *this.get_ivar("backend_id");
let backend_id = BackendId::AvFoundation(backend_id);
let callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get(&backend_id).unwrap();
if let Some(callback) = callbacks.utterance_end {
let utterance_id = UtteranceId::AvFoundation(utterance);
callback(utterance_id);
}
}
}
unsafe {
decl.add_method(
sel!(speechSynthesizer:didStartSpeechUtterance:),
speech_synthesizer_did_start_speech_utterance
as extern "C" fn(&Object, Sel, *const Object, id) -> (),
);
decl.add_method(
sel!(speechSynthesizer:didFinishSpeechUtterance:),
speech_synthesizer_did_finish_speech_utterance
as extern "C" fn(&Object, Sel, *const Object, id) -> (),
);
}
let delegate_class = decl.register();
let delegate_obj: *mut Object = unsafe { msg_send![delegate_class, new] };
let mut backend_id = NEXT_BACKEND_ID.lock().unwrap();
let rv = unsafe {
let synth: *mut Object = msg_send![class!(AVSpeechSynthesizer), new];
delegate_obj
.as_mut()
.unwrap()
.set_ivar("backend_id", *backend_id);
let _: () = msg_send![synth, setDelegate: delegate_obj];
AvFoundation {
id: BackendId::AvFoundation(*backend_id),
delegate: delegate_obj,
synth: synth,
rate: 0.5,
volume: 1.,
@ -157,6 +218,7 @@ impl Backend for AvFoundation {
impl Drop for AvFoundation {
fn drop(&mut self) {
unsafe {
let _: Object = msg_send![self.delegate, release];
let _: Object = msg_send![self.synth, release];
}
}