Monaca で音声入力してみた

## はじめに
昨今、色々なクラウドサービスがありますが、
今回はクラウドサービスを使わず、Android や iOS が用意している音声入力キットを利用した方法を紹介したいと思います。
Android はオフラインでも音声入力できました。（iOS はできなさそう…。）

## 動作環境
・iOS : 10 以上
・Android : 調査中

== MEMO ==
後述プラグインのAndroidソースを見てみると、`android.speech.RecognitionListener`を使っています。
公式ドキュメントを見ると、API Level 8 となっているので、Android 2.2.x 以上で動くはず・・・？
私はAndroid 8.0系では動作確認できました。

## プラグイン

下記を Monaca のプラグインに追加してください。
https://github.com/pbakondy/cordova-plugin-speechrecognition

## プログラム
#### HTML
音声入力結果を出力するテキストフィールドと、
音声入力を開始するボタンを設置します。

``` html
<input type="search" id="searchword">
<ons-button onclick="inputVoice()" id="voice_input_btn" >
  <ons-icon icon="fa-microphone" size="23px" />
</ons-button>
```

#### Javascript
iOS と Android でプラグインの使い方が若干異なりますので、
デバイスの OS を判定し、処理を分けています。
詳細はソース内のコメントを参照ください。

``` javascript
// プラグインの音声入力が可能かどうか判定
window.plugins.speechRecognition.isRecognitionAvailable(
  function(available) {
    if(available){
      // 利用可能なら、マイク使用の許可を求める。
      window.plugins.speechRecognition.requestPermission(
        function(res) {
          // 成功時、特に何もしない。
          console.log("permission is changed!");
        }, function(err){
          // 失敗時、警告メッセージを出し、音声入力ボタンを非活性に。
          console.error(err);
          alert("マイクに接続できませんでした。");
          $("#voice_input_btn").prop("disabled", false);    //jquery使ってます。
      });
    }
  }, function(err){
    // 利用不可なら、警告メッセージを出し、音声入力ボタンを非活性に。
    console.error(err);
    alert("音声入力プラグインが利用できません。");
    $("#voice_input_btn").prop("disabled", false);    //jquery使ってます。
});

// 音声入力用メソッド
function inputVoice(){
  // 音声入力の事前設定
  var micOptions = {
    language : "ja-JP", // 言語は日本語
    matches : 1         // 結果の候補数
  }

  // 音声入力 開始
  if(monaca.isAndroid) {
    // Android の場合は startListening を呼ぶだけ。
    window.plugins.speechRecognition.startListening( micSuccess,  micError,  micOptions );
  } else if(monaca.isIOS) {
    // iOS の場合は startListening の後、stopListening を呼ぶ必要有。
    // ダイアログを立ち上げ、ダイアログ上で OK を押すと、対象のフィールドに値を書き込む。
    showIosVoiceDialog(micOptions);
  } else {
    // 非対応 OS の場合はメッセージを出す。
    alert("音声入力は Android もしくは iOS のみの対応となっております。")
  }
}

// 音声入力成功時のコールバックメソッド
function micSuccess(result){
    // テキストインプットに結果を出力
    $("#searchword").val(result) ;    //jquery使ってます。
}

// 音声入力失敗時のコールバックメソッド
function micError(result) {
    // エラーメッセージを出力
    alert("mic error : " + result) ;
}

function showIosVoiceDialog(micOptions) {
  // 音声入力開始
  window.plugins.speechRecognition.startListening( micSuccess,  micError,  micOptions );

  // 音声入力中のダイアログを表示する。
  ons.notification.confirm({
    messageHTML: '<div style="text-align:center"><ons-icon icon="fa-microphone" size="30px" /><br><span style="font-size:14px">音声入力中...</span></div>',
    title: '',
    primaryButtonIndex: 1,
    cancelable: false,
    modifier: 'material',
    callback: function(index) {
        switch(index) {
          case 1:
            //OKを押した時、音声入力終了
            window.plugins.speechRecognition.stopListening();
            break;
          case 0:
            // Cancelを押した時の処理
            // MEMO:中断したいけど、中断メソッドがプラグインに用意されていない模様
            window.plugins.speechRecognition.stopListening();
            break;
        }
    }
  });
}
```

## おわりに
今回はクラウドサービスを使わない音声入力を紹介しました。
プログラムが冗長な気がしますが、ご了承ください。

個人的には Android がオフラインで音声入力できるのが強みかなと思ってます。（端末に依存しそうな気はしていますが…。）

ご参考程度に。