1#![allow(non_upper_case_globals)]
2
3use libc::size_t;
4use std::{
5 collections::HashMap,
6 ffi::{CStr, CString},
7 fmt,
8 marker::Send,
9 os::raw::{c_char, c_int},
10 sync::{Arc, Mutex},
11};
12
13use lazy_static::lazy_static;
14use speech_dispatcher_sys::*;
15
16#[derive(Clone, Copy, Debug)]
17#[repr(u32)]
18pub enum Mode {
19 Single = SPDConnectionMode::SPD_MODE_SINGLE,
20 Threaded = SPDConnectionMode::SPD_MODE_THREADED,
21}
22
23#[derive(Clone, Copy, Debug)]
24#[repr(u32)]
25pub enum Priority {
26 Important = SPDPriority::SPD_IMPORTANT,
27 Message = SPDPriority::SPD_MESSAGE,
28 Text = SPDPriority::SPD_TEXT,
29 Notification = SPDPriority::SPD_NOTIFICATION,
30 Progress = SPDPriority::SPD_PROGRESS,
31}
32
33#[derive(Clone, Copy, Debug)]
34#[repr(u32)]
35pub enum VoiceType {
36 Male1 = SPDVoiceType::SPD_MALE1 as u32,
37 Male2 = SPDVoiceType::SPD_MALE2 as u32,
38 Male3 = SPDVoiceType::SPD_MALE3 as u32,
39 Female1 = SPDVoiceType::SPD_FEMALE1 as u32,
40 Female2 = SPDVoiceType::SPD_FEMALE2 as u32,
41 Female3 = SPDVoiceType::SPD_FEMALE3 as u32,
42 ChildMale = SPDVoiceType::SPD_CHILD_MALE as u32,
43 ChildFemale = SPDVoiceType::SPD_CHILD_FEMALE as u32,
44}
45
46#[derive(Clone, Debug, Hash, PartialEq)]
47pub struct Voice {
48 pub name: String,
50 pub language: String,
52 pub variant: Option<String>,
54}
55
56impl Voice {
57 unsafe fn try_from(v: &SPDVoice) -> Result<Self, std::str::Utf8Error> {
60 let name = CStr::from_ptr(v.name).to_str()?.to_owned();
62 let language = CStr::from_ptr(v.language).to_str()?.to_owned();
63 let variant = CStr::from_ptr(v.variant).to_str()?;
64 let variant = if variant == "none" {
65 None
66 } else {
67 Some(variant.to_owned())
68 };
69 Ok(Self {
70 name,
71 language,
72 variant,
73 })
74 }
75}
76
77pub type Address = SPDConnectionAddress;
78
79#[derive(Clone, Copy, Debug)]
80#[repr(u32)]
81pub enum DataMode {
82 Text = SPDDataMode::SPD_DATA_TEXT,
83 SSML = SPDDataMode::SPD_DATA_SSML,
84}
85
86#[derive(Clone, Copy, Debug)]
87#[repr(u32)]
88pub enum Notification {
89 Begin = SPDNotification::SPD_BEGIN,
90 End = SPDNotification::SPD_END,
91 IndexMarks = SPDNotification::SPD_INDEX_MARKS,
92 Cancel = SPDNotification::SPD_CANCEL,
93 Pause = SPDNotification::SPD_PAUSE,
94 Resume = SPDNotification::SPD_RESUME,
95 All = SPDNotification::SPD_ALL,
96}
97
98#[derive(Clone, Copy, Debug)]
99#[repr(u32)]
100pub enum Punctuation {
101 All = SPDPunctuation::SPD_PUNCT_ALL,
102 #[cfg(feature = "0_10")]
103 Most = SPDPunctuation::SPD_PUNCT_MOST,
104 Some = SPDPunctuation::SPD_PUNCT_SOME,
105 None = SPDPunctuation::SPD_PUNCT_NONE,
106}
107
108#[derive(Clone, Copy, Debug)]
109#[repr(u32)]
110pub enum CapitalLetters {
111 None = SPDCapitalLetters::SPD_CAP_NONE,
112 Spell = SPDCapitalLetters::SPD_CAP_SPELL,
113 Icon = SPDCapitalLetters::SPD_CAP_ICON,
114}
115
116fn c_int_to_result(r: c_int) -> Result<(), Error> {
118 match r {
119 0 => Ok(()),
120 _ => Err(Error::OperationFailed),
121 }
122}
123
124#[derive(Default)]
125struct Callbacks {
126 begin: Option<Box<dyn FnMut(size_t, size_t)>>,
127 end: Option<Box<dyn FnMut(size_t, size_t)>>,
128 index_mark: Option<Box<dyn FnMut(size_t, size_t, String)>>,
129 cancel: Option<Box<dyn FnMut(size_t, size_t)>>,
130 pause: Option<Box<dyn FnMut(size_t, size_t)>>,
131 resume: Option<Box<dyn FnMut(size_t, size_t)>>,
132}
133
134unsafe impl Send for Callbacks {}
135
136unsafe impl Sync for Callbacks {}
137
138lazy_static! {
139 static ref callbacks: Mutex<HashMap<size_t, Callbacks>> = {
140 let m = HashMap::new();
141 Mutex::new(m)
142 };
143}
144
145unsafe extern "C" fn cb(msg_id: size_t, client_id: size_t, state: u32) {
146 let state = match state {
147 SPDNotificationType_SPD_EVENT_BEGIN => Notification::Begin,
148 SPDNotificationType_SPD_EVENT_END => Notification::End,
149 SPDNotificationType_SPD_EVENT_CANCEL => Notification::Cancel,
150 SPDNotificationType_SPD_EVENT_PAUSE => Notification::Pause,
151 SPDNotificationType_SPD_EVENT_RESUME => Notification::Resume,
152 _ => panic!("Unknown notification received in callback: {}", state),
153 };
154 if let Some(c) = callbacks.lock().unwrap().get_mut(&client_id) {
155 let f = match state {
156 Notification::Begin => &mut c.begin,
157 Notification::End => &mut c.end,
158 Notification::Cancel => &mut c.cancel,
159 Notification::Pause => &mut c.pause,
160 Notification::Resume => &mut c.resume,
161 _ => panic!("Unknown notification type"),
162 };
163 if let Some(f) = f.as_mut() {
164 f(msg_id, client_id);
165 }
166 }
167}
168
169unsafe extern "C" fn cb_im(msg_id: size_t, client_id: size_t, state: u32, index_mark: *mut c_char) {
170 let index_mark = CStr::from_ptr(index_mark);
171 let index_mark = index_mark.to_string_lossy().to_string();
172 let state = match state {
173 SPDNotificationType_SPD_EVENT_INDEX_MARK => Notification::IndexMarks,
174 _ => panic!("Unknown notification received in IM callback: {}", state),
175 };
176 if let Some(c) = callbacks.lock().unwrap().get_mut(&client_id) {
177 let f = match state {
178 Notification::IndexMarks => &mut c.index_mark,
179 _ => panic!("Unknown notification type"),
180 };
181 if let Some(f) = f.as_mut() {
182 f(msg_id, client_id, index_mark);
183 }
184 }
185}
186
187#[derive(Debug)]
188pub enum Error {
189 InitializationError,
192 OperationFailed,
194}
195
196impl std::error::Error for Error {}
197
198impl fmt::Display for Error {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 use Error::*;
201 match self {
202 InitializationError => write!(f, "failed to initialize"),
203 OperationFailed => write!(f, "operation failed"),
204 }
205 }
206}
207
208#[derive(Clone, Debug)]
209pub struct Connection(pub Arc<*mut SPDConnection>, size_t);
210
211impl Connection {
212 pub fn open<S: Into<String>>(
213 client_name: S,
214 connection_name: S,
215 user_name: S,
216 mode: Mode,
217 ) -> Result<Self, Error> {
218 let clientname = CString::new(client_name.into()).unwrap();
219 let connectionname = CString::new(connection_name.into()).unwrap();
220 let username = CString::new(user_name.into()).unwrap();
221 let connection = unsafe {
222 let c = spd_open(
223 clientname.as_ptr(),
224 connectionname.as_ptr(),
225 username.as_ptr(),
226 mode as u32,
227 );
228 if c.is_null() {
229 Err(Error::InitializationError)
230 } else {
231 Ok(Self::setup_connection(c))
232 }
233 };
234 let mut c = Self(Arc::new(connection?), 0);
235 c.setup()?;
236 Ok(c)
237 }
238
239 pub unsafe fn open2<S: Into<String>>(
240 client_name: S,
241 connection_name: S,
242 user_name: S,
243 mode: Mode,
244 address: *mut Address,
245 autospawn: bool,
246 ) -> Result<Self, Error> {
247 let auto_spawn = if autospawn { 1 } else { 0 };
248 let error_result = vec![CString::new("").unwrap().into_raw()].as_mut_ptr();
249 let clientname = CString::new(client_name.into()).unwrap();
250 let connectionname = CString::new(connection_name.into()).unwrap();
251 let username = CString::new(user_name.into()).unwrap();
252 let connection = {
253 let c = spd_open2(
254 clientname.as_ptr(),
255 connectionname.as_ptr(),
256 username.as_ptr(),
257 mode as u32,
258 address,
259 auto_spawn,
260 error_result,
261 );
262 if c.is_null() {
263 Err(Error::InitializationError)
264 } else {
265 Ok(Self::setup_connection(c))
266 }
267 };
268 let mut c = Self(Arc::new(connection?), 0);
269 c.setup()?;
270 Ok(c)
271 }
272
273 unsafe fn setup_connection(c: *mut SPDConnection) -> *mut SPDConnection {
274 (*c).callback_begin = Some(cb);
275 (*c).callback_end = Some(cb);
276 (*c).callback_cancel = Some(cb);
277 (*c).callback_pause = Some(cb);
278 (*c).callback_resume = Some(cb);
279 (*c).callback_im = Some(cb_im);
280 c
281 }
282
283 fn setup(&mut self) -> Result<(), Error> {
284 let client_id = self.send_data("HISTORY GET CLIENT_ID\r\n", true);
285 if let Some(client_id) = client_id {
286 let client_id: Vec<&str> = client_id.split("\r\n").collect();
287 let client_id = client_id.get(0);
288 if let Some(client_id) = client_id {
289 let client_id: Vec<&str> = client_id.split("-").collect();
290 if let Some(client_id) = client_id.get(1) {
291 if let Ok(client_id) = client_id.parse::<size_t>() {
292 self.1 = client_id;
293 }
294 }
295 }
296 }
297 callbacks.lock().unwrap().insert(self.1, Default::default());
298 self.set_notification_on(Notification::All)
299 .map_err(|_| Error::InitializationError)?;
300 Ok(())
301 }
302
303 pub fn close(&self) {
304 unsafe { spd_close(*self.0) };
305 }
306
307 pub fn say<S: Into<String>>(&self, priority: Priority, text: S) -> Option<u64> {
308 let text: String = text.into();
309 let param = CString::new(text).unwrap();
310 let rv = unsafe { spd_say(*self.0, priority as u32, param.as_ptr()) };
311 if rv != -1 {
312 Some(rv as u64)
313 } else {
314 None
315 }
316 }
317
318 pub fn sayf<S: Into<String>>(&self, priority: Priority, format: S) -> Option<i32> {
319 let format: String = format.into();
320 let param = CString::new(format).unwrap();
321 let rv = unsafe { spd_sayf(*self.0, priority as u32, param.as_ptr()) };
322 if rv != -1 {
323 Some(rv)
324 } else {
325 None
326 }
327 }
328
329 pub fn stop(&self) -> Result<(), Error> {
330 let v = unsafe { spd_stop(*self.0) };
331 c_int_to_result(v)
332 }
333
334 pub fn stop_all(&self) -> Result<(), Error> {
335 let v = unsafe { spd_stop_all(*self.0) };
336 c_int_to_result(v)
337 }
338
339 pub fn stop_uid(&self, target_uid: i32) -> Result<(), Error> {
340 let v = unsafe { spd_stop_uid(*self.0, target_uid) };
341 c_int_to_result(v)
342 }
343
344 pub fn cancel(&self) -> Result<(), Error> {
345 let v = unsafe { spd_cancel(*self.0) };
346 c_int_to_result(v)
347 }
348
349 pub fn cancel_all(&self) -> Result<(), Error> {
350 let v = unsafe { spd_cancel_all(*self.0) };
351 c_int_to_result(v)
352 }
353
354 pub fn cancel_uid(&self, target_uid: i32) -> Result<(), Error> {
355 let v = unsafe { spd_cancel_uid(*self.0, target_uid) };
356 c_int_to_result(v)
357 }
358
359 pub fn pause(&self) -> Result<(), Error> {
360 let v = unsafe { spd_pause(*self.0) };
361 c_int_to_result(v)
362 }
363
364 pub fn pause_all(&self) -> Result<(), Error> {
365 let v = unsafe { spd_pause_all(*self.0) };
366 c_int_to_result(v)
367 }
368
369 pub fn pause_uid(&self, target_uid: i32) -> Result<(), Error> {
370 let v = unsafe { spd_pause_uid(*self.0, target_uid) };
371 c_int_to_result(v)
372 }
373
374 pub fn resume(&self) -> Result<(), Error> {
375 let v = unsafe { spd_resume(*self.0) };
376 c_int_to_result(v)
377 }
378
379 pub fn resume_all(&self) -> Result<(), Error> {
380 let v = unsafe { spd_resume_all(*self.0) };
381 c_int_to_result(v)
382 }
383
384 pub fn resume_uid(&self, target_uid: i32) -> Result<(), Error> {
385 let v = unsafe { spd_resume_uid(*self.0, target_uid) };
386 c_int_to_result(v)
387 }
388
389 pub fn key<S: Into<String>>(&self, priority: Priority, key_name: S) -> Result<(), Error> {
390 let param = CString::new(key_name.into()).unwrap();
391 let v = unsafe { spd_key(*self.0, priority as u32, param.as_ptr()) };
392 c_int_to_result(v)
393 }
394
395 pub fn char<S: Into<String>>(&self, priority: Priority, char: S) -> Result<(), Error> {
396 let param = CString::new(char.into()).unwrap();
397 let v = unsafe { spd_char(*self.0, priority as u32, param.as_ptr()) };
398 c_int_to_result(v)
399 }
400
401 pub fn wchar(&self, priority: Priority, wchar: i32) -> Result<(), Error> {
402 let v = unsafe { spd_wchar(*self.0, priority as u32, wchar as wchar_t) };
403 c_int_to_result(v)
404 }
405
406 pub fn sound_icon<S: Into<String>>(
407 &self,
408 priority: Priority,
409 icon_name: S,
410 ) -> Result<(), Error> {
411 let param = CString::new(icon_name.into()).unwrap();
412 let v = unsafe { spd_char(*self.0, priority as u32, param.as_ptr()) };
413 c_int_to_result(v)
414 }
415
416 pub fn set_voice_type(&self, voice_type: VoiceType) -> Result<(), Error> {
417 #[cfg(all(any(feature = "0_9", feature = "0_10"), not(feature = "0_11")))]
418 let v = unsafe { spd_set_voice_type(*self.0, voice_type as u32) };
419 #[cfg(all(not(feature = "0_9"), any(feature = "0_11", not(feature = "0_10"))))]
420 let v = unsafe { spd_set_voice_type(*self.0, voice_type as i32) };
421 c_int_to_result(v)
422 }
423
424 pub fn set_voice_type_all(&self, voice_type: VoiceType) -> Result<(), Error> {
425 #[cfg(all(any(feature = "0_9", feature = "0_10"), not(feature = "0_11")))]
426 let v = unsafe { spd_set_voice_type_all(*self.0, voice_type as u32) };
427 #[cfg(all(not(feature = "0_9"), any(feature = "0_11", not(feature = "0_10"))))]
428 let v = unsafe { spd_set_voice_type_all(*self.0, voice_type as i32) };
429 c_int_to_result(v)
430 }
431
432 pub fn set_voice_type_uid(&self, voice_type: VoiceType, target_uid: u32) -> Result<(), Error> {
433 #[cfg(all(any(feature = "0_9", feature = "0_10"), not(feature = "0_11")))]
434 let v = unsafe { spd_set_voice_type_uid(*self.0, voice_type as u32, target_uid) };
435 #[cfg(all(not(feature = "0_9"), any(feature = "0_11", not(feature = "0_10"))))]
436 let v = unsafe { spd_set_voice_type_uid(*self.0, voice_type as i32, target_uid) };
437 c_int_to_result(v)
438 }
439
440 pub fn get_voice_type(&self) -> Result<VoiceType, Error> {
441 let v = unsafe { spd_get_voice_type(*self.0) };
442 Ok(match v {
443 SPDVoiceType::SPD_MALE1 => VoiceType::Male1,
444 SPDVoiceType::SPD_MALE2 => VoiceType::Male2,
445 SPDVoiceType::SPD_MALE3 => VoiceType::Male3,
446 SPDVoiceType::SPD_FEMALE1 => VoiceType::Female1,
447 SPDVoiceType::SPD_FEMALE2 => VoiceType::Female2,
448 SPDVoiceType::SPD_FEMALE3 => VoiceType::Female3,
449 SPDVoiceType::SPD_CHILD_MALE => VoiceType::ChildMale,
450 SPDVoiceType::SPD_CHILD_FEMALE => VoiceType::ChildFemale,
451 _ => return Err(Error::OperationFailed), })
453 }
454
455 pub fn set_synthesis_voice(&self, voice: &Voice) -> Result<(), Error> {
456 let param = CString::new(voice.name.clone()).unwrap();
457 let v = unsafe { spd_set_synthesis_voice(*self.0, param.as_ptr()) };
458 c_int_to_result(v)
459 }
460
461 pub fn set_synthesis_voice_all<S: Into<String>>(&self, voice_name: S) -> Result<(), Error> {
462 let param = CString::new(voice_name.into()).unwrap();
463 let v = unsafe { spd_set_synthesis_voice_all(*self.0, param.as_ptr()) };
464 c_int_to_result(v)
465 }
466
467 pub fn set_synthesis_voice_uid<S: Into<String>>(
468 &self,
469 voice_name: S,
470 target_uid: u32,
471 ) -> Result<(), Error> {
472 let param = CString::new(voice_name.into()).unwrap();
473 let v = unsafe { spd_set_synthesis_voice_uid(*self.0, param.as_ptr(), target_uid) };
474 c_int_to_result(v)
475 }
476
477 pub fn set_data_mode(&self, mode: DataMode) -> Result<(), Error> {
478 let v = unsafe { spd_set_data_mode(*self.0, mode as u32) };
479 c_int_to_result(v)
480 }
481
482 pub fn set_notification_on(&self, notification: Notification) -> Result<(), Error> {
483 let v = unsafe { spd_set_notification_on(*self.0, notification as u32) };
484 c_int_to_result(v)
485 }
486
487 pub fn set_notification_off(&self, notification: Notification) -> Result<(), Error> {
488 let v = unsafe { spd_set_notification_off(*self.0, notification as u32) };
489 c_int_to_result(v)
490 }
491
492 pub fn set_notification<S: Into<String>>(
493 &self,
494 notification: Notification,
495 state: S,
496 ) -> Result<(), Error> {
497 let param = CString::new(state.into()).unwrap();
498 let v = unsafe { spd_set_notification(*self.0, notification as u32, param.as_ptr()) };
499 c_int_to_result(v)
500 }
501
502 pub fn set_voice_rate(&self, rate: i32) -> Result<(), Error> {
503 let v = unsafe { spd_set_voice_rate(*self.0, rate) };
504 c_int_to_result(v)
505 }
506
507 pub fn set_voice_rate_all(&self, rate: i32) -> Result<(), Error> {
508 let v = unsafe { spd_set_voice_rate_all(*self.0, rate) };
509 c_int_to_result(v)
510 }
511
512 pub fn set_voice_rate_uid(&self, rate: i32, target_uid: u32) -> Result<(), Error> {
513 let v = unsafe { spd_set_voice_rate_uid(*self.0, rate, target_uid) };
514 c_int_to_result(v)
515 }
516
517 pub fn get_voice_rate(&self) -> i32 {
518 unsafe { spd_get_voice_rate(*self.0) }
519 }
520
521 pub fn set_voice_pitch(&self, pitch: i32) -> Result<(), Error> {
522 let v = unsafe { spd_set_voice_pitch(*self.0, pitch) };
523 c_int_to_result(v)
524 }
525
526 pub fn set_voice_pitch_all(&self, pitch: i32) -> Result<(), Error> {
527 let v = unsafe { spd_set_voice_pitch_all(*self.0, pitch) };
528 c_int_to_result(v)
529 }
530
531 pub fn set_voice_pitch_uid(&self, pitch: i32, target_uid: u32) -> Result<(), Error> {
532 let v = unsafe { spd_set_voice_pitch_uid(*self.0, pitch, target_uid) };
533 c_int_to_result(v)
534 }
535
536 pub fn get_voice_pitch(&self) -> i32 {
537 unsafe { spd_get_voice_pitch(*self.0) }
538 }
539
540 pub fn set_volume(&self, volume: i32) -> Result<(), Error> {
541 let v = unsafe { spd_set_volume(*self.0, volume) };
542 c_int_to_result(v)
543 }
544
545 pub fn set_volume_all(&self, volume: i32) -> Result<(), Error> {
546 let v = unsafe { spd_set_volume_all(*self.0, volume) };
547 c_int_to_result(v)
548 }
549
550 pub fn set_volume_uid(&self, volume: i32, target_uid: u32) -> Result<(), Error> {
551 let v = unsafe { spd_set_volume_uid(*self.0, volume, target_uid) };
552 c_int_to_result(v)
553 }
554
555 pub fn get_volume(&self) -> i32 {
556 unsafe { spd_get_volume(*self.0) }
557 }
558
559 pub fn set_punctuation(&self, punctuation: Punctuation) -> Result<(), Error> {
560 let v = unsafe { spd_set_punctuation(*self.0, punctuation as u32) };
561 c_int_to_result(v)
562 }
563
564 pub fn set_punctuation_all(&self, punctuation: Punctuation) -> Result<(), Error> {
565 let v = unsafe { spd_set_punctuation_all(*self.0, punctuation as u32) };
566 c_int_to_result(v)
567 }
568
569 pub fn set_punctuation_uid(
570 &self,
571 punctuation: Punctuation,
572 target_uid: u32,
573 ) -> Result<(), Error> {
574 let v = unsafe { spd_set_punctuation_uid(*self.0, punctuation as u32, target_uid) };
575 c_int_to_result(v)
576 }
577
578 pub fn set_capital_letters(&self, capital_letters: CapitalLetters) -> Result<(), Error> {
579 let v = unsafe { spd_set_capital_letters(*self.0, capital_letters as u32) };
580 c_int_to_result(v)
581 }
582
583 pub fn set_capital_letters_all(&self, capital_letters: CapitalLetters) -> Result<(), Error> {
584 let v = unsafe { spd_set_capital_letters_all(*self.0, capital_letters as u32) };
585 c_int_to_result(v)
586 }
587
588 pub fn set_capital_letters_uid(
589 &self,
590 capital_letters: CapitalLetters,
591 target_uid: u32,
592 ) -> Result<(), Error> {
593 let v = unsafe { spd_set_capital_letters_uid(*self.0, capital_letters as u32, target_uid) };
594 c_int_to_result(v)
595 }
596
597 pub fn set_spelling(&self, spelling: bool) -> Result<(), Error> {
598 let s = if spelling {
599 SPDSpelling::SPD_SPELL_ON
600 } else {
601 SPDSpelling::SPD_SPELL_OFF
602 };
603 let v = unsafe { spd_set_spelling(*self.0, s) };
604 c_int_to_result(v)
605 }
606
607 pub fn set_spelling_all(&self, spelling: bool) -> Result<(), Error> {
608 let s = if spelling {
609 SPDSpelling::SPD_SPELL_ON
610 } else {
611 SPDSpelling::SPD_SPELL_OFF
612 };
613 let v = unsafe { spd_set_spelling_all(*self.0, s) };
614 c_int_to_result(v)
615 }
616
617 pub fn set_spelling_uid(&self, spelling: bool, target_uid: u32) -> Result<(), Error> {
618 let s = if spelling {
619 SPDSpelling::SPD_SPELL_ON
620 } else {
621 SPDSpelling::SPD_SPELL_OFF
622 };
623 let v = unsafe { spd_set_spelling_uid(*self.0, s, target_uid) };
624 c_int_to_result(v)
625 }
626
627 pub fn set_language<S: Into<String>>(&self, language: S) -> Result<(), Error> {
628 let param = CString::new(language.into()).unwrap();
629 let v = unsafe { spd_set_language(*self.0, param.as_ptr()) };
630 c_int_to_result(v)
631 }
632
633 pub fn set_language_all<S: Into<String>>(&self, language: S) -> Result<(), Error> {
634 let param = CString::new(language.into()).unwrap();
635 let v = unsafe { spd_set_language_all(*self.0, param.as_ptr()) };
636 c_int_to_result(v)
637 }
638
639 pub fn set_language_uid<S: Into<String>>(
640 &self,
641 language: S,
642 target_uid: u32,
643 ) -> Result<(), Error> {
644 let param = CString::new(language.into()).unwrap();
645 let v = unsafe { spd_set_language_uid(*self.0, param.as_ptr(), target_uid) };
646 c_int_to_result(v)
647 }
648
649 pub fn get_language(&self) -> Result<&str, Error> {
650 let language = unsafe { spd_get_language(*self.0) };
651 if language.is_null() {
652 Err(Error::OperationFailed)
653 } else {
654 let language = unsafe { CStr::from_ptr(language) };
655 language.to_str().map_err(|_| Error::OperationFailed)
656 }
657 }
658
659 pub fn set_output_module<S: Into<String>>(&self, output_module: S) -> Result<(), Error> {
660 let param = CString::new(output_module.into()).unwrap();
661 let v = unsafe { spd_set_output_module(*self.0, param.as_ptr()) };
662 c_int_to_result(v)
663 }
664
665 pub fn set_output_module_all<S: Into<String>>(&self, output_module: S) -> Result<(), Error> {
666 let param = CString::new(output_module.into()).unwrap();
667 let v = unsafe { spd_set_output_module_all(*self.0, param.as_ptr()) };
668 c_int_to_result(v)
669 }
670
671 pub fn set_output_module_uid<S: Into<String>>(
672 &self,
673 output_module: S,
674 target_uid: u32,
675 ) -> Result<(), Error> {
676 let param = CString::new(output_module.into()).unwrap();
677 let v = unsafe { spd_set_output_module_uid(*self.0, param.as_ptr(), target_uid) };
678 c_int_to_result(v)
679 }
680
681 pub fn send_data<S: Into<String>>(&self, data: S, wait_for_reply: bool) -> Option<String> {
682 let wfr: i32 = if wait_for_reply {
683 SPD_WAIT_REPLY as i32
684 } else {
685 SPD_NO_REPLY as i32
686 };
687 let data = CString::new(data.into()).unwrap();
688 let rv = unsafe { spd_send_data(*self.0, data.as_ptr(), wfr) };
689 if rv.is_null() {
690 None
691 } else {
692 let rv = unsafe { CStr::from_ptr(rv) };
693 Some(rv.to_string_lossy().to_string())
694 }
695 }
696
697 pub fn on_begin(&self, f: Option<Box<dyn FnMut(size_t, size_t)>>) {
698 if let Ok(mut cbs) = callbacks.lock() {
699 let cb = cbs.get_mut(&self.1);
700 if let Some(cb) = cb {
701 cb.begin = f;
702 }
703 }
704 }
705
706 pub fn on_end(&self, f: Option<Box<dyn FnMut(size_t, size_t)>>) {
707 if let Ok(mut cbs) = callbacks.lock() {
708 let cb = cbs.get_mut(&self.1);
709 if let Some(cb) = cb {
710 cb.end = f;
711 }
712 }
713 }
714
715 pub fn on_cancel(&self, f: Option<Box<dyn FnMut(size_t, size_t)>>) {
716 if let Ok(mut cbs) = callbacks.lock() {
717 let cb = cbs.get_mut(&self.1);
718 if let Some(cb) = cb {
719 cb.cancel = f;
720 }
721 }
722 }
723
724 pub fn on_pause(&self, f: Option<Box<dyn FnMut(size_t, size_t)>>) {
725 if let Ok(mut cbs) = callbacks.lock() {
726 let cb = cbs.get_mut(&self.1);
727 if let Some(cb) = cb {
728 cb.pause = f;
729 }
730 }
731 }
732
733 pub fn on_resume(&self, f: Option<Box<dyn FnMut(size_t, size_t)>>) {
734 if let Ok(mut cbs) = callbacks.lock() {
735 let cb = cbs.get_mut(&self.1);
736 if let Some(cb) = cb {
737 cb.resume = f;
738 }
739 }
740 }
741
742 pub fn on_index_mark(&self, f: Option<Box<dyn FnMut(size_t, size_t, String)>>) {
743 if let Ok(mut cbs) = callbacks.lock() {
744 let cb = cbs.get_mut(&self.1);
745 if let Some(cb) = cb {
746 cb.index_mark = f;
747 }
748 }
749 }
750
751 pub fn list_synthesis_voices(&self) -> Result<Vec<Voice>, Error> {
752 let start = unsafe { spd_list_synthesis_voices(*self.0) };
753 let slice = unsafe { null_term_array_ptr_to_slice(start) }.ok_or(Error::OperationFailed)?;
754 let voices = unsafe {
755 slice
756 .iter()
757 .map(|v| v.read())
758 .flat_map(|v| {
759 if v.name.is_null() || v.language.is_null() || v.variant.is_null() {
760 None
761 } else {
762 Voice::try_from(&v).ok()
763 }
764 })
765 .collect()
766 };
767 unsafe {
768 free_spd_voices(start);
769 }
770 Ok(voices)
771 }
772
773 pub fn list_output_modules(&self) -> Result<Vec<String>, Error> {
774 let start = unsafe { spd_list_modules(*self.0) };
775 let slice = unsafe { null_term_array_ptr_to_slice(start) }.ok_or(Error::OperationFailed)?;
776 let modules = unsafe {
777 slice
778 .iter()
779 .flat_map(|v| CStr::from_ptr(*v).to_str().ok().map(String::from))
780 .collect()
781 };
782 unsafe {
783 free_spd_modules(start);
784 }
785 Ok(modules)
786 }
787
788 pub fn client_id(&self) -> size_t {
789 self.1
790 }
791}
792
793unsafe fn null_term_array_ptr_to_slice<'a, T>(start: *mut *mut T) -> Option<&'a [*mut T]> {
796 if start.is_null() {
797 return None;
798 }
799 let mut current = start;
800 let mut len = 0;
801
802 while !current.read().is_null() {
803 len += 1;
804 current = current.add(1);
805 }
806
807 Some(std::slice::from_raw_parts(start, len))
808}
809
810unsafe impl Send for Connection {}
811
812impl Drop for Connection {
813 fn drop(&mut self) {
814 if Arc::strong_count(&self.0) <= 1 {
815 self.close();
816 callbacks.lock().unwrap().remove(&self.1);
817 }
818 }
819}