web-dev-qa-db-ja.com

サポートされているにもかかわらず、speechSynthesisがモバイルSafariで機能しない

スピーチシンセシスAPIを使用しようとしています。デスクトップブラウザーとモバイルChromeで機能しますが、モバイルSafariでは機能しません。

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

少しテストを追加しましたが、APIがSafariでサポートされているようですが、機能していないのは権限の問題でしょうか?

  if ("speechSynthesis" in window) {
    alert("yay");
  } else {
    alert("no");
  }
5
Evanss

私の側では、この問題はモバイルSafariでの適切なloading音声合成に分解されました。

順番に確認することがいくつかあります。

  • 声がロードされていますか?
  • 音声がシステムにインストールされていますか?
  • 発話は正しく設定されていますか?
  • 発言機能はユーザー対話イベント内から呼び出されますか?

次の例は、これらのチェックをまとめたもので、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>

コードの詳細はスニペット内のコメントとして追加されます。

0
Jankapunkt

音声を取得するタイミングの問題である可能性があるため、ページをロードするときに音声を要求すると、ユーザーが[発声]ボタンをクリックする前に準備が整います。

例を簡単にするために、タイムアウトは設定していません。

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 "はオンになっていますか?

1
Frazer