summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/SCsub3
-rw-r--r--platform/linuxbsd/detect.py24
-rw-r--r--platform/linuxbsd/display_server_x11.cpp141
-rw-r--r--platform/linuxbsd/display_server_x11.h27
-rw-r--r--platform/linuxbsd/export/export.cpp4
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp16
-rw-r--r--platform/linuxbsd/export/export_plugin.h1
-rw-r--r--platform/linuxbsd/gl_manager_x11.h15
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp10
-rw-r--r--platform/linuxbsd/joypad_linux.cpp2
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp109
-rw-r--r--platform/linuxbsd/os_linuxbsd.h4
-rw-r--r--platform/linuxbsd/speechd-so_wrap.c881
-rw-r--r--platform/linuxbsd/speechd-so_wrap.h330
-rw-r--r--platform/linuxbsd/tts_linux.cpp261
-rw-r--r--platform/linuxbsd/tts_linux.h78
16 files changed, 1833 insertions, 73 deletions
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index cec8706fbc..09a432eae2 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -20,6 +20,9 @@ if "x11" in env and env["x11"]:
"key_mapping_x11.cpp",
]
+if "speechd" in env and env["speechd"]:
+ common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"])
+
if "vulkan" in env and env["vulkan"]:
common_linuxbsd.append("vulkan_context_x11.cpp")
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 03c85d09ad..19cf341c85 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -75,6 +75,7 @@ def get_opts():
BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True),
+ BoolVariable("speechd", "Detect and use Speech Dispatcher for Text-to-Speech support", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
BoolVariable("x11", "Enable X11 display", True),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
@@ -115,7 +116,7 @@ def configure(env):
## Architecture
- is64 = sys.maxsize > 2 ** 32
+ is64 = sys.maxsize > 2**32
if env["bits"] == "default":
env["bits"] = "64" if is64 else "32"
@@ -162,6 +163,7 @@ def configure(env):
if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]:
env.extra_suffix += ".san"
+ env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"])
if env["use_ubsan"]:
env.Append(
@@ -318,29 +320,41 @@ def configure(env):
if os.system("pkg-config --exists alsa") == 0: # 0 means found
env["alsa"] = True
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
+ env.ParseConfig("pkg-config alsa --cflags") # Only cflags, we dlopen the library.
else:
print("Warning: ALSA libraries not found. Disabling the ALSA audio driver.")
if env["pulseaudio"]:
if os.system("pkg-config --exists libpulse") == 0: # 0 means found
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
- env.ParseConfig("pkg-config --cflags libpulse")
+ env.ParseConfig("pkg-config libpulse --cflags") # Only cflags, we dlopen the library.
else:
+ env["pulseaudio"] = False
print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
if env["dbus"]:
if os.system("pkg-config --exists dbus-1") == 0: # 0 means found
env.Append(CPPDEFINES=["DBUS_ENABLED"])
- env.ParseConfig("pkg-config --cflags --libs dbus-1")
+ env.ParseConfig("pkg-config dbus-1 --cflags --libs")
else:
print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.")
+ if env["speechd"]:
+ if os.system("pkg-config --exists speech-dispatcher") == 0: # 0 means found
+ env.Append(CPPDEFINES=["SPEECHD_ENABLED"])
+ env.ParseConfig("pkg-config speech-dispatcher --cflags") # Only cflags, we dlopen the library.
+ else:
+ env["speechd"] = False
+ print("Warning: Speech Dispatcher development libraries not found. Disabling Text-to-Speech support.")
+
if platform.system() == "Linux":
env.Append(CPPDEFINES=["JOYDEV_ENABLED"])
if env["udev"]:
if os.system("pkg-config --exists libudev") == 0: # 0 means found
env.Append(CPPDEFINES=["UDEV_ENABLED"])
+ env.ParseConfig("pkg-config libudev --cflags") # Only cflags, we dlopen the library.
else:
+ env["udev"] = False
print("Warning: libudev development libraries not found. Disabling controller hotplugging support.")
else:
env["udev"] = False # Linux specific
@@ -365,11 +379,11 @@ def configure(env):
if not env["use_volk"]:
env.ParseConfig("pkg-config vulkan --cflags --libs")
if not env["builtin_glslang"]:
- # No pkgconfig file for glslang so far
+ # No pkgconfig file so far, hardcode expected lib name.
env.Append(LIBS=["glslang", "SPIRV"])
env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LIBS=["GL"])
+ env.ParseConfig("pkg-config gl --cflags --libs")
env.Append(LIBS=["pthread"])
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 07cb6a23e8..027f8562eb 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -139,6 +139,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
case FEATURE_KEEP_SCREEN_ON:
#endif
case FEATURE_CLIPBOARD_PRIMARY:
+ case FEATURE_TEXT_TO_SPEECH:
return true;
default: {
}
@@ -307,6 +308,45 @@ void DisplayServerX11::_flush_mouse_motion() {
xi.relative_motion.y = 0;
}
+#ifdef SPEECHD_ENABLED
+
+bool DisplayServerX11::tts_is_speaking() const {
+ ERR_FAIL_COND_V(!tts, false);
+ return tts->is_speaking();
+}
+
+bool DisplayServerX11::tts_is_paused() const {
+ ERR_FAIL_COND_V(!tts, false);
+ return tts->is_paused();
+}
+
+Array DisplayServerX11::tts_get_voices() const {
+ ERR_FAIL_COND_V(!tts, Array());
+ return tts->get_voices();
+}
+
+void DisplayServerX11::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND(!tts);
+ tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
+}
+
+void DisplayServerX11::tts_pause() {
+ ERR_FAIL_COND(!tts);
+ tts->pause();
+}
+
+void DisplayServerX11::tts_resume() {
+ ERR_FAIL_COND(!tts);
+ tts->resume();
+}
+
+void DisplayServerX11::tts_stop() {
+ ERR_FAIL_COND(!tts);
+ tts->stop();
+}
+
+#endif
+
void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
@@ -363,15 +403,15 @@ DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const {
return mouse_mode;
}
-void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) {
+void DisplayServerX11::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (mouse_mode == MOUSE_MODE_CAPTURED) {
- last_mouse_pos = p_to;
+ last_mouse_pos = p_position;
} else {
WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
XWarpPointer(x11_display, None, windows[window_id].x11_window,
- 0, 0, 0, 0, (int)p_to.x, (int)p_to.y);
+ 0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
}
}
@@ -670,17 +710,17 @@ void DisplayServerX11::_clipboard_transfer_ownership(Atom p_source, Window x11_w
int DisplayServerX11::get_screen_count() const {
_THREAD_SAFE_METHOD_
+ int count = 0;
// Using Xinerama Extension
int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return 0;
+ if (XineramaQueryExtension(x11_display, &event_base, &error_base)) {
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ XFree(xsi);
+ } else {
+ count = XScreenCount(x11_display);
}
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- XFree(xsi);
return count;
}
@@ -712,6 +752,19 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
if (xsi) {
XFree(xsi);
}
+ } else {
+ int count = XScreenCount(x11_display);
+ if (p_screen < count) {
+ Window root = XRootWindow(x11_display, p_screen);
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, root, &xwa);
+ rect.position.x = xwa.x;
+ rect.position.y = xwa.y;
+ rect.size.width = xwa.width;
+ rect.size.height = xwa.height;
+ } else {
+ ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+ }
}
return rect;
@@ -1732,8 +1785,15 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a
if (result == Success && data) {
Atom *atoms = (Atom *)data;
- Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
- Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+ Atom wm_act_max_horz;
+ Atom wm_act_max_vert;
+ if (strcmp(p_atom_name, "_NET_WM_STATE") == 0) {
+ wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ } else {
+ wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
+ wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+ }
bool found_wm_act_max_horz = false;
bool found_wm_act_max_vert = false;
@@ -2123,7 +2183,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
unsigned char *data = nullptr;
if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
if (data && (format == 32) && (len >= 5)) {
- borderless = !((Hints *)data)->decorations;
+ borderless = !(reinterpret_cast<Hints *>(data)->decorations);
}
if (data) {
XFree(data);
@@ -2155,7 +2215,7 @@ void DisplayServerX11::window_request_attention(WindowID p_window) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- WindowData &wd = windows[p_window];
+ const WindowData &wd = windows[p_window];
// Using EWMH -- Extended Window Manager Hints
//
// Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
@@ -2181,7 +2241,7 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- WindowData &wd = windows[p_window];
+ const WindowData &wd = windows[p_window];
XEvent xev;
Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
@@ -2527,10 +2587,9 @@ DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display,
unsigned long bytes_after = 0;
unsigned char *ret = nullptr;
- int read_bytes = 1024;
-
// Keep trying to read the property until there are no bytes unread.
if (p_property != None) {
+ int read_bytes = 1024;
do {
if (ret != nullptr) {
XFree(ret);
@@ -2550,7 +2609,7 @@ DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display,
return p;
}
-static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) {
+static Atom pick_target_from_list(Display *p_display, const Atom *p_list, int p_count) {
static const char *target_type = "text/uri-list";
for (int i = 0; i < p_count; i++) {
@@ -3045,7 +3104,7 @@ void DisplayServerX11::_window_changed(XEvent *event) {
}
void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
- ((DisplayServerX11 *)(get_singleton()))->_dispatch_input_event(p_event);
+ static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event);
}
void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
@@ -3055,7 +3114,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
Callable::CallError ce;
{
- List<WindowID>::Element *E = popup_list.front();
+ List<WindowID>::Element *E = popup_list.back();
if (E && Object::cast_to<InputEventKey>(*p_event)) {
// Redirect keyboard input to active popup.
if (windows.has(E->get())) {
@@ -3099,7 +3158,7 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
}
void DisplayServerX11::_poll_events_thread(void *ud) {
- DisplayServerX11 *display_server = (DisplayServerX11 *)ud;
+ DisplayServerX11 *display_server = static_cast<DisplayServerX11 *>(ud);
display_server->_poll_events();
}
@@ -3201,20 +3260,24 @@ Rect2i DisplayServerX11::window_get_popup_safe_rect(WindowID p_window) const {
}
void DisplayServerX11::popup_open(WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
WindowData &wd = windows[p_window];
if (wd.is_popup) {
- // Close all popups, up to current popup parent, or every popup if new window is not transient.
+ // Find current popup parent, or root popup if new window is not transient.
+ List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back();
while (E) {
if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
- _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
- List<WindowID>::Element *F = E->prev();
- popup_list.erase(E);
- E = F;
+ C = E;
+ E = E->prev();
} else {
break;
}
}
+ if (C) {
+ _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ }
time_since_popup = OS::get_singleton()->get_ticks_msec();
popup_list.push_back(p_window);
@@ -3222,16 +3285,22 @@ void DisplayServerX11::popup_open(WindowID p_window) {
}
void DisplayServerX11::popup_close(WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
List<WindowID>::Element *E = popup_list.find(p_window);
while (E) {
- _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
List<WindowID>::Element *F = E->next();
+ WindowID win_id = E->get();
popup_list.erase(E);
+
+ _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
E = F;
}
}
void DisplayServerX11::mouse_process_popups() {
+ _THREAD_SAFE_METHOD_
+
if (popup_list.is_empty()) {
return;
}
@@ -3252,7 +3321,9 @@ void DisplayServerX11::mouse_process_popups() {
Vector2i pos = Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
if ((pos != last_mouse_monitor_pos) || (mask != last_mouse_monitor_mask)) {
if (((mask & Button1Mask) || (mask & Button2Mask) || (mask & Button3Mask) || (mask & Button4Mask) || (mask & Button5Mask))) {
+ List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back();
+ // Find top popup to close.
while (E) {
// Popup window area.
Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get()));
@@ -3263,12 +3334,13 @@ void DisplayServerX11::mouse_process_popups() {
} else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
break;
} else {
- _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
- List<WindowID>::Element *F = E->prev();
- popup_list.erase(E);
- E = F;
+ C = E;
+ E = E->prev();
}
}
+ if (C) {
+ _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ }
}
}
last_mouse_monitor_mask = mask;
@@ -4601,6 +4673,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
+#ifdef SPEECHD_ENABLED
+ // Init TTS
+ tts = memnew(TTS_Linux);
+#endif
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
@@ -4953,6 +5030,10 @@ DisplayServerX11::~DisplayServerX11() {
memfree(xmbstring);
}
+#ifdef SPEECHD_ENABLED
+ memdelete(tts);
+#endif
+
#ifdef DBUS_ENABLED
memdelete(screensaver);
#endif
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 63d32d939d..3d49886b94 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -46,6 +46,10 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
+#if defined(SPEECHD_ENABLED)
+#include "tts_linux.h"
+#endif
+
#if defined(GLES3_ENABLED)
#include "gl_manager_x11.h"
#endif
@@ -108,10 +112,14 @@ class DisplayServerX11 : public DisplayServer {
#endif
#if defined(DBUS_ENABLED)
- FreeDesktopScreenSaver *screensaver;
+ FreeDesktopScreenSaver *screensaver = nullptr;
bool keep_screen_on = false;
#endif
+#ifdef SPEECHD_ENABLED
+ TTS_Linux *tts = nullptr;
+#endif
+
struct WindowData {
Window x11_window;
::XIC xic;
@@ -168,7 +176,7 @@ class DisplayServerX11 : public DisplayServer {
String internal_clipboard_primary;
Window xdnd_source_window;
::Display *x11_display;
- char *xmbstring;
+ char *xmbstring = nullptr;
int xmblen;
unsigned long last_timestamp;
::Time last_keyrelease_time;
@@ -249,7 +257,7 @@ class DisplayServerX11 : public DisplayServer {
typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
xrr_get_monitors_t xrr_get_monitors;
xrr_free_monitors_t xrr_free_monitors;
- void *xrandr_handle;
+ void *xrandr_handle = nullptr;
Bool xrandr_ext_ok;
struct Property {
@@ -298,10 +306,21 @@ public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
+#ifdef SPEECHD_ENABLED
+ virtual bool tts_is_speaking() const override;
+ virtual bool tts_is_paused() const override;
+ virtual Array tts_get_voices() const override;
+
+ virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
+ virtual void tts_pause() override;
+ virtual void tts_resume() override;
+ virtual void tts_stop() override;
+#endif
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
- virtual void mouse_warp_to_position(const Point2i &p_to) override;
+ virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
virtual MouseButton mouse_get_button_state() const override;
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index 8aa6c47c15..ec83e52f09 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -44,10 +44,6 @@ void register_linuxbsd_exporter() {
platform->set_name("Linux/X11");
platform->set_extension("x86_32");
platform->set_extension("x86_64", "binary_format/64_bits");
- platform->set_release_32("linux_x11_32_release");
- platform->set_debug_32("linux_x11_32_debug");
- platform->set_release_64("linux_x11_64_release");
- platform->set_debug_64("linux_x11_64_debug");
platform->set_os_name("LinuxBSD");
platform->set_chmod_flags(0755);
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index 08fc9c0452..9f7fab6ee8 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -34,8 +34,8 @@
#include "editor/editor_node.h"
Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
- FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE);
f->store_line("#!/bin/sh");
f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'");
@@ -77,6 +77,10 @@ void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, cons
extensions[p_feature_key] = p_extension;
}
+String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_target, const String &p_arch) const {
+ return "linux_x11_" + p_arch + "_" + p_target;
+}
+
List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
for (const KeyValue<String, String> &E : extensions) {
@@ -97,8 +101,8 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito
Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
// Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE);
+ if (f.is_null()) {
return ERR_CANT_OPEN;
}
@@ -106,7 +110,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
{
uint32_t magic = f->get_32();
if (magic != 0x464c457f) { // 0x7F + "ELF"
- f->close();
return ERR_FILE_CORRUPT;
}
}
@@ -116,7 +119,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
int bits = f->get_8() * 32;
if (bits == 32 && p_embedded_size >= 0x100000000) {
- f->close();
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
}
@@ -161,7 +163,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
f->seek(string_data_pos);
strings = (uint8_t *)memalloc(string_data_size);
if (!strings) {
- f->close();
return ERR_OUT_OF_MEMORY;
}
f->get_buffer(strings, string_data_size);
@@ -194,7 +195,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
}
memfree(strings);
- f->close();
return found ? OK : ERR_FILE_CORRUPT;
}
diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h
index 593916e586..f46fc68e1d 100644
--- a/platform/linuxbsd/export/export_plugin.h
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -45,6 +45,7 @@ public:
void set_extension(const String &p_extension, const String &p_feature_key = "default");
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+ virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
};
diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h
index 0bb0a446ab..fb2c74a2b6 100644
--- a/platform/linuxbsd/gl_manager_x11.h
+++ b/platform/linuxbsd/gl_manager_x11.h
@@ -52,21 +52,20 @@ public:
private:
// any data specific to the window
struct GLWindow {
- GLWindow() { in_use = false; }
- bool in_use;
+ bool in_use = false;
// the external ID .. should match the GL window number .. unused I think
- DisplayServer::WindowID window_id;
- int width;
- int height;
+ DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
+ int width = 0;
+ int height = 0;
::Window x11_window;
- int gldisplay_id;
+ int gldisplay_id = 0;
};
struct GLDisplay {
GLDisplay() { context = nullptr; }
~GLDisplay();
- GLManager_X11_Private *context;
+ GLManager_X11_Private *context = nullptr;
::Display *x11_display;
XVisualInfo x_vi;
XSetWindowAttributes x_swa;
@@ -82,7 +81,7 @@ private:
LocalVector<GLWindow> _windows;
LocalVector<GLDisplay> _displays;
- GLWindow *_current_window;
+ GLWindow *_current_window = nullptr;
void _internal_set_current_window(GLWindow *p_win);
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
index 7c9f81bd3f..9fe00568fb 100644
--- a/platform/linuxbsd/godot_linuxbsd.cpp
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -33,10 +33,20 @@
#include <stdlib.h>
#include <unistd.h>
+#if defined(SANITIZERS_ENABLED)
+#include <sys/resource.h>
+#endif
+
#include "main/main.h"
#include "os_linuxbsd.h"
int main(int argc, char *argv[]) {
+#if defined(SANITIZERS_ENABLED)
+ // Note: Set stack size to be at least 30 MB (vs 8 MB default) to avoid overflow, address sanitizer can increase stack usage up to 3 times.
+ struct rlimit stack_lim = { 0x1E00000, 0x1E00000 };
+ setrlimit(RLIMIT_STACK, &stack_lim);
+#endif
+
OS_LinuxBSD os;
setlocale(LC_CTYPE, "");
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 65d53b266f..22a9518a25 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -95,7 +95,7 @@ JoypadLinux::~JoypadLinux() {
void JoypadLinux::joy_thread_func(void *p_user) {
if (p_user) {
- JoypadLinux *joy = (JoypadLinux *)p_user;
+ JoypadLinux *joy = static_cast<JoypadLinux *>(p_user);
joy->run_joypad_thread();
}
}
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 86874687ad..b73d4dc626 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -131,20 +131,19 @@ void OS_LinuxBSD::initialize_joypads() {
String OS_LinuxBSD::get_unique_id() const {
static String machine_id;
if (machine_id.is_empty()) {
- if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) {
+ Ref<FileAccess> f = FileAccess::open("/etc/machine-id", FileAccess::READ);
+ if (f.is_valid()) {
while (machine_id.is_empty() && !f->eof_reached()) {
machine_id = f->get_line().strip_edges();
}
- f->close();
- memdelete(f);
}
}
return machine_id;
}
String OS_LinuxBSD::get_processor_name() const {
- FileAccessRef f = FileAccess::open("/proc/cpuinfo", FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string."));
+ Ref<FileAccess> f = FileAccess::open("/proc/cpuinfo", FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string."));
while (!f->eof_reached()) {
const String line = f->get_line();
@@ -243,6 +242,91 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc";
}
+uint64_t OS_LinuxBSD::get_embedded_pck_offset() const {
+ Ref<FileAccess> f = FileAccess::open(get_executable_path(), FileAccess::READ);
+ if (f.is_null()) {
+ return 0;
+ }
+
+ // Read and check ELF magic number.
+ {
+ uint32_t magic = f->get_32();
+ if (magic != 0x464c457f) { // 0x7F + "ELF"
+ return 0;
+ }
+ }
+
+ // Read program architecture bits from class field.
+ int bits = f->get_8() * 32;
+
+ // Get info about the section header table.
+ int64_t section_table_pos;
+ int64_t section_header_size;
+ if (bits == 32) {
+ section_header_size = 40;
+ f->seek(0x20);
+ section_table_pos = f->get_32();
+ f->seek(0x30);
+ } else { // 64
+ section_header_size = 64;
+ f->seek(0x28);
+ section_table_pos = f->get_64();
+ f->seek(0x3c);
+ }
+ int num_sections = f->get_16();
+ int string_section_idx = f->get_16();
+
+ // Load the strings table.
+ uint8_t *strings;
+ {
+ // Jump to the strings section header.
+ f->seek(section_table_pos + string_section_idx * section_header_size);
+
+ // Read strings data size and offset.
+ int64_t string_data_pos;
+ int64_t string_data_size;
+ if (bits == 32) {
+ f->seek(f->get_position() + 0x10);
+ string_data_pos = f->get_32();
+ string_data_size = f->get_32();
+ } else { // 64
+ f->seek(f->get_position() + 0x18);
+ string_data_pos = f->get_64();
+ string_data_size = f->get_64();
+ }
+
+ // Read strings data.
+ f->seek(string_data_pos);
+ strings = (uint8_t *)memalloc(string_data_size);
+ if (!strings) {
+ return 0;
+ }
+ f->get_buffer(strings, string_data_size);
+ }
+
+ // Search for the "pck" section.
+ int64_t off = 0;
+ for (int i = 0; i < num_sections; ++i) {
+ int64_t section_header_pos = section_table_pos + i * section_header_size;
+ f->seek(section_header_pos);
+
+ uint32_t name_offset = f->get_32();
+ if (strcmp((char *)strings + name_offset, "pck") == 0) {
+ if (bits == 32) {
+ f->seek(section_header_pos + 0x10);
+ off = f->get_32();
+ } else { // 64
+ f->seek(section_header_pos + 0x18);
+ off = f->get_64();
+ }
+ break;
+ }
+ }
+ memfree(strings);
+
+ return off;
+}
+
String OS_LinuxBSD::get_config_path() const {
if (has_environment("XDG_CONFIG_HOME")) {
if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) {
@@ -465,7 +549,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
// Create needed directories for decided trash can location.
{
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = dir_access->make_dir_recursive(trash_path);
// Issue an error if trash can is not created properly.
@@ -512,13 +596,14 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n";
{
Error err;
- FileAccessRef file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\"");
- file->store_string(trash_info);
- file->close();
+ {
+ Ref<FileAccess> file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\"");
+ file->store_string(trash_info);
+ }
// Rename our resource before moving it to the trash can.
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
err = dir_access->rename(path, renamed_path);
ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + path + "\" to \"" + renamed_path + "\"");
}
@@ -535,7 +620,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
// Issue an error if "mv" failed to move the given resource to the trash can.
if (err != OK || retval != 0) {
ERR_PRINT("move_to_trash: Could not move the resource \"" + path + "\" to the trash can \"" + trash_path + "/files\"");
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
err = dir_access->rename(renamed_path, path);
ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename \"" + renamed_path + "\" back to its original name: \"" + path + "\"");
return FAILED;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index d3857e85f8..3f97b86eae 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -63,7 +63,7 @@ class OS_LinuxBSD : public OS_Unix {
CrashHandler crash_handler;
- MainLoop *main_loop;
+ MainLoop *main_loop = nullptr;
protected:
virtual void initialize() override;
@@ -78,6 +78,8 @@ public:
virtual MainLoop *get_main_loop() const override;
+ virtual uint64_t get_embedded_pck_offset() const override;
+
virtual String get_config_path() const override;
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
diff --git a/platform/linuxbsd/speechd-so_wrap.c b/platform/linuxbsd/speechd-so_wrap.c
new file mode 100644
index 0000000000..749474e181
--- /dev/null
+++ b/platform/linuxbsd/speechd-so_wrap.c
@@ -0,0 +1,881 @@
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by ./dynload-wrapper/generate-wrapper.py 0.3 on 2022-04-28 14:34:21
+// flags: ./dynload-wrapper/generate-wrapper.py --sys-include <libspeechd.h> --include /usr/include/speech-dispatcher/libspeechd.h --soname libspeechd.so.2 --init-name speechd --omit-prefix spd_get_client_list --output-header speechd-so_wrap.h --output-implementation speechd-so_wrap.c
+//
+#include <stdint.h>
+
+#define SPDConnectionAddress__free SPDConnectionAddress__free_dylibloader_orig_speechd
+#define spd_get_default_address spd_get_default_address_dylibloader_orig_speechd
+#define spd_open spd_open_dylibloader_orig_speechd
+#define spd_open2 spd_open2_dylibloader_orig_speechd
+#define spd_close spd_close_dylibloader_orig_speechd
+#define spd_say spd_say_dylibloader_orig_speechd
+#define spd_sayf spd_sayf_dylibloader_orig_speechd
+#define spd_stop spd_stop_dylibloader_orig_speechd
+#define spd_stop_all spd_stop_all_dylibloader_orig_speechd
+#define spd_stop_uid spd_stop_uid_dylibloader_orig_speechd
+#define spd_cancel spd_cancel_dylibloader_orig_speechd
+#define spd_cancel_all spd_cancel_all_dylibloader_orig_speechd
+#define spd_cancel_uid spd_cancel_uid_dylibloader_orig_speechd
+#define spd_pause spd_pause_dylibloader_orig_speechd
+#define spd_pause_all spd_pause_all_dylibloader_orig_speechd
+#define spd_pause_uid spd_pause_uid_dylibloader_orig_speechd
+#define spd_resume spd_resume_dylibloader_orig_speechd
+#define spd_resume_all spd_resume_all_dylibloader_orig_speechd
+#define spd_resume_uid spd_resume_uid_dylibloader_orig_speechd
+#define spd_key spd_key_dylibloader_orig_speechd
+#define spd_char spd_char_dylibloader_orig_speechd
+#define spd_wchar spd_wchar_dylibloader_orig_speechd
+#define spd_sound_icon spd_sound_icon_dylibloader_orig_speechd
+#define spd_set_voice_type spd_set_voice_type_dylibloader_orig_speechd
+#define spd_set_voice_type_all spd_set_voice_type_all_dylibloader_orig_speechd
+#define spd_set_voice_type_uid spd_set_voice_type_uid_dylibloader_orig_speechd
+#define spd_get_voice_type spd_get_voice_type_dylibloader_orig_speechd
+#define spd_set_synthesis_voice spd_set_synthesis_voice_dylibloader_orig_speechd
+#define spd_set_synthesis_voice_all spd_set_synthesis_voice_all_dylibloader_orig_speechd
+#define spd_set_synthesis_voice_uid spd_set_synthesis_voice_uid_dylibloader_orig_speechd
+#define spd_set_data_mode spd_set_data_mode_dylibloader_orig_speechd
+#define spd_set_notification_on spd_set_notification_on_dylibloader_orig_speechd
+#define spd_set_notification_off spd_set_notification_off_dylibloader_orig_speechd
+#define spd_set_notification spd_set_notification_dylibloader_orig_speechd
+#define spd_set_voice_rate spd_set_voice_rate_dylibloader_orig_speechd
+#define spd_set_voice_rate_all spd_set_voice_rate_all_dylibloader_orig_speechd
+#define spd_set_voice_rate_uid spd_set_voice_rate_uid_dylibloader_orig_speechd
+#define spd_get_voice_rate spd_get_voice_rate_dylibloader_orig_speechd
+#define spd_set_voice_pitch spd_set_voice_pitch_dylibloader_orig_speechd
+#define spd_set_voice_pitch_all spd_set_voice_pitch_all_dylibloader_orig_speechd
+#define spd_set_voice_pitch_uid spd_set_voice_pitch_uid_dylibloader_orig_speechd
+#define spd_get_voice_pitch spd_get_voice_pitch_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range spd_set_voice_pitch_range_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range_all spd_set_voice_pitch_range_all_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range_uid spd_set_voice_pitch_range_uid_dylibloader_orig_speechd
+#define spd_set_volume spd_set_volume_dylibloader_orig_speechd
+#define spd_set_volume_all spd_set_volume_all_dylibloader_orig_speechd
+#define spd_set_volume_uid spd_set_volume_uid_dylibloader_orig_speechd
+#define spd_get_volume spd_get_volume_dylibloader_orig_speechd
+#define spd_set_punctuation spd_set_punctuation_dylibloader_orig_speechd
+#define spd_set_punctuation_all spd_set_punctuation_all_dylibloader_orig_speechd
+#define spd_set_punctuation_uid spd_set_punctuation_uid_dylibloader_orig_speechd
+#define spd_set_capital_letters spd_set_capital_letters_dylibloader_orig_speechd
+#define spd_set_capital_letters_all spd_set_capital_letters_all_dylibloader_orig_speechd
+#define spd_set_capital_letters_uid spd_set_capital_letters_uid_dylibloader_orig_speechd
+#define spd_set_spelling spd_set_spelling_dylibloader_orig_speechd
+#define spd_set_spelling_all spd_set_spelling_all_dylibloader_orig_speechd
+#define spd_set_spelling_uid spd_set_spelling_uid_dylibloader_orig_speechd
+#define spd_set_language spd_set_language_dylibloader_orig_speechd
+#define spd_set_language_all spd_set_language_all_dylibloader_orig_speechd
+#define spd_set_language_uid spd_set_language_uid_dylibloader_orig_speechd
+#define spd_get_language spd_get_language_dylibloader_orig_speechd
+#define spd_set_output_module spd_set_output_module_dylibloader_orig_speechd
+#define spd_set_output_module_all spd_set_output_module_all_dylibloader_orig_speechd
+#define spd_set_output_module_uid spd_set_output_module_uid_dylibloader_orig_speechd
+#define spd_get_message_list_fd spd_get_message_list_fd_dylibloader_orig_speechd
+#define spd_list_modules spd_list_modules_dylibloader_orig_speechd
+#define free_spd_modules free_spd_modules_dylibloader_orig_speechd
+#define spd_get_output_module spd_get_output_module_dylibloader_orig_speechd
+#define spd_list_voices spd_list_voices_dylibloader_orig_speechd
+#define spd_list_synthesis_voices spd_list_synthesis_voices_dylibloader_orig_speechd
+#define free_spd_voices free_spd_voices_dylibloader_orig_speechd
+#define spd_execute_command_with_list_reply spd_execute_command_with_list_reply_dylibloader_orig_speechd
+#define spd_execute_command spd_execute_command_dylibloader_orig_speechd
+#define spd_execute_command_with_reply spd_execute_command_with_reply_dylibloader_orig_speechd
+#define spd_execute_command_wo_mutex spd_execute_command_wo_mutex_dylibloader_orig_speechd
+#define spd_send_data spd_send_data_dylibloader_orig_speechd
+#define spd_send_data_wo_mutex spd_send_data_wo_mutex_dylibloader_orig_speechd
+#include <libspeechd.h>
+#undef SPDConnectionAddress__free
+#undef spd_get_default_address
+#undef spd_open
+#undef spd_open2
+#undef spd_close
+#undef spd_say
+#undef spd_sayf
+#undef spd_stop
+#undef spd_stop_all
+#undef spd_stop_uid
+#undef spd_cancel
+#undef spd_cancel_all
+#undef spd_cancel_uid
+#undef spd_pause
+#undef spd_pause_all
+#undef spd_pause_uid
+#undef spd_resume
+#undef spd_resume_all
+#undef spd_resume_uid
+#undef spd_key
+#undef spd_char
+#undef spd_wchar
+#undef spd_sound_icon
+#undef spd_set_voice_type
+#undef spd_set_voice_type_all
+#undef spd_set_voice_type_uid
+#undef spd_get_voice_type
+#undef spd_set_synthesis_voice
+#undef spd_set_synthesis_voice_all
+#undef spd_set_synthesis_voice_uid
+#undef spd_set_data_mode
+#undef spd_set_notification_on
+#undef spd_set_notification_off
+#undef spd_set_notification
+#undef spd_set_voice_rate
+#undef spd_set_voice_rate_all
+#undef spd_set_voice_rate_uid
+#undef spd_get_voice_rate
+#undef spd_set_voice_pitch
+#undef spd_set_voice_pitch_all
+#undef spd_set_voice_pitch_uid
+#undef spd_get_voice_pitch
+#undef spd_set_voice_pitch_range
+#undef spd_set_voice_pitch_range_all
+#undef spd_set_voice_pitch_range_uid
+#undef spd_set_volume
+#undef spd_set_volume_all
+#undef spd_set_volume_uid
+#undef spd_get_volume
+#undef spd_set_punctuation
+#undef spd_set_punctuation_all
+#undef spd_set_punctuation_uid
+#undef spd_set_capital_letters
+#undef spd_set_capital_letters_all
+#undef spd_set_capital_letters_uid
+#undef spd_set_spelling
+#undef spd_set_spelling_all
+#undef spd_set_spelling_uid
+#undef spd_set_language
+#undef spd_set_language_all
+#undef spd_set_language_uid
+#undef spd_get_language
+#undef spd_set_output_module
+#undef spd_set_output_module_all
+#undef spd_set_output_module_uid
+#undef spd_get_message_list_fd
+#undef spd_list_modules
+#undef free_spd_modules
+#undef spd_get_output_module
+#undef spd_list_voices
+#undef spd_list_synthesis_voices
+#undef free_spd_voices
+#undef spd_execute_command_with_list_reply
+#undef spd_execute_command
+#undef spd_execute_command_with_reply
+#undef spd_execute_command_wo_mutex
+#undef spd_send_data
+#undef spd_send_data_wo_mutex
+#include <dlfcn.h>
+#include <stdio.h>
+void (*SPDConnectionAddress__free_dylibloader_wrapper_speechd)( SPDConnectionAddress*);
+SPDConnectionAddress* (*spd_get_default_address_dylibloader_wrapper_speechd)( char**);
+SPDConnection* (*spd_open_dylibloader_wrapper_speechd)(const char*,const char*,const char*, SPDConnectionMode);
+SPDConnection* (*spd_open2_dylibloader_wrapper_speechd)(const char*,const char*,const char*, SPDConnectionMode, SPDConnectionAddress*, int, char**);
+void (*spd_close_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_say_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+int (*spd_sayf_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*,...);
+int (*spd_stop_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_stop_all_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_stop_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+int (*spd_cancel_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_cancel_all_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_cancel_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+int (*spd_pause_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_pause_all_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_pause_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+int (*spd_resume_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_resume_all_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_resume_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+int (*spd_key_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+int (*spd_char_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+int (*spd_wchar_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority, wchar_t);
+int (*spd_sound_icon_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+int (*spd_set_voice_type_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType);
+int (*spd_set_voice_type_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType);
+int (*spd_set_voice_type_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType, unsigned int);
+SPDVoiceType (*spd_get_voice_type_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_set_synthesis_voice_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_synthesis_voice_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_synthesis_voice_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+int (*spd_set_data_mode_dylibloader_wrapper_speechd)( SPDConnection*, SPDDataMode);
+int (*spd_set_notification_on_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification);
+int (*spd_set_notification_off_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification);
+int (*spd_set_notification_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification,const char*);
+int (*spd_set_voice_rate_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_rate_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_rate_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+int (*spd_get_voice_rate_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_set_voice_pitch_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_pitch_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_pitch_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+int (*spd_get_voice_pitch_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_set_voice_pitch_range_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_pitch_range_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_voice_pitch_range_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+int (*spd_set_volume_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_volume_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+int (*spd_set_volume_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+int (*spd_get_volume_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_set_punctuation_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation);
+int (*spd_set_punctuation_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation);
+int (*spd_set_punctuation_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation, unsigned int);
+int (*spd_set_capital_letters_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters);
+int (*spd_set_capital_letters_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters);
+int (*spd_set_capital_letters_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters, unsigned int);
+int (*spd_set_spelling_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling);
+int (*spd_set_spelling_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling);
+int (*spd_set_spelling_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling, unsigned int);
+int (*spd_set_language_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_language_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_language_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+char* (*spd_get_language_dylibloader_wrapper_speechd)( SPDConnection*);
+int (*spd_set_output_module_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_output_module_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+int (*spd_set_output_module_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+int (*spd_get_message_list_fd_dylibloader_wrapper_speechd)( SPDConnection*, int, int*, char**);
+char** (*spd_list_modules_dylibloader_wrapper_speechd)( SPDConnection*);
+void (*free_spd_modules_dylibloader_wrapper_speechd)( char**);
+char* (*spd_get_output_module_dylibloader_wrapper_speechd)( SPDConnection*);
+char** (*spd_list_voices_dylibloader_wrapper_speechd)( SPDConnection*);
+SPDVoice** (*spd_list_synthesis_voices_dylibloader_wrapper_speechd)( SPDConnection*);
+void (*free_spd_voices_dylibloader_wrapper_speechd)( SPDVoice**);
+char** (*spd_execute_command_with_list_reply_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+int (*spd_execute_command_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+int (*spd_execute_command_with_reply_dylibloader_wrapper_speechd)( SPDConnection*, char*, char**);
+int (*spd_execute_command_wo_mutex_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+char* (*spd_send_data_dylibloader_wrapper_speechd)( SPDConnection*,const char*, int);
+char* (*spd_send_data_wo_mutex_dylibloader_wrapper_speechd)( SPDConnection*,const char*, int);
+int initialize_speechd(int verbose) {
+ void *handle;
+ char *error;
+ handle = dlopen("libspeechd.so.2", RTLD_LAZY);
+ if (!handle) {
+ if (verbose) {
+ fprintf(stderr, "%s\n", dlerror());
+ }
+ return(1);
+ }
+ dlerror();
+// SPDConnectionAddress__free
+ *(void **) (&SPDConnectionAddress__free_dylibloader_wrapper_speechd) = dlsym(handle, "SPDConnectionAddress__free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_default_address
+ *(void **) (&spd_get_default_address_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_default_address");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_open
+ *(void **) (&spd_open_dylibloader_wrapper_speechd) = dlsym(handle, "spd_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_open2
+ *(void **) (&spd_open2_dylibloader_wrapper_speechd) = dlsym(handle, "spd_open2");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_close
+ *(void **) (&spd_close_dylibloader_wrapper_speechd) = dlsym(handle, "spd_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_say
+ *(void **) (&spd_say_dylibloader_wrapper_speechd) = dlsym(handle, "spd_say");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_sayf
+ *(void **) (&spd_sayf_dylibloader_wrapper_speechd) = dlsym(handle, "spd_sayf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_stop
+ *(void **) (&spd_stop_dylibloader_wrapper_speechd) = dlsym(handle, "spd_stop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_stop_all
+ *(void **) (&spd_stop_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_stop_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_stop_uid
+ *(void **) (&spd_stop_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_stop_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_cancel
+ *(void **) (&spd_cancel_dylibloader_wrapper_speechd) = dlsym(handle, "spd_cancel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_cancel_all
+ *(void **) (&spd_cancel_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_cancel_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_cancel_uid
+ *(void **) (&spd_cancel_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_cancel_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_pause
+ *(void **) (&spd_pause_dylibloader_wrapper_speechd) = dlsym(handle, "spd_pause");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_pause_all
+ *(void **) (&spd_pause_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_pause_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_pause_uid
+ *(void **) (&spd_pause_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_pause_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_resume
+ *(void **) (&spd_resume_dylibloader_wrapper_speechd) = dlsym(handle, "spd_resume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_resume_all
+ *(void **) (&spd_resume_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_resume_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_resume_uid
+ *(void **) (&spd_resume_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_resume_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_key
+ *(void **) (&spd_key_dylibloader_wrapper_speechd) = dlsym(handle, "spd_key");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_char
+ *(void **) (&spd_char_dylibloader_wrapper_speechd) = dlsym(handle, "spd_char");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_wchar
+ *(void **) (&spd_wchar_dylibloader_wrapper_speechd) = dlsym(handle, "spd_wchar");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_sound_icon
+ *(void **) (&spd_sound_icon_dylibloader_wrapper_speechd) = dlsym(handle, "spd_sound_icon");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_type
+ *(void **) (&spd_set_voice_type_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_type_all
+ *(void **) (&spd_set_voice_type_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_type_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_type_uid
+ *(void **) (&spd_set_voice_type_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_type_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_voice_type
+ *(void **) (&spd_get_voice_type_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_voice_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_synthesis_voice
+ *(void **) (&spd_set_synthesis_voice_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_synthesis_voice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_synthesis_voice_all
+ *(void **) (&spd_set_synthesis_voice_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_synthesis_voice_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_synthesis_voice_uid
+ *(void **) (&spd_set_synthesis_voice_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_synthesis_voice_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_data_mode
+ *(void **) (&spd_set_data_mode_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_data_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_notification_on
+ *(void **) (&spd_set_notification_on_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_notification_on");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_notification_off
+ *(void **) (&spd_set_notification_off_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_notification_off");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_notification
+ *(void **) (&spd_set_notification_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_notification");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_rate
+ *(void **) (&spd_set_voice_rate_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_rate_all
+ *(void **) (&spd_set_voice_rate_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_rate_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_rate_uid
+ *(void **) (&spd_set_voice_rate_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_rate_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_voice_rate
+ *(void **) (&spd_get_voice_rate_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_voice_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch
+ *(void **) (&spd_set_voice_pitch_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch_all
+ *(void **) (&spd_set_voice_pitch_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch_uid
+ *(void **) (&spd_set_voice_pitch_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_voice_pitch
+ *(void **) (&spd_get_voice_pitch_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_voice_pitch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch_range
+ *(void **) (&spd_set_voice_pitch_range_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch_range_all
+ *(void **) (&spd_set_voice_pitch_range_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch_range_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_voice_pitch_range_uid
+ *(void **) (&spd_set_voice_pitch_range_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_voice_pitch_range_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_volume
+ *(void **) (&spd_set_volume_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_volume_all
+ *(void **) (&spd_set_volume_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_volume_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_volume_uid
+ *(void **) (&spd_set_volume_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_volume_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_volume
+ *(void **) (&spd_get_volume_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_punctuation
+ *(void **) (&spd_set_punctuation_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_punctuation");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_punctuation_all
+ *(void **) (&spd_set_punctuation_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_punctuation_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_punctuation_uid
+ *(void **) (&spd_set_punctuation_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_punctuation_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_capital_letters
+ *(void **) (&spd_set_capital_letters_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_capital_letters");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_capital_letters_all
+ *(void **) (&spd_set_capital_letters_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_capital_letters_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_capital_letters_uid
+ *(void **) (&spd_set_capital_letters_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_capital_letters_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_spelling
+ *(void **) (&spd_set_spelling_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_spelling");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_spelling_all
+ *(void **) (&spd_set_spelling_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_spelling_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_spelling_uid
+ *(void **) (&spd_set_spelling_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_spelling_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_language
+ *(void **) (&spd_set_language_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_language");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_language_all
+ *(void **) (&spd_set_language_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_language_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_language_uid
+ *(void **) (&spd_set_language_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_language_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_language
+ *(void **) (&spd_get_language_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_language");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_output_module
+ *(void **) (&spd_set_output_module_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_output_module");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_output_module_all
+ *(void **) (&spd_set_output_module_all_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_output_module_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_set_output_module_uid
+ *(void **) (&spd_set_output_module_uid_dylibloader_wrapper_speechd) = dlsym(handle, "spd_set_output_module_uid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_message_list_fd
+ *(void **) (&spd_get_message_list_fd_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_message_list_fd");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_list_modules
+ *(void **) (&spd_list_modules_dylibloader_wrapper_speechd) = dlsym(handle, "spd_list_modules");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// free_spd_modules
+ *(void **) (&free_spd_modules_dylibloader_wrapper_speechd) = dlsym(handle, "free_spd_modules");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_get_output_module
+ *(void **) (&spd_get_output_module_dylibloader_wrapper_speechd) = dlsym(handle, "spd_get_output_module");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_list_voices
+ *(void **) (&spd_list_voices_dylibloader_wrapper_speechd) = dlsym(handle, "spd_list_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_list_synthesis_voices
+ *(void **) (&spd_list_synthesis_voices_dylibloader_wrapper_speechd) = dlsym(handle, "spd_list_synthesis_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// free_spd_voices
+ *(void **) (&free_spd_voices_dylibloader_wrapper_speechd) = dlsym(handle, "free_spd_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_execute_command_with_list_reply
+ *(void **) (&spd_execute_command_with_list_reply_dylibloader_wrapper_speechd) = dlsym(handle, "spd_execute_command_with_list_reply");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_execute_command
+ *(void **) (&spd_execute_command_dylibloader_wrapper_speechd) = dlsym(handle, "spd_execute_command");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_execute_command_with_reply
+ *(void **) (&spd_execute_command_with_reply_dylibloader_wrapper_speechd) = dlsym(handle, "spd_execute_command_with_reply");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_execute_command_wo_mutex
+ *(void **) (&spd_execute_command_wo_mutex_dylibloader_wrapper_speechd) = dlsym(handle, "spd_execute_command_wo_mutex");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_send_data
+ *(void **) (&spd_send_data_dylibloader_wrapper_speechd) = dlsym(handle, "spd_send_data");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// spd_send_data_wo_mutex
+ *(void **) (&spd_send_data_wo_mutex_dylibloader_wrapper_speechd) = dlsym(handle, "spd_send_data_wo_mutex");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+return 0;
+}
diff --git a/platform/linuxbsd/speechd-so_wrap.h b/platform/linuxbsd/speechd-so_wrap.h
new file mode 100644
index 0000000000..8e1c053348
--- /dev/null
+++ b/platform/linuxbsd/speechd-so_wrap.h
@@ -0,0 +1,330 @@
+#ifndef DYLIBLOAD_WRAPPER_SPEECHD
+#define DYLIBLOAD_WRAPPER_SPEECHD
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by ./dynload-wrapper/generate-wrapper.py 0.3 on 2022-04-28 14:34:21
+// flags: ./dynload-wrapper/generate-wrapper.py --sys-include <libspeechd.h> --include /usr/include/speech-dispatcher/libspeechd.h --soname libspeechd.so.2 --init-name speechd --omit-prefix spd_get_client_list --output-header speechd-so_wrap.h --output-implementation speechd-so_wrap.c
+//
+#include <stdint.h>
+
+#define SPDConnectionAddress__free SPDConnectionAddress__free_dylibloader_orig_speechd
+#define spd_get_default_address spd_get_default_address_dylibloader_orig_speechd
+#define spd_open spd_open_dylibloader_orig_speechd
+#define spd_open2 spd_open2_dylibloader_orig_speechd
+#define spd_close spd_close_dylibloader_orig_speechd
+#define spd_say spd_say_dylibloader_orig_speechd
+#define spd_sayf spd_sayf_dylibloader_orig_speechd
+#define spd_stop spd_stop_dylibloader_orig_speechd
+#define spd_stop_all spd_stop_all_dylibloader_orig_speechd
+#define spd_stop_uid spd_stop_uid_dylibloader_orig_speechd
+#define spd_cancel spd_cancel_dylibloader_orig_speechd
+#define spd_cancel_all spd_cancel_all_dylibloader_orig_speechd
+#define spd_cancel_uid spd_cancel_uid_dylibloader_orig_speechd
+#define spd_pause spd_pause_dylibloader_orig_speechd
+#define spd_pause_all spd_pause_all_dylibloader_orig_speechd
+#define spd_pause_uid spd_pause_uid_dylibloader_orig_speechd
+#define spd_resume spd_resume_dylibloader_orig_speechd
+#define spd_resume_all spd_resume_all_dylibloader_orig_speechd
+#define spd_resume_uid spd_resume_uid_dylibloader_orig_speechd
+#define spd_key spd_key_dylibloader_orig_speechd
+#define spd_char spd_char_dylibloader_orig_speechd
+#define spd_wchar spd_wchar_dylibloader_orig_speechd
+#define spd_sound_icon spd_sound_icon_dylibloader_orig_speechd
+#define spd_set_voice_type spd_set_voice_type_dylibloader_orig_speechd
+#define spd_set_voice_type_all spd_set_voice_type_all_dylibloader_orig_speechd
+#define spd_set_voice_type_uid spd_set_voice_type_uid_dylibloader_orig_speechd
+#define spd_get_voice_type spd_get_voice_type_dylibloader_orig_speechd
+#define spd_set_synthesis_voice spd_set_synthesis_voice_dylibloader_orig_speechd
+#define spd_set_synthesis_voice_all spd_set_synthesis_voice_all_dylibloader_orig_speechd
+#define spd_set_synthesis_voice_uid spd_set_synthesis_voice_uid_dylibloader_orig_speechd
+#define spd_set_data_mode spd_set_data_mode_dylibloader_orig_speechd
+#define spd_set_notification_on spd_set_notification_on_dylibloader_orig_speechd
+#define spd_set_notification_off spd_set_notification_off_dylibloader_orig_speechd
+#define spd_set_notification spd_set_notification_dylibloader_orig_speechd
+#define spd_set_voice_rate spd_set_voice_rate_dylibloader_orig_speechd
+#define spd_set_voice_rate_all spd_set_voice_rate_all_dylibloader_orig_speechd
+#define spd_set_voice_rate_uid spd_set_voice_rate_uid_dylibloader_orig_speechd
+#define spd_get_voice_rate spd_get_voice_rate_dylibloader_orig_speechd
+#define spd_set_voice_pitch spd_set_voice_pitch_dylibloader_orig_speechd
+#define spd_set_voice_pitch_all spd_set_voice_pitch_all_dylibloader_orig_speechd
+#define spd_set_voice_pitch_uid spd_set_voice_pitch_uid_dylibloader_orig_speechd
+#define spd_get_voice_pitch spd_get_voice_pitch_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range spd_set_voice_pitch_range_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range_all spd_set_voice_pitch_range_all_dylibloader_orig_speechd
+#define spd_set_voice_pitch_range_uid spd_set_voice_pitch_range_uid_dylibloader_orig_speechd
+#define spd_set_volume spd_set_volume_dylibloader_orig_speechd
+#define spd_set_volume_all spd_set_volume_all_dylibloader_orig_speechd
+#define spd_set_volume_uid spd_set_volume_uid_dylibloader_orig_speechd
+#define spd_get_volume spd_get_volume_dylibloader_orig_speechd
+#define spd_set_punctuation spd_set_punctuation_dylibloader_orig_speechd
+#define spd_set_punctuation_all spd_set_punctuation_all_dylibloader_orig_speechd
+#define spd_set_punctuation_uid spd_set_punctuation_uid_dylibloader_orig_speechd
+#define spd_set_capital_letters spd_set_capital_letters_dylibloader_orig_speechd
+#define spd_set_capital_letters_all spd_set_capital_letters_all_dylibloader_orig_speechd
+#define spd_set_capital_letters_uid spd_set_capital_letters_uid_dylibloader_orig_speechd
+#define spd_set_spelling spd_set_spelling_dylibloader_orig_speechd
+#define spd_set_spelling_all spd_set_spelling_all_dylibloader_orig_speechd
+#define spd_set_spelling_uid spd_set_spelling_uid_dylibloader_orig_speechd
+#define spd_set_language spd_set_language_dylibloader_orig_speechd
+#define spd_set_language_all spd_set_language_all_dylibloader_orig_speechd
+#define spd_set_language_uid spd_set_language_uid_dylibloader_orig_speechd
+#define spd_get_language spd_get_language_dylibloader_orig_speechd
+#define spd_set_output_module spd_set_output_module_dylibloader_orig_speechd
+#define spd_set_output_module_all spd_set_output_module_all_dylibloader_orig_speechd
+#define spd_set_output_module_uid spd_set_output_module_uid_dylibloader_orig_speechd
+#define spd_get_message_list_fd spd_get_message_list_fd_dylibloader_orig_speechd
+#define spd_list_modules spd_list_modules_dylibloader_orig_speechd
+#define free_spd_modules free_spd_modules_dylibloader_orig_speechd
+#define spd_get_output_module spd_get_output_module_dylibloader_orig_speechd
+#define spd_list_voices spd_list_voices_dylibloader_orig_speechd
+#define spd_list_synthesis_voices spd_list_synthesis_voices_dylibloader_orig_speechd
+#define free_spd_voices free_spd_voices_dylibloader_orig_speechd
+#define spd_execute_command_with_list_reply spd_execute_command_with_list_reply_dylibloader_orig_speechd
+#define spd_execute_command spd_execute_command_dylibloader_orig_speechd
+#define spd_execute_command_with_reply spd_execute_command_with_reply_dylibloader_orig_speechd
+#define spd_execute_command_wo_mutex spd_execute_command_wo_mutex_dylibloader_orig_speechd
+#define spd_send_data spd_send_data_dylibloader_orig_speechd
+#define spd_send_data_wo_mutex spd_send_data_wo_mutex_dylibloader_orig_speechd
+#include <libspeechd.h>
+#undef SPDConnectionAddress__free
+#undef spd_get_default_address
+#undef spd_open
+#undef spd_open2
+#undef spd_close
+#undef spd_say
+#undef spd_sayf
+#undef spd_stop
+#undef spd_stop_all
+#undef spd_stop_uid
+#undef spd_cancel
+#undef spd_cancel_all
+#undef spd_cancel_uid
+#undef spd_pause
+#undef spd_pause_all
+#undef spd_pause_uid
+#undef spd_resume
+#undef spd_resume_all
+#undef spd_resume_uid
+#undef spd_key
+#undef spd_char
+#undef spd_wchar
+#undef spd_sound_icon
+#undef spd_set_voice_type
+#undef spd_set_voice_type_all
+#undef spd_set_voice_type_uid
+#undef spd_get_voice_type
+#undef spd_set_synthesis_voice
+#undef spd_set_synthesis_voice_all
+#undef spd_set_synthesis_voice_uid
+#undef spd_set_data_mode
+#undef spd_set_notification_on
+#undef spd_set_notification_off
+#undef spd_set_notification
+#undef spd_set_voice_rate
+#undef spd_set_voice_rate_all
+#undef spd_set_voice_rate_uid
+#undef spd_get_voice_rate
+#undef spd_set_voice_pitch
+#undef spd_set_voice_pitch_all
+#undef spd_set_voice_pitch_uid
+#undef spd_get_voice_pitch
+#undef spd_set_voice_pitch_range
+#undef spd_set_voice_pitch_range_all
+#undef spd_set_voice_pitch_range_uid
+#undef spd_set_volume
+#undef spd_set_volume_all
+#undef spd_set_volume_uid
+#undef spd_get_volume
+#undef spd_set_punctuation
+#undef spd_set_punctuation_all
+#undef spd_set_punctuation_uid
+#undef spd_set_capital_letters
+#undef spd_set_capital_letters_all
+#undef spd_set_capital_letters_uid
+#undef spd_set_spelling
+#undef spd_set_spelling_all
+#undef spd_set_spelling_uid
+#undef spd_set_language
+#undef spd_set_language_all
+#undef spd_set_language_uid
+#undef spd_get_language
+#undef spd_set_output_module
+#undef spd_set_output_module_all
+#undef spd_set_output_module_uid
+#undef spd_get_message_list_fd
+#undef spd_list_modules
+#undef free_spd_modules
+#undef spd_get_output_module
+#undef spd_list_voices
+#undef spd_list_synthesis_voices
+#undef free_spd_voices
+#undef spd_execute_command_with_list_reply
+#undef spd_execute_command
+#undef spd_execute_command_with_reply
+#undef spd_execute_command_wo_mutex
+#undef spd_send_data
+#undef spd_send_data_wo_mutex
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define SPDConnectionAddress__free SPDConnectionAddress__free_dylibloader_wrapper_speechd
+#define spd_get_default_address spd_get_default_address_dylibloader_wrapper_speechd
+#define spd_open spd_open_dylibloader_wrapper_speechd
+#define spd_open2 spd_open2_dylibloader_wrapper_speechd
+#define spd_close spd_close_dylibloader_wrapper_speechd
+#define spd_say spd_say_dylibloader_wrapper_speechd
+#define spd_sayf spd_sayf_dylibloader_wrapper_speechd
+#define spd_stop spd_stop_dylibloader_wrapper_speechd
+#define spd_stop_all spd_stop_all_dylibloader_wrapper_speechd
+#define spd_stop_uid spd_stop_uid_dylibloader_wrapper_speechd
+#define spd_cancel spd_cancel_dylibloader_wrapper_speechd
+#define spd_cancel_all spd_cancel_all_dylibloader_wrapper_speechd
+#define spd_cancel_uid spd_cancel_uid_dylibloader_wrapper_speechd
+#define spd_pause spd_pause_dylibloader_wrapper_speechd
+#define spd_pause_all spd_pause_all_dylibloader_wrapper_speechd
+#define spd_pause_uid spd_pause_uid_dylibloader_wrapper_speechd
+#define spd_resume spd_resume_dylibloader_wrapper_speechd
+#define spd_resume_all spd_resume_all_dylibloader_wrapper_speechd
+#define spd_resume_uid spd_resume_uid_dylibloader_wrapper_speechd
+#define spd_key spd_key_dylibloader_wrapper_speechd
+#define spd_char spd_char_dylibloader_wrapper_speechd
+#define spd_wchar spd_wchar_dylibloader_wrapper_speechd
+#define spd_sound_icon spd_sound_icon_dylibloader_wrapper_speechd
+#define spd_set_voice_type spd_set_voice_type_dylibloader_wrapper_speechd
+#define spd_set_voice_type_all spd_set_voice_type_all_dylibloader_wrapper_speechd
+#define spd_set_voice_type_uid spd_set_voice_type_uid_dylibloader_wrapper_speechd
+#define spd_get_voice_type spd_get_voice_type_dylibloader_wrapper_speechd
+#define spd_set_synthesis_voice spd_set_synthesis_voice_dylibloader_wrapper_speechd
+#define spd_set_synthesis_voice_all spd_set_synthesis_voice_all_dylibloader_wrapper_speechd
+#define spd_set_synthesis_voice_uid spd_set_synthesis_voice_uid_dylibloader_wrapper_speechd
+#define spd_set_data_mode spd_set_data_mode_dylibloader_wrapper_speechd
+#define spd_set_notification_on spd_set_notification_on_dylibloader_wrapper_speechd
+#define spd_set_notification_off spd_set_notification_off_dylibloader_wrapper_speechd
+#define spd_set_notification spd_set_notification_dylibloader_wrapper_speechd
+#define spd_set_voice_rate spd_set_voice_rate_dylibloader_wrapper_speechd
+#define spd_set_voice_rate_all spd_set_voice_rate_all_dylibloader_wrapper_speechd
+#define spd_set_voice_rate_uid spd_set_voice_rate_uid_dylibloader_wrapper_speechd
+#define spd_get_voice_rate spd_get_voice_rate_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch spd_set_voice_pitch_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch_all spd_set_voice_pitch_all_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch_uid spd_set_voice_pitch_uid_dylibloader_wrapper_speechd
+#define spd_get_voice_pitch spd_get_voice_pitch_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch_range spd_set_voice_pitch_range_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch_range_all spd_set_voice_pitch_range_all_dylibloader_wrapper_speechd
+#define spd_set_voice_pitch_range_uid spd_set_voice_pitch_range_uid_dylibloader_wrapper_speechd
+#define spd_set_volume spd_set_volume_dylibloader_wrapper_speechd
+#define spd_set_volume_all spd_set_volume_all_dylibloader_wrapper_speechd
+#define spd_set_volume_uid spd_set_volume_uid_dylibloader_wrapper_speechd
+#define spd_get_volume spd_get_volume_dylibloader_wrapper_speechd
+#define spd_set_punctuation spd_set_punctuation_dylibloader_wrapper_speechd
+#define spd_set_punctuation_all spd_set_punctuation_all_dylibloader_wrapper_speechd
+#define spd_set_punctuation_uid spd_set_punctuation_uid_dylibloader_wrapper_speechd
+#define spd_set_capital_letters spd_set_capital_letters_dylibloader_wrapper_speechd
+#define spd_set_capital_letters_all spd_set_capital_letters_all_dylibloader_wrapper_speechd
+#define spd_set_capital_letters_uid spd_set_capital_letters_uid_dylibloader_wrapper_speechd
+#define spd_set_spelling spd_set_spelling_dylibloader_wrapper_speechd
+#define spd_set_spelling_all spd_set_spelling_all_dylibloader_wrapper_speechd
+#define spd_set_spelling_uid spd_set_spelling_uid_dylibloader_wrapper_speechd
+#define spd_set_language spd_set_language_dylibloader_wrapper_speechd
+#define spd_set_language_all spd_set_language_all_dylibloader_wrapper_speechd
+#define spd_set_language_uid spd_set_language_uid_dylibloader_wrapper_speechd
+#define spd_get_language spd_get_language_dylibloader_wrapper_speechd
+#define spd_set_output_module spd_set_output_module_dylibloader_wrapper_speechd
+#define spd_set_output_module_all spd_set_output_module_all_dylibloader_wrapper_speechd
+#define spd_set_output_module_uid spd_set_output_module_uid_dylibloader_wrapper_speechd
+#define spd_get_message_list_fd spd_get_message_list_fd_dylibloader_wrapper_speechd
+#define spd_list_modules spd_list_modules_dylibloader_wrapper_speechd
+#define free_spd_modules free_spd_modules_dylibloader_wrapper_speechd
+#define spd_get_output_module spd_get_output_module_dylibloader_wrapper_speechd
+#define spd_list_voices spd_list_voices_dylibloader_wrapper_speechd
+#define spd_list_synthesis_voices spd_list_synthesis_voices_dylibloader_wrapper_speechd
+#define free_spd_voices free_spd_voices_dylibloader_wrapper_speechd
+#define spd_execute_command_with_list_reply spd_execute_command_with_list_reply_dylibloader_wrapper_speechd
+#define spd_execute_command spd_execute_command_dylibloader_wrapper_speechd
+#define spd_execute_command_with_reply spd_execute_command_with_reply_dylibloader_wrapper_speechd
+#define spd_execute_command_wo_mutex spd_execute_command_wo_mutex_dylibloader_wrapper_speechd
+#define spd_send_data spd_send_data_dylibloader_wrapper_speechd
+#define spd_send_data_wo_mutex spd_send_data_wo_mutex_dylibloader_wrapper_speechd
+extern void (*SPDConnectionAddress__free_dylibloader_wrapper_speechd)( SPDConnectionAddress*);
+extern SPDConnectionAddress* (*spd_get_default_address_dylibloader_wrapper_speechd)( char**);
+extern SPDConnection* (*spd_open_dylibloader_wrapper_speechd)(const char*,const char*,const char*, SPDConnectionMode);
+extern SPDConnection* (*spd_open2_dylibloader_wrapper_speechd)(const char*,const char*,const char*, SPDConnectionMode, SPDConnectionAddress*, int, char**);
+extern void (*spd_close_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_say_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+extern int (*spd_sayf_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*,...);
+extern int (*spd_stop_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_stop_all_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_stop_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+extern int (*spd_cancel_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_cancel_all_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_cancel_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+extern int (*spd_pause_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_pause_all_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_pause_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+extern int (*spd_resume_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_resume_all_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_resume_uid_dylibloader_wrapper_speechd)( SPDConnection*, int);
+extern int (*spd_key_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+extern int (*spd_char_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+extern int (*spd_wchar_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority, wchar_t);
+extern int (*spd_sound_icon_dylibloader_wrapper_speechd)( SPDConnection*, SPDPriority,const char*);
+extern int (*spd_set_voice_type_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType);
+extern int (*spd_set_voice_type_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType);
+extern int (*spd_set_voice_type_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDVoiceType, unsigned int);
+extern SPDVoiceType (*spd_get_voice_type_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_set_synthesis_voice_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_synthesis_voice_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_synthesis_voice_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+extern int (*spd_set_data_mode_dylibloader_wrapper_speechd)( SPDConnection*, SPDDataMode);
+extern int (*spd_set_notification_on_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification);
+extern int (*spd_set_notification_off_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification);
+extern int (*spd_set_notification_dylibloader_wrapper_speechd)( SPDConnection*, SPDNotification,const char*);
+extern int (*spd_set_voice_rate_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_rate_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_rate_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+extern int (*spd_get_voice_rate_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_set_voice_pitch_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_pitch_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_pitch_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+extern int (*spd_get_voice_pitch_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_set_voice_pitch_range_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_pitch_range_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_voice_pitch_range_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+extern int (*spd_set_volume_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_volume_all_dylibloader_wrapper_speechd)( SPDConnection*, signed int);
+extern int (*spd_set_volume_uid_dylibloader_wrapper_speechd)( SPDConnection*, signed int, unsigned int);
+extern int (*spd_get_volume_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_set_punctuation_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation);
+extern int (*spd_set_punctuation_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation);
+extern int (*spd_set_punctuation_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDPunctuation, unsigned int);
+extern int (*spd_set_capital_letters_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters);
+extern int (*spd_set_capital_letters_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters);
+extern int (*spd_set_capital_letters_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDCapitalLetters, unsigned int);
+extern int (*spd_set_spelling_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling);
+extern int (*spd_set_spelling_all_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling);
+extern int (*spd_set_spelling_uid_dylibloader_wrapper_speechd)( SPDConnection*, SPDSpelling, unsigned int);
+extern int (*spd_set_language_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_language_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_language_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+extern char* (*spd_get_language_dylibloader_wrapper_speechd)( SPDConnection*);
+extern int (*spd_set_output_module_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_output_module_all_dylibloader_wrapper_speechd)( SPDConnection*,const char*);
+extern int (*spd_set_output_module_uid_dylibloader_wrapper_speechd)( SPDConnection*,const char*, unsigned int);
+extern int (*spd_get_message_list_fd_dylibloader_wrapper_speechd)( SPDConnection*, int, int*, char**);
+extern char** (*spd_list_modules_dylibloader_wrapper_speechd)( SPDConnection*);
+extern void (*free_spd_modules_dylibloader_wrapper_speechd)( char**);
+extern char* (*spd_get_output_module_dylibloader_wrapper_speechd)( SPDConnection*);
+extern char** (*spd_list_voices_dylibloader_wrapper_speechd)( SPDConnection*);
+extern SPDVoice** (*spd_list_synthesis_voices_dylibloader_wrapper_speechd)( SPDConnection*);
+extern void (*free_spd_voices_dylibloader_wrapper_speechd)( SPDVoice**);
+extern char** (*spd_execute_command_with_list_reply_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+extern int (*spd_execute_command_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+extern int (*spd_execute_command_with_reply_dylibloader_wrapper_speechd)( SPDConnection*, char*, char**);
+extern int (*spd_execute_command_wo_mutex_dylibloader_wrapper_speechd)( SPDConnection*, char*);
+extern char* (*spd_send_data_dylibloader_wrapper_speechd)( SPDConnection*,const char*, int);
+extern char* (*spd_send_data_wo_mutex_dylibloader_wrapper_speechd)( SPDConnection*,const char*, int);
+int initialize_speechd(int verbose);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp
new file mode 100644
index 0000000000..aea1183d3d
--- /dev/null
+++ b/platform/linuxbsd/tts_linux.cpp
@@ -0,0 +1,261 @@
+/*************************************************************************/
+/* tts_linux.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tts_linux.h"
+
+#include "core/config/project_settings.h"
+#include "servers/text_server.h"
+
+TTS_Linux *TTS_Linux::singleton = nullptr;
+
+void TTS_Linux::speech_init_thread_func(void *p_userdata) {
+ TTS_Linux *tts = (TTS_Linux *)p_userdata;
+ if (tts) {
+ MutexLock thread_safe_method(tts->_thread_safe_);
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+ if (initialize_speechd(dylibloader_verbose) == 0) {
+ CharString class_str;
+ String config_name = GLOBAL_GET("application/config/name");
+ if (config_name.length() == 0) {
+ class_str = "Godot_Engine";
+ } else {
+ class_str = config_name.utf8();
+ }
+ tts->synth = spd_open(class_str, "Godot_Engine_Speech_API", "Godot_Engine", SPD_MODE_THREADED);
+ if (tts->synth) {
+ tts->synth->callback_end = &speech_event_callback;
+ tts->synth->callback_cancel = &speech_event_callback;
+ tts->synth->callback_im = &speech_event_index_mark;
+ spd_set_notification_on(tts->synth, SPD_END);
+ spd_set_notification_on(tts->synth, SPD_CANCEL);
+
+ print_verbose("Text-to-Speech: Speech Dispatcher initialized.");
+ } else {
+ print_verbose("Text-to-Speech: Cannot initialize Speech Dispatcher synthesizer!");
+ }
+ } else {
+ print_verbose("Text-to-Speech: Cannot load Speech Dispatcher library!");
+ }
+ }
+}
+
+void TTS_Linux::speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark) {
+ TTS_Linux *tts = TTS_Linux::get_singleton();
+ if (tts && tts->ids.has(p_msg_id)) {
+ MutexLock thread_safe_method(tts->_thread_safe_);
+ // Get word offset from the index mark injected to the text stream.
+ String mark = String::utf8(p_index_mark);
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_BOUNDARY, tts->ids[p_msg_id], mark.to_int());
+ }
+}
+
+void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type) {
+ TTS_Linux *tts = TTS_Linux::get_singleton();
+ if (tts) {
+ MutexLock thread_safe_method(tts->_thread_safe_);
+ List<DisplayServer::TTSUtterance> &queue = tts->queue;
+ if (!tts->paused && tts->ids.has(p_msg_id)) {
+ if (p_type == SPD_EVENT_END) {
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[p_msg_id]);
+ tts->ids.erase(p_msg_id);
+ tts->last_msg_id = -1;
+ tts->speaking = false;
+ } else if (p_type == SPD_EVENT_CANCEL) {
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, tts->ids[p_msg_id]);
+ tts->ids.erase(p_msg_id);
+ tts->last_msg_id = -1;
+ tts->speaking = false;
+ }
+ }
+ if (!tts->speaking && queue.size() > 0) {
+ DisplayServer::TTSUtterance &message = queue.front()->get();
+
+ // Inject index mark after each word.
+ String text;
+ String language;
+ SPDVoice **voices = spd_list_synthesis_voices(tts->synth);
+ if (voices != nullptr) {
+ SPDVoice **voices_ptr = voices;
+ while (*voices_ptr != nullptr) {
+ if (String::utf8((*voices_ptr)->name) == message.voice) {
+ language = String::utf8((*voices_ptr)->language);
+ break;
+ }
+ voices_ptr++;
+ }
+ free_spd_voices(voices);
+ }
+ PackedInt32Array breaks = TS->string_get_word_breaks(message.text, language);
+ int prev = 0;
+ for (int i = 0; i < breaks.size(); i++) {
+ text += message.text.substr(prev, breaks[i] - prev);
+ text += "<mark name=\"" + String::num_int64(breaks[i], 10) + "\"/>";
+ prev = breaks[i];
+ }
+ text += message.text.substr(prev, -1);
+
+ spd_set_synthesis_voice(tts->synth, message.voice.utf8().get_data());
+ spd_set_volume(tts->synth, message.volume * 2 - 100);
+ spd_set_voice_pitch(tts->synth, (message.pitch - 1) * 100);
+ float rate = 0;
+ if (message.rate > 1.f) {
+ rate = log10(MIN(message.rate, 2.5f)) / log10(2.5f) * 100;
+ } else if (message.rate < 1.f) {
+ rate = log10(MAX(message.rate, 0.5f)) / log10(0.5f) * -100;
+ }
+ spd_set_voice_rate(tts->synth, rate);
+ spd_set_data_mode(tts->synth, SPD_DATA_SSML);
+ tts->last_msg_id = spd_say(tts->synth, SPD_TEXT, text.utf8().get_data());
+ tts->ids[tts->last_msg_id] = message.id;
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_STARTED, message.id);
+
+ queue.pop_front();
+ tts->speaking = true;
+ }
+ }
+}
+
+bool TTS_Linux::is_speaking() const {
+ return speaking;
+}
+
+bool TTS_Linux::is_paused() const {
+ return paused;
+}
+
+Array TTS_Linux::get_voices() const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!synth, Array());
+ Array list;
+ SPDVoice **voices = spd_list_synthesis_voices(synth);
+ if (voices != nullptr) {
+ SPDVoice **voices_ptr = voices;
+ while (*voices_ptr != nullptr) {
+ Dictionary voice_d;
+ voice_d["name"] = String::utf8((*voices_ptr)->name);
+ voice_d["id"] = String::utf8((*voices_ptr)->name);
+ voice_d["language"] = String::utf8((*voices_ptr)->language) + "_" + String::utf8((*voices_ptr)->variant);
+ list.push_back(voice_d);
+
+ voices_ptr++;
+ }
+ free_spd_voices(voices);
+ }
+ return list;
+}
+
+void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!synth);
+ if (p_interrupt) {
+ stop();
+ }
+
+ if (p_text.is_empty()) {
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, p_utterance_id);
+ return;
+ }
+
+ DisplayServer::TTSUtterance message;
+ message.text = p_text;
+ message.voice = p_voice;
+ message.volume = CLAMP(p_volume, 0, 100);
+ message.pitch = CLAMP(p_pitch, 0.f, 2.f);
+ message.rate = CLAMP(p_rate, 0.1f, 10.f);
+ message.id = p_utterance_id;
+ queue.push_back(message);
+
+ if (is_paused()) {
+ resume();
+ } else {
+ speech_event_callback(0, 0, SPD_EVENT_BEGIN);
+ }
+}
+
+void TTS_Linux::pause() {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!synth);
+ if (spd_pause(synth) == 0) {
+ paused = true;
+ }
+}
+
+void TTS_Linux::resume() {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!synth);
+ spd_resume(synth);
+ paused = false;
+}
+
+void TTS_Linux::stop() {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!synth);
+ for (DisplayServer::TTSUtterance &message : queue) {
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, message.id);
+ }
+ if ((last_msg_id != -1) && ids.has(last_msg_id)) {
+ DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, ids[last_msg_id]);
+ }
+ queue.clear();
+ ids.clear();
+ last_msg_id = -1;
+ spd_cancel(synth);
+ spd_resume(synth);
+ speaking = false;
+ paused = false;
+}
+
+TTS_Linux *TTS_Linux::get_singleton() {
+ return singleton;
+}
+
+TTS_Linux::TTS_Linux() {
+ singleton = this;
+ // Speech Dispatcher init can be slow, it might wait for helper process to start on background, so run it in the thread.
+ init_thread.start(speech_init_thread_func, this);
+}
+
+TTS_Linux::~TTS_Linux() {
+ init_thread.wait_to_finish();
+ if (synth) {
+ spd_close(synth);
+ }
+
+ singleton = nullptr;
+}
diff --git a/platform/linuxbsd/tts_linux.h b/platform/linuxbsd/tts_linux.h
new file mode 100644
index 0000000000..4d39af8970
--- /dev/null
+++ b/platform/linuxbsd/tts_linux.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* tts_linux.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TTS_LINUX_H
+#define TTS_LINUX_H
+
+#include "core/os/thread.h"
+#include "core/os/thread_safe.h"
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/variant/array.h"
+#include "servers/display_server.h"
+
+#include "speechd-so_wrap.h"
+
+class TTS_Linux {
+ _THREAD_SAFE_CLASS_
+
+ List<DisplayServer::TTSUtterance> queue;
+ SPDConnection *synth = nullptr;
+ bool speaking = false;
+ bool paused = false;
+ int last_msg_id = -1;
+ Map<int, int> ids;
+
+ Thread init_thread;
+
+ static void speech_init_thread_func(void *p_userdata);
+ static void speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type);
+ static void speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark);
+
+ static TTS_Linux *singleton;
+
+public:
+ static TTS_Linux *get_singleton();
+
+ bool is_speaking() const;
+ bool is_paused() const;
+ Array get_voices() const;
+
+ void speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false);
+ void pause();
+ void resume();
+ void stop();
+
+ TTS_Linux();
+ ~TTS_Linux();
+};
+
+#endif // TTS_LINUX_H