我试图使用语音合成API。在桌面浏览器和手机Chrome上可以使用,但在手机Safari上不能使用。
const msg = new SpeechSynthesisUtterance("Hello World");
window.speechSynthesis.speak(msg);
我添加了一个小测试,似乎该API是支持在Safari上,它可能是一个权限问题,它不工作?
if ("speechSynthesis" in window) {
alert("yay");
} else {
alert("no");
}
在我的终端,这个问题被分解为适当的 装载 手机Safari上的语音合成。
有一些事情需要依次检查。
下面的例子总结了这些检查,并适用于MacOS桌面浏览器和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>
代码的细节作为注释添加在片段中。
这可能只是一个获取声音的时间问题,所以如果我们在加载页面时请求它们,它们将在用户点击Speak按钮之前准备好。
我没有放入任何超时,以保持例子的简单性。
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>
这是一个非常基本的例子,没有选择要使用的语音或任何语言。
如果这不起作用,那就是另一个问题了。你有没有测试过声音在你的设备上工作?是"静音"上?