admin管理员组文章数量:1289828
Im trying to use the speechSynthesis API. It's working on desktop browsers and mobile Chrome but not mobile Safari.
const msg = new SpeechSynthesisUtterance("Hello World");
window.speechSynthesis.speak(msg);
I added a little test and it seems the API is supported on Safari, could it be a permissions issue that it's not working?
if ("speechSynthesis" in window) {
alert("yay");
} else {
alert("no");
}
Im trying to use the speechSynthesis API. It's working on desktop browsers and mobile Chrome but not mobile Safari.
const msg = new SpeechSynthesisUtterance("Hello World");
window.speechSynthesis.speak(msg);
I added a little test and it seems the API is supported on Safari, could it be a permissions issue that it's not working?
if ("speechSynthesis" in window) {
alert("yay");
} else {
alert("no");
}
Share
Improve this question
asked May 7, 2020 at 13:15
EvanssEvanss
23.2k100 gold badges322 silver badges555 bronze badges
3
- Is your 'speak' javascript attached to a user interaction? – Frazer Commented May 22, 2020 at 21:33
- @Frazer no it's based on a timer, however the user has already clicked a button to start the timer. – Evanss Commented May 23, 2020 at 13:47
- Can you add that bit of the code? – Frazer Commented May 23, 2020 at 19:02
3 Answers
Reset to default 4On my end the issue broke down to proper loading speech synthesis on mobile Safari.
There are some things to check in order:
- are voices loaded?
- are voices even installed on your system?
- is the utterance configured correctly?
- is the speak function called from within a user interaction event?
The following example summarizes these checks and works on MacOS desktop Browsers plus iOS Safari:
let _speechSynth
let _voices
const _cache = {}
/**
* retries until there have been voices loaded. No stopper flag included in this example.
* Note that this function assumes, that there are voices installed on the host system.
*/
function loadVoicesWhenAvailable (onComplete = () => {}) {
_speechSynth = window.speechSynthesis
const voices = _speechSynth.getVoices()
if (voices.length !== 0) {
_voices = voices
onComplete()
} else {
return setTimeout(function () { loadVoicesWhenAvailable(onComplete) }, 100)
}
}
/**
* Returns the first found voice for a given language code.
*/
function getVoices (locale) {
if (!_speechSynth) {
throw new Error('Browser does not support speech synthesis')
}
if (_cache[locale]) return _cache[locale]
_cache[locale] = _voices.filter(voice => voice.lang === locale)
return _cache[locale]
}
/**
* Speak a certain text
* @param locale the locale this voice requires
* @param text the text to speak
* @param onEnd callback if tts is finished
*/
function playByText (locale, text, onEnd) {
const voices = getVoices(locale)
// TODO load preference here, e.g. male / female etc.
// TODO but for now we just use the first occurrence
const utterance = new window.SpeechSynthesisUtterance()
utterance.voice = voices[0]
utterance.pitch = 1
utterance.rate = 1
utterance.voiceURI = 'native'
utterance.volume = 1
utterance.rate = 1
utterance.pitch = 0.8
utterance.text = text
utterance.lang = locale
if (onEnd) {
utterance.onend = onEnd
}
_speechSynth.cancel() // cancel current speak, if any is running
_speechSynth.speak(utterance)
}
// on document ready
loadVoicesWhenAvailable(function () {
console.log("loaded")
})
function speak () {
setTimeout(() => playByText("en-US", "Hello, world"), 300)
}
<button onclick="speak()">speak</button>
Details on the code are added as ments within the snippet.
It may just be a question of timing to get the voices, so if we request them when loading the page they'll be ready before the user clicks the Speak button.
I haven't put in any timeout to keep the example simple.
if ( 'speechSynthesis' in window ) {
speechSynthesis.cancel(); // removes anything 'stuck'
speechSynthesis.getVoices();
// Safari loads voices synchronously so now safe to enable
speakBtn.disabled = false;
}
const speak = () => {
const utter = new SpeechSynthesisUtterance();
utter.text = textToSpeak.value || textToSpeak.placeholder;
speechSynthesis.speak(utter);
};
speakBtn.addEventListener('click', speak);
<input type="text" id="textToSpeak" placeholder="1, 2, 3">
<button type="button" id="speakBtn" disabled>Speak</button>
This is a very basic example, not selecting the voice to be used or any language.
If this doesn't work there is another problem. Have you tested that the sound works on your device? Is the "soft mute" on?
As per @Frazer's ment, mobile Safari seems to require that the first utterance happens during a user interaction (even if it's empty!) in order to enable utterances in non-user-interactive places like timeouts/intervals. This works for me:
function speak(msg) {
speechSynthesis.speak(new SpeechSynthesisUtterance(msg));
}
const startTimerButton = document.getElementById('start-timer');
startTimerButton.addEventListener('click', () => {
// Mobile Safari requires an utterance (even a blank one) during
// a user interaction to enable utterances during timeouts.
speak('');
setInterval(() => {
speak('another five seconds passed');
}, 5 * 1000);
});
<button id="start-timer">Start</button>
本文标签: javascriptspeechSynthesis not working on mobile Safari even though it39s supportedStack Overflow
版权声明:本文标题:javascript - speechSynthesis not working on mobile Safari even though it's supported - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741409169a2377128.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论