FS#13977 - rbutil: fix SAPI5 TTS test output and playback (Alessio Lenzi)
rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
| Newsgroups | gmane.comp.systems.archos.rockbox.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit 21e95258f2d3f7c8c62cd01872afe9926301bf8d Author: Solomon Peachy <[email protected]> Date: Sun Aug 9 08:00:50 2026 -0400 FS#13977 - rbutil: fix SAPI5 TTS test output and playback (Alessio Lenzi) After the SAPI5 error handling added for FS#13972, the Test TTS button can fail with SAPI error 5 even though the engine and voice are configured correctly. The test also destroys its QSoundEffect and temporary file before asynchronous playback can complete. Config::testTts() used a QTemporaryFile with no .wav extension. TTSSapi::voice() removes the requested output before synthesis so that a stale file cannot be mistaken for successful output. SAPI SpFileStream was therefore asked to create an extensionless output file and returned error 5 (invalid procedure call or argument). After successful synthesis, QSoundEffect was allocated on the stack, its loop count was set to zero, and the temporary file was removed when testTts() returned. This does not allow asynchronous playback to complete reliably. * create a temporary directory and requests an initially nonexistent tts-test.wav inside it; * keep the directory and generated wave file alive for playback; * keep QSoundEffect alive until playback finishes or fails; * request one playback and clean up all temporary data afterward. Change-Id: I8e482ab846e6445889118e121025ec48d3776d6b diff --git a/utils/rbutilqt/configure.cpp b/utils/rbutilqt/configure.cpp index 7b6d634c3f..d8a2a5a4c2 100644 --- a/utils/rbutilqt/configure.cpp +++ b/utils/rbutilqt/configure.cpp @@ -939,17 +939,20 @@ void Config::testTts() } QString filename; - QTemporaryFile file(this); + QTemporaryDir* tempDir = nullptr; // keep filename empty if the TTS can do speaking for itself. if(!(tts->capabilities() & TTSBase::CanSpeak)) { - file.open(); - filename = file.fileName(); - file.close(); + // SAPI's SpFileStream requires a filename with a wave extension. + // Give the engine a path that does not exist yet, matching normal + // voice-file generation, and keep its directory until playback ends. + tempDir = new QTemporaryDir(); + filename = tempDir->filePath("tts-test.wav"); } if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError) { tts->stop(); + delete tempDir; QMessageBox::warning(this,tr("Could not voice test string."), tr("Could not voice test string.\n") + errstr + tr("\nPlease configure TTS engine.")); @@ -957,17 +960,28 @@ void Config::testTts() return; } tts->stop(); - if(!filename.isEmpty()) { - QSoundEffect effect; - effect.setSource(QUrl::fromLocalFile(filename)); - effect.setLoopCount(0); - effect.setVolume(1.0f); - effect.play(); - } ui.testTTS->setEnabled(true); delete tts; /* Config objects are never deleted (in fact, they are leaked..), so we can't rely on QObject, since that would delete the TTSBase instance on application exit */ + if(tempDir != nullptr) { + QSoundEffect* effect = new QSoundEffect(this); + connect(effect, &QObject::destroyed, [tempDir]() { + delete tempDir; + }); + connect(effect, &QSoundEffect::playingChanged, effect, [effect]() { + if(!effect->isPlaying()) + effect->deleteLater(); + }); + connect(effect, &QSoundEffect::statusChanged, effect, [effect]() { + if(effect->status() == QSoundEffect::Error) + effect->deleteLater(); + }); + effect->setSource(QUrl::fromLocalFile(filename)); + effect->setLoopCount(1); + effect->setVolume(1.0f); + effect->play(); + } #endif } -- rockbox-cvs mailing list [email protected] https://lists.haxx.se/mailman/listinfo/rockbox-cvs