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 2023-12-04 23:00:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qt6-speech (Old) and /work/SRC/openSUSE:Factory/.qt6-speech.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "qt6-speech" Mon Dec 4 23:00:20 2023 rev:11 rq:1130430 version:6.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/qt6-speech/qt6-speech.changes 2023-10-13 23:15:19.996456401 +0200 +++ /work/SRC/openSUSE:Factory/.qt6-speech.new.25432/qt6-speech.changes 2023-12-04 23:00:37.201697154 +0100 @@ -1,0 +2,6 @@ +Mon Nov 27 14:00:19 UTC 2023 - Christophe Marin <[email protected]> + +- Update to 6.6.1: + * https://www.qt.io/blog/qt-6.6.1-released + +------------------------------------------------------------------- Old: ---- qtspeech-everywhere-src-6.6.0.tar.xz New: ---- qtspeech-everywhere-src-6.6.1.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qt6-speech.spec ++++++ --- /var/tmp/diff_new_pack.crz4RT/_old 2023-12-04 23:00:37.845719916 +0100 +++ /var/tmp/diff_new_pack.crz4RT/_new 2023-12-04 23:00:37.845719916 +0100 @@ -16,7 +16,7 @@ # -%define real_version 6.6.0 +%define real_version 6.6.1 %define short_version 6.6 %define tar_name qtspeech-everywhere-src %define tar_suffix %{nil} @@ -27,7 +27,7 @@ %endif # Name: qt6-speech%{?pkg_suffix} -Version: 6.6.0 +Version: 6.6.1 Release: 0 Summary: Qt 6 TextToSpeech Library and Plugin License: LGPL-3.0-only OR (GPL-2.0-only OR GPL-3.0-or-later) ++++++ qtspeech-everywhere-src-6.6.0.tar.xz -> qtspeech-everywhere-src-6.6.1.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/.cmake.conf new/qtspeech-everywhere-src-6.6.1/.cmake.conf --- old/qtspeech-everywhere-src-6.6.0/.cmake.conf 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/.cmake.conf 2023-11-20 22:06:39.000000000 +0100 @@ -1,2 +1,2 @@ -set(QT_REPO_MODULE_VERSION "6.6.0") +set(QT_REPO_MODULE_VERSION "6.6.1") set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/.tag new/qtspeech-everywhere-src-6.6.1/.tag --- old/qtspeech-everywhere-src-6.6.0/.tag 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/.tag 2023-11-20 22:06:39.000000000 +0100 @@ -1 +1 @@ -f3916f5c43c8abab354b79317a5f3bfd100ceb23 +311ef13dd5c4fffbfd6ae6dd15e4b9601087da57 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/CMakeLists.txt new/qtspeech-everywhere-src-6.6.1/CMakeLists.txt --- old/qtspeech-everywhere-src-6.6.0/CMakeLists.txt 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/CMakeLists.txt 2023-11-20 22:06:39.000000000 +0100 @@ -13,8 +13,14 @@ LANGUAGES CXX C ) -find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Multimedia) -find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Gui Widgets Test QuickTest Qml) +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core) +find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Gui Multimedia Widgets Test QuickTest Qml) + +if(NOT TARGET Qt6::Multimedia) + message(NOTICE "Skipping the build as the condition \"TARGET Qt6::Multimedia\" is not met.") + return() +endif() + qt_internal_project_setup() qt_build_repo() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/dependencies.yaml new/qtspeech-everywhere-src-6.6.1/dependencies.yaml --- old/qtspeech-everywhere-src-6.6.0/dependencies.yaml 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/dependencies.yaml 2023-11-20 22:06:39.000000000 +0100 @@ -1,10 +1,10 @@ dependencies: ../qtbase: - ref: 33f5e985e480283bb0ca9dea5f82643e825ba87c + ref: e2cbce919ccefcae2b18f90257d67bc6e24c3c94 required: true ../qtdeclarative: - ref: e559d5cf2b66c4a973f83f173d57676a21d287ef + ref: 30cb9f48bacdd8092b2264e6067476cafb2d7e39 required: false ../qtmultimedia: - ref: fcb9950381ab8a5647d121fd9b305e4d9d734402 + ref: 5f78c51aea34666b0440533eddc7f2b5f0a350dc required: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/examples/speech/hello_speak/mainwindow.cpp new/qtspeech-everywhere-src-6.6.1/examples/speech/hello_speak/mainwindow.cpp --- old/qtspeech-everywhere-src-6.6.0/examples/speech/hello_speak/mainwindow.cpp 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/examples/speech/hello_speak/mainwindow.cpp 2023-11-20 22:06:39.000000000 +0100 @@ -70,12 +70,31 @@ void MainWindow::engineSelected(int index) { - QString engineName = ui.engine->itemData(index).toString(); + ui.engine->setEnabled(false); + + const QString engineName = ui.engine->itemData(index).toString(); delete m_speech; m_speech = engineName == u"default" ? new QTextToSpeech(this) : new QTextToSpeech(engineName, this); + // some engines initialize asynchronously + if (m_speech->state() == QTextToSpeech::Ready) { + onEngineReady(); + } else { + connect(m_speech, &QTextToSpeech::stateChanged, this, &MainWindow::onEngineReady, + Qt::SingleShotConnection); + } +} + +void MainWindow::onEngineReady() +{ + ui.engine->setEnabled(true); + if (m_speech->state() != QTextToSpeech::Ready) { + stateChanged(m_speech->state()); + return; + } + const bool hasPauseResume = m_speech->engineCapabilities() & QTextToSpeech::Capability::PauseResume; ui.pauseButton->setVisible(hasPauseResume); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/examples/speech/hello_speak/mainwindow.h new/qtspeech-everywhere-src-6.6.1/examples/speech/hello_speak/mainwindow.h --- old/qtspeech-everywhere-src-6.6.0/examples/speech/hello_speak/mainwindow.h 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/examples/speech/hello_speak/mainwindow.h 2023-11-20 22:06:39.000000000 +0100 @@ -28,6 +28,8 @@ void localeChanged(const QLocale &locale); private: + void onEngineReady(); + Ui::MainWindow ui; QTextToSpeech *m_speech = nullptr; QList<QVoice> m_voices; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/examples/speech/quickspeech/Main.qml new/qtspeech-everywhere-src-6.6.1/examples/speech/quickspeech/Main.qml --- old/qtspeech-everywhere-src-6.6.0/examples/speech/quickspeech/Main.qml 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/examples/speech/quickspeech/Main.qml 2023-11-20 22:06:39.000000000 +0100 @@ -22,7 +22,10 @@ //! [initialize] //! [stateChanged] - onStateChanged: (state) => { + onStateChanged: updateStateLabel(state) + + function updateStateLabel(state) + { switch (state) { case TextToSpeech.Ready: statusLabel.text = qsTr("Ready") @@ -173,10 +176,24 @@ Component.onCompleted: { enginesComboBox.currentIndex = tts.availableEngines().indexOf(tts.engine) + // some engines initialize asynchronously + if (tts.state == TextToSpeech.Ready) { + engineReady() + } else { + tts.stateChanged.connect(root.engineReady) + } + + tts.updateStateLabel(tts.state) + } + + function engineReady() { + tts.stateChanged.disconnect(root.engineReady) + if (tts.state != TextToSpeech.Ready) { + tts.updateStateLabel(tts.state) + return; + } updateLocales() updateVoices() - - tts.onStateChanged(tts.state) } function updateLocales() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/examples/speech/quickspeech/doc/src/quickspeech.qdoc new/qtspeech-everywhere-src-6.6.1/examples/speech/quickspeech/doc/src/quickspeech.qdoc --- old/qtspeech-everywhere-src-6.6.0/examples/speech/quickspeech/doc/src/quickspeech.qdoc 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/examples/speech/quickspeech/doc/src/quickspeech.qdoc 2023-11-20 22:06:39.000000000 +0100 @@ -31,7 +31,7 @@ Switch cases are used to update the Label \c statusLabel in the footer. - \skipto onStateChanged: (state) + \skipto onStateChanged: updateStateLabel(state) \printuntil } \section1 Highlighting words as they are spoken diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/CMakeLists.txt new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/CMakeLists.txt --- old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/CMakeLists.txt 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/CMakeLists.txt 2023-11-20 22:06:39.000000000 +0100 @@ -7,7 +7,7 @@ endif() if(WIN32) add_subdirectory(sapi) - if(TARGET Qt::Multimedia AND NOT MINGW) + if(NOT MINGW) add_subdirectory(winrt) endif() endif() @@ -20,6 +20,6 @@ if(ANDROID) add_subdirectory(android) endif() -if(QT_FEATURE_flite AND TARGET Qt::Multimedia) +if(QT_FEATURE_flite) add_subdirectory(flite) endif() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/sapi/qtexttospeech_sapi.cpp new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/sapi/qtexttospeech_sapi.cpp --- old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/sapi/qtexttospeech_sapi.cpp 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/sapi/qtexttospeech_sapi.cpp 2023-11-20 22:06:39.000000000 +0100 @@ -563,7 +563,7 @@ m_state = QTextToSpeech::Ready; break; case SPEI_WORD_BOUNDARY: - emit sayingWord(currentText.sliced(event.lParam - textOffset, event.wParam), + emit sayingWord(currentText.sliced(event.lParam, event.wParam), event.lParam - textOffset, event.wParam); break; // these are the other TTS events which might be interesting for us at some point diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt.cpp new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt.cpp --- old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt.cpp 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt.cpp 2023-11-20 22:06:39.000000000 +0100 @@ -423,7 +423,8 @@ elapsedTimer.invalidate(); } else { boundaryTimer.stop(); - playedTime += elapsedTimer.nsecsElapsed() / 1000; + if (elapsedTimer.isValid()) + playedTime += elapsedTimer.nsecsElapsed() / 1000; elapsedTimer.invalidate(); audioSink->suspend(); } @@ -442,7 +443,8 @@ state = QTextToSpeech::Speaking; break; case QAudio::SuspendedState: - state = QTextToSpeech::Paused; + if (audioSource->m_pause != AudioSource::NoPause) + state = QTextToSpeech::Paused; break; } if (state != oldState) @@ -546,11 +548,41 @@ void QTextToSpeechEngineWinRT::pause(QTextToSpeech::BoundaryHint boundaryHint) { - Q_UNUSED(boundaryHint); Q_D(QTextToSpeechEngineWinRT); - if (d->audioSource) - d->audioSource->pause(); + if (!d->audioSource) + return; + + auto pauseBoundaryType = AudioSource::Boundary::Unknown; + switch (boundaryHint) { + case QTextToSpeech::BoundaryHint::Default: + d->audioSource->pause(0); + return; + case QTextToSpeech::BoundaryHint::Immediate: + d->audioSource->pause(0); + if (d->audioSink) + d->audioSink->suspend(); + return; + case QTextToSpeech::BoundaryHint::Word: + pauseBoundaryType = AudioSource::Boundary::Word; + break; + case QTextToSpeech::BoundaryHint::Sentence: + pauseBoundaryType = AudioSource::Boundary::Sentence; + break; + case QTextToSpeech::BoundaryHint::Utterance: + // taken care off by engine-independent implementation + return; + } + + // find the next boundary of the matching type + const auto nextBoundary = std::find_if(d->currentBoundary + 1, d->boundaries.constEnd(), + [pauseBoundaryType](auto &&it){ + return it.type == pauseBoundaryType; + }); + if (nextBoundary != d->boundaries.constEnd()) { + d->audioSource->pause(d->audioSource->format() + .bytesForDuration(nextBoundary->startTime)); + } } void QTextToSpeechEngineWinRT::resume() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp --- old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.cpp 2023-11-20 22:06:39.000000000 +0100 @@ -107,7 +107,7 @@ Q_ASSERT(bufferByteAccess); - const qint64 available = bytesInBuffer(); + qint64 available = bytesInBuffer(); maxlen = qMin(available, maxlen); if (!maxlen && atEnd()) @@ -127,6 +127,7 @@ pbyte += WaveHeaderLength; m_bufferOffset += WaveHeaderLength; maxlen -= WaveHeaderLength; + available -= WaveHeaderLength; } } @@ -135,15 +136,34 @@ break; case PauseRequested: { Q_ASSERT(audioFormat.sampleFormat() == QAudioFormat::Int16); - // we are dealing with artificially created sound, so we don't have + + 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; + } else { + // wait for the next chunk + break; + } + m_pause = Paused; + m_pauseRequestedAt = 0; + break; + } + // If no byte to pause at is specified, look for silence in the current + // chunk. We are dealing with artificially created sound, so we don't have // to find a large enough window with overall low energy; we can just - // look for a series (e.g. 1/20th of a second) of samples with value 0. - const int silenceDuration = audioFormat.sampleRate() / 20; + // 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); + if (sampleCount < silenceDuration) + break; qint64 silenceCount = 0; for (qint64 index = 0; index < sampleCount; ++index) { - if (!sample[index]) { + if (qAbs(sample[index]) < 10) { ++silenceCount; } else if (silenceCount > silenceDuration) { // long enough silence found, only provide the data until we are in the @@ -161,6 +181,9 @@ silenceCount = 0; } } + // no silence found - stop after this chunk + if (m_pause != Paused) + m_pause = Paused; break; } case Paused: @@ -180,6 +203,7 @@ else m_bufferOffset += maxlen; + m_bytesRead += maxlen; return maxlen; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h --- old/qtspeech-everywhere-src-6.6.0/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/plugins/tts/winrt/qtexttospeech_winrt_audiosource.h 2023-11-20 22:06:39.000000000 +0100 @@ -51,14 +51,16 @@ Paused } m_pause = NoPause; - void pause() + void pause(quint64 atByte) { m_pause = PauseRequested; + m_pauseRequestedAt = atByte; } void resume() { m_pause = NoPause; + m_pauseRequestedAt = 0; if (bytesAvailable()) emit readyRead(); } @@ -126,6 +128,8 @@ UINT32 m_bufferOffset = 0; // RIFF header has been checked at the beginning of the stream bool m_riffHeaderChecked = false; + quint64 m_bytesRead = 0; + quint64 m_pauseRequestedAt = 0; void populateBoundaries(); QList<Boundary> boundaries; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/tts/configure.cmake new/qtspeech-everywhere-src-6.6.1/src/tts/configure.cmake --- old/qtspeech-everywhere-src-6.6.0/src/tts/configure.cmake 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/tts/configure.cmake 2023-11-20 22:06:39.000000000 +0100 @@ -20,19 +20,13 @@ #### Features -if (Flite_FOUND AND NOT TARGET Qt::Multimedia) - message(WARNING - "Flite was found, but Qt::Multimedia is not configured.\n" - "The Flite engine will be disabled.") -endif() - qt_feature("flite" PRIVATE LABEL "Flite" - CONDITION Flite_FOUND AND TARGET Qt::Multimedia + CONDITION Flite_FOUND ) qt_feature("flite_alsa" PRIVATE LABEL "Flite with ALSA" - CONDITION Flite_FOUND AND ALSA_FOUND AND TARGET Qt::Multimedia + CONDITION Flite_FOUND AND ALSA_FOUND ) qt_feature("speechd" PUBLIC LABEL "Speech Dispatcher" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/src/tts/doc/qttexttospeech.qdocconf new/qtspeech-everywhere-src-6.6.1/src/tts/doc/qttexttospeech.qdocconf --- old/qtspeech-everywhere-src-6.6.0/src/tts/doc/qttexttospeech.qdocconf 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/src/tts/doc/qttexttospeech.qdocconf 2023-11-20 22:06:39.000000000 +0100 @@ -56,3 +56,6 @@ navigation.landingpage = "Qt TextToSpeech" navigation.cppclassespage = "Qt TextToSpeech C++ Classes" navigation.qmltypespage = "Qt TextToSpeech QML Types" + +# Highlighted examples in Data Processing & IO category +manifestmeta.highlighted.names = "QtTextToSpeech/Quick Speech" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/tests/auto/qtexttospeech/CMakeLists.txt new/qtspeech-everywhere-src-6.6.1/tests/auto/qtexttospeech/CMakeLists.txt --- old/qtspeech-everywhere-src-6.6.0/tests/auto/qtexttospeech/CMakeLists.txt 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/tests/auto/qtexttospeech/CMakeLists.txt 2023-11-20 22:06:39.000000000 +0100 @@ -1,11 +1,6 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -if(NOT TARGET Qt::Multimedia) - message(WARNING "The test case requires Qt::Multimedia to verify the presence of audio devices") - return() -endif() - qt_internal_add_test(tst_qtexttospeech SOURCES tst_qtexttospeech.cpp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtspeech-everywhere-src-6.6.0/tests/auto/qtexttospeech/tst_qtexttospeech.cpp new/qtspeech-everywhere-src-6.6.1/tests/auto/qtexttospeech/tst_qtexttospeech.cpp --- old/qtspeech-everywhere-src-6.6.0/tests/auto/qtexttospeech/tst_qtexttospeech.cpp 2023-10-04 00:00:46.000000000 +0200 +++ new/qtspeech-everywhere-src-6.6.1/tests/auto/qtexttospeech/tst_qtexttospeech.cpp 2023-11-20 22:06:39.000000000 +0100 @@ -901,11 +901,10 @@ void tst_QTextToSpeech::synthesize() { QFETCH_GLOBAL(QString, engine); - if (engine != "mock" && !hasDefaultAudioOutput()) - QSKIP("No audio device present"); - QFETCH(QString, text); + const bool canCheckDuration = engine == "mock" || hasDefaultAudioOutput(); + QTextToSpeech tts(engine); if (!(tts.engineCapabilities() & QTextToSpeech::Capability::Synthesize)) QSKIP("This engine doesn't support synthesize()"); @@ -934,13 +933,15 @@ } }); - // first, measure how long it takes to speak the text - tts.say(text); - QTRY_VERIFY(running); - QTRY_VERIFY(finished); + // first, measure how long it takes to speak the text. We can't do that if we + // can't play audio. + if (canCheckDuration) { + tts.say(text); + QTRY_VERIFY(running); + QTRY_VERIFY(finished); + } running = false; - QAudioFormat pcmFormat; QByteArray pcmData; @@ -955,16 +956,20 @@ QTRY_VERIFY(finished); QVERIFY(pcmFormat.isValid()); - // bytesForDuration takes micro seconds, we measured in milliseconds. - const qint32 bytesExpected = pcmFormat.bytesForDuration(speechTime * 1000); + QVERIFY(!pcmData.isEmpty()); - // We should have as much data as the format requires for the time it took - // to play the speech, +/- 10% as we can't measure the exact audio duration. - QCOMPARE_GE(pcmData.size(), double(bytesExpected) * 0.9); - if (engine == "flite") // flite is very unreliable - QCOMPARE_LT(pcmData.size(), double(bytesExpected) * 1.5); - else - QCOMPARE_LT(pcmData.size(), double(bytesExpected) * 1.1); + if (canCheckDuration) { + // bytesForDuration takes micro seconds, we measured in milliseconds. + const qint32 bytesExpected = pcmFormat.bytesForDuration(speechTime * 1000); + + // We should have as much data as the format requires for the time it took + // to play the speech, +/- 10% as we can't measure the exact audio duration. + QCOMPARE_GE(pcmData.size(), double(bytesExpected) * 0.9); + if (engine == "flite") // flite is very unreliable + QCOMPARE_LT(pcmData.size(), double(bytesExpected) * 1.5); + else + QCOMPARE_LT(pcmData.size(), double(bytesExpected) * 1.1); + } } /*!
