Help us understand the problem. What is going on with this article?

webkitSpeechRecgnitionを扱う

はじめに

音声認識のためのインターフェイスである webkitSpeechRecognition を扱った際に得た知見をまとめました。本記事では、常にマイクから音声を聞きながら、声が発せられてから無音になるまでの間に話された言葉を文字列として取得する方法について述べていきます。

構造を理解する

まずは以下のコードを実行します。 onなんとか 系が多いので、どのようなタイミングで発火するのかを確認しましょう。

main.js
const rec = new webkitSpeechRecognition()
rec.continuous = false
rec.interimResults = false
rec.lang = 'ja-JP'

rec.onresult = e => {
  console.log('on result')

  for (var i = e.resultIndex; i < e.results.length; i++) {
    if (!e.results[i].isFinal) continue

    const { transcript } = e.results[i][0]
    console.log(`Recognised: ${transcript}`)
  }

  rec.stop()
}

rec.onstart = () => { console.log('on start') }
rec.onend = () => { console.log('on end') }

rec.onspeechstart = () => { console.log('on speech start') }
rec.onspeechend = () => { console.log('on speech end') }

rec.onosundstart = () => { console.log('on sound start') }
rec.onsoundend = () => { console.log('on sound end') }

rec.onaudiostart = () => { console.log('on audio start') }
rec.onaudioend = () => { console.log('on audio end') }

rec.start()

声を発した瞬間に on speech start と表示されましたので、 onspeechstart は声が発せられることがトリガーだと考えられます。その他についてもまとめてみましょう。

  • onstart
    • rec.start() がされた時
  • onend
    • rec.stop() がされた時
  • onspeechstart
    • 発声の始めを声が受け付けた時
  • onsoundstartonaudiostart
    • 不明
  • - onspeechendonsoundendonaudioendonresult
    • 発声が終了した時
    • 判別できなかったが、順序はいつも上記の順番

常に音声を取得し続ける

常に音声を取得し続けるためには発声が終了し、結果が出た後にまた rec.start() をする必要があります。

const rec = new webkitSpeechRecognition()
rec.continuous = false
rec.interimResults = false
rec.lang = 'ja-JP'

rec.onresult = e => {
  rec.stop()

  for (var i = e.resultIndex; i < e.results.length; i++) {
    if (!e.results[i].isFinal) continue

    const { transcript } = e.results[i][0]
    console.log(`Recognised: ${transcript}`)
  }
}

rec.onend = () => { rec.start() }

rec.start()

上記のコードのように、 rec.onendrec.start() することで終了後に開始することができます。 rec.stop() の位置をfor文の下にすると上手く動作しなかったため注意してください。

おまけ - audioデータも取得する

MediaRecorder を使って文字列とaudioデータの両方を取得しましょう。ここではaudioデータはbase64に変換しています。

main.js
const onSuccess = stream => {
  let base64 = ''
  let chunks = []

  const mediaRecorder = new MediaRecorder(stream)
  mediaRecorder.onstop = e => {
    const blob = new Blob(chunks, { type: 'audio/wav' })
    const reader = new window.FileReader()
    reader.readAsDataURL(blob)
    reader.onloadend = () => { base64 = reader.result }
    chunks = []
  }
  mediaRecorder.ondataavailable = e => { chunks.push(e.data) }

  const speechRecognition = new webkitSpeechRecognition()
  speechRecognition.continuous = false
  speechRecognition.interimResults = false
  speechRecognition.lang = 'ja-JP'

  speechRecognition.onresult = function (e) {
    speechRecognition.stop()
    for (let i = e.resultIndex; i < e.results.length; i++) {
      if (!e.results[i].isFinal) continue

      const { transcript } = e.results[i][0]
      console.log(`Recognized: ${transcript}`)
      console.log(`Base64: ${base64}`)
    }
  }

  speechRecognition.onspeechstart = () => { mediaRecorder.start() }
  speechRecognition.onaudioend = () => { mediaRecorder.stop() }
  speechRecognition.onend = () => { speechRecognition.start() }

  speechRecognition.start()
}

navigator.mediaDevices.getUserMedia({ audio: true })
  .then(onSuccess)

ブラウザに getUserMedia() が実装されていないことがあるので注意してください。また途中でエラーを吐くことがたまにあるため、原因がわかった方はコメント等で教えて頂けると幸いです。

おわりに

私はこの知見を初参加のハッカソン中に得ました。開発が始まって1時間しないうちにパソコンに向かって「おにぎり」と連呼してテストを行っていたので、周囲からは変な人と思われていたでしょう...。何はともあれハッカソンは無事終わりました。この記事によって知見が共有され、どこかで使われることがあるならばとても嬉しいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした