Skip to content

Commit

Permalink
Make locking typesafe
Browse files Browse the repository at this point in the history
  • Loading branch information
bplevin36 committed Jun 17, 2021
1 parent d43c411 commit 6bf0b87
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
rustflags = "-L espeak-ng/src/.libs"
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ crate-type = ["cdylib"]

[dependencies]
espeak-sys = { path = "./espeak-sys" }
libc = "0.2"
parking_lot = "0.11"

[dependencies.pyo3]
Expand Down
33 changes: 24 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,36 @@ use std::ptr::{addr_of_mut, null, null_mut};

use espeak_sys::{espeakCHARS_AUTO ,espeak_AUDIO_OUTPUT, espeak_ERROR, espeak_Initialize,
espeak_ListVoices, espeak_SetVoiceByName, espeak_TextToPhonemes};
use parking_lot::RawMutex as Mutex;
use parking_lot::lock_api::RawMutex;
use parking_lot::{Mutex, const_mutex};
use pyo3::prelude::*;
use pyo3::exceptions::PyRuntimeError;
use pyo3::wrap_pyfunction;
use libc::{c_int, c_char};

/// Lock that prevents changing the voice
static VOICE_LOCK: Mutex = RawMutex::INIT;
/// Library functions that depend on internal lib state
type LibFuncs = (
unsafe extern "C" fn(*const c_char) -> espeak_ERROR,
unsafe extern "C" fn(textptr: *const *const c_void, textmode: c_int, phonememode: c_int) -> *const c_char
);
static LIB: Mutex<LibFuncs> = const_mutex((espeak_SetVoiceByName, espeak_TextToPhonemes));

#[pymodule]
fn espeak_py(_py: Python, m: &PyModule) -> PyResult<()> {
let data_path;
let path_ptr;
#[cfg(target_os = "linux")]
{
data_path = CString::new("/usr/lib/x86_64-linux-gnu/espeak-ng-data")?;
path_ptr = data_path.as_ptr();
}
#[cfg(not(target_os = "linux"))]
{
path_ptr = null();
}
unsafe {
let _rate = espeak_Initialize(espeak_AUDIO_OUTPUT::AUDIO_OUTPUT_RETRIEVAL, 0, null(), 0);
let _rate = espeak_Initialize(espeak_AUDIO_OUTPUT::AUDIO_OUTPUT_RETRIEVAL, 0, path_ptr, 0);
}
drop(data_path);
m.add_function(wrap_pyfunction!(text_to_phonemes, m)?).unwrap();
m.add_function(wrap_pyfunction!(list_voices, m)?).unwrap();
Ok(())
Expand All @@ -28,9 +44,9 @@ fn espeak_py(_py: Python, m: &PyModule) -> PyResult<()> {
fn text_to_phonemes(text: &str, language: &str) -> PyResult<String> {
// set language
let lang = CString::new(language).unwrap();
let (set_voice, to_phonemes) = *(LIB.lock());
unsafe {
VOICE_LOCK.lock();
match espeak_SetVoiceByName(lang.as_ptr()) {
match set_voice(lang.as_ptr()) {
espeak_ERROR::EE_OK => (),
espeak_ERROR::EE_INTERNAL_ERROR => return Err(PyRuntimeError::new_err("espeak internal error while setting language")),
_ => return Err(PyRuntimeError::new_err("espeak unknown error while setting language")),
Expand All @@ -44,15 +60,14 @@ fn text_to_phonemes(text: &str, language: &str) -> PyResult<String> {
let mut ipas = String::new();
loop {
let phonemes_ptr = unsafe {
espeak_TextToPhonemes(espeak_text_ptr, espeakCHARS_AUTO as _, phonememode)
to_phonemes(espeak_text_ptr, espeakCHARS_AUTO as _, phonememode)
};
// copy phonemes into Rust heap
let phonemes_cstr = unsafe { CStr::from_ptr(phonemes_ptr) };
let phonemes_str = phonemes_cstr.to_str()?;
ipas.push_str(phonemes_str);
// if not null, we need to make another call
if c_text_ptr.is_null() {
unsafe { VOICE_LOCK.unlock(); }
return Ok(ipas)
}
// add newline to imitate espeak executable behavior
Expand Down

0 comments on commit 6bf0b87

Please sign in to comment.