即使支持 speechSynthesis,它也无法在移动 Safari 上运行
speechSynthesis not working on mobile Safari even though it's supported
我正在尝试使用 speechSynthesis 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>
有关代码的详细信息已添加为代码段中的注释。
这可能只是获取声音的时间问题,因此如果我们在加载页面时请求它们,它们将在用户单击“说话”按钮之前准备就绪。
为了简单起见,我没有设置任何超时。
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>
这是一个非常基本的示例,没有选择要使用的语音或任何语言。
如果这不起作用,那就是另一个问题。您是否测试过声音在您的设备上有效? “soft mute”是否开启?
我正在尝试使用 speechSynthesis 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>
有关代码的详细信息已添加为代码段中的注释。
这可能只是获取声音的时间问题,因此如果我们在加载页面时请求它们,它们将在用户单击“说话”按钮之前准备就绪。
为了简单起见,我没有设置任何超时。
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>
这是一个非常基本的示例,没有选择要使用的语音或任何语言。
如果这不起作用,那就是另一个问题。您是否测试过声音在您的设备上有效? “soft mute”是否开启?