Bluetoothマイクから音声入力する方法

  • 13
    いいね
  • 0
    コメント

この記事はAndroid Advent Calendar 2016の21日目の投稿です。

はじめに

みなさんはきっと思うのでしょう、ヘッドセットが繋がっていれば勝手にそのヘッドセットのマイクが使われるということ。WindowsやmacOSではほぼ当たり前のこと(だよね?)。しかし、ここはAndroidの世界、当たり前のことが通用しない世界なんです。Bluetoothデバイスが繋がっていても、マイクのAPI等からBluetoothヘッドセットのマイクから音を拾うことはありません。

そんなBluetoothマイクを使いたいあなたに、マイクを使用するための方法を共有します!!

Bluetoothマイクから音声入力する方法

Bluetoothに主に2つのリンク方法があります。音声通話に使用されるSCOとデータ通信に使われるACLです。

SCOモードにしてから音声入力を開始すると、Bluetoothマイクを音声入力に使うことが出来るようになります。

では、どうやってSCOモードにできるのか。

簡単に説明すると、AudioManager#startBluetoothSco()を呼んでSCOモードへの遷移を要求します。ただし、AudioManagerのモードをMODE_IN_COMMUNICATIONに変更していないと、SCOモードにならないです。setModeの代わりにAudioManager#setBluetoothScoOn()trueを渡しても同様の効果あります。

mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); // or setBluetoothScoOn
mAudioManager.startBluetoothSco();

しかし、これだけですぐにSCOモードに入る訳ではなく、マイクの使用はSCOモードに入った通知を受け取ってからでないと開始してはいけません。しても良いんだけど、SCOモードに入るまではBluetoothマイク使われません。その通知はBroadcastReceiverで受け取れます。

public void onReceive(Context context, Intent intent) {
  if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(intent.getAction())) {
    int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR);
    if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
      // SCOモードに入った!!! (・∀・)
    }
}

実はSCOモードに遷移するところで失敗することが多いです。SCOモードに入った通知を受け取るまでは何度かリトライすると良いでしょう。

無事SCOモードに入ったところで、音声入力を開始しましょう!ここでは通常の AudioRecordSpeechRecognizer の利用方法でOKです。

マイクを使う必要がなくなったら、SCOモードから抜けましょう。モードをMODE_NORMALに戻すのを忘れずに。

mAudioManager.stopBluetoothSco();
mAudioManager.setMode(AudioManager.MODE_NORMAL);

startしたら、必ずstopするように!stop呼ばないと次のstartは必ず失敗します。余分にstopを呼んでも良いぐらいの気持ちで。

と、いろいろ雑に書いたけど、ここらへんを全部やってくれる、api.aiのSDKサンプルコードを参考すると良いです!特にBluetoothController.javaが参考になるのではないかと思います。感動モノだ! (もっと早くこのサンプルコードに出会いたかった・・涙)

いろいろ注意点

  • Bluetoothマイク使用中はSCOモードになるので音質が低下します(= mono, 16kHz or 8kHz)。音楽や効果音など再生している場合は特に注意、火傷します。
  • Bluetoothのマイクが高性能でない場合もあります。Bluetoothマイクを使わない選択肢も与える必要があるでしょう。
  • 何度かBluetoothマイクの音を拾うことに失敗したら、スマホ本体のマイクにフォールバックを検討した方がユーザにとっては良いだろう。設定とか変更するの分かりにくいし、カスタマーサポートの問い合わせやその返答のコスト減らしたいよな。何より、このせいで悪いレビュー書かれたら嫌だよな。
  • 車載器に繋がっている時にSCOモードにすると、通話中画面になる場合があります。車載器によります。通話中モードにならない車載器もあります。
  • Bluetoothはいろいろと闇が多いです。一度ハマると数日は帰ってこれないと思っても良いでしょう。PMの了承を予め取ることが大切です。
  • 決してBluetooth APIが返してくるエラーコードをそのまま信用してはならない。問題は別なところにあります。きっと。いや、絶対。
  • そもそもエラーコードにはドキュメントがありません。Android Bluetoothスタックのソースコードを読みましょう。ちなみにAPIレベルによって実装が違います。

最後に

Drivemode社では運転者向けのアプリを作りたい仲間を募集しています!詳しくはこちら→ https://drivemode.workable.com/jobs/397748

ちなみに、社内共通語は英語です。英語に自信の無い人でも、1年ぐらいで普通に喋るようになるらしいです!

この投稿は Android Advent Calendar 201621日目の記事です。