音声認識APIを利用する

音声認識を実装してみる。
実装方法は以下の2通りを説明する。

音声認識を実装するにあたり、AndroidManifest.xmlに以下のパーミッションを追加しておく必要がある。

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

下2つは機種によっては不要かも?

Androidで用意された音声認識用のセットを用いる

予め使いやすいように音声認識用のセットを用意していくれているので、実装は簡単。
画面上のボタンを押下することで、以下のような画面を起動する。

f:id:ats337:20140417011205p:plain

この画面が出ている間に、聞き取った音声を取得する。

Activityを継承したクラスに以下のように実装する。

    // ボタンが押された時に呼び出されるメソッド
    public void onRecordClick(View view) {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Please Speech!!");
        startActivityForResult(intent, 0);
    }

    // startActivityForResultで呼び出したActivityから応答される結果を受け取るコールバックメソッド
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 0 && resultCode == RESULT_OK) {
            // 結果文字列リスト
            ArrayList<String> results = data
                    .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);

            // TODO ここに取得した文字列に対する処理を記述

        }
    }

音声認識の画面はAndroid自体が用意しており、RecognizerIntent.ACTION_RECOGNIZE_SPEECHを設定したIntentインスタンスを生成し、
startActivityForResultを呼び出すことで簡単に実装することができる。

音声を認識したら、onActivityResultが呼び出されるので、
取得処理はここに実装する。
認識した音声はdata.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)で取得することができる。
ここで取得できるのはArrayListインスタンスであるが、中身となるString文字列には、
認識した文字列の候補が返却される。
聞き取った単語がArrayListの1要素として応答されるわけではないので注意。

音声認識処理を独自実装する

独自実装する場合はSpeechRecognizerクラスを使用する。

        // インスタンス生成
        SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(this);
        // リスナを設定
        recognizer.setRecognitionListener(new RecognitionListenerImpl());
        // リッスンスタート
        recognizer.startListening(intent);

上記で音声認識を開始できる。
終了する時はrecognizer.stopListening()で停止することができる。

音声認識のコールバックを受け付けるためにRecognitionListenerインターフェースを実装したクラスを作成して、setRecognitionListenerで設定している。

RecognitionListenerImplクラスは以下

public class RecognitionListenerImpl implements RecognitionListener {
    // 音声認識を開始する準備が整った時に呼び出される
    @Override
    public void onReadyForSpeech(Bundle bundle) {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onReadyForSpeech");
    }

    // 音声の聞き取りを開始した時に呼び出される
    @Override
    public void onBeginningOfSpeech() {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onBeginningOfSpeech");
    }

    // 音量(?)が変わった時に呼び出される
    @Override
    public void onRmsChanged(float v) {
    }

    // ちょっとよくわからない。呼び出されなかった。
    @Override
    public void onBufferReceived(byte[] bytes) {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onBufferReceived");
    }

    // 音声の聞き取りを終了した時に呼び出される
    @Override
    public void onEndOfSpeech() {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onEndOfSpeech");
    }

    // エラーが発生した時に呼び出される
    @Override
    public void onError(int i) {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onError : " + i);
    }

    // 結果を返却するときに呼び出される
    @Override
    public void onResults(Bundle bundle) {
        List<String> list = (List) bundle.get(SpeechRecognizer.RESULTS_RECOGNITION);
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onResults");
        for (String str : list) {
            Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), str);
        }
    }

    // 部分的に結果を返却する時に呼び出される。
    @Override
    public void onPartialResults(Bundle bundle) {
        List<String> list = (List) bundle.get(SpeechRecognizer.RESULTS_RECOGNITION);
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onPartialResults");
        for (String str : list) {
            Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), str);
        }
    }

    // 呼び出されたことない。よくわからない。
    @Override
    public void onEvent(int i, Bundle bundle) {
        Log.v(RecognitionListenerImpl.this.getClass().getSimpleName(), "onEvent : " + i);
    }

上記のように、コールバックメソッドを実装していくことになる。

ちなみに、startListeningを呼び出した後、10秒くらい無音だと音声認識が終了してしまう。
また、音声を認識させている時でも、一定時間無音の状態だと終了してしまうようだ。

intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 3600000);
   intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 3600000);
   intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3600000);

Intentに上記の設定をすれば、1時間起動しっぱなしになるんじゃないかと思って試したけど、結果は変わらなかった。