speechd_module_sys/lib.rs
1//!# Low-level binding for `libspeechd_module`
2//!
3//! To use this module you must implement at least the following functions
4//! *as global symbols* in your own code and not doing so will result in
5//! linking errors (see each function for details):
6//!
7//! * [`module_config`]
8//! * [`module_init`]
9//! * [`module_list_voices`]
10//! * [`module_speak`] or [`module_speak_sync`]
11//! * [`module_pause`]
12//! * [`module_stop`]
13//! * [`module_close`]
14//!
15//! In addition you must also implement the following functions, unless you
16//! compile and link against
17//! [`module_utils.c`](https://github.com/brailcom/speechd/blob/master/src/modules/module_utils.c)
18//! from the speech-dispatcher distribution (again see each function for
19//! details):
20//!
21//! * [`module_loop`]
22//! * [`module_set`]
23//! * [`module_audio_set`]
24//! * [`module_audio_init`]
25//! * [`module_loglevel_set`]
26//! * [`module_debug`]
27
28#[cfg(doc)]
29use std::io;
30use std::os::fd;
31use std::os::raw;
32
33pub mod audio;
34
35mod types;
36pub use types::*;
37
38
39// Detect missing feature flags, but only if this is *not* a documentation build
40#[cfg(
41 all(
42 any(
43 all(feature = "static", feature = "dynamic"),
44 all(not(feature = "static"), not(feature = "dynamic")),
45 ),
46 not(doc),
47 not(speechd_module_doc), // Workaround for `cargo doc` running check when documenating a dependant
48 ),
49)]
50compile_error!("You must select either the `static` or `dynamic` linking feature for the `speechd-module-sys` crate");
51
52
53// Functions to be provided by the module
54unsafe extern "C" {
55 /// Read the module configuration from the given optional/nullable path,
56 /// called at startup
57 ///
58 /// Returning a non-zero code from the function will abort module startup.
59 ///
60 /// Your module implementation *must* export it’s own version of this
61 /// function as:
62 ///
63 /// ```
64 /// #[unsafe(no_mangle)]
65 /// unsafe extern "C" fn module_config(configfile: *const raw::c_char) -> raw::c_int {
66 /// 0 // Stub implementation
67 /// }
68 /// ```
69 #[must_use]
70 pub unsafe fn module_config(configfile: *const raw::c_char) -> raw::c_int;
71
72 /// Called after server sends the `INIT` command
73 ///
74 /// `msg` is an optional out-pointer to a [`malloc`](libc::malloc)’d
75 /// C string with your response.
76 ///
77 /// Returning a non-zero code from the function will abort module startup.
78 ///
79 /// Your module implementation *must* export it’s own version of this
80 /// function as:
81 ///
82 /// ```
83 /// #[unsafe(no_mangle)]
84 /// unsafe extern "C" fn module_init(msg: *mut *const raw::c_char) -> raw::c_int {
85 /// 0 // Stub implementation
86 /// }
87 /// ```
88 #[must_use]
89 pub unsafe fn module_init(msg: *mut *const raw::c_char) -> raw::c_int;
90
91 /// List voices
92 ///
93 /// Response is a `NULL`-terminated, [`malloc`](libc::malloc)’d array of
94 /// pointers to each configured module voice. See the [`Voice`] data
95 /// structure for the format of indivial voices.
96 ///
97 /// Returning `NULL` from the function will abort module startup.
98 ///
99 /// Your module implementation *must* export it’s own version of this
100 /// function as:
101 ///
102 /// ```
103 /// # use std::ptr;
104 /// #[unsafe(no_mangle)]
105 /// extern "C" fn module_list_voices() -> *const *const Voice {
106 /// // Stub implementation
107 /// unsafe {
108 /// let res = libc::malloc(size_of<*const Voice>());
109 /// assert!(res != ptr::null_mut());
110 /// *res = ptr::null();
111 /// res
112 /// }
113 /// }
114 /// ```
115 #[must_use]
116 pub safe fn module_list_voices() -> *const *const Voice;
117
118 /// Asynchronous speak
119 ///
120 /// Your module implementation *must* export it’s own version of *either*
121 /// [`module_speak_sync`] *or* this function as:
122 ///
123 /// ```
124 /// #[unsafe(no_mangle)]
125 /// unsafe extern "C" fn module_speak(data: *const raw::c_char, len: usize, msgtype: MessageType) -> raw::c_int {
126 /// // Implementation
127 /// }
128 /// ```
129 #[must_use]
130 pub unsafe fn module_speak(data: *const raw::c_char, len: usize, msgtype: MessageType) -> raw::c_int;
131
132 /// Synchonous speak
133 ///
134 /// Your module implementation *must* export it’s own version of *either*
135 /// [`module_speak`] *or* function as:
136 ///
137 /// ```
138 /// #[unsafe(no_mangle)]
139 /// unsafe extern "C" fn module_speak_sync(data: *const raw::c_char, len: usize, msgtype: MessageType) -> raw::c_int {
140 /// // Implementation
141 /// }
142 /// ```
143 #[must_use]
144 pub unsafe fn module_speak_sync(data: *const raw::c_char, len: usize, msgtype: MessageType) -> raw::c_int;
145
146 /// Stop and drop the current utterance, preferably after reaching and
147 /// reporting the next `__spd_` index mark
148 ///
149 /// Your module implementation *must* export it’s own version of this
150 /// function as:
151 ///
152 /// ```
153 /// #[unsafe(no_mangle)]
154 /// extern "C" fn module_pause() -> usize {
155 /// // Implementation
156 /// }
157 /// ```
158 #[must_use]
159 pub safe fn module_pause() -> usize;
160
161 /// Immediately stop and drop the current utterance
162 ///
163 /// Your module implementation *must* export it’s own version of this
164 /// function as:
165 ///
166 /// ```
167 /// #[unsafe(no_mangle)]
168 /// extern "C" fn module_stop() -> raw::c_int {
169 /// // Implementation
170 /// }
171 /// ```
172 #[must_use]
173 pub safe fn module_stop() -> raw::c_int;
174
175 /// Called before exit
176 ///
177 /// Your module implementation *must* export it’s own version of this
178 /// function as:
179 ///
180 /// ```
181 /// #[unsafe(no_mangle)]
182 /// extern "C" fn module_close() -> raw::c_int {
183 /// // Implementation
184 /// }
185 /// ```
186 #[must_use]
187 pub safe fn module_close() -> raw::c_int;
188}
189
190
191// Functions that would be provided by `module_utils.c` but are not included
192// in the default distribution and hence unavailable unless you link with that
193// C file in your build
194unsafe extern "C" {
195 /// Called after init confirmed
196 ///
197 /// This should invoke [`module_process`] to process SSIP commands from stdin.
198 ///
199 /// Your module implementation *must* export it’s own version of this
200 /// function, unless your build system builds and links with its own
201 /// version of `module-utils.c` from the speech-dispatcher distribution.
202 ///
203 /// ```
204 /// #[unsafe(no_mangle)]
205 /// unsafe extern "C" fn module_loop() -> raw::c_int {
206 /// // Minimal implementation
207 /// if modapi::module_process(io::stdin().as_fd(), 1) != 0 {
208 /// eprintln!("Standard input is end-of-stream");
209 /// }
210 ///
211 /// 0
212 /// }
213 /// ```
214 #[must_use]
215 pub safe fn module_loop() -> raw::c_int;
216
217 /// Set parameter, see the `SET` command of section 5.2.2 (“Communication
218 /// Protocol for Output Modules”) of the speech-dispatcher manual
219 /// for a list of standard properties
220 ///
221 /// Your module implementation *must* export it’s own version of this
222 /// function, unless your build system builds and links with its own
223 /// version of `module-utils.c` from the speech-dispatcher distribution.
224 ///
225 /// ```
226 /// #[unsafe(no_mangle)]
227 /// unsafe extern "C" fn module_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int {
228 /// // Implementation
229 /// }
230 /// ```
231 #[must_use]
232 pub unsafe fn module_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int;
233
234 /// Set audio parameter
235 ///
236 /// Your module implementation *must* export it’s own version of this
237 /// function, unless your build system builds and links with its own
238 /// version of `module-utils.c` from the speech-dispatcher distribution.
239 ///
240 /// Note that this function is only required when using client audio
241 /// playback. Implementations relying on server playback being available
242 /// may stub this.
243 ///
244 /// ```
245 /// #[unsafe(no_mangle)]
246 /// unsafe extern "C" fn module_audio_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int {
247 /// -1 // Stub implementation
248 /// }
249 /// ```
250 #[must_use]
251 pub unsafe fn module_audio_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int;
252
253 /// Initialize audio
254 ///
255 /// Your module implementation *must* export it’s own version of this
256 /// function, unless your build system builds and links with its own
257 /// version of `module-utils.c` from the speech-dispatcher distribution.
258 ///
259 /// Note that this function is only required when using client audio
260 /// playback. Implementations relying on server playback being available
261 /// may stub this.
262 ///
263 /// ```
264 /// # use std::ptr;
265 /// #[unsafe(no_mangle)]
266 /// unsafe extern "C" fn module_audio_init(status_info: *mut *mut raw::c_char) -> raw::c_int {
267 /// // Stub implementation
268 /// let resp = c"This speech-dispatcher module was compiled without client audio support";
269 /// unsafe {
270 /// let ptr = libc::malloc(size_of_val(resp));
271 /// assert!(ptr != ptr::null_mut());
272 /// libc::memcpy(ptr, resp.as_ptr(), size_of_val(resp));
273 /// *status_info = ptr;
274 /// }
275 ///
276 /// -1
277 /// }
278 /// ```
279 #[must_use]
280 pub unsafe fn module_audio_init(status_info: *mut *mut raw::c_char) -> raw::c_int;
281
282 /// Set logging subsystem parameter
283 ///
284 /// Generally `var` will only ever be the string “log_level” and `val` will
285 /// be an integer string in the range of 0 to 5, see
286 /// section 2.4.7 (“Log Levels”) of the speech-dispatcher manual for the
287 /// list of standard logging levels.
288 ///
289 /// Your module implementation *must* export it’s own version of this
290 /// function, unless your build system builds and links with its own
291 /// version of `module-utils.c` from the speech-dispatcher distribution.
292 ///
293 /// ```
294 /// #[unsafe(no_mangle)]
295 /// unsafe extern "C" fn module_loglevel_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int {
296 /// // Implementation
297 /// }
298 /// ```
299 #[must_use]
300 pub unsafe fn module_loglevel_set(var: *const raw::c_char, val: *const raw::c_char) -> raw::c_int;
301
302 /// Enable or disable debugging into the given file
303 ///
304 /// The `enable` parameter is a boolean integer with values 0 (false) or
305 /// 1 (true) to disable or enable (respectively) verbose file debugging.
306 ///
307 /// The `file` parameter is the NUL-terminated path where the debug file
308 /// should be written to.
309 ///
310 /// Your module implementation *must* export it’s own version of this
311 /// function, unless your build system builds and links with its own
312 /// version of `module-utils.c` from the speech-dispatcher distribution.
313 ///
314 /// ```
315 /// #[unsafe(no_mangle)]
316 /// unsafe extern "C" fn module_debug(enable: raw::c_int, file: *const raw::c_char) -> raw::c_int {
317 /// // Implementation
318 /// }
319 /// ```
320 #[must_use]
321 pub unsafe fn module_debug(enable: raw::c_int, file: *const raw::c_char) -> raw::c_int;
322}
323
324// There are provided by the module
325unsafe extern "C" {
326 /// Notify the library that the module will send its audio as wave events
327 /// to the server using [`module_tts_output_server`]
328 pub safe fn module_audio_set_server();
329
330 /// Forward an audio chunk to the server
331 ///
332 /// Can be called as many times as desired, e.g. for each chunk produced by
333 /// the synthesizer.
334 pub unsafe fn module_tts_output_server(track: *const audio::Track, format: audio::Format);
335
336 /// Read and return one line of input read from the given file descriptor
337 ///
338 /// The returned pointer must be `free`’d using [`libc::free`].
339 ///
340 /// Since this function implements its own buffering, it must always be
341 /// called with the same input, usually simply stdin.
342 ///
343 /// When `block` is set to 1, will wait until a line of input is received,
344 /// thus never returning [`ptr::null_mut()`](std::ptr::null_mut).
345 ///
346 /// On I/O error or end-of-file, [`exit`](libc::exit) is called.
347 ///
348 /// For Rust code it is recommended to only use this function with
349 /// [`io::stdin().as_fd()`](io::stdin) (since the required [`module_process`]
350 /// function uses this function to read input and it has internal
351 /// buffering) and rely on [`std::io`] for any other file I/O operations.
352 #[must_use]
353 pub safe fn module_readline(fd: fd::BorrowedFd<'_>, block: raw::c_int) -> *mut raw::c_char;
354
355 /// Protects multi-line answers against asynchronous event reporting
356 ///
357 /// Rust consumers should generally not need this. It is only required if
358 /// you intend to send custom SSIP messages on [`io::stdout`]. Prefer using
359 /// [`module_tts_output_server`], [`module_speak_ok`], [`module_speak_error`],
360 /// [`module_report_index_mark`], [`module_report_icon`] and the
361 /// `module_report_event_*` class of functions to print SSIP message for
362 /// you.
363 ///
364 /// If you *do* need to send SSID message yourself, lock this mutex using
365 /// [`libc::pthread_mutex_lock`], print you messages
366 /// **using [`libc::printf`]** (or other bufferred **C I/O**), call
367 /// [`libc::fflush`] to ensure your response is writte, then unlock the
368 /// mutex using [`libc::pthread_mutex_unlock`].
369 pub static mut module_stdout_mutex: libc::pthread_mutex_t;
370
371 /// Callback for [`module_speak_sync`] to confirm the data is OK before
372 /// actually synthesizing
373 ///
374 /// The server may send stop requests, so resetting the stop state must be
375 /// done before calling this.
376 pub safe fn module_speak_ok();
377
378 /// Callback for [`module_speak_sync`] to mark the data as not OK, before
379 /// returning from [`module_speak_sync`]
380 pub safe fn module_speak_error();
381
382 /// Callback to report reaching an index mark
383 pub unsafe fn module_report_index_mark(mark: *const raw::c_char);
384
385 /// Callback to report the start of synthesis
386 pub safe fn module_report_event_begin();
387
388 /// Callback to report finishing synthesis
389 pub safe fn module_report_event_end();
390
391 /// Callback to confirm a [`module_stop`] request
392 pub safe fn module_report_event_stop();
393
394 /// Callback to confirm a [`module_pause`] request
395 pub safe fn module_report_event_pause();
396
397 /// Callback to report reaching a sound icon
398 pub unsafe fn module_report_icon(icon: *const raw::c_char);
399
400 /// Process the module input, interpreting the SSIP protocol and calling
401 /// appropriate module-provided functions
402 ///
403 /// This can be either
404 ///
405 /// * be called with `block` set to 1, to only return when the server sends
406 /// `QUIT` (acting as the main loop for the module)
407 /// * or called with `block` set to 0, to only process what was already
408 /// sent by the server and not wait for any further requests.
409 ///
410 /// Typically this would be called periodically by the module, to let the
411 /// server inform the module when it should stop.
412 #[must_use]
413 pub safe fn module_process(fd: fd::BorrowedFd<'_>, block: raw::c_int) -> raw::c_int;
414}