API du pont JavaScript
Synthèse vocale
Les voix de l'appareil, lues depuis la page.
SpeechRecognition standard web#
webkitSpeechRecognition / SpeechRecognition — speech to text
Exemple
L'API Web Speech standard pour la dictée : l'utilisateur parle, la page reçoit du texte. Chrome sur Android l'a et la WebView d'Android non, donc l'application la fournit au-dessus du module de reconnaissance vocale d'Android. Le code écrit pour Chrome fonctionne sans modification.
Renvoie : start() commence l'écoute ; les événements result portent event.results[i][0].transcript (et .confidence, .isFinal) ; les événements error portent event.error (not-allowed, no-speech, audio-capture, network, aborted, language-not-supported, service-not-allowed) ; end arrive toujours en dernier. Nécessite : le microphone. La compilation l'active d'elle-même quand votre code mentionne SpeechRecognition, et Android demande à l'utilisateur la première fois que start() s'exécute.
<button id="mic">Dictate</button>
<textarea id="note"></textarea>
<script>
const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
const mic = document.getElementById('mic');
if (!Rec) {
mic.hidden = true; // no speech recogniser on this phone
} else {
mic.addEventListener('click', () => {
const rec = new Rec();
rec.lang = 'en-IN'; // leave empty for the page / phone language
rec.interimResults = true; // live text while the user speaks
rec.onresult = (e) => {
let text = '';
for (const r of e.results) text += r[0].transcript;
document.getElementById('note').value = text;
};
rec.onerror = (e) => {
if (e.error === 'not-allowed') alert('Allow the microphone to dictate.');
};
rec.onend = () => { mic.disabled = false; };
mic.disabled = true;
rec.start();
});
}
</script>Dictée continue qui s'arrête sur demande et signale chaque erreur :
const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
let rec = null;
function toggleDictation() {
if (!Rec) return showMessage('Voice typing is not available on this phone.');
if (rec) { rec.stop(); return; } // stop() delivers what was heard
rec = new Rec();
rec.continuous = true;
rec.onresult = (e) => {
for (let i = e.resultIndex; i < e.results.length; i++) {
if (e.results[i].isFinal) appendToNote(e.results[i][0].transcript);
}
};
rec.onerror = (e) => {
const msg = { 'not-allowed': 'Allow the microphone first.', 'no-speech': 'Nothing was heard.',
'audio-capture': 'No microphone found.', 'network': 'Speech service unreachable.' }[e.error];
if (msg) showMessage(msg);
};
rec.onend = () => { rec = null; };
rec.start();
}Dire une commande et agir en conséquence, dans la langue du téléphone :
const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
function listenForCommand() {
if (!Rec) return;
const rec = new Rec();
rec.lang = navigator.language;
rec.onresult = (e) => {
const said = e.results[0][0].transcript.toLowerCase();
if (said.includes('next')) goNext();
else if (said.includes('back')) goBack();
else showMessage('Heard: ' + said);
};
rec.onerror = (e) => {
if (e.error === 'language-not-supported') showMessage('This language is not supported here.');
};
rec.start();
}Remarques : continuous = true continue d'écouter à travers les phrases jusqu'à ce que vous appeliez stop() ; après trois tours silencieux, il se termine avec no-speech, afin qu'un module de reconnaissance oublié n'écoute pas indéfiniment. stop() transmet ce qui a été entendu ; abort() l'abandonne. La reconnaissance s'arrête quand l'application passe en arrière-plan, comme quand un onglet Chrome est masqué. Seules les pages appartenant à l'application (ses propres fichiers, ou le site du créateur) peuvent utiliser le microphone de cette façon ; tout autre site obtient not-allowed. L'API est absente quand le téléphone n'a pas de service de reconnaissance vocale ; vérifiez donc sa présence comme ci-dessus. Transports internes : __srStart, __srStop, __srAbort, __srAvailable ; les résultats arrivent sous forme de appmint:sr. Les applications créées avec l'IA utilisent speech.start() depuis @/lib/appmintNative.
speechSynthesis standard web#
window.speechSynthesis + SpeechSynthesisUtterance
Exemple
Lit du texte à voix haute avec le moteur de synthèse vocale du téléphone, en utilisant l'API Web Speech habituelle.
Renvoie : speechSynthesis.speak(u) ne renvoie rien ; les événements start / boundary / end / error / pause / resume de l'énoncé (comme propriétés onstart … ou avec addEventListener) vous disent ce qui s'est passé. getVoices() renvoie de façon synchrone un tableau de { voiceURI, name, lang, localService, default }. Nécessite : rien. La WebView Android n'a aucune API vocale fonctionnelle ; l'application installe celle-ci au démarrage du document dans chaque frame.
Dire une phrase et savoir quand c'est terminé :
function say(text) {
if (!('speechSynthesis' in window)) { alert('Speech is not available here'); return; }
var u = new SpeechSynthesisUtterance(text);
u.lang = 'en-US'; // BCP-47 tag: 'ta-IN', 'hi-IN', 'fr-FR' ...
u.rate = 1.2; // 0.1 .. 4 (1 = normal)
u.pitch = 1; // 0.1 .. 4 (1 = normal)
u.onstart = function () { document.body.classList.add('speaking'); };
u.onend = function () { document.body.classList.remove('speaking'); };
u.onerror = function (e) {
document.body.classList.remove('speaking');
console.log('Speech failed:', e.error); // 'synthesis-failed'
};
speechSynthesis.speak(u); // queues after anything already speaking
}
document.getElementById('stop').onclick = function () {
if ('speechSynthesis' in window) speechSynthesis.cancel(); // stops now, clears the queue
};Les voix arrivent un instant après le démarrage. Relisez-les quand voiceschanged se déclenche :
var voices = [];
function loadVoices() {
voices = speechSynthesis.getVoices(); // [] until the engine is ready
var tamil = voices.filter(function (v) { return v.lang.indexOf('ta') === 0; });
document.getElementById('tamil-btn').hidden = tamil.length === 0;
}
if ('speechSynthesis' in window) {
loadVoices();
speechSynthesis.addEventListener('voiceschanged', loadVoices);
}
function sayWithVoice(text, voice) {
var u = new SpeechSynthesisUtterance(text);
u.voice = voice; // a voice from getVoices(): that exact voice is used
u.volume = 0.8; // 0 .. 1
speechSynthesis.speak(u);
}Un lecteur d'article avec un seul bouton Pause / Reprendre qui met en évidence le paragraphe en cours de lecture :
var toggle = document.getElementById('pause-toggle');
toggle.onclick = function () {
if (!('speechSynthesis' in window) || !speechSynthesis.speaking) return;
if (speechSynthesis.paused) speechSynthesis.resume(); // continues from the last word
else speechSynthesis.pause();
};
function readArticle() {
if (!('speechSynthesis' in window)) return;
speechSynthesis.cancel(); // start over
document.querySelectorAll('article p').forEach(function (p) {
var u = new SpeechSynthesisUtterance(p.textContent);
u.onstart = function () { p.classList.add('reading'); };
u.onend = u.onerror = function () { p.classList.remove('reading'); };
u.onpause = function () { toggle.textContent = 'Resume'; };
u.onresume = function () { toggle.textContent = 'Pause'; };
speechSynthesis.speak(u); // paragraphs queue in order
});
toggle.textContent = 'Pause';
}Remarques :
volume(0-1),voice(la voix exacte provenant degetVoices()),rate,pitchetlangparviennent tous au moteur du téléphone. Avec unevoiceet unelang, la voix l'emporte ; avec aucune des deux, la voix par défaut du moteur parle.boundaryse déclenche avant chaque mot aveccharIndex/charLength(Android 8+ ; les moteurs qui ne signalent pas de positions de mots n'en envoient pas).pause()/resume(): Le moteur d'Android ne peut pas faire de pause au milieu d'un mot, doncpause()l'arrête etresume()dit le reste de la phrase à partir du dernier mot signalé par le moteur (les événementspause/resumese déclenchent). Sur un moteur qui ne signale pas de positions de mots,resume()relance cet énoncé depuis son début.speakingrestetruependant la pause ;pendingvauttruetant que des énoncés en file attendent.cancel()déclencheerroravecerror: 'interrupted'sur l'énoncé en cours de lecture et'canceled'sur ceux en file, comme le dit le standard : ne les présentez pas comme des échecs.- Si le téléphone n'a pas de données vocales pour la langue, le moteur peut quand même parler dans sa langue par défaut. Vérifiez d'abord
getVoices()pour la langue. - Les événements bruts derrière cela sont
appmint:tts(voirttsSpeak). Vous n'en avez pas besoin quand vous utilisez cette API.
__srAbort pont#
window.WebToApk.__srAbort(id: String)
SpeechRecognition.abort() : arrête immédiatement, sans conserver.
Exemple
Documenté avec WebToApk.__srStart : l'exemple qui s'y trouve illustre aussi celui-ci.
Transport interne derrière webkitSpeechRecognition / SpeechRecognition (démarrer, arrêter, abandonner, et savoir si un module de reconnaissance existe sur le téléphone). Les pages utilisent l'API standard ; n'appelez jamais ceux-ci directement, car les méthodes __ peuvent changer sans préavis.
Renvoie : __srStart(id, options) renvoie "" quand l'écoute démarre, ou un nom d'erreur Web Speech (not-allowed, service-not-allowed). Tout le reste arrive sous forme d'événements appmint:sr : {id, type} pour start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, et {id, type:'error', error}. Nécessite : le microphone (armé d'après la forme de l'appel).
Utilisez l'API publique :
const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();Dictée continue avec texte en direct et une langue :
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
const rec = new SR();
rec.lang = 'en-US';
rec.continuous = true;
rec.interimResults = true;
rec.onresult = (e) => {
const r = e.results[e.results.length - 1];
note.value = r[0].transcript + (r.isFinal ? '\n' : '');
};
micBtn.onclick = () => rec.start();
stopBtn.onclick = () => rec.stop();
}Signaler les erreurs, comme un microphone refusé :
rec.onerror = (e) => {
if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');Remarques : Implémenté dans le shell de l'application (SpeechRecognitionBridge.kt) au-dessus du SpeechRecognizer d'Android. __srStart est refusé pour les pages qui n'appartiennent pas à l'application.
__srAvailable pont#
window.WebToApk.__srAvailable(): Boolean
Indique si un service de reconnaissance vocale est installé (webkitSpeechRecognition n'existe que dans ce cas).
Exemple
Documenté avec WebToApk.__srStart : l'exemple qui s'y trouve illustre aussi celui-ci.
Transport interne derrière webkitSpeechRecognition / SpeechRecognition (démarrer, arrêter, abandonner, et savoir si un module de reconnaissance existe sur le téléphone). Les pages utilisent l'API standard ; n'appelez jamais ceux-ci directement, car les méthodes __ peuvent changer sans préavis.
Renvoie : __srStart(id, options) renvoie "" quand l'écoute démarre, ou un nom d'erreur Web Speech (not-allowed, service-not-allowed). Tout le reste arrive sous forme d'événements appmint:sr : {id, type} pour start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, et {id, type:'error', error}. Nécessite : le microphone (armé d'après la forme de l'appel).
Utilisez l'API publique :
const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();Dictée continue avec texte en direct et une langue :
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
const rec = new SR();
rec.lang = 'en-US';
rec.continuous = true;
rec.interimResults = true;
rec.onresult = (e) => {
const r = e.results[e.results.length - 1];
note.value = r[0].transcript + (r.isFinal ? '\n' : '');
};
micBtn.onclick = () => rec.start();
stopBtn.onclick = () => rec.stop();
}Signaler les erreurs, comme un microphone refusé :
rec.onerror = (e) => {
if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');Remarques : Implémenté dans le shell de l'application (SpeechRecognitionBridge.kt) au-dessus du SpeechRecognizer d'Android. __srStart est refusé pour les pages qui n'appartiennent pas à l'application.
__srStart pont#
window.WebToApk.__srStart(id: String, optionsJson: String): String
SpeechRecognition.start() : "" au démarrage (les événements arrivent sous forme de `appmint:sr`), sinon le nom d'erreur Web Speech. Contrôlé par origine : ce que dit l'utilisateur est une donnée personnelle.
Exemple
Transport interne derrière webkitSpeechRecognition / SpeechRecognition (démarrer, arrêter, abandonner, et savoir si un module de reconnaissance existe sur le téléphone). Les pages utilisent l'API standard ; n'appelez jamais ceux-ci directement, car les méthodes __ peuvent changer sans préavis.
Renvoie : __srStart(id, options) renvoie "" quand l'écoute démarre, ou un nom d'erreur Web Speech (not-allowed, service-not-allowed). Tout le reste arrive sous forme d'événements appmint:sr : {id, type} pour start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, et {id, type:'error', error}. Nécessite : le microphone (armé d'après la forme de l'appel).
Utilisez l'API publique :
const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();Dictée continue avec texte en direct et une langue :
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
const rec = new SR();
rec.lang = 'en-US';
rec.continuous = true;
rec.interimResults = true;
rec.onresult = (e) => {
const r = e.results[e.results.length - 1];
note.value = r[0].transcript + (r.isFinal ? '\n' : '');
};
micBtn.onclick = () => rec.start();
stopBtn.onclick = () => rec.stop();
}Signaler les erreurs, comme un microphone refusé :
rec.onerror = (e) => {
if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');Remarques : Implémenté dans le shell de l'application (SpeechRecognitionBridge.kt) au-dessus du SpeechRecognizer d'Android. __srStart est refusé pour les pages qui n'appartiennent pas à l'application.
__srStop pont#
window.WebToApk.__srStop(id: String)
SpeechRecognition.stop() : arrête l'écoute, transmet ce qui a été entendu.
Exemple
Documenté avec WebToApk.__srStart : l'exemple qui s'y trouve illustre aussi celui-ci.
Transport interne derrière webkitSpeechRecognition / SpeechRecognition (démarrer, arrêter, abandonner, et savoir si un module de reconnaissance existe sur le téléphone). Les pages utilisent l'API standard ; n'appelez jamais ceux-ci directement, car les méthodes __ peuvent changer sans préavis.
Renvoie : __srStart(id, options) renvoie "" quand l'écoute démarre, ou un nom d'erreur Web Speech (not-allowed, service-not-allowed). Tout le reste arrive sous forme d'événements appmint:sr : {id, type} pour start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, et {id, type:'error', error}. Nécessite : le microphone (armé d'après la forme de l'appel).
Utilisez l'API publique :
const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();Dictée continue avec texte en direct et une langue :
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
const rec = new SR();
rec.lang = 'en-US';
rec.continuous = true;
rec.interimResults = true;
rec.onresult = (e) => {
const r = e.results[e.results.length - 1];
note.value = r[0].transcript + (r.isFinal ? '\n' : '');
};
micBtn.onclick = () => rec.start();
stopBtn.onclick = () => rec.stop();
}Signaler les erreurs, comme un microphone refusé :
rec.onerror = (e) => {
if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');Remarques : Implémenté dans le shell de l'application (SpeechRecognitionBridge.kt) au-dessus du SpeechRecognizer d'Android. __srStart est refusé pour les pages qui n'appartiennent pas à l'application.
__ttsSpeak pont#
window.WebToApk.__ttsSpeak(json: String)
Le speak complet du polyfill speechSynthesis : `{text, lang, rate, pitch, volume (0-1), voice (un nom de getVoices(), ou ''), id}`. [ttsSpeak] reste disponible pour les pages qui appellent directement le pont ; il n'a ni volume ni voix.
Exemple
Transport interne derrière speechSynthesis.speak(utterance) : l'énoncé complet (texte, langue, débit, hauteur, volume et voix choisie) sous forme d'une seule chaîne JSON. Les pages utilisent l'API standard speechSynthesis ; ne l'appelez jamais directement.
Renvoie : rien. La progression arrive sous forme d'événements appmint:tts, que la couche speechSynthesis transforme en événements start / boundary / end / error de l'énoncé. Nécessite : rien.
L'API standard que cela prend en charge :
function readAloud(text) {
if (!('speechSynthesis' in window)) return;
var voice = speechSynthesis.getVoices().filter(function (v) { return v.lang === 'en-GB'; })[0];
var u = new SpeechSynthesisUtterance(text);
if (voice) u.voice = voice; // that exact voice
u.volume = 0.6; // 0 .. 1
u.addEventListener('boundary', function (e) { highlightWordAt(e.charIndex, e.charLength); });
u.addEventListener('end', function () { clearHighlight(); });
speechSynthesis.speak(u);
}Un sélecteur de voix que l'utilisateur choisit une fois ; chaque énoncé suivant utilise exactement cette voix :
var picker = document.getElementById('voice-picker');
function listVoices() {
var saved = localStorage.getItem('voiceName') || '';
picker.innerHTML = '';
speechSynthesis.getVoices().forEach(function (v) {
picker.add(new Option(v.name + ' (' + v.lang + ')', v.name, false, v.name === saved));
});
}
if ('speechSynthesis' in window) {
listVoices(); // [] until the engine is ready
speechSynthesis.onvoiceschanged = listVoices;
}
picker.onchange = function () { localStorage.setItem('voiceName', picker.value); };
function speakWithSavedVoice(text) {
var name = localStorage.getItem('voiceName');
var voice = speechSynthesis.getVoices().filter(function (v) { return v.name === name; })[0];
var u = new SpeechSynthesisUtterance(text);
if (voice) u.voice = voice; // its language is used too when u.lang is empty
speechSynthesis.speak(u);
}Consignes d'entraînement : discret et rapide pour les comptes à rebours, plein volume et plus aigu pour le changement :
function cue(text, loud) {
if (!('speechSynthesis' in window)) return;
var u = new SpeechSynthesisUtterance(text);
u.lang = 'en-US';
u.rate = 1.4; // 0.1 .. 4
u.pitch = loud ? 1.3 : 1; // 0.1 .. 4
u.volume = loud ? 1 : 0.4; // 0 .. 1
u.onerror = function (e) {
if (e.error === 'synthesis-failed') console.log('Cue not spoken:', text);
};
speechSynthesis.speak(u); // queues after the previous cue
}
cue('Ten seconds left', false);
cue('Switch sides!', true);Remarques : Le JSON est {text, lang, rate, pitch, volume, voice, id} (voice est un nom de getVoices() ou ''). L'ancien ttsSpeak(text, lang, rate, pitch, id) reste disponible pour les pages qui appellent directement le pont ; il n'a ni volume ni voix.
ttsCancel pont#
window.WebToApk.ttsCancel()
Sert de base au polyfill window.speechSynthesis, installé au démarrage du document dans chaque frame : les pages doivent utiliser l'API STANDARD speechSynthesis et celles-ci seront appelées pour elles. La WebView Android n'a pas de speechSynthesis fonctionnel, d'où cette redirection.
Décrit par son groupe, Synthèse vocale, plutôt que seul.
Exemple
Arrête immédiatement la parole et jette tout ce qui attendait d'être dit. Les pages appellent normalement le speechSynthesis.cancel() standard, qui appelle ceci pour vous.
Retourne : rien. Nécessite : rien.
La méthode publique (utilisez celle-ci) :
document.getElementById('stop-reading').addEventListener('click', function () {
if ('speechSynthesis' in window) speechSynthesis.cancel();
});L'appel brut :
if (window.WebToApk && typeof window.WebToApk.ttsCancel === 'function') {
window.WebToApk.ttsCancel();
}Ne dire que le tout dernier statut et abandonner tout ce qui est encore en file (suivi de livraison, score en direct) :
function announceLatest(text) {
if (!('speechSynthesis' in window)) return;
speechSynthesis.cancel(); // the old line gets error 'interrupted', queued ones 'canceled'
var u = new SpeechSynthesisUtterance(text);
u.onerror = function (e) {
if (e.error === 'interrupted' || e.error === 'canceled') return; // replaced, not a failure
showToast('Could not read that aloud');
};
speechSynthesis.speak(u);
}
announceLatest('Your driver is 5 minutes away');
announceLatest('Your driver has arrived'); // cuts the first one offRemarques : Une parole interrompue ou abandonnée n'envoie aucun événement appmint:tts end ou error, donc le onend d'un énoncé ne s'exécute pas après une annulation. Si vous suivez vous-même des identifiants ttsSpeak bruts, oubliez-les quand vous appelez ttsCancel().
ttsGetVoices pont#
window.WebToApk.ttsGetVoices(): String
Tableau JSON des voix installées : [{name, lang, default}]. Vide tant que le moteur n'a pas fini son initialisation : la page reçoit alors 'voiceschanged' et les redemande, exactement comme le contrat asynchrone de getVoices() de Chrome.
Exemple
Liste les voix de synthèse vocale installées sur le téléphone. Les pages utilisent normalement le speechSynthesis.getVoices() standard, qui appelle ceci pour vous.
Renvoie : une chaîne JSON, de façon synchrone : [{ "name": "en-us-x-sfg-local", "lang": "en-US", "default": false }, ...]. Elle vaut "[]" tant que le moteur n'a pas démarré. Nécessite : rien.
La méthode publique (utilisez celle-ci) :
function fillLanguages() {
var langs = {};
speechSynthesis.getVoices().forEach(function (v) { langs[v.lang] = true; });
document.getElementById('langs').textContent = Object.keys(langs).join(', ');
}
if ('speechSynthesis' in window) {
fillLanguages();
speechSynthesis.onvoiceschanged = fillLanguages;
}L'appel brut (rappelez-vous JSON.parse):
function nativeVoices() {
if (!(window.WebToApk && typeof window.WebToApk.ttsGetVoices === 'function')) return [];
try { return JSON.parse(window.WebToApk.ttsGetVoices()); } catch (e) { return []; }
}
window.addEventListener('appmint:tts', function (e) {
if (e.detail && e.detail.event === 'voiceschanged') {
var hindi = nativeVoices().filter(function (v) { return v.lang.indexOf('hi') === 0; });
document.getElementById('hindi-btn').hidden = hindi.length === 0;
}
});Parler dans la langue du téléphone quand une voix est installée pour elle, sinon laisser le moteur utiliser sa voix par défaut :
function bestSpeechLang() {
if (!(window.WebToApk && typeof window.WebToApk.ttsGetVoices === 'function')) return '';
var voices;
try { voices = JSON.parse(window.WebToApk.ttsGetVoices()); } catch (e) { return ''; }
var want = navigator.language || 'en-US'; // e.g. 'ta-IN'
var exact = voices.filter(function (v) { return v.lang === want; })[0];
if (exact) return exact.lang;
var base = want.split('-')[0];
var near = voices.filter(function (v) { return v.lang.split('-')[0] === base; })[0];
return near ? near.lang : ''; // '' = the engine's default voice
}
if (window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function') {
window.WebToApk.ttsSpeak(greetingText(), bestSpeechLang(), 1.0, 1.0, 'greeting');
}Remarques : lang est une balise BCP-47 comme en-US ou ta-IN. Le name d'une voix est l'identifiant propre au moteur et ne peut pas être choisi par nom pour parler ; seule sa langue est utilisée.
ttsIsSpeaking pont#
window.WebToApk.ttsIsSpeaking(): Boolean
Sert de base au polyfill window.speechSynthesis, installé au démarrage du document dans chaque frame : les pages doivent utiliser l'API STANDARD speechSynthesis et celles-ci seront appelées pour elles. La WebView Android n'a pas de speechSynthesis fonctionnel, d'où cette redirection.
Décrit par son groupe, Synthèse vocale, plutôt que seul.
Exemple
Indique si le moteur de synthèse vocale du téléphone est en train de parler à cet instant. Les pages utilisent normalement speechSynthesis.speaking ou le onend de l'énoncé à la place.
Renvoie : true / false, de façon synchrone. false avant que le moteur n'ait démarré. Nécessite : rien.
La méthode publique (utilisez celle-ci) :
if ('speechSynthesis' in window && speechSynthesis.speaking) {
speechSynthesis.cancel();
}L'appel brut interroge le moteur lui-même, donc il est exact même si la parole a été lancée avec le ttsSpeak:
function isSpeaking() {
if (window.WebToApk && typeof window.WebToApk.ttsIsSpeaking === 'function') {
return window.WebToApk.ttsIsSpeaking() === true;
}
return false;
}
var btn = document.getElementById('read-btn');
setInterval(function () {
btn.textContent = isSpeaking() ? 'Stop' : 'Read aloud';
}, 500);Attendre que l'application ait fini de parler avant de lancer l'enregistrement, pour que le micro ne capte pas sa propre voix :
function whenQuiet(fn) {
if (!(window.WebToApk && typeof window.WebToApk.ttsIsSpeaking === 'function')) { fn(); return; }
(function check() {
if (window.WebToApk.ttsIsSpeaking()) setTimeout(check, 300);
else fn();
})();
}
document.getElementById('answer-btn').addEventListener('click', function () {
whenQuiet(startRecordingAnswer); // e.g. after the question was read aloud
});Remarques : N'interrogez pas trop vite ; un événement (onend, ou appmint:tts avec event: 'end') est préférable quand vous avez lancé la parole vous-même.
ttsSpeak pont#
window.WebToApk.ttsSpeak(text: String, lang: String, rate: Double, pitch: Double, utteranceId: String)
Sert de base au polyfill window.speechSynthesis, installé au démarrage du document dans chaque frame : les pages doivent utiliser l'API STANDARD speechSynthesis et celles-ci seront appelées pour elles. La WebView Android n'a pas de speechSynthesis fonctionnel, d'où cette redirection.
Décrit par son groupe, Synthèse vocale, plutôt que seul.
Exemple
Commence à lire le texte avec le moteur de synthèse vocale du téléphone. Les pages utilisent normalement l'API standard speechSynthesis, qui appelle ceci pour vous.
Renvoie : rien. La progression arrive plus tard sous forme d'événement appmint:tts (et du hook window.onAppMintTts(detail)) avec detail = { id, event }, où event vaut 'start', 'end' ou 'error', et id est l'utteranceId que vous avez transmis. Nécessite : rien.
La méthode publique (utilisez celle-ci) :
if ('speechSynthesis' in window) {
var u = new SpeechSynthesisUtterance('Your order is ready');
u.lang = 'en-GB';
u.onend = function () { console.log('done'); };
speechSynthesis.speak(u);
}L'appel brut, si vous voulez vos propres identifiants. Arguments : text, lang, rate, pitch, utteranceId:
var ttsWaiting = {};
window.addEventListener('appmint:tts', function (e) {
var d = e.detail || {};
if (d.event === 'voiceschanged') return; // engine ready, id is ''
var done = ttsWaiting[d.id];
if (!done || d.event === 'start') return;
delete ttsWaiting[d.id];
done(d.event === 'end'); // 'end' = spoke it, 'error' = failed
});
function speakRaw(text) {
return new Promise(function (resolve) {
if (!(window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function')) { resolve(false); return; }
var id = 'mine_' + Date.now();
ttsWaiting[id] = resolve;
window.WebToApk.ttsSpeak(String(text), 'en-US', 1.0, 1.0, id);
});
}
speakRaw('Hello').then(function (ok) { console.log(ok ? 'spoken' : 'could not speak'); });Lire une liste d'étapes dans l'ordre avec vos propres identifiants, et mettre en évidence l'étape en cours de lecture :
var steps = Array.prototype.slice.call(document.querySelectorAll('.recipe-step'));
window.addEventListener('appmint:tts', function (e) {
var d = e.detail || {};
var m = /^recipe_(\d+)$/.exec(d.id || '');
if (!m) return; // not one of ours
var el = steps[Number(m[1])];
if (d.event === 'start') el.classList.add('reading');
if (d.event === 'end' || d.event === 'error') el.classList.remove('reading');
});
document.getElementById('read-recipe').addEventListener('click', function () {
if (!(window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function')) return;
steps.forEach(function (el, i) {
// '' = the engine's default voice; 0.9 = a little slower for cooking
window.WebToApk.ttsSpeak(el.textContent, '', 0.9, 1.0, 'recipe_' + i);
});
});Remarques : Les énoncés sont mis en file l'un après l'autre. lang peut être '' (la voix par défaut du moteur) ; rate et pitch sont limités à 0,1-4. Si le moteur est encore en cours de démarrage, le texte attend et est dit quand il est prêt ; si le moteur ne peut pas démarrer, chaque énoncé en attente reçoit 'error'. Utilisez votre propre préfixe d'identifiant ; les identifiants commençant par wta_u appartiennent à la couche speechSynthesis. Sur Android 8+, appmint:tts transporte aussi {id, event: 'boundary', charIndex, charLength} avant chaque mot. Cet appel brut n'a ni volume ni voix : speechSynthesis a les deux.
ttsWarmUp pont#
window.WebToApk.ttsWarmUp()
Sert de base au polyfill window.speechSynthesis, installé au démarrage du document dans chaque frame : les pages doivent utiliser l'API STANDARD speechSynthesis et celles-ci seront appelées pour elles. La WebView Android n'a pas de speechSynthesis fonctionnel, d'où cette redirection.
Décrit par son groupe, Synthèse vocale, plutôt que seul.
Exemple
Démarre tôt le moteur de synthèse vocale du téléphone, pour que le premier speak() n'ait aucun délai et que getVoices() se remplisse. La couche speechSynthesis de l'application l'appelle déjà au chargement de la page, donc les pages n'en ont presque jamais besoin.
Renvoie : rien. Quand le moteur est prêt, l'événement appmint:tts se déclenche avec detail = { id: '', event: 'voiceschanged' } (et speechSynthesis.onvoiceschanged s'exécute). Nécessite : rien.
La méthode publique (à utiliser) : lisez simplement les voix quand elles sont prêtes.
if ('speechSynthesis' in window) {
speechSynthesis.onvoiceschanged = function () {
console.log('voices:', speechSynthesis.getVoices().length);
};
}L'appel brut, puis attendre l'événement ready :
window.addEventListener('appmint:tts', function (e) {
if (e.detail && e.detail.event === 'voiceschanged') {
var list = JSON.parse(window.WebToApk.ttsGetVoices());
console.log('engine ready,', list.length, 'voices');
}
});
if (window.WebToApk && typeof window.WebToApk.ttsWarmUp === 'function') {
window.WebToApk.ttsWarmUp(); // safe to call many times
}Démarrer le moteur à l'ouverture d'un écran « Lire à voix haute » et activer son bouton quand le moteur est prêt :
var readBtn = document.getElementById('read-aloud');
function engineReady() {
try { return JSON.parse(window.WebToApk.ttsGetVoices()).length > 0; } catch (e) { return false; }
}
function openReaderScreen() {
showReaderScreen();
if (!(window.WebToApk && typeof window.WebToApk.ttsWarmUp === 'function')) return;
readBtn.disabled = !engineReady(); // already started earlier? enable right away
window.WebToApk.ttsWarmUp(); // no-op when the engine is already running
}
window.addEventListener('appmint:tts', function (e) {
if (e.detail && e.detail.event === 'voiceschanged') readBtn.disabled = false;
});Remarques : voiceschanged ne se déclenche qu'une fois, quand le moteur a fini de démarrer. S'il a déjà démarré (par exemple parce que la couche speechSynthesis l'a préchauffé), vous ne le recevrez plus ; appelez directement ttsGetVoices().