diff --git a/assets/js/app.js b/assets/js/app.js index 3b14347..78dad45 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -14180,8 +14180,26 @@ async function testTTS() { s.tts_rate = parseFloat(document.getElementById('setting-tts-rate')?.value) || 1; s.tts_pitch = parseFloat(document.getElementById('setting-tts-pitch')?.value) || 1; saveSettingsToStorage(s); + if (statusEl) { statusEl.style.display = 'block'; statusEl.className = 'settings-status'; statusEl.textContent = '⏳ Invio al motore TTS Android...'; } + // Register callbacks: Android will call these after speak completes/fails + let _ttsTestTimer = null; + window._kioskTtsDone = (uid) => { + clearTimeout(_ttsTestTimer); + window._kioskTtsDone = null; window._kioskTtsError = null; + if (statusEl) { statusEl.className = 'settings-status success'; statusEl.textContent = '✅ Voce riprodotta correttamente.'; } + }; + window._kioskTtsError = (uid, code) => { + clearTimeout(_ttsTestTimer); + window._kioskTtsDone = null; window._kioskTtsError = null; + const msg = code == -1 ? 'sintesi non riuscita' : code == -2 ? 'lingua non supportata' : code == -3 ? 'servizio non disponibile' : ('codice ' + code); + if (statusEl) { statusEl.className = 'settings-status error'; statusEl.textContent = '❌ Errore TTS Android (' + msg + ') — installa o aggiorna Google Text-to-Speech dal Play Store.'; } + }; + // Timeout: if Android doesn't callback within 4s, warn about media volume + _ttsTestTimer = setTimeout(() => { + window._kioskTtsDone = null; window._kioskTtsError = null; + if (statusEl) { statusEl.className = 'settings-status error'; statusEl.textContent = '⚠️ Nessun feedback ricevuto. Controlla: 1) volume media del dispositivo non sia 0; 2) Google Text-to-Speech installato e aggiornato; 3) pacchetto vocale italiano scaricato.'; } + }, 4000); _speakBrowser('Test vocale EverShelf. La sintesi vocale funziona correttamente.'); - if (statusEl) { statusEl.style.display = 'block'; statusEl.className = 'settings-status success'; statusEl.textContent = '✅ Riproduzione in corso — controlla l\'audio del dispositivo.'; } return; } if (!window.speechSynthesis) { diff --git a/evershelf-kiosk/app/src/main/kotlin/it/dadaloop/evershelf/kiosk/KioskActivity.kt b/evershelf-kiosk/app/src/main/kotlin/it/dadaloop/evershelf/kiosk/KioskActivity.kt index b276849..08dbbf8 100644 --- a/evershelf-kiosk/app/src/main/kotlin/it/dadaloop/evershelf/kiosk/KioskActivity.kt +++ b/evershelf-kiosk/app/src/main/kotlin/it/dadaloop/evershelf/kiosk/KioskActivity.kt @@ -18,7 +18,9 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.provider.Settings +import android.media.AudioManager import android.speech.tts.TextToSpeech +import android.speech.tts.UtteranceProgressListener import android.view.View import android.view.WindowInsets import android.view.WindowInsetsController @@ -144,6 +146,25 @@ class KioskActivity : AppCompatActivity() { if (res == TextToSpeech.LANG_MISSING_DATA || res == TextToSpeech.LANG_NOT_SUPPORTED) { tts?.language = Locale.getDefault() } + tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() { + override fun onStart(utteranceId: String?) {} + override fun onDone(utteranceId: String?) { + runOnUiThread { + webView.evaluateJavascript("if(window._kioskTtsDone)window._kioskTtsDone('$utteranceId')", null) + } + } + @Deprecated("Deprecated in API 21") + override fun onError(utteranceId: String?) { + runOnUiThread { + webView.evaluateJavascript("if(window._kioskTtsError)window._kioskTtsError('$utteranceId','error')", null) + } + } + override fun onError(utteranceId: String?, errorCode: Int) { + runOnUiThread { + webView.evaluateJavascript("if(window._kioskTtsError)window._kioskTtsError('$utteranceId',$errorCode)", null) + } + } + }) ttsReady = true } } @@ -466,7 +487,10 @@ class KioskActivity : AppCompatActivity() { if (!ttsReady) return engine.setSpeechRate(rate.coerceIn(0.1f, 4f)) engine.setPitch(pitch.coerceIn(0.1f, 4f)) - engine.speak(text, android.speech.tts.TextToSpeech.QUEUE_FLUSH, null, "kiosk_tts") + val params = Bundle().apply { + putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC) + } + engine.speak(text, TextToSpeech.QUEUE_FLUSH, params, "kiosk_tts") } @JavascriptInterface fun stopSpeech() { tts?.stop() }