SpeechRecognizerを使った音声認識を行う


TechBoosterでは、RecognizerIntentを利用した音声認識の方法を紹介しています。

音声認識を利用する

RecognizerIntentを利用した方法では、マイクの絵が表示されているダイアログが出力され、
音声認識が行われます。
このAndroid標準のダイアログを表示せず、独自の画像等で音声入力状態を表示したい場合などに利用出来るのがSpeechRecognizerを使った音声認識の方法になります。

本エントリでは、3枚の画像を使って、3種類の入力状態を表示するサンプルを元に
SpeechRecognizerの使い方を紹介していきます。

SpeechRecognizerを作成する

SpeechRecognizerクラスは、Androidの音声認識用に用意されているServiceに
アクセスするためのクラスです。
SpeechRecognizerクラスの使用に当たって、3つのポイントがあります。

1.インスタンス生成は、createSpeechRecognizerメソッドを利用する
2.createSpeechRecognizerメソッドはアプリケーションのメインスレッドで呼び出す
3.RECORD_AUDIOのパーミッションが必要

これらのポイントを踏まえて、SpeechRecognizerを作成したサンプルコードは以下になります。
サンプルではonCreate時に作成するようにしています。

public class SpeechRecognizerSampleActivity extends Activity implements
		OnClickListener, RecognitionListener {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		iv = (ImageView)findViewById(R.id.imageView1);

		// listener登録
		((Button) findViewById(R.id.button1)).setOnClickListener(this);

		mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
		mSpeechRecognizer.setRecognitionListener(this);

	}

11行目でSpeechRecognizerのインスタンスを生成しています。
12行目では、RecognitionServiceからのコールバックを受けるRecognitionListenerを登録しています。
サンプルでは、RecognitionListenerをimplementsしているため、thisを引き渡しています。

SpeechRecognizerクラスのインスタンスを生成した後には、
SpeechRecognizerクラスのstartListeningメソッドを使って、音声認識イベントを開始します。
サンプルでは、以下の通りボタン押下時に呼び出しています。

	 	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
			intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
					RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

			intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
					getPackageName());
			mSpeechRecognizer.startListening(intent);
			break;
		default:
			break;
		}
	}

11行目でstartListeningメソッドを呼び出しています。
startListeningメソッドには、Intentを引き渡す必要があり、11行目以前の行でIntentを作成しています。
作成するIntentは、RecognizerIntentを利用するときと同じです。
詳しい解説は、コチラの記事を参照ください。

RecognitionListenerを用意する

上記サンプル内でも触れましたが、RecognitionServiceからの処理通知を受け取るため、
SpeechRecognizerへRecognitionListenerを登録する必要が有ります。

RecognitionListenerが持つメソッドのうち、
重要なメソッドは以下表の通りです。

[table “239” not found /]

表内のメソッドの内、サンプルでは、onReadyForSpeechメソッドで入力待ちの画像に、
onBiginningOfSpeechメソッドで入力開始の画像に、
onEndOfSpeechメソッドで初期画像に変更する処理を入れています。
また、onResultsメソッドにおいて、音声認識結果を取得しToastに表示しています。

onErrorメソッドで取得出来るエラー通知には、
以下の9種類が存在します。

[table “240” not found /]

エラーハンドリングを行わない場合、ユーザからは何が起こっているのか全く解らないため
適切な処理をいれるようにしましょう。

以下のサンプルコードは、RecognitionListenerをimplementsした場合にOverrideする
必要が有るメソッド群です。

	// 音声認識準備完了
	@Override
	public void onReadyForSpeech(Bundle params) {
		Toast.makeText(this, "音声認識準備完了", Toast.LENGTH_SHORT);
		iv.setImageResource(R.drawable.ready);
	}

	// 音声入力開始
	@Override
	public void onBeginningOfSpeech() {
		Toast.makeText(this, "入力開始", Toast.LENGTH_SHORT);
		iv.setImageResource(R.drawable.listen);
	}

	// 録音データのフィードバック用
	@Override
	public void onBufferReceived(byte[] buffer) {
		Log.v(LOGTAG,"onBufferReceived");
	}

	// 入力音声のdBが変化した
	@Override
	public void onRmsChanged(float rmsdB) {
		Log.v(LOGTAG,"recieve : " + rmsdB + "dB");
	}

	// 音声入力終了
	@Override
	public void onEndOfSpeech() {
		Toast.makeText(this, "入力終了", Toast.LENGTH_SHORT);
		iv.setImageResource(R.drawable.tb);
	}

	// ネットワークエラー又は、音声認識エラー
	@Override
	public void onError(int error) {
		switch (error) {
		case SpeechRecognizer.ERROR_AUDIO:
			// 音声データ保存失敗
			break;
		case SpeechRecognizer.ERROR_CLIENT:
			// Android端末内のエラー(その他)
			break;
		case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
			// 権限無し
			break;
		case SpeechRecognizer.ERROR_NETWORK:
			// ネットワークエラー(その他)
			Log.e(LOGTAG, "network error");
			break;
		case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
			// ネットワークタイムアウトエラー
			Log.e(LOGTAG, "network timeout");
			break;
		case SpeechRecognizer.ERROR_NO_MATCH:
			// 音声認識結果無し
			Toast.makeText(this, "no match Text data", Toast.LENGTH_LONG);
			break;
		case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
			// RecognitionServiceへ要求出せず
			break;
		case SpeechRecognizer.ERROR_SERVER:
			// Server側からエラー通知
			break;
		case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
			// 音声入力無し
			Toast.makeText(this, "no input?", Toast.LENGTH_LONG);
			break;
		default:
		}
	}

	// イベント発生時に呼び出される
	@Override
	public void onEvent(int eventType, Bundle params) {
		Log.v(LOGTAG,"onEvent");
	}

	// 部分的な認識結果が得られる場合に呼び出される
	@Override
	public void onPartialResults(Bundle partialResults) {
		Log.v(LOGTAG,"onPartialResults");
	}

	// 認識結果
	@Override
	public void onResults(Bundle results) {
		ArrayList recData = results
				.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

		String getData = new String();
		for (String s : recData) {
			getData += s + ",";
		}

		Toast.makeText(this, getData, Toast.LENGTH_SHORT).show();
	}

音声認識の結果取得までに、onReadyForSpeechメソッド(3行目)、onBeginningOfSpeechメソッド(10行目)、onEndOfSpeechメソッド(29行目)、(onErrorメソッド(36行目))、onResultsメソッド(87行目)の順に呼び出されます。
onRmsChangedメソッド(23行目)やonBufferReceivedメソッド(17行目)は、音声入力の都度呼び出される為、一度の音声認識を行う際に複数回呼び出されます。

onReadyForSpeechメソッド(3行目)は、startListeningメソッドが呼び出された後に、
バックグラウンドで音声認識の準備が出来た時によびだされます。
その後、音声入力開始時にonBeginningOfSpeechメソッド(10行目)が呼び出され、
音声入力完了時にonEndOfSpeechメソッド(29行目)が呼び出されます。
音声入力完了後には、音声認識の処理が行われます。
音声認識の処理は、サーバー側で行われるため、通信環境が必要である点にも注意しましょう。

サーバー側での音声認識処理が終わった後に、onResultsメソッド(87行目)が呼び出されます。
認識結果は、RecognizerIntentを利用した場合と変わらず、SpeechRecognizer.RESULTS_RECOGNITIONを指定してBundleから取得します。ArrayList型で取得できるため、サンプルでは全認識結果をStringデータとし、Toastに表示しています。

最後に、具体的なサンプルの動作をスクリーンショットを用いて紹介します。
起動時には、以下の画面が表示され、ボタン押下と共に二枚目の画像に変化します。

Ready表示状態で、音声入力を行います。
ここでは「sample」と発生しました。
音声入力中には以下の画像が表示されます。

音声認識後、結果がToastで表示されます。
3つめに「sample」が取得できています。