Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qt6-speech for openSUSE:Factory 
checked in at 2026-10-18 19:21:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qt6-speech (Old)
 and      /work/SRC/openSUSE:Factory/.qt6-speech.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qt6-speech"

Sun Oct 18 19:21:39 2026 rev:31 rq:1384414 version:6.12.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qt6-speech/qt6-speech.changes    2026-08-21 
16:52:20.350875522 +0200
+++ /work/SRC/openSUSE:Factory/.qt6-speech.new.3698736/qt6-speech.changes       
2026-10-18 19:21:55.262270388 +0200
@@ -1,0 +2,6 @@
+Wed Sep 30 16:16:53 UTC 2026 - Christophe Marin <[email protected]>
+
+- Update to 6.12.0
+  https://www.qt.io/blog/qt-6.12-released
+
+-------------------------------------------------------------------

Old:
----
  qtspeech-everywhere-src-6.11.2.tar.xz

New:
----
  qtspeech-everywhere-src-6.12.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qt6-speech.spec ++++++
--- /var/tmp/diff_new_pack.dBfgGJ/_old  2026-10-18 19:21:55.976299990 +0200
+++ /var/tmp/diff_new_pack.dBfgGJ/_new  2026-10-18 19:21:55.977300032 +0200
@@ -16,8 +16,8 @@
 #
 
 
-%define real_version 6.11.2
-%define short_version 6.11
+%define real_version 6.12.0
+%define short_version 6.12
 %define tar_name qtspeech-everywhere-src
 %define tar_suffix %{nil}
 #
@@ -26,21 +26,15 @@
 %define pkg_suffix -docs
 %endif
 #
-# Not available in Leap 15
-%if 0%{?suse_version} > 1500
-%bcond_without flite
-%endif
 Name:           qt6-speech%{?pkg_suffix}
-Version:        6.11.2
+Version:        6.12.0
 Release:        0
 Summary:        Qt 6 TextToSpeech Library and Plugin
 License:        GPL-2.0-only OR LGPL-3.0-only OR GPL-3.0-only
 URL:            https://www.qt.io
 Source0:        
https://download.qt.io/official_releases/qt/%{short_version}/%{real_version}%{tar_suffix}/submodules/%{tar_name}-%{real_version}%{tar_suffix}.tar.xz
-%if %{with flite}
 # Flite is built without Alsa, adding it to BuildRequires isn't needed
 BuildRequires:  flite-devel > 2.0
-%endif
 BuildRequires:  pkgconfig
 BuildRequires:  cmake(Qt6Concurrent) = %{real_version}
 BuildRequires:  cmake(Qt6Core) = %{real_version}
@@ -116,9 +110,7 @@
 
 %files -n qt6-texttospeech
 %dir %{_qt6_pluginsdir}/texttospeech/
-%if %{with flite}
 %{_qt6_pluginsdir}/texttospeech/libqtexttospeech_flite.so
-%endif
 %{_qt6_pluginsdir}/texttospeech/libqtexttospeech_mock.so
 %{_qt6_pluginsdir}/texttospeech/libqtexttospeech_speechd.so
 %{_qt6_qmldir}/QtTextToSpeech/

++++++ qtspeech-everywhere-src-6.11.2.tar.xz -> 
qtspeech-everywhere-src-6.12.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/.cmake.conf 
new/qtspeech-everywhere-src-6.12.0/.cmake.conf
--- old/qtspeech-everywhere-src-6.11.2/.cmake.conf      2026-08-12 
18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/.cmake.conf      2026-09-26 
19:45:17.000000000 +0200
@@ -1,8 +1,9 @@
-set(QT_REPO_MODULE_VERSION "6.11.2")
+set(QT_REPO_MODULE_VERSION "6.12.0")
 set(QT_EXTRA_INTERNAL_TARGET_DEFINES
     "QT_ENABLE_STRICT_MODE_UP_TO=QT_VERSION_CHECK(6,11,0)"
     # not yet in strict mode:
     "QT_LEAN_HEADERS=1"
+    "QT_NO_DISCONNECT_CONST_CONNECTION=1"
     "QT_NO_QPAIR=1"
     "QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD=1"
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/.tag 
new/qtspeech-everywhere-src-6.12.0/.tag
--- old/qtspeech-everywhere-src-6.11.2/.tag     2026-08-12 18:34:55.000000000 
+0200
+++ new/qtspeech-everywhere-src-6.12.0/.tag     2026-09-26 19:45:17.000000000 
+0200
@@ -1 +1 @@
-ae2de454bc73956632841221c535959f6f950346
+332f8a148bf01739140c3a00dd54f3ed98f3b546
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/CONTRIBUTING.md 
new/qtspeech-everywhere-src-6.12.0/CONTRIBUTING.md
--- old/qtspeech-everywhere-src-6.11.2/CONTRIBUTING.md  1970-01-01 
01:00:00.000000000 +0100
+++ new/qtspeech-everywhere-src-6.12.0/CONTRIBUTING.md  2026-09-26 
19:45:17.000000000 +0200
@@ -0,0 +1,11 @@
+## Qt contribution guidelines
+
+We welcome contributions to Qt!
+
+Note that we cannot accept pull requests on GitHub. All contributions
+to the Qt project are exclusively handled through the
+[Gerrit code review system](https://codereview.qt-project.org).
+
+See
+[contribute.qt-project.org](https://contribute.qt-project.org/) to learn
+more.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/REUSE.toml 
new/qtspeech-everywhere-src-6.12.0/REUSE.toml
--- old/qtspeech-everywhere-src-6.11.2/REUSE.toml       2026-08-12 
18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/REUSE.toml       2026-09-26 
19:45:17.000000000 +0200
@@ -2,7 +2,6 @@
 
 [[annotations]]
 path = ["src/tts/doc/QtTextToSpeechDoc",
-        "src/plugins/tts/android/jar/AndroidManifest.xml",
         "src/plugins/**json"]
 precedence = "closest"
 comment = "src and plugin"
@@ -32,7 +31,7 @@
 SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
 
 [[annotations]]
-path = ["**/doc/images/**", "**.qdocconf", "config_help.txt"]
+path = ["**/doc/images/**", "**.qdocconf", "config_help.txt", 
"CONTRIBUTING.md"]
 comment = "documentation"
 precedence = "closest"
 SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
@@ -46,6 +45,15 @@
 SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
 
 [[annotations]]
+path = ["src/**/build.gradle", "src/**/settings.gradle",
+        "src/**/gradle.properties", "src/**/libs.versions.toml"]
+precedence = "override"
+comment = "build system"
+SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
+SPDX-License-Identifier = "BSD-3-Clause"
+
+
+[[annotations]]
 path = ["**/qt_attribution.json"]
 comment = "documentation"
 precedence = "override"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/dependencies.yaml 
new/qtspeech-everywhere-src-6.12.0/dependencies.yaml
--- old/qtspeech-everywhere-src-6.11.2/dependencies.yaml        2026-08-12 
18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/dependencies.yaml        2026-09-26 
19:45:17.000000000 +0200
@@ -1,10 +1,10 @@
 dependencies:
   ../qtbase:
-    ref: ef55f427f2c8b410d34f8a7681020a3000cf6866
+    ref: 025bdad181de241e81bf853c8a2d7bf3d19261a9
     required: true
   ../qtdeclarative:
-    ref: 4e3399c26ec57246c08de019cfcbda8d23604cfa
+    ref: 4332fbbb4c340463dc8cee36dda0c85d932122d8
     required: false
   ../qtmultimedia:
-    ref: 6f162ccac1425edbd7b4d1582fabab5973b43d6c
+    ref: 6ca885f084a3984749d53bb50a0e08bdc60e86cc
     required: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtspeech-everywhere-src-6.11.2/licenseRule.json 
new/qtspeech-everywhere-src-6.12.0/licenseRule.json
--- old/qtspeech-everywhere-src-6.11.2/licenseRule.json 2026-08-12 
18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/licenseRule.json 2026-09-26 
19:45:17.000000000 +0200
@@ -57,9 +57,9 @@
         }
     },
     {
-        "comment": "Files with the following endings are Documentation 
licensed.",
-        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", 
"qt_attribution.json",
-                                 "config_help.txt"],
+        "comment": "Files with the following endings are documentation 
licensed.",
+        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", 
"CONTRIBUTING.md",
+                                "qt_attribution.json", "config_help.txt"],
         "location":{
             "": {
                 "comment": "",
@@ -103,6 +103,11 @@
                 "comment": "Default",
                 "file type": "documentation",
                 "spdx": ["LicenseRef-Qt-Commercial OR 
GFDL-1.3-no-invariants-only"]
+            },
+            ".*(\\.gradle|gradle\\.properties|libs\\.versions\\.toml)$": {
+                "comment": "Android Gradle build files",
+                "file type": "build system",
+                "spdx": ["BSD-3-Clause"]
             }
         }
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/CMakeLists.txt 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/CMakeLists.txt
--- old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/CMakeLists.txt   
2026-08-12 18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/CMakeLists.txt   
2026-09-26 19:45:17.000000000 +0200
@@ -17,6 +17,9 @@
 if(ANDROID)
     add_subdirectory(android)
 endif()
+if(OHOS)
+    add_subdirectory(ohos)
+endif()
 if(QT_FEATURE_flite)
     add_subdirectory(flite)
 endif()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/AndroidManifest.xml
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/AndroidManifest.xml
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/AndroidManifest.xml
  2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/AndroidManifest.xml
  1970-01-01 01:00:00.000000000 +0100
@@ -1,7 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android";
-    android:versionCode="1"
-    android:versionName="1.0"
-    package="org.qtproject.qt.android.qspeech">
-    <supports-screens android:largeScreens="true" android:normalScreens="true" 
android:anyDensity="true" android:smallScreens="true"/>
-</manifest>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/CMakeLists.txt 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/CMakeLists.txt
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/CMakeLists.txt   
    2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/CMakeLists.txt   
    2026-09-26 19:45:17.000000000 +0200
@@ -6,7 +6,6 @@
 )
 
 qt_internal_add_jar(Qt${QtSpeech_VERSION_MAJOR}AndroidTextToSpeech
-    INCLUDE_JARS ${QT_ANDROID_JAR}
     SOURCES ${java_sources}
     OUTPUT_DIR "${QT_BUILD_DIR}/jar"
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/build.gradle 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/build.gradle
--- old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/build.gradle 
1970-01-01 01:00:00.000000000 +0100
+++ new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/build.gradle 
2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,18 @@
+plugins {
+    alias(libs.plugins.android.library)
+}
+
+android {
+    namespace = 'org.qtproject.qt.android.speech'
+    compileSdk = (project.findProperty('compileSdk') ?: '36') as int
+
+    defaultConfig {
+        minSdk = (project.findProperty('minSdk') ?: '28') as int
+    }
+
+    sourceSets {
+        main {
+            java.srcDirs = ['src']
+        }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/gradle/libs.versions.toml
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/gradle/libs.versions.toml
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/gradle/libs.versions.toml
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/gradle/libs.versions.toml
    2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,5 @@
+[versions]
+agp = "9.2.1"
+
+[plugins]
+android-library = { id = "com.android.library", version.ref = "agp" }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/gradle.properties
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/gradle.properties
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/gradle.properties
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/gradle.properties
    2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx3200m -XX:MaxMetaspaceSize=768m 
-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# Enable building projects in parallel
+org.gradle.parallel=true
+
+# Allow AndroidX usage
+android.useAndroidX=true
+
+# Enable caching
+org.gradle.configuration-cache=true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/settings.gradle 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/settings.gradle
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/settings.gradle  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/settings.gradle  
    2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,17 @@
+pluginManagement {
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.name = 'Qt6AndroidTextToSpeech'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/src/org/qtproject/qt/android/speech/QtTextToSpeech.java
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/src/org/qtproject/qt/android/speech/QtTextToSpeech.java
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/android/jar/src/org/qtproject/qt/android/speech/QtTextToSpeech.java
      2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/android/jar/src/org/qtproject/qt/android/speech/QtTextToSpeech.java
      2026-09-26 19:45:17.000000000 +0200
@@ -73,7 +73,9 @@
         }
 
         @Override
+        @SuppressWarnings("deprecation")
         public void onError(String utteranceId) {
+            // Needed for compilation even on 21+ (abstract)
             onError(utteranceId, TextToSpeech.ERROR);
         }
 
@@ -297,7 +299,7 @@
     Locale getLocale()
     {
         //Log.d(TAG, "getLocale: " + mLocale);
-        final Locale language = mTts.getLanguage();
+        final Locale language = mTts.getVoice().getLocale();
         if (language == null)
             return null;
         String languageCode = language.getLanguage();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/darwin/CMakeLists.txt 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/darwin/CMakeLists.txt
--- old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/darwin/CMakeLists.txt    
2026-08-12 18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/darwin/CMakeLists.txt    
2026-09-26 19:45:17.000000000 +0200
@@ -14,5 +14,6 @@
         Qt::Gui
         Qt::TextToSpeech
         Qt::Multimedia
+        ${FWFoundation}
         ${FWAVFoundation}
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/CMakeLists.txt 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/CMakeLists.txt
--- old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/CMakeLists.txt      
1970-01-01 01:00:00.000000000 +0100
+++ new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/CMakeLists.txt      
2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,23 @@
+# Copyright (C) 2026 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_find_package(NodeAddonApi MODULE PROVIDED_TARGETS 
NodeAddonApi::NodeAddonApi)
+
+qt_internal_add_plugin(QTextToSpeechOhosPlugin
+    OUTPUT_NAME qttexttospeech_ohos
+    PLUGIN_TYPE texttospeech
+    EXCEPTIONS
+    SOURCES
+        corespeechkit/texttospeechproxy.cpp corespeechkit/texttospeechproxy.h
+        qtexttospeech_ohos.cpp qtexttospeech_ohos.h
+        qtexttospeech_ohos_plugin.cpp qtexttospeech_ohos_plugin.h
+    DEFINES
+        NAPI_CPP_EXCEPTIONS
+    LIBRARIES
+        NodeAddonApi::NodeAddonApi
+        Qt::Core
+        Qt::CorePrivate
+        Qt::TextToSpeech
+        Qt::Multimedia
+        ace_napi.z
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.cpp
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.cpp
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.cpp
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.cpp
 2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,451 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#include "texttospeechproxy.h"
+
+#include <QtCore/quuid.h>
+#include <QtCore/private/qcore_ohos_p.h>
+#include <QtCore/private/qnapi_p.h>
+#include <QtCore/private/qohoslogger_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace CoreSpeechKit {
+
+namespace {
+
+std::optional<TtsCompletionType> tryParseTtsCompletionType(const QNapi::Object 
&response)
+{
+    static constexpr int ohosSynthesisCompleteTypeValue = 0;
+    static constexpr int ohosSpeechCompleteTypeValue = 1;
+
+    auto optTypeValue = QNapi::getOptionalPropOrEmpty<QNapi::Number>(response, 
"type");
+    if (optTypeValue.IsEmpty())
+        return {};
+
+    switch (optTypeValue.Int32Value()) {
+    case ohosSynthesisCompleteTypeValue:
+        return TtsCompletionType::SynthesisComplete;
+    case ohosSpeechCompleteTypeValue:
+        return TtsCompletionType::SpeechComplete;
+    default:
+        return {};
+    }
+}
+
+// Source of values used for EngineMode can be found under section 'online':
+// 
https://developer.huawei.com/consumer/en/doc/harmonyos-references/hms-ai-texttospeech#section1638144844811
+enum class EngineMode
+{
+    Online = 0,
+    Offline = 1,
+};
+
+// Source of values used for SpeechPlayType can be found under section 
'extraParams.playType':
+// 
https://developer.huawei.com/consumer/en/doc/harmonyos-references/hms-ai-texttospeech#section7843122735210
+enum class SpeechPlayType
+{
+    SynthesisOnly = 0,
+    SynthesisAndPlayback = 1,
+};
+
+// Source of values used for SpeechQueueMode can be found under section 
'extraParams.queueMode':
+// 
https://developer.huawei.com/consumer/en/doc/harmonyos-references/hms-ai-texttospeech#section7843122735210
+enum class SpeechQueueMode
+{
+    Queue = 0,
+    Preemption = 1,
+};
+
+constexpr auto engineMode = EngineMode::Offline;
+constexpr auto speechPlayType = SpeechPlayType::SynthesisAndPlayback;
+constexpr auto speechQueueMode = SpeechQueueMode::Preemption;
+
+class TextToSpeechProxyImpl : public TextToSpeechProxy
+{
+public:
+    static q23::expected<std::shared_ptr<TextToSpeechProxyImpl>, std::string> 
tryMakeInstance(
+        const std::string &language, int personTimbre);
+
+    void speak(const SpeakParams &params) override;
+    void stop() override;
+    std::vector<VoiceInfo> listVoices() override;
+
+    void setEngineEventsListener(
+        std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener);
+
+private:
+    struct JsScopeData
+    {
+        std::shared_ptr<QNapi::Reference<QNapi::Object>> textToSpeechEngineRef;
+    };
+
+    explicit TextToSpeechProxyImpl(const std::string &language, 
std::shared_ptr<JsScopeData> jsScopeData);
+
+    static q23::expected<std::shared_ptr<JsScopeData>, std::string> 
tryMakeJsScopeData(
+        const std::string &language, int personTimbre);
+
+    std::shared_ptr<JsScopeData> m_jsScopeData;
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
m_engineEventsListener;
+    const std::string m_language;
+};
+
+class QtThreadBasedEngineEventsListener : public 
TextToSpeechProxy::EngineEventsListener
+{
+public:
+    QtThreadBasedEngineEventsListener(
+        std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
baseEngineEventsListener);
+
+    virtual void onStart(std::string utteranceId) override;
+    virtual void onComplete(std::string utteranceId, 
std::optional<TtsCompletionType> optCompletionType) override;
+    virtual void onStop(std::string utteranceId) override;
+    virtual void onError(
+        std::string utteranceId, std::uint32_t errorCode, std::string 
errorMessage) override;
+
+private:
+     std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
m_baseEngineEventsListener;
+};
+
+QtThreadBasedEngineEventsListener::QtThreadBasedEngineEventsListener(
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
baseEngineEventsListener)
+    : m_baseEngineEventsListener(baseEngineEventsListener)
+{
+}
+
+void QtThreadBasedEngineEventsListener::onStart(std::string utteranceId)
+{
+    QtOhos::invokeInQtThread(
+        [weakBaseEngineEventsListener = 
QtOhos::makeWeakPtr(m_baseEngineEventsListener), utteranceId]() {
+            auto baseEngineEventsListener = 
weakBaseEngineEventsListener.lock();
+            if (baseEngineEventsListener)
+                baseEngineEventsListener->onStart(utteranceId);
+        });
+}
+
+void QtThreadBasedEngineEventsListener::onComplete(
+    std::string utteranceId, std::optional<TtsCompletionType> 
optCompletionType)
+{
+    QtOhos::invokeInQtThread(
+        [weakBaseEngineEventsListener = 
QtOhos::makeWeakPtr(m_baseEngineEventsListener), utteranceId, 
optCompletionType]() {
+            auto baseEngineEventsListener = 
weakBaseEngineEventsListener.lock();
+            if (baseEngineEventsListener)
+                baseEngineEventsListener->onComplete(utteranceId, 
optCompletionType);
+        });
+}
+
+void QtThreadBasedEngineEventsListener::onStop(std::string utteranceId)
+{
+    QtOhos::invokeInQtThread(
+        [weakBaseEngineEventsListener = 
QtOhos::makeWeakPtr(m_baseEngineEventsListener), utteranceId]() {
+            auto baseEngineEventsListener = 
weakBaseEngineEventsListener.lock();
+            if (baseEngineEventsListener)
+                baseEngineEventsListener->onStop(utteranceId);
+        });
+}
+
+void QtThreadBasedEngineEventsListener::onError(
+            std::string utteranceId, std::uint32_t errorCode, std::string 
errorMessage)
+{
+    QtOhos::invokeInQtThread(
+        [weakBaseEngineEventsListener = 
QtOhos::makeWeakPtr(m_baseEngineEventsListener), utteranceId, errorCode, 
errorMessage]() {
+            auto baseEngineEventsListener = 
weakBaseEngineEventsListener.lock();
+            if (baseEngineEventsListener)
+                baseEngineEventsListener->onError(utteranceId, errorCode, 
errorMessage);
+        });
+}
+
+std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
makeEngineEventsListenerQtDecorator(
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener)
+{
+    return 
std::make_shared<QtThreadBasedEngineEventsListener>(engineEventsListener);
+}
+
+std::string createUuid()
+{
+    return QUuid::createUuid().toString(QUuid::WithoutBraces).toStdString();
+}
+
+std::function<void(const QOhosCallbackInfo &)> makeOnStateCallbackDelegate(
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener,
+    void (TextToSpeechProxy::EngineEventsListener::*memberPtr)(std::string))
+{
+    return [weakEngineEventsListener = 
QtOhos::makeWeakPtr(engineEventsListener), memberPtr](const QNapi::CallbackInfo 
&cbInfo) {
+        auto utteranceId = cbInfo.getFirstArg<QNapi::String>(Q_FUNC_INFO);
+        auto engineEventsListener = weakEngineEventsListener.lock();
+        if (engineEventsListener)
+            (engineEventsListener.get()->*memberPtr)(utteranceId);
+    };
+}
+
+std::function<void(const QOhosCallbackInfo &)> makeOnCompleteCallbackDelegate(
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener)
+{
+    return [weakEngineEventsListener = 
QtOhos::makeWeakPtr(engineEventsListener)](const QNapi::CallbackInfo &cbInfo) {
+        QNapi::String utteranceId;
+        QNapi::Object response;
+        cbInfo.getLeadingArgs(Q_FUNC_INFO, utteranceId, response);
+        auto optCompletionType = tryParseTtsCompletionType(response);
+        if (!optCompletionType) {
+            qOhosPrintfWarning(
+                "%s: unexpected completion type in response: %s, utteranceId: 
%s",
+                Q_FUNC_INFO, QNapi::toJsonString(response).c_str(), 
utteranceId.Utf8Value().c_str());
+        }
+        auto engineEventsListener = weakEngineEventsListener.lock();
+        if (engineEventsListener)
+            engineEventsListener->onComplete(utteranceId, optCompletionType);
+    };
+}
+
+void setEngineListenerInJsThread(
+    QOhosJsState &jsState, QNapi::Object engine,
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener)
+{
+    engine.eval(
+        "setListener(*)",
+        {
+            QNapi::makeObject(
+                jsState.env(),
+                {
+                    {
+                        "onStart",
+                        makeOnStateCallbackDelegate(
+                            engineEventsListener,
+                            &TextToSpeechProxy::EngineEventsListener::onStart)
+                    },
+                    {
+                        "onComplete",
+                        makeOnCompleteCallbackDelegate(engineEventsListener)
+                    },
+                    {
+                        "onStop",
+                        makeOnStateCallbackDelegate(
+                            engineEventsListener,
+                            &TextToSpeechProxy::EngineEventsListener::onStop)
+                    },
+                    {
+                        "onError",
+                        [weakEngineEventsListener = 
QtOhos::makeWeakPtr(engineEventsListener)](const QNapi::CallbackInfo &cbInfo) {
+                            QNapi::String utteranceId;
+                            QNapi::Number errorCode;
+                            QNapi::String errorMessage;
+                            cbInfo.getLeadingArgs(Q_FUNC_INFO, utteranceId, 
errorCode, errorMessage);
+                            auto engineEventsListener = 
weakEngineEventsListener.lock();
+                            if (engineEventsListener) {
+                                engineEventsListener->onError(
+                                    utteranceId, errorCode, errorMessage);
+                            }
+                        }
+                    },
+                })
+        });
+}
+
+void tryCreateEngineImpl(
+    QOhosJsState &jsState, const std::string &language, int personTimbre,
+    
QOhosTaskPromise<q23::expected<std::shared_ptr<QNapi::Reference<QNapi::Object>>,
 std::string>> taskPromise)
+{
+    auto thenCatchPromises = 
std::move(taskPromise).makeThenCatchBranches(Q_FUNC_INFO);
+    jsState.evalToPromiseOrRejectOnThrow(
+        "@kit.CoreSpeechKit.textToSpeech.createEngine(*)",
+        {
+            QNapi::makeObject(
+                jsState.env(),
+                {
+                    {"language", language},
+                    {"person", personTimbre},
+                    {"online", static_cast<int>(engineMode)},
+                }),
+        })
+    .onThen(
+        [thenPromise = std::move(thenCatchPromises.first)](const 
QOhosCallbackInfo &cbInfo) {
+            auto engine = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
+            auto engineRef = 
QtOhos::moveToSharedPtr(QNapi::Reference<>::makePersistentFrom(engine));
+            thenPromise(
+                QtOhos::makeSharedPtrWithAttachedExtraData(
+                    engineRef,
+                    QtOhos::makeDestroyNotifier(
+                        [engineRef]() {
+                            try {
+                                engineRef->eval("shutdown()");
+                            } catch (const Napi::Error &error) {
+                                qOhosPrintfError(
+                                    "%s: shutdown() failed with error: %s", 
Q_FUNC_INFO, error.what());
+                            }
+                        })
+                ));
+        })
+    .onCatch(
+        [catchPromise = std::move(thenCatchPromises.second)](const 
QOhosCallbackInfo &cbInfo) {
+            auto errorObj = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
+            
catchPromise(q23::unexpected(errorObj.get<QNapi::String>("message")));
+        });
+}
+
+q23::expected<std::shared_ptr<TextToSpeechProxyImpl>, std::string> 
TextToSpeechProxyImpl::tryMakeInstance(
+    const std::string &language, int personTimbre)
+{
+    auto jsScopeDataOrError = tryMakeJsScopeData(language, personTimbre);
+    if (!jsScopeDataOrError)
+        return q23::unexpected(std::move(jsScopeDataOrError.error()));
+
+    return std::shared_ptr<TextToSpeechProxyImpl>(
+        new TextToSpeechProxyImpl(language, 
std::move(jsScopeDataOrError.value())));
+}
+
+void TextToSpeechProxyImpl::setEngineEventsListener(
+    std::shared_ptr<TextToSpeechProxy::EngineEventsListener> 
engineEventsListener)
+{
+    m_engineEventsListener = 
makeEngineEventsListenerQtDecorator(engineEventsListener);
+    QOhosJsThreadGateway::runAndWait(
+        [&](QOhosJsState &jsState) {
+            setEngineListenerInJsThread(
+                jsState, m_jsScopeData->textToSpeechEngineRef->Value(),
+                m_engineEventsListener);
+        },
+        Q_FUNC_INFO);
+}
+
+q23::expected<std::shared_ptr<TextToSpeechProxyImpl::JsScopeData>, 
std::string> TextToSpeechProxyImpl::tryMakeJsScopeData(
+    const std::string &language, int personTimbre)
+{
+    return 
QOhosJsThreadGateway::evalWithPromise<q23::expected<std::shared_ptr<TextToSpeechProxyImpl::JsScopeData>,
 std::string>>(
+        [&](QOhosJsState &jsState, auto evalPromise) {
+            auto sharedEvalPromise = QtOhos::moveToSharedPtr(
+                std::move(evalPromise).makeChained(Q_FUNC_INFO));
+            tryCreateEngineImpl(
+                jsState, language, personTimbre,
+                
QOhosTaskPromise<q23::expected<std::shared_ptr<QNapi::Reference<QNapi::Object>>,
 std::string>>(
+                    
[sharedEvalPromise](q23::expected<std::shared_ptr<QNapi::Reference<QNapi::Object>>,
 std::string> engineRefOrError) {
+                        if (!engineRefOrError) {
+                            
(*sharedEvalPromise)(q23::unexpected(std::move(engineRefOrError.error())));
+                            return;
+                        }
+                        (*sharedEvalPromise)(
+                            QtOhos::makeProxyWithJsThreadDeleter(
+                                QtOhos::moveToSharedPtr(
+                                    TextToSpeechProxyImpl::JsScopeData {
+                                        .textToSpeechEngineRef = 
engineRefOrError.value(),
+                                    })));
+                    },
+                    {},
+                    Q_FUNC_INFO));
+        },
+        Q_FUNC_INFO);
+}
+
+TextToSpeechProxyImpl::TextToSpeechProxyImpl(
+    const std::string &language, std::shared_ptr<JsScopeData> jsScopeData)
+    : m_jsScopeData(std::move(jsScopeData))
+    , m_language(language)
+{
+}
+
+void TextToSpeechProxyImpl::speak(const SpeakParams &params)
+{
+    QOhosJsThreadGateway::runAndWait(
+        [&](QOhosJsState &jsState) {
+            m_jsScopeData->textToSpeechEngineRef->eval(
+                "speak(*)",
+                {
+                    params.text,
+                    QNapi::makeObject(
+                        jsState.env(),
+                        {
+                            {"requestId", createUuid()},
+                            {
+                                "extraParams",
+                                QNapi::makeObject(
+                                    jsState.env(),
+                                    {
+                                        {"queueMode", 
static_cast<int>(speechQueueMode)},
+                                        {"speed", params.speed},
+                                        {"volume", params.volume},
+                                        {"pitch", params.pitch},
+                                        {"languageContext", 
params.languageContext},
+                                        {"playType", 
static_cast<int>(speechPlayType)},
+                                    })
+                            },
+                        }),
+                });
+        },
+        Q_FUNC_INFO);
+}
+
+void TextToSpeechProxyImpl::stop()
+{
+    QOhosJsThreadGateway::runAndWait(
+        [&](QOhosJsState &) {
+            m_jsScopeData->textToSpeechEngineRef->eval("stop()");
+        },
+        Q_FUNC_INFO);
+}
+
+std::vector<VoiceInfo> TextToSpeechProxyImpl::listVoices()
+{
+    return QOhosJsThreadGateway::evalWithPromise<std::vector<VoiceInfo>>(
+        [&](QOhosJsState &jsState, QOhosTaskPromise<std::vector<VoiceInfo>> 
evalPromise) {
+            auto thenCatchPromises = 
std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
+            m_jsScopeData->textToSpeechEngineRef->evalToPromiseOrRejectOnThrow(
+                "listVoices(*)",
+                {
+                    QNapi::makeObject(
+                        jsState.env(),
+                        {
+                            {"requestId", createUuid()},
+                            {"online", static_cast<int>(engineMode)},
+                        })
+                })
+            .onThen(
+                [thenPromise = std::move(thenCatchPromises.first)](const 
QOhosCallbackInfo &cbInfo) {
+                    auto voicesArray = 
cbInfo.getFirstArg<QNapi::Array>(Q_FUNC_INFO);
+
+                    thenPromise(
+                        QNapi::getArrayElements<std::vector<VoiceInfo>, 
QNapi::Object>(
+                            voicesArray,
+                            [](QNapi::Object jsVoice) {
+                                return VoiceInfo{
+                                    .language = 
jsVoice.get<QNapi::String>("language"),
+                                    .style = 
jsVoice.get<QNapi::String>("style"),
+                                    .gender = 
jsVoice.get<QNapi::String>("gender"),
+                                    .description = 
jsVoice.get<QNapi::String>("description"),
+                                    .personTimbre = 
jsVoice.get<QNapi::Number>("person"),
+                                };
+                            }));
+                })
+            .onCatch(
+                [catchPromise = std::move(thenCatchPromises.second)](const 
QOhosCallbackInfo &cbInfo) {
+                    QtOhos::logJsCallbackError(cbInfo, "listVoices() failed");
+                    catchPromise({});
+                });
+        },
+        Q_FUNC_INFO);
+}
+
+}
+
+TextToSpeechProxy::TextToSpeechProxy() = default;
+
+TextToSpeechProxy::~TextToSpeechProxy() = default;
+
+TextToSpeechProxy::EngineEventsListener::EngineEventsListener() = default;
+
+TextToSpeechProxy::EngineEventsListener::~EngineEventsListener() = default;
+
+q23::expected<std::function<std::shared_ptr<TextToSpeechProxy>(std::shared_ptr<TextToSpeechProxy::EngineEventsListener>)>,
 std::string> tryMakeTextToSpeechProxyFactory(
+    const std::string &language, int personTimbre)
+{
+    auto proxyImplInstanceOrError = 
TextToSpeechProxyImpl::tryMakeInstance(language, personTimbre);
+    if (!proxyImplInstanceOrError)
+        return q23::unexpected(std::move(proxyImplInstanceOrError.error()));
+
+    return 
std::function<std::shared_ptr<TextToSpeechProxy>(std::shared_ptr<TextToSpeechProxy::EngineEventsListener>)>(
+        [proxyImplInstance = 
std::move(proxyImplInstanceOrError.value())](std::shared_ptr<TextToSpeechProxy::EngineEventsListener>
 engineEventsListener) {
+            proxyImplInstance->setEngineEventsListener(engineEventsListener);
+            return proxyImplInstance;
+        });
+}
+
+}
+
+QT_END_NAMESPACE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.h
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.h
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.h
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/corespeechkit/texttospeechproxy.h
   2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,82 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#ifndef TEXTTOSPEECHPROXY_H
+#define TEXTTOSPEECHPROXY_H
+
+#include <QtCore/private/qexpected_p.h>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+namespace CoreSpeechKit {
+
+enum class TtsCompletionType
+{
+    SynthesisComplete,
+    SpeechComplete,
+};
+
+struct SpeakParams
+{
+    std::string text;
+    double speed;
+    double volume;
+    double pitch;
+    std::string languageContext;
+};
+
+struct VoiceInfo
+{
+    std::string language;
+    std::string style;
+    std::string gender;
+    std::string description;
+    int personTimbre;
+};
+
+class TextToSpeechProxy
+{
+    Q_DISABLE_COPY_MOVE(TextToSpeechProxy)
+public:
+    class EngineEventsListener
+    {
+        Q_DISABLE_COPY_MOVE(EngineEventsListener)
+    public:
+        virtual ~EngineEventsListener();
+
+        virtual void onStart(std::string utteranceId) = 0;
+        virtual void onComplete(std::string utteranceId, 
std::optional<TtsCompletionType> optCompletionType) = 0;
+        virtual void onStop(std::string utteranceId) = 0;
+        virtual void onError(
+            std::string utteranceId, std::uint32_t errorCode, std::string 
errorMessage) = 0;
+
+    protected:
+        EngineEventsListener();
+    };
+
+    virtual ~TextToSpeechProxy();
+
+    virtual void speak(const SpeakParams &params) = 0;
+    virtual void stop() = 0;
+    virtual std::vector<VoiceInfo> listVoices() = 0;
+
+protected:
+    TextToSpeechProxy();
+};
+
+q23::expected<std::function<std::shared_ptr<TextToSpeechProxy>(std::shared_ptr<TextToSpeechProxy::EngineEventsListener>)>,
 std::string> tryMakeTextToSpeechProxyFactory(
+    const std::string &language, int personTimbre);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/ohos_plugin.json 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/ohos_plugin.json
--- old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/ohos_plugin.json    
1970-01-01 01:00:00.000000000 +0100
+++ new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/ohos_plugin.json    
2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,9 @@
+{
+    "Keys": ["ohos"],
+    "Provider": "ohos",
+    "Version": 100,
+    "Priority": 100,
+    "Capabilities": [
+        "Speak"
+    ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos.cpp 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos.cpp
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos.cpp  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos.cpp  
    2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,369 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#include "qtexttospeech_ohos.h"
+#include "qtexttospeech_ohos_plugin.h"
+
+#include "corespeechkit/texttospeechproxy.h"
+
+#include <QtTextToSpeech/qvoice.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qlocale.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+constexpr const char *chineseLanguage = "zh-CN";
+constexpr const char *chineseLanguageContext = "zh-CN";
+constexpr int defaultPersonTimbre = 0;
+
+QVoice::Gender mapVoiceGender(const std::string &gender)
+{
+    return gender == "male"   ? QVoice::Gender::Male   :
+           gender == "female" ? QVoice::Gender::Female :
+                                QVoice::Gender::Unknown;
+}
+
+QVariantMap mapVoiceExtraData(const CoreSpeechKit::VoiceInfo &info)
+{
+    return QVariantMap{
+        {QStringLiteral("style"), QString::fromStdString(info.style)},
+        {QStringLiteral("person"), info.personTimbre},
+    };
+}
+
+double mapVolumeToOhosVolume(double volume)
+{
+    constexpr double maxTtsVolume = 2.0;
+    return volume * maxTtsVolume;
+}
+
+double mapRateToOhosSpeed(double rate)
+{
+    constexpr double minTtsRate = 0.5;
+    constexpr double normalTtsRate = 1.0;
+
+    return rate < 0
+        ? minTtsRate * rate + normalTtsRate
+        : rate + normalTtsRate;
+}
+
+double mapPitchToOhosPitch(double pitch)
+{
+    constexpr double minTtsPitch = 0.5;
+    constexpr double normalTtsPitch = 1.0;
+
+    return pitch < 0
+        ? minTtsPitch * pitch + normalTtsPitch
+        : pitch + normalTtsPitch;
+}
+
+class QTextToSpeechEngineOhos : public QTextToSpeechEngine
+{
+public:
+    QTextToSpeechEngineOhos(
+        const QVariantMap &parameters, QObject *parent,
+        std::function<std::shared_ptr<CoreSpeechKit::TextToSpeechProxy>(
+            
std::shared_ptr<CoreSpeechKit::TextToSpeechProxy::EngineEventsListener>)> 
ttsProxyFactory);
+
+    QList<QLocale> availableLocales() const override;
+    QList<QVoice> availableVoices() const override;
+    void say(const QString &text) override;
+    void synthesize(const QString &text) override;
+    void stop(QTextToSpeech::BoundaryHint boundaryHint) override;
+    void pause(QTextToSpeech::BoundaryHint boundaryHint) override;
+    void resume() override;
+    double rate() const override;
+    bool setRate(double rate) override;
+    double pitch() const override;
+    bool setPitch(double pitch) override;
+    QLocale locale() const override;
+    bool setLocale(const QLocale &locale) override;
+    double volume() const override;
+    bool setVolume(double volume) override;
+    QVoice voice() const override;
+    bool setVoice(const QVoice &voice) override;
+    QTextToSpeech::State state() const override;
+    QTextToSpeech::ErrorReason errorReason() const override;
+    QString errorString() const override;
+
+private:
+    class TextToSpeechEngineEventsListener
+        : public CoreSpeechKit::TextToSpeechProxy::EngineEventsListener
+    {
+    public:
+        explicit TextToSpeechEngineEventsListener(QTextToSpeechEngineOhos 
&owner);
+
+        void onStart(std::string utteranceId) override;
+        void onComplete(std::string utteranceId, 
std::optional<CoreSpeechKit::TtsCompletionType> optCompletionType) override;
+        void onStop(std::string utteranceId) override;
+        void onError(std::string utteranceId, std::uint32_t errorCode, 
std::string errorMsg) override;
+
+        QTextToSpeechEngineOhos& m_owner;
+    };
+
+    void handleOnStart(const QString &utteranceId);
+    void handleOnComplete(const QString &utteranceId, 
std::optional<CoreSpeechKit::TtsCompletionType> optCompletionType);
+    void handleOnStop(const QString &utteranceId);
+    void handleOnError(
+        const QString &utteranceId, std::uint32_t errorCode, const QString 
&errorMessage);
+    void setState(QTextToSpeech::State state);
+
+    std::shared_ptr<CoreSpeechKit::TextToSpeechProxy> m_ttsProxy;
+
+    QTextToSpeech::State m_state;
+    QList<QVoice> m_voices;
+    QList<QLocale> m_locales;
+    QLocale m_currentLocale;
+    double m_volume;
+    double m_rate;
+    double m_pitch;
+};
+
+QTextToSpeechEngineOhos::TextToSpeechEngineEventsListener::TextToSpeechEngineEventsListener(
+    QTextToSpeechEngineOhos &owner)
+    : m_owner(owner)
+{
+}
+
+void 
QTextToSpeechEngineOhos::TextToSpeechEngineEventsListener::onStart(std::string 
utteranceId)
+{
+    m_owner.handleOnStart(QString::fromStdString(utteranceId));
+}
+
+void QTextToSpeechEngineOhos::TextToSpeechEngineEventsListener::onComplete(
+    std::string utteranceId, std::optional<CoreSpeechKit::TtsCompletionType> 
optCompletionType)
+{
+    m_owner.handleOnComplete(QString::fromStdString(utteranceId), 
optCompletionType);
+}
+
+void 
QTextToSpeechEngineOhos::TextToSpeechEngineEventsListener::onStop(std::string 
utteranceId)
+{
+    m_owner.handleOnStop(QString::fromStdString(utteranceId));
+}
+
+void QTextToSpeechEngineOhos::TextToSpeechEngineEventsListener::onError(
+    std::string utteranceId, std::uint32_t errorCode, std::string errorMessage)
+{
+    m_owner.handleOnError(
+         QString::fromStdString(utteranceId), errorCode, 
QString::fromStdString(errorMessage));
+}
+
+QTextToSpeechEngineOhos::QTextToSpeechEngineOhos(
+    const QVariantMap &, QObject *parent,
+    
std::function<std::shared_ptr<CoreSpeechKit::TextToSpeechProxy>(std::shared_ptr<CoreSpeechKit::TextToSpeechProxy::EngineEventsListener>)>
 ttsProxyFactory)
+    : QTextToSpeechEngine(parent)
+    , m_state(QTextToSpeech::Ready)
+    , m_volume(1.0)
+    , m_rate(0.0)
+    , m_pitch(0.0)
+{
+    m_ttsProxy = 
ttsProxyFactory(std::make_shared<TextToSpeechEngineEventsListener>(*this));
+    for (const auto &voiceInfo : m_ttsProxy->listVoices()) {
+        QLocale locale(QString::fromStdString(voiceInfo.language));
+        m_voices.append(
+            createVoice(
+                QString::fromStdString(voiceInfo.description), locale,
+                mapVoiceGender(voiceInfo.gender), QVoice::Other,
+                mapVoiceExtraData(voiceInfo)));
+
+        if (!m_locales.contains(locale))
+            m_locales.append(locale);
+    }
+
+    if (!m_locales.isEmpty())
+        m_currentLocale = m_locales.first();
+}
+
+void QTextToSpeechEngineOhos::handleOnStart(const QString &)
+{
+    setState(QTextToSpeech::Speaking);
+}
+
+void QTextToSpeechEngineOhos::handleOnComplete(
+    const QString &, std::optional<CoreSpeechKit::TtsCompletionType> 
optCompletionType)
+{
+    if (!optCompletionType) {
+        setState(QTextToSpeech::Error);
+        return;
+    }
+
+    if (*optCompletionType == CoreSpeechKit::TtsCompletionType::SpeechComplete)
+        setState(QTextToSpeech::Ready);
+}
+
+void QTextToSpeechEngineOhos::handleOnStop(const QString &)
+{
+    setState(QTextToSpeech::Ready);
+}
+
+void QTextToSpeechEngineOhos::handleOnError(
+    const QString &utteranceId, std::uint32_t errorCode, const QString 
&errorMessage)
+{
+    setState(QTextToSpeech::Error);
+    qCWarning(lcSpeechTtsOhos)
+        << Q_FUNC_INFO << ": text to speech error: code" << errorCode
+        << errorMessage << ", utteranceId:" << utteranceId;
+}
+
+void QTextToSpeechEngineOhos::setState(QTextToSpeech::State state)
+{
+    if (state != m_state) {
+        m_state = state;
+        Q_EMIT stateChanged(m_state);
+    }
+}
+
+QList<QLocale> QTextToSpeechEngineOhos::availableLocales() const
+{
+    return m_locales;
+}
+
+QList<QVoice> QTextToSpeechEngineOhos::availableVoices() const
+{
+    QList<QVoice> voices;
+    for (const auto &voice : m_voices) {
+        if (voice.locale() == m_currentLocale)
+            voices << voice;
+    }
+
+    return voices;
+}
+
+void QTextToSpeechEngineOhos::say(const QString &text)
+{
+    if (text.isEmpty())
+        return;
+
+    m_ttsProxy->speak(
+        {
+            .text = text.toStdString(),
+            .speed = mapRateToOhosSpeed(m_rate),
+            .volume = mapVolumeToOhosVolume(m_volume),
+            .pitch = mapPitchToOhosPitch(m_pitch),
+            .languageContext = chineseLanguageContext,
+        });
+}
+
+void QTextToSpeechEngineOhos::synthesize(const QString &)
+{
+    qCWarning(lcSpeechTtsOhos) << Q_FUNC_INFO << ": synthesize feature is not 
supported";
+}
+
+void QTextToSpeechEngineOhos::stop(QTextToSpeech::BoundaryHint)
+{
+    m_ttsProxy->stop();
+}
+
+void QTextToSpeechEngineOhos::pause(QTextToSpeech::BoundaryHint)
+{
+    qCWarning(lcSpeechTtsOhos) << Q_FUNC_INFO << ": pause feature is not 
supported";
+}
+
+void QTextToSpeechEngineOhos::resume()
+{
+    qCWarning(lcSpeechTtsOhos) << Q_FUNC_INFO << ": resume feature is not 
supported";
+}
+
+double QTextToSpeechEngineOhos::rate() const
+{
+    return m_rate;
+}
+
+bool QTextToSpeechEngineOhos::setRate(double rate)
+{
+    m_rate = rate;
+    return true;
+}
+
+double QTextToSpeechEngineOhos::pitch() const
+{
+    return m_pitch;
+}
+
+bool QTextToSpeechEngineOhos::setPitch(double pitch)
+{
+    m_pitch = pitch;
+    return true;
+}
+
+QLocale QTextToSpeechEngineOhos::locale() const
+{
+    return m_currentLocale;
+}
+
+bool QTextToSpeechEngineOhos::setLocale(const QLocale &locale)
+{
+    if (!m_locales.contains(locale))
+        return false;
+
+    m_currentLocale = locale;
+    return true;
+}
+
+double QTextToSpeechEngineOhos::volume() const
+{
+    return m_volume;
+}
+
+bool QTextToSpeechEngineOhos::setVolume(double volume)
+{
+    m_volume = volume;
+    return true;
+}
+
+QVoice QTextToSpeechEngineOhos::voice() const
+{
+    return {};
+}
+
+bool QTextToSpeechEngineOhos::setVoice(const QVoice &)
+{
+    return false;
+}
+
+QTextToSpeech::State QTextToSpeechEngineOhos::state() const
+{
+    return m_state;
+}
+
+QTextToSpeech::ErrorReason QTextToSpeechEngineOhos::errorReason() const
+{
+    qCWarning(lcSpeechTtsOhos) << Q_FUNC_INFO << ": errorReason feature is not 
supported";
+    return QTextToSpeech::ErrorReason::NoError;
+}
+
+QString QTextToSpeechEngineOhos::errorString() const
+{
+    qCWarning(lcSpeechTtsOhos) << Q_FUNC_INFO << ": errorString feature is not 
supported";
+    return QString();
+}
+
+}
+
+QTextToSpeechEngine *createQTextToSpeechEngineOhos(
+    const QVariantMap &parameters, QObject *parent, QString *errorString)
+{
+    auto ttsProxyFactoryOrError = 
CoreSpeechKit::tryMakeTextToSpeechProxyFactory(
+        chineseLanguage, defaultPersonTimbre);
+
+    if (!ttsProxyFactoryOrError) {
+        if (errorString != nullptr)
+            *errorString = 
QString::fromStdString(ttsProxyFactoryOrError.error());
+        return nullptr;
+    }
+    return new QTextToSpeechEngineOhos(
+        parameters, parent, std::move(ttsProxyFactoryOrError.value()));
+}
+
+QT_END_NAMESPACE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos.h 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos.h
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos.h    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos.h    
    2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,21 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#ifndef QTEXTTOSPEECHENGINE_OHOS_H
+#define QTEXTTOSPEECHENGINE_OHOS_H
+
+#include <QtTextToSpeech/qtexttospeechengine.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+QTextToSpeechEngine *createQTextToSpeechEngineOhos(
+    const QVariantMap &parameters, QObject *parent, QString *errorString);
+
+QT_END_NAMESPACE
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.cpp
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.cpp
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.cpp
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.cpp
       2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,19 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#include "qtexttospeech_ohos_plugin.h"
+
+#include "qtexttospeech_ohos.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSpeechTtsOhos, "qt.speech.tts.ohos")
+
+QTextToSpeechEngine *QTextToSpeechOhosPlugin::createTextToSpeechEngine(
+    const QVariantMap &parameters, QObject *parent, QString *errorString) const
+{
+    return createQTextToSpeechEngineOhos(parameters, parent, errorString);
+}
+
+QT_END_NAMESPACE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.h
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.h
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.h
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/ohos/qtexttospeech_ohos_plugin.h
 2026-09-26 19:45:17.000000000 +0200
@@ -0,0 +1,32 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR 
GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#ifndef QTEXTTOSPEECHPLUGIN_OHOS_H
+#define QTEXTTOSPEECHPLUGIN_OHOS_H
+
+#include <QtTextToSpeech/qtexttospeechengine.h>
+#include <QtTextToSpeech/qtexttospeechplugin.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSpeechTtsOhos)
+
+class QTextToSpeechOhosPlugin : public QObject, public QTextToSpeechPlugin
+{
+    Q_OBJECT
+    Q_INTERFACES(QTextToSpeechPlugin)
+    Q_PLUGIN_METADATA(IID "org.qt-project.qt.speech.tts.plugin/6.0"
+        FILE "ohos_plugin.json")
+
+public:
+    QTextToSpeechEngine *createTextToSpeechEngine(
+        const QVariantMap &parameters, QObject *parent, QString *errorString) 
const override;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp
        2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp
        2026-09-26 19:45:17.000000000 +0200
@@ -4,8 +4,9 @@
 
 #include "qtexttospeech_winrt_audiosource.h"
 
-#include <QtCore/QDebug>
-#include <QtCore/QTimer>
+#include <QtCore/qdebug.h>
+#include <QtCore/qspan.h>
+#include <QtCore/qtimer.h>
 
 #include <QtCore/private/qfunctions_winrt_p.h>
 #include <QtCore/private/qsystemerror_p.h>
@@ -91,7 +92,7 @@
 
 qint64 AudioSource::bytesAvailable() const
 {
-    return bytesInBuffer() + QIODevice::bytesAvailable();
+    return m_bufferSpan.size_bytes() + QIODevice::bytesAvailable();
 }
 
 /*
@@ -105,31 +106,18 @@
     if (!maxlen)
         return 0;
 
-    Q_ASSERT(bufferByteAccess);
-
-    qint64 available = bytesInBuffer();
-    maxlen = qMin(available, maxlen);
-
-    if (!maxlen && atEnd())
+    if (m_bufferSpan.isEmpty() && atEnd())
         return -1;
 
-    byte *pbyte = nullptr;
-    bufferByteAccess->Buffer(&pbyte);
-    pbyte += m_bufferOffset;
-
-    // Check and skip the RIFF header if present to prevent an audible
-    // click at the start of playback.
-    if (!m_riffHeaderChecked) {
-        m_riffHeaderChecked = true;
-        static const int WaveHeaderLength = 44;
-        const char *descriptor = reinterpret_cast<const char*>(pbyte);
-        if (maxlen >= WaveHeaderLength && !qstrncmp(descriptor, "RIFF", 4)) {
-            pbyte += WaveHeaderLength;
-            m_bufferOffset += WaveHeaderLength;
-            maxlen -= WaveHeaderLength;
-            available -= WaveHeaderLength;
-        }
-    }
+    auto take = [](auto span, qsizetype n) {
+        return span.first(std::min(span.size(), n));
+    };
+
+    auto drop = [](auto span, qsizetype n) {
+        return span.subspan(std::min(span.size(), n));
+    };
+
+    QSpan source = take(m_bufferSpan, maxlen);
 
     switch (m_pause) {
     case NoPause:
@@ -140,12 +128,11 @@
         if (m_pauseRequestedAt) {
             if (m_pauseRequestedAt <= m_bytesRead) {
                 // we missed the window, pause immediately
-                maxlen = 0;
-            } else if (m_pauseRequestedAt <= m_bytesRead + maxlen) {
-                maxlen = qMax(quint64(0), m_pauseRequestedAt - m_bytesRead) + 
44;
+                source = {};
+            } else if (m_pauseRequestedAt <= m_bytesRead + 
quint64(source.size())) {
+                source = take(source, qsizetype(m_pauseRequestedAt - 
m_bytesRead));
             } else {
-                // wait for the next chunk
-                break;
+                break; // pause point is in a later chunk
             }
             m_pause = Paused;
             m_pauseRequestedAt = 0;
@@ -157,29 +144,26 @@
         // look for a series (e.g. 1/50th of a second) of samples with low
         // absolute values.
         const int silenceDuration = audioFormat.sampleRate() / 50;
-        const short *sample = reinterpret_cast<short*>(pbyte);
-        const qsizetype sampleCount = maxlen / sizeof(short);
+        const auto samples = QSpan(reinterpret_cast<const short 
*>(source.data()),
+                                   source.size() / sizeof(short));
 
-        const bool isInitialPauseRequest = 
!m_pauseDetectionSilenceCount.has_value();
-        if (isInitialPauseRequest)
+        if (!m_pauseDetectionSilenceCount.has_value())
             m_pauseDetectionSilenceCount = 0;
 
-        for (qint64 index = 0; index < sampleCount; ++index) {
-            if (qAbs(sample[index]) < 10) {
+        for (qsizetype i = 0; i < samples.size(); ++i) {
+            if (qAbs(samples[i]) < 10)
                 *m_pauseDetectionSilenceCount += 1;
-            } else {
+            else {
                 *m_pauseDetectionSilenceCount = 0;
                 continue;
             }
-
             if (*m_pauseDetectionSilenceCount > silenceDuration) {
-                // long enough silence found, only provide the data until we 
are in the silence.
-
+                // long enough silence found, only provide data until we are 
in the silence.
                 // we will still try to play at least half of the silent part
-                const int silentSamplesToPlay = silenceDuration / 2;
-                maxlen = index > silentSamplesToPlay ? (index - 
silentSamplesToPlay) * sizeof(short)
-                                                     : index * sizeof(short);
-
+                const qsizetype silentSamplesToPlay = silenceDuration / 2;
+                source = take(source,
+                              (i > silentSamplesToPlay ? i - 
silentSamplesToPlay : i)
+                                      * sizeof(short));
                 m_pause = Paused;
                 m_pauseDetectionSilenceCount = std::nullopt;
                 break;
@@ -196,23 +180,20 @@
     }
     case Paused:
         // starve the sink so that it goes idle
-        maxlen = 0;
-        break;
+        return 0;
     }
 
-    if (!maxlen)
+    if (source.isEmpty())
         return 0;
 
-    memcpy(data, pbyte, maxlen);
+    memcpy(data, source.data(), source.size());
+    m_bufferSpan = drop(m_bufferSpan, source.size());
 
-    // We emptied the buffer, so schedule fetching more
-    if (available <= maxlen)
+    if (m_bufferSpan.isEmpty())
         fetchMore();
-    else
-        m_bufferOffset += maxlen;
 
-    m_bytesRead += maxlen;
-    return maxlen;
+    m_bytesRead += source.size();
+    return source.size();
 }
 
 bool AudioSource::atEnd() const
@@ -401,7 +382,24 @@
 
     HRESULT hr = read->GetResults(&m_buffer);
     RETURN_HR_IF_FAILED("Could not access buffer.");
-    m_bufferOffset = 0;
+
+    m_bufferSpan = [&] {
+        byte *ptr = nullptr;
+        bufferByteAccess->Buffer(&ptr);
+        UINT32 length = 0;
+        m_buffer->get_Length(&length);
+        return QSpan(reinterpret_cast<const char *>(ptr), qsizetype(length));
+    }();
+
+    // Skip the RIFF header in the first buffer to prevent an audible click.
+    constexpr qsizetype WaveHeaderLength = 44;
+    if (!m_headerConsumed) {
+        Q_ASSERT(m_bytesRead == 0);
+        Q_ASSERT(m_bufferSpan.size() >= WaveHeaderLength);
+        Q_ASSERT(QByteArrayView(m_bufferSpan).startsWith("RIFF"));
+        m_bufferSpan = m_bufferSpan.subspan(WaveHeaderLength);
+        m_headerConsumed = true;
+    }
 
     ComPtr<IAsyncInfo> asyncInfo;
     if (HRESULT hr = readOperation.As(&asyncInfo); SUCCEEDED(hr))
@@ -409,22 +407,12 @@
     readOperation.Reset();
 
     // inform the sink that more data has arrived
-    if (m_pause == NoPause && bytesInBuffer())
+    if (m_pause == NoPause && !m_bufferSpan.isEmpty())
         emit readyRead();
 
     return S_OK;
 }
 
-qint64 AudioSource::bytesInBuffer() const
-{
-    if (!m_buffer)
-        return 0;
-
-    UINT32 bytes;
-    m_buffer->get_Length(&bytes);
-    return bytes - m_bufferOffset;
-}
-
 /*
     Starts an asynchronous read operation. There can only be one such
     operation pending at any given time, so fetchMore must only be called
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h
 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h
--- 
old/qtspeech-everywhere-src-6.11.2/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h
  2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h
  2026-09-26 19:45:17.000000000 +0200
@@ -6,6 +6,7 @@
 #define QTEXTTOSPEECHENGINE_WINRT_AUDIOSOURCE_H
 
 #include <QtCore/QIODevice>
+#include <QtCore/qspan.h>
 #include <QtMultimedia/QAudioFormat>
 
 #include <robuffer.h>
@@ -98,7 +99,6 @@
     // we don't destroy by accident, polymorphically, or via a QObject parent
     ~AudioSource() override;
 
-    qint64 bytesInBuffer() const;
     bool fetchMore();
 
     QAudioFormat audioFormat;
@@ -113,12 +113,11 @@
     ComPtr<IBuffer> m_buffer;
     // access to the raw pcm bytes in the IBuffer; this took much reading of 
Windows header files...
     ComPtr<::Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
-    // The data in the IBuffer might be paritally consumed
-    UINT32 m_bufferOffset = 0;
-    // RIFF header has been checked at the beginning of the stream
-    bool m_riffHeaderChecked = false;
+    // Span into the current IBuffer, shrunk as data is consumed
+    QSpan<const char> m_bufferSpan;
     quint64 m_bytesRead = 0;
     quint64 m_pauseRequestedAt = 0;
+    bool m_headerConsumed{};
     std::optional<qint64> m_pauseDetectionSilenceCount;
 
     void populateBoundaries();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/tts/doc/src/qttexttospeech-engines.qdoc 
new/qtspeech-everywhere-src-6.12.0/src/tts/doc/src/qttexttospeech-engines.qdoc
--- 
old/qtspeech-everywhere-src-6.11.2/src/tts/doc/src/qttexttospeech-engines.qdoc  
    2026-08-12 18:34:55.000000000 +0200
+++ 
new/qtspeech-everywhere-src-6.12.0/src/tts/doc/src/qttexttospeech-engines.qdoc  
    2026-09-26 19:45:17.000000000 +0200
@@ -79,6 +79,21 @@
             \li There is no API in Qt to get the list of installed engines.
     \endtable
 
+    \section1 HarmonyOS
+
+    The HarmonyOS engine uses the 
\l{https://developer.huawei.com/consumer/en/doc/harmonyos-references/hms-ai-texttospeech}
+    {Core Speech Kit} text-to-speech APIs.
+    The system engine synthesizes and plays back the speech.
+
+    The Core Speech Kit engine is created for a fixed language, which the 
plugin sets to
+    \c {zh-CN}. As stated in the 
\l{https://developer.huawei.com/consumer/en/doc/harmonyos-references/hms-ai-texttospeech#createengineparams}
+    {createEngine() documentation}, only Chinese and English are supported, 
with
+    \c {zh-CN} recommended for Chinese and \c {en-US} for English.
+
+    \note The HarmonyOS engine only has the 
\l{QTextToSpeech::Capabilities}{Speak}
+    capability. It supports neither 
\l{QTextToSpeech::Capabilities}{PauseResume},
+    \l{QTextToSpeech::Capabilities}{WordByWordProgress}, nor
+    \l{QTextToSpeech::Capabilities}{Synthesize}.
 
     \section1 Flite
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtspeech-everywhere-src-6.11.2/src/tts/qtexttospeech.h 
new/qtspeech-everywhere-src-6.12.0/src/tts/qtexttospeech.h
--- old/qtspeech-everywhere-src-6.11.2/src/tts/qtexttospeech.h  2026-08-12 
18:34:55.000000000 +0200
+++ new/qtspeech-everywhere-src-6.12.0/src/tts/qtexttospeech.h  2026-09-26 
19:45:17.000000000 +0200
@@ -7,12 +7,11 @@
 
 #include <QtCore/qlocale.h>
 #include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
 #include <QtCore/qshareddata.h>
 #include <QtTextToSpeech/qtexttospeech_global.h>
 #include <QtTextToSpeech/qvoice.h>
 
-#include <QtCore/qmap.h>
-
 #include <QtCore/q20type_traits.h>
 
 QT_BEGIN_NAMESPACE

Reply via email to