Second commit is to be removed.
Signed-off-by: Bernhard Kölbl besentv@gmail.com
-- v2: windows.media.speech: Implement Vosk create and release functions in the unixlib. windows.media.speech: Add a unixlib stub.
From: Bernhard Kölbl besentv@gmail.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- configure.ac | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac index 9ff7c5e8914..e9264e74801 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,8 @@ AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug an AC_ARG_WITH(unwind, AS_HELP_STRING([--without-unwind],[do not use the libunwind library (exception handling)])) AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) +AC_ARG_WITH(vosk, AS_HELP_STRING([--without-vosk],[do not use Vosk]), + [if test "x$withval" = "xno"; then ac_cv_header_vosk_api_h=no; fi]) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) @@ -483,7 +485,8 @@ AC_CHECK_HEADERS(\ syscall.h \ utime.h \ valgrind/memcheck.h \ - valgrind/valgrind.h + valgrind/valgrind.h \ + vosk_api.h ) WINE_HEADER_MAJOR() AC_HEADER_STAT() @@ -1787,6 +1790,17 @@ then WINE_WARNING([No sound system was found. Windows applications will be silent.]) fi
+dnl **** Check for Vosk **** +if test "$ac_cv_header_vosk_api_h" = "yes" +then + WINE_CHECK_SONAME(vosk,vosk_recognizer_new,[AC_SUBST(VOSK_LIBS,"-lvosk") + ac_cv_lib_vosk=yes + AC_DEFINE_UNQUOTED(HAVE_VOSK,1,[Define to 1 if Vosk is available])],,) +fi +WINE_NOTICE_WITH(vosk,[test "x$ac_cv_lib_vosk" != xyes], + [libvosk ${notice_platform}development files not found (or too old), Vosk aka speech recognition won't be supported.], + [enable_vosk]) + dnl *** Check for Vulkan *** if test "x$with_vulkan" != "xno" then
From: Bernhard Kölbl besentv@gmail.com
--- configure | 90 +++++++++++++++++++++++++++++++++++++++++++++ include/config.h.in | 9 +++++ 2 files changed, 99 insertions(+)
diff --git a/configure b/configure index c1c6c4cf93b..28de5ae1851 100755 --- a/configure +++ b/configure @@ -656,6 +656,7 @@ RT_LIBS WINELOADER_PROGRAMS DELAYLOADFLAG MSVCRTFLAGS +VOSK_LIBS NETAPI_LIBS NETAPI_CFLAGS PROCSTAT_LIBS @@ -936,6 +937,7 @@ with_udev with_unwind with_usb with_v4l2 +with_vosk with_vulkan with_xcomposite with_xcursor @@ -2450,6 +2452,7 @@ Optional Packages: handling) --without-usb do not use the libusb library --without-v4l2 do not use v4l2 (video capture) + --without-vosk do not use Vosk --without-vulkan do not use Vulkan --without-xcomposite do not use the Xcomposite extension --without-xcursor do not use the Xcursor extension @@ -4360,6 +4363,13 @@ then : fi
+# Check whether --with-vosk was given. +if test ${with_vosk+y} +then : + withval=$with_vosk; if test "x$withval" = "xno"; then ac_cv_header_vosk_api_h=no; fi +fi + + # Check whether --with-vulkan was given. if test ${with_vulkan+y} then : @@ -8282,6 +8292,12 @@ if test "x$ac_cv_header_valgrind_valgrind_h" = xyes then : printf "%s\n" "#define HAVE_VALGRIND_VALGRIND_H 1" >>confdefs.h
+fi +ac_fn_c_check_header_compile "$LINENO" "vosk_api.h" "ac_cv_header_vosk_api_h" "$ac_includes_default" +if test "x$ac_cv_header_vosk_api_h" = xyes +then : + printf "%s\n" "#define HAVE_VOSK_API_H 1" >>confdefs.h + fi
ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" @@ -18252,6 +18268,79 @@ then as_fn_append wine_warnings "|No sound system was found. Windows applications will be silent." fi
+if test "$ac_cv_header_vosk_api_h" = "yes" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lvosk" >&5 +printf %s "checking for -lvosk... " >&6; } +if test ${ac_cv_lib_soname_vosk+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_soname_save_LIBS=$LIBS +LIBS="-lvosk $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char vosk_recognizer_new (); +int +main (void) +{ +return vosk_recognizer_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_vosk=`$ac_cv_path_LDD conftest.exe | grep "vosk" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_vosk=`$OTOOL -L conftest$ac_exeext | grep "libvosk\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*/(libvosk.[0-9A-Za-z.]*dylib).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_vosk=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libvosk\.$LIBEXT" | sed -e "s/^.*\[\(libvosk\.$LIBEXT[^ ]*\)\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_vosk:+false} : +then : + ac_cv_lib_soname_vosk=`$LDD conftest$ac_exeext | grep "libvosk\.$LIBEXT" | sed -e "s/^.*(libvosk.$LIBEXT[^ ]*).*$/\1/"';2,$d'` +fi ;; + esac +else $as_nop + ac_cv_lib_soname_vosk= +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS +fi +if ${ac_cv_lib_soname_vosk:+false} : +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_vosk" >&5 +printf "%s\n" "$ac_cv_lib_soname_vosk" >&6; } + +printf "%s\n" "#define SONAME_LIBVOSK "$ac_cv_lib_soname_vosk"" >>confdefs.h + + VOSK_LIBS="-lvosk" + + ac_cv_lib_vosk=yes + +printf "%s\n" "#define HAVE_VOSK 1" >>confdefs.h + +fi +fi +if test "x$ac_cv_lib_vosk" != xyes +then : + case "x$with_vosk" in + x) as_fn_append wine_notices "|libvosk ${notice_platform}development files not found (or too old), Vosk aka speech recognition won't be supported." ;; + xno) ;; + *) as_fn_error $? "libvosk ${notice_platform}development files not found (or too old), Vosk aka speech recognition won't be supported. +This is an error since --with-vosk was requested." "$LINENO" 5 ;; +esac +enable_vosk=${enable_vosk:-no} +fi + if test "x$with_vulkan" != "xno" then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lvulkan" >&5 @@ -23121,6 +23210,7 @@ GSSAPI_LIBS = $GSSAPI_LIBS PROCSTAT_LIBS = $PROCSTAT_LIBS NETAPI_CFLAGS = $NETAPI_CFLAGS NETAPI_LIBS = $NETAPI_LIBS +VOSK_LIBS = $VOSK_LIBS MSVCRTFLAGS = $MSVCRTFLAGS DELAYLOADFLAG = $DELAYLOADFLAG WINELOADER_PROGRAMS = $WINELOADER_PROGRAMS diff --git a/include/config.h.in b/include/config.h.in index fe2fc36a914..2858797aa59 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -645,6 +645,12 @@ /* Define to 1 if you have the <valgrind/valgrind.h> header file. */ #undef HAVE_VALGRIND_VALGRIND_H
+/* Define to 1 if Vosk is available */ +#undef HAVE_VOSK + +/* Define to 1 if you have the <vosk_api.h> header file. */ +#undef HAVE_VOSK_API_H + /* Define to 1 if you have the <X11/extensions/shape.h> header file. */ #undef HAVE_X11_EXTENSIONS_SHAPE_H
@@ -789,6 +795,9 @@ /* Define to the soname of the libv4l2 library. */ #undef SONAME_LIBV4L2
+/* Define to the soname of the libvosk library. */ +#undef SONAME_LIBVOSK + /* Define to the soname of the libvulkan library. */ #undef SONAME_LIBVULKAN
From: Bernhard Kölbl besentv@gmail.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/Makefile.in | 5 +- dlls/windows.media.speech/main.c | 24 +++++++ dlls/windows.media.speech/private.h | 4 ++ dlls/windows.media.speech/unixlib.h | 38 +++++++++++ dlls/windows.media.speech/vosk.c | 90 +++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 dlls/windows.media.speech/unixlib.h create mode 100644 dlls/windows.media.speech/vosk.c
diff --git a/dlls/windows.media.speech/Makefile.in b/dlls/windows.media.speech/Makefile.in index 10903cb1d7b..0e7aef05f35 100644 --- a/dlls/windows.media.speech/Makefile.in +++ b/dlls/windows.media.speech/Makefile.in @@ -1,5 +1,7 @@ MODULE = windows.media.speech.dll +UNIXLIB = windows.media.speech.so IMPORTS = combase uuid +UNIX_LIBS = $(VOSK_LIBS)
C_SRCS = \ async.c \ @@ -8,6 +10,7 @@ C_SRCS = \ main.c \ recognizer.c \ synthesizer.c \ - vector.c + vector.c \ + vosk.c
IDL_SRCS = classes.idl diff --git a/dlls/windows.media.speech/main.c b/dlls/windows.media.speech/main.c index e772a791588..7ead1d73569 100644 --- a/dlls/windows.media.speech/main.c +++ b/dlls/windows.media.speech/main.c @@ -20,10 +20,34 @@ #include "initguid.h" #include "private.h"
+#include "unixlib.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(speech);
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + NTSTATUS status; + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + if ((status = __wine_init_unix_call()) != STATUS_SUCCESS) + WARN("Initializing unixlib failed with status %lx.\n", status); + + if ((status = WINE_UNIX_CALL(unix_vosk_process_attach, NULL)) != STATUS_SUCCESS) + WARN("Initializing unixlib failed with status %lx.\n", status); + + if (status) + return FALSE; + + break; + } + return TRUE; +} + HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) { FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index e80d73ec1fb..2f804fbf1a7 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -22,6 +22,10 @@
#include <stdarg.h>
+#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winerror.h" +#include "winternl.h" #define COBJMACROS #include "corerror.h" #include "windef.h" diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h new file mode 100644 index 00000000000..daf45e01258 --- /dev/null +++ b/dlls/windows.media.speech/unixlib.h @@ -0,0 +1,38 @@ +/* + * Unix library interface for Windows.Media.Speech + * + * Copyright 2023 Bernhard Kölbl for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINDOWS_MEDIA_SPEECH_UNIXLIB_H +#define __WINE_WINDOWS_MEDIA_SPEECH_UNIXLIB_H + +#include <stdbool.h> +#include <stdint.h> + +#include "windef.h" +#include "winternl.h" +#include "wtypes.h" + +#include "wine/unixlib.h" + +enum unix_funcs +{ + unix_vosk_process_attach +}; + +#endif diff --git a/dlls/windows.media.speech/vosk.c b/dlls/windows.media.speech/vosk.c new file mode 100644 index 00000000000..d3591d9b809 --- /dev/null +++ b/dlls/windows.media.speech/vosk.c @@ -0,0 +1,90 @@ +/* + * Vosk interface for Windows.Media.Speech + * + * Copyright 2023 Bernhard Kölbl for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <stdarg.h> +#include <dlfcn.h> + +#ifdef HAVE_VOSK_API_H +#include <vosk_api.h> +#endif /* HAVE_VOSK_API_H */ + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winerror.h" +#include "winternl.h" + +#include "wine/debug.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(vosk); + +#ifdef HAVE_VOSK_API_H + +#ifdef SONAME_LIBVOSK +static void *libvosk_handle; +#endif /* SONAME_LIBVOSK */ + +static NTSTATUS vosk_process_attach( void *args ) +{ + TRACE("args %p.\n", args); + +#ifdef SONAME_LIBVOSK + if (!(libvosk_handle = dlopen(SONAME_LIBVOSK, RTLD_NOW))) + { + WARN("Failed to load library %s, reason %s.\n", SONAME_LIBVOSK, dlerror()); + return STATUS_DLL_NOT_FOUND; + } + + return STATUS_SUCCESS; +#else /* SONAME_LIBVOSK */ + return STATUS_NOT_SUPPORTED; +#endif /* SONAME_LIBVOSK */ +} + +#else /* HAVE_VOSK_API_H */ + +#define MAKE_UNSUPPORTED_FUNC( f ) \ + static NTSTATUS f( void *args ) \ + { \ + WARN("wine was compiled without libvosk support. Speech recognition won't work.\n"); \ + return STATUS_NOT_SUPPORTED; \ + } + +MAKE_UNSUPPORTED_FUNC(vosk_process_attach) +#undef MAKE_UNSUPPORTED_FUNC + +#endif /* HAVE_VOSK_API_H */ + +unixlib_entry_t __wine_unix_call_funcs[] = +{ + vosk_process_attach, +}; + +unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + vosk_process_attach, +};
From: Bernhard Kölbl besentv@gmail.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 16 ++ dlls/windows.media.speech/unixlib.h | 17 +- dlls/windows.media.speech/vosk.c | 240 ++++++++++++++++++++++++- 3 files changed, 271 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index c2f386206b8..f37e13d96cc 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -25,6 +25,9 @@
#include "wine/debug.h"
+#include "unixlib.h" +#include "wine/unixlib.h" + WINE_DEFAULT_DEBUG_CHANNEL(speech);
/* @@ -171,6 +174,8 @@ struct session IAudioCaptureClient *capture_client; WAVEFORMATEX capture_wfx;
+ vosk_instance vosk_instance; + HANDLE worker_thread, worker_control_event, audio_buf_event; BOOLEAN worker_running, worker_paused; CRITICAL_SECTION cs; @@ -318,7 +323,9 @@ static ULONG WINAPI session_AddRef( ISpeechContinuousRecognitionSession *iface ) static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface ) { struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + struct vosk_release_params vosk_release_params; ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref);
if (!ref) @@ -344,6 +351,9 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface impl->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&impl->cs);
+ vosk_release_params.instance = impl->vosk_instance; + WINE_UNIX_CALL(unix_vosk_release, &vosk_release_params); + IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -1083,6 +1093,7 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface { struct recognizer *impl; struct session *session; + struct vosk_create_params vosk_create_params; struct vector_iids constraints_iids = { .iterable = &IID_IIterable_ISpeechRecognitionConstraint, @@ -1125,6 +1136,11 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface if (FAILED(hr = recognizer_factory_create_audio_capture(session))) goto error;
+ vosk_create_params.sample_rate = (float)session->capture_wfx.nSamplesPerSec; + vosk_create_params.instance = &session->vosk_instance; + if (FAILED(hr = HRESULT_FROM_NT(WINE_UNIX_CALL(unix_vosk_create, &vosk_create_params)))) + goto error; + InitializeCriticalSection(&session->cs); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs");
diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h index daf45e01258..f0edf8c883c 100644 --- a/dlls/windows.media.speech/unixlib.h +++ b/dlls/windows.media.speech/unixlib.h @@ -30,9 +30,24 @@
#include "wine/unixlib.h"
+typedef UINT64 vosk_instance; + +struct vosk_create_params +{ + vosk_instance *instance; + float sample_rate; +}; + +struct vosk_release_params +{ + vosk_instance instance; +}; + enum unix_funcs { - unix_vosk_process_attach + unix_vosk_process_attach, + unix_vosk_create, + unix_vosk_release, };
#endif diff --git a/dlls/windows.media.speech/vosk.c b/dlls/windows.media.speech/vosk.c index d3591d9b809..ffeba51b9b9 100644 --- a/dlls/windows.media.speech/vosk.c +++ b/dlls/windows.media.speech/vosk.c @@ -24,8 +24,16 @@
#include "config.h"
+#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> + #include <stdarg.h> +#include <dirent.h> #include <dlfcn.h> +#include <errno.h>
#ifdef HAVE_VOSK_API_H #include <vosk_api.h> @@ -40,7 +48,16 @@
#include "unixlib.h"
-WINE_DEFAULT_DEBUG_CHANNEL(vosk); +WINE_DEFAULT_DEBUG_CHANNEL(speech); + +#ifdef HAVE_VOSK_API_H + +#define MAKE_FUNCPTR( f ) static typeof(f) * p##f; +MAKE_FUNCPTR(vosk_model_new) +MAKE_FUNCPTR(vosk_recognizer_new) +MAKE_FUNCPTR(vosk_model_free) +MAKE_FUNCPTR(vosk_recognizer_free) +#undef MAKE_FUNCPTR
#ifdef HAVE_VOSK_API_H
@@ -59,12 +76,227 @@ static NTSTATUS vosk_process_attach( void *args ) return STATUS_DLL_NOT_FOUND; }
+#define LOAD_FUNCPTR( f ) \ + do if((p##f = dlsym(libvosk_handle, #f)) == NULL) \ + { \ + ERR("Failed to load symbol %s\n", #f); \ + goto error; \ + } while(0) + LOAD_FUNCPTR(vosk_model_new); + LOAD_FUNCPTR(vosk_recognizer_new); + LOAD_FUNCPTR(vosk_model_free); + LOAD_FUNCPTR(vosk_recognizer_free); +#undef LOAD_FUNCPTR return STATUS_SUCCESS; +error: + dlclose(libvosk_handle); + libvosk_handle = NULL; + return STATUS_ENTRYPOINT_NOT_FOUND; #else /* SONAME_LIBVOSK */ return STATUS_NOT_SUPPORTED; #endif /* SONAME_LIBVOSK */ }
+static inline vosk_instance to_vosk_instance( VoskRecognizer *ptr ) +{ + return (vosk_instance)(UINT_PTR)ptr; +} + +static inline VoskRecognizer *from_vosk_instance( vosk_instance instance ) +{ + return (VoskRecognizer *)(UINT_PTR)instance; +} + +static inline void str_to_lower(char *str) +{ + char *s; + + for (s = str; s && *s; ++s) + *s = tolower(*s); +} + +static NTSTATUS errno_to_status( int err ) +{ + TRACE("errno = %d\n", err); + switch (err) + { + case EAGAIN: return STATUS_SHARING_VIOLATION; + case EBADF: return STATUS_INVALID_HANDLE; + case EBUSY: return STATUS_DEVICE_BUSY; + case ENOSPC: return STATUS_DISK_FULL; + case EPERM: + case EROFS: + case EACCES: return STATUS_ACCESS_DENIED; + case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND; + case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND; + case EISDIR: return STATUS_INVALID_DEVICE_REQUEST; + case EMFILE: + case ENFILE: return STATUS_TOO_MANY_OPENED_FILES; + case EINVAL: return STATUS_INVALID_PARAMETER; + case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case EPIPE: return STATUS_PIPE_DISCONNECTED; + case EIO: return STATUS_DEVICE_NOT_READY; +#ifdef ENOMEDIUM + case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE; +#endif + case ENXIO: return STATUS_NO_SUCH_DEVICE; + case ENOTTY: + case EOPNOTSUPP:return STATUS_NOT_SUPPORTED; + case ECONNRESET:return STATUS_PIPE_DISCONNECTED; + case EFAULT: return STATUS_ACCESS_VIOLATION; + case ESPIPE: return STATUS_ILLEGAL_FUNCTION; + case ELOOP: return STATUS_REPARSE_POINT_NOT_RESOLVED; +#ifdef ETIME /* Missing on FreeBSD */ + case ETIME: return STATUS_IO_TIMEOUT; +#endif + case ENOEXEC: /* ?? */ + case EEXIST: /* ?? */ + default: + FIXME("Converting errno %d to STATUS_UNSUCCESSFUL\n", err); + return STATUS_UNSUCCESSFUL; + } +} + +static NTSTATUS find_model_by_lang_and_path(const char *folder, const char *lcid, VoskModel **model) +{ + static const char *vosk_model_identifier_small = "vosk-model-small-"; + static const char *vosk_model_identifier = "vosk-model-"; + char lang[3], lang_region[6], *dir_name, *path; + NTSTATUS status = STATUS_UNSUCCESSFUL; + struct dirent *dirent; + DIR *dir; + + TRACE("folder %s, lcid %s, model %p.\n", folder, debugstr_a(lcid), model); + + if (!folder || !model || strlen(lcid) < 4) + return STATUS_UNSUCCESSFUL; + + lstrcpynA(lang, lcid, 3); + lstrcpynA(lang_region, lcid, 6); + + str_to_lower(lang); + str_to_lower(lang_region); + + *model = NULL; + + if ((dir = opendir(folder)) == NULL) + return errno_to_status(errno); + + while ((dirent = readdir(dir))) + { + if (dirent->d_type != DT_DIR) + continue; + + if (!strcmp(dir_name = dirent->d_name, "..")) + continue; + + if (strstr(dir_name, vosk_model_identifier_small)) + dir_name += strlen(vosk_model_identifier_small); + else if (strstr(dir_name, vosk_model_identifier)) + dir_name += strlen(vosk_model_identifier); + + if (strstr(dir_name, lang_region) != dir_name && strstr(dir_name, lang) != dir_name) + continue; + + path = malloc(strlen(folder) + 1 /* '/' */ + strlen(dirent->d_name) + 1); + sprintf(path, "%s/%s", folder, dirent->d_name); + + TRACE("Trying to load Vosk model %s.\n", debugstr_a(path)); + + *model = pvosk_model_new(path); + free(path); + + if (*model) + { + status = STATUS_SUCCESS; + break; + } + } + + closedir(dir); + + return status; +} + +static NTSTATUS get_model_by_lang(const char *lcid, VoskModel **model) +{ + static const char *cache_vosk = "/.cache/vosk"; + static const char *vosk = "/vosk"; + NTSTATUS status = STATUS_UNSUCCESSFUL; + char *path = NULL, *env = NULL; + + TRACE("lcid %s, model %p.\n", debugstr_a(lcid), model); + + if (!lcid || !model) + return STATUS_UNSUCCESSFUL; + + if (!find_model_by_lang_and_path(getenv("VOSK_MODEL_PATH"), lcid, model)) + return STATUS_SUCCESS; + if (!find_model_by_lang_and_path("/usr/share/vosk", lcid, model)) + return STATUS_SUCCESS; + + if ((env = getenv("XDG_CACHE_HOME"))) + { + path = malloc(strlen(env) + strlen(vosk) + 1); + sprintf(path, "%s%s", env, vosk); + + status = find_model_by_lang_and_path(path, lcid, model); + } + else if ((env = getenv("HOME"))) + { + path = malloc(strlen(env) + strlen(cache_vosk) + 1); + sprintf(path, "%s%s", env, cache_vosk); + + status = find_model_by_lang_and_path(path, lcid, model); + } + + if (path) + free(path); + + return status; +} + +static NTSTATUS vosk_create( void *args ) +{ + struct vosk_create_params *params = args; + VoskRecognizer *recognizer = NULL; + VoskModel *model = NULL; + NTSTATUS status; + + TRACE("args %p.\n", args); + + if ((status = get_model_by_lang(getenv("LC_NAME"), &model)) != STATUS_SUCCESS) + return status; + + if (!(recognizer = pvosk_recognizer_new(model, params->sample_rate))) + goto error; + + /* The model is kept alive inside the recognizer, so we can safely free our ref here. */ + pvosk_model_free(model); + + *params->instance = to_vosk_instance(recognizer); + return STATUS_SUCCESS; + +error: + if (model) pvosk_model_free(model); + *params->instance = to_vosk_instance( NULL ); + return STATUS_UNSUCCESSFUL; +} + +static NTSTATUS vosk_release(void *args) +{ + struct vosk_release_params *params = args; + + TRACE("args %p.\n", args); + + if (!params->instance) + return STATUS_UNSUCCESSFUL; + + pvosk_recognizer_free(from_vosk_instance(params->instance)); + + return STATUS_SUCCESS; +} + #else /* HAVE_VOSK_API_H */
#define MAKE_UNSUPPORTED_FUNC( f ) \ @@ -75,6 +307,8 @@ static NTSTATUS vosk_process_attach( void *args ) }
MAKE_UNSUPPORTED_FUNC(vosk_process_attach) +MAKE_UNSUPPORTED_FUNC(vosk_create) +MAKE_UNSUPPORTED_FUNC(vosk_release) #undef MAKE_UNSUPPORTED_FUNC
#endif /* HAVE_VOSK_API_H */ @@ -82,9 +316,13 @@ MAKE_UNSUPPORTED_FUNC(vosk_process_attach) unixlib_entry_t __wine_unix_call_funcs[] = { vosk_process_attach, + vosk_create, + vosk_release, };
unixlib_entry_t __wine_unix_call_wow64_funcs[] = { vosk_process_attach, + vosk_create, + vosk_release, };
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=129016
Your paranoid android.
=== debian11 (build log) ===
../wine/dlls/windows.media.speech/vosk.c:53: error: unterminated #ifdef Task: The win32 Wine build failed
=== debian11b (build log) ===
../wine/dlls/windows.media.speech/vosk.c:53: error: unterminated #ifdef Task: The wow64 Wine build failed