SpeechSynthesis在移动Safari上无法工作,即使它被支持。

问题描述 投票:2回答:1

我试图使用语音合成API。在桌面浏览器和手机Chrome上可以使用,但在手机Safari上不能使用。

  const msg = new SpeechSynthesisUtterance("Hello World");
  window.speechSynthesis.speak(msg);

我添加了一个小测试,似乎该API是支持在Safari上,它可能是一个权限问题,它不工作?

  if ("speechSynthesis" in window) {
    alert("yay");
  } else {
    alert("no");
  }
javascript mobile-safari text-to-speech
1个回答
0
投票

在我的终端,这个问题被分解为适当的 装载 手机Safari上的语音合成。

有一些事情需要依次检查。

  • 是否加载了声音?
  • 语音是否已经安装在你的系统上?
  • 语句的配置是否正确?
  • 是否从用户交互事件中调用了speak函数?

下面的例子总结了这些检查,并适用于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>

代码的细节作为注释添加在片段中。


1
投票

这可能只是一个获取声音的时间问题,所以如果我们在加载页面时请求它们,它们将在用户点击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>

这是一个非常基本的例子,没有选择要使用的语音或任何语言。

如果这不起作用,那就是另一个问题了。你有没有测试过声音在你的设备上工作?是"静音"上?

© www.soinside.com 2019 - 2024. All rights reserved.