Skip to content

Commit 35db264

Browse files
committed
docs: update README C API table, add pause/resume/synth_to_bytes to all bindings
- README: add tts_pause, tts_resume, tts_synth_to_bytes, tts_free_bytes to C API table - Python: add pause(), resume(), synth_to_bytes() with ctypes bindings - .NET: add Pause(), Resume(), SynthToBytes() with P/Invoke declarations - Swift: add pause(), resume(), synthToBytes() returning Data? - Fix cbindgen.toml: remove duplicate after_includes/trailer (cpp_compat handles extern C) - Regenerated header is now clean with single extern "C" block - Clippy fixes: add #[must_use] to preprocess_speech_markdown, allow vec_init_then_push
1 parent 6ceaa64 commit 35db264

8 files changed

Lines changed: 76 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ All functions are `extern "C"`, `#[no_mangle]`:
150150
| `tts_speak(ctx, text)` | Speak async, returns 0/-1 |
151151
| `tts_speak_sync(ctx, text)` | Speak sync (blocking) |
152152
| `tts_stop(ctx)` | Stop speech |
153+
| `tts_pause(ctx)` | Pause in-progress speech |
154+
| `tts_resume(ctx)` | Resume paused speech |
155+
| `tts_synth_to_bytes(ctx, text, out_bytes, out_len)` | Synth to buffer (returns 0/-1) |
156+
| `tts_free_bytes(bytes, len)` | Free buffer from tts_synth_to_bytes |
153157
| `tts_get_voices(ctx, out_voices, out_count)` | Get voice list |
154158
| `tts_free_voices(voices, count)` | Free voice array |
155159
| `tts_set_voice(ctx, voice_id)` | Set voice |

bindings/dotnet/TtsClient.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ public static class Native
1111
[DllImport("rust_tts_wrapper")] public static extern int tts_speak(IntPtr ctx, string text);
1212
[DllImport("rust_tts_wrapper")] public static extern int tts_speak_sync(IntPtr ctx, string text);
1313
[DllImport("rust_tts_wrapper")] public static extern void tts_stop(IntPtr ctx);
14+
[DllImport("rust_tts_wrapper")] public static extern void tts_pause(IntPtr ctx);
15+
[DllImport("rust_tts_wrapper")] public static extern void tts_resume(IntPtr ctx);
16+
[DllImport("rust_tts_wrapper")] public static extern int tts_synth_to_bytes(IntPtr ctx, string text, out IntPtr outBytes, out UIntPtr outLen);
17+
[DllImport("rust_tts_wrapper")] public static extern void tts_free_bytes(IntPtr bytes, UIntPtr len);
1418
[DllImport("rust_tts_wrapper")] public static extern void tts_set_voice(IntPtr ctx, string voiceId);
1519
[DllImport("rust_tts_wrapper")] public static extern void tts_set_rate(IntPtr ctx, float rate);
1620
[DllImport("rust_tts_wrapper")] public static extern void tts_set_pitch(IntPtr ctx, float pitch);
@@ -46,6 +50,21 @@ public void SpeakSync(string text) =>
4650
Native.tts_speak_sync(_ctx, text);
4751

4852
public void Stop() => Native.tts_stop(_ctx);
53+
public void Pause() => Native.tts_pause(_ctx);
54+
public void Resume() => Native.tts_resume(_ctx);
55+
56+
public byte[] SynthToBytes(string text)
57+
{
58+
IntPtr bufPtr;
59+
UIntPtr len;
60+
int result = Native.tts_synth_to_bytes(_ctx, text, out bufPtr, out len);
61+
if (result != 0) throw new InvalidOperationException("Synthesis to bytes failed");
62+
byte[] data = new byte[len.ToUInt32()];
63+
if (data.Length > 0) Marshal.Copy(bufPtr, data, 0, data.Length);
64+
Native.tts_free_bytes(bufPtr, len);
65+
return data;
66+
}
67+
4968
public void SetVoice(string voiceId) => Native.tts_set_voice(_ctx, voiceId);
5069
public void SetRate(float rate) => Native.tts_set_rate(_ctx, rate);
5170
public void SetPitch(float pitch) => Native.tts_set_pitch(_ctx, pitch);

bindings/python/tts_wrapper.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ def _load_lib():
3333
_lib.tts_speak_sync.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
3434
_lib.tts_stop.restype = None
3535
_lib.tts_stop.argtypes = [ctypes.c_void_p]
36+
_lib.tts_pause.restype = None
37+
_lib.tts_pause.argtypes = [ctypes.c_void_p]
38+
_lib.tts_resume.restype = None
39+
_lib.tts_resume.argtypes = [ctypes.c_void_p]
40+
_lib.tts_synth_to_bytes.restype = ctypes.c_int32
41+
_lib.tts_synth_to_bytes.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_uint8)), ctypes.POINTER(ctypes.c_size_t)]
42+
_lib.tts_free_bytes.restype = None
43+
_lib.tts_free_bytes.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t]
3644
_lib.tts_set_voice.restype = None
3745
_lib.tts_set_voice.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
3846
_lib.tts_set_rate.restype = None
@@ -102,6 +110,23 @@ def speak_sync(self, text: str) -> None:
102110
def stop(self) -> None:
103111
self._lib.tts_stop(self._ctx)
104112

113+
def pause(self) -> None:
114+
self._lib.tts_pause(self._ctx)
115+
116+
def resume(self) -> None:
117+
self._lib.tts_resume(self._ctx)
118+
119+
def synth_to_bytes(self, text: str) -> bytes:
120+
buf = ctypes.POINTER(ctypes.c_uint8)()
121+
length = ctypes.c_size_t()
122+
result = self._lib.tts_synth_to_bytes(self._ctx, text.encode(), ctypes.byref(buf), ctypes.byref(length))
123+
if result != 0:
124+
raise RuntimeError("Synthesis to bytes failed")
125+
data = ctypes.string_at(buf, length.value) if buf and length.value > 0 else b""
126+
if buf:
127+
self._lib.tts_free_bytes(buf, length.value)
128+
return data
129+
105130
def set_voice(self, voice_id: str) -> None:
106131
self._lib.tts_set_voice(self._ctx, voice_id.encode())
107132

bindings/swift/TtsClient.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ public class TTSClient {
5555
rust_tts_wrapper.tts_stop(ctx)
5656
}
5757

58+
public func pause() {
59+
guard let ctx else { return }
60+
rust_tts_wrapper.tts_pause(ctx)
61+
}
62+
63+
public func resume() {
64+
guard let ctx else { return }
65+
rust_tts_wrapper.tts_resume(ctx)
66+
}
67+
68+
public func synthToBytes(_ text: String) -> Data? {
69+
guard let ctx else { return nil }
70+
var bufPtr: UnsafeMutablePointer<UInt8>?
71+
var length: Int = 0
72+
let result = text.withCString { textPtr in
73+
rust_tts_wrapper.tts_synth_to_bytes(ctx, textPtr, &bufPtr, &length)
74+
}
75+
guard result == 0, let buf = bufPtr, length > 0 else { return nil }
76+
defer { rust_tts_wrapper.tts_free_bytes(buf, UInt(length)) }
77+
return Data(bytes: buf, count: length)
78+
}
79+
5880
public func setVoice(_ voiceId: String) {
5981
guard let ctx else { return }
6082
voiceId.withCString { ptr in

cbindgen.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,3 @@ autogen_warning = "/* Auto-generated. Do not edit. */"
44
no_includes = true
55
sys_includes = ["stdint.h", "stdbool.h"]
66
cpp_compat = true
7-
after_includes = "#ifdef __cplusplus\nextern \"C\" {\n#endif"
8-
trailer = "#ifdef __cplusplus\n}\n#endif"

include/tts_wrapper.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55

66
#include <stdint.h>
77
#include <stdbool.h>
8-
#ifdef __cplusplus
9-
extern "C" {
10-
#endif
118

129
typedef struct tts_ctx tts_ctx;
1310

@@ -66,6 +63,10 @@ typedef struct tts_engine_info {
6663
char *credential_keys_json;
6764
} tts_engine_info;
6865

66+
#ifdef __cplusplus
67+
extern "C" {
68+
#endif // __cplusplus
69+
6970
/**
7071
* Create a new TTS engine instance.
7172
*

src/engine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn preprocess_speech_markdown(text: &str, platform: &str) -> (String, bool)
4242
}
4343

4444
#[cfg(not(feature = "cloud"))]
45+
#[must_use]
4546
pub fn preprocess_speech_markdown(text: &str, _platform: &str) -> (String, bool) {
4647
(text.to_string(), false)
4748
}

src/factory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub fn engine_count() -> usize {
4141

4242
/// Return a list of all registered engine descriptors.
4343
#[must_use]
44+
#[allow(clippy::vec_init_then_push)]
4445
pub fn engine_list() -> Vec<EngineDescriptor> {
4546
let mut engines = Vec::new();
4647

0 commit comments

Comments
 (0)