Posted at

SpeechRecognizerで「メリークリスマス」を音声認識してみよう

More than 1 year has passed since last update.

最近寒くなりましたね!

クリスマスも近づいていて、寂しいなーと思いながらGoogleホームにでも話しかけたいのですが購入してないのでこの機会に音声認識を使ってみました!


SpeechRecognizer とは?

SpeechRecognizerとは音声認識機能を使うためのサービスにアクセスするクラスです。

createSpeechRecognizer(Context)でインスタンスを作ってアクセス出来て、メインスレッドに限って呼び出せます!

あとRECORD_AUDIOpermissionが必要になります。

継続的に使うことを意図してないので、その場合はかなりの量のバッテリーを使ってしまうらしいです。


試してみる

スタートボタンを押してから音声を取り始め、その音声をテキストに出すまでのコードを書いてみます!

まずはpermissionが必要なためAndroidManifest.xmlRECORD_AUDIOpermissionを追加します!

あと音声認識の処理がサーバーで行われるため、通信が繋がってないと使えないのでINTERNETpermissionも追加します。


AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

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

次はレイアウトです。

テキスト表示のためのTextViewとスタートボタン、5秒のカウントダウンを表示するためのTextViewで構成されてます。


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/buttonView"
android:layout_centerHorizontal="true"
android:textSize="18sp"
tools:text="ここにテキスト表示" />

<Button
android:id="@+id/buttonView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="スタート" />

<TextView
android:id="@+id/countTextViwe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/buttonView"
android:layout_centerHorizontal="true"
android:textSize="23sp"
tools:text="あと5秒!" />

</RelativeLayout>


最後にMainActivity.javaですが、permission拒否の処理とかエラーハンドリングはしてないです。

スタートボタンを押して5秒の間なにか言うとそれがテキストに表示されます!

ただし「メリークリスマス」と言った場合だけ文字列を比較してToastが出るようにしました。

簡単な単語や短い文章ぐらいしか認識できないのでクォリティーを高めるためにはエラーハンドリングをしっかり書いたり、RecognitionListenerの中身をカスタムしないといけない気がします。


MainActivity.java

public class MainActivity extends AppCompatActivity {

private static final int MILLIS_IN_FUTURE = 11 * 500;
private static final int COUNT_DOWN_INTERVAL = 1000;

private Intent intent;
private SpeechRecognizer mRecognizer;
private TextView textView;

private int count = 5;
private TextView countTextView;
private CountDownTimer countDownTimer;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = (TextView) findViewById(R.id.textView);
countTextView = (TextView) findViewById(R.id.countTextViwe);

// permission チェック
if (ContextCompat.checkSelfPermission(this, RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, RECORD_AUDIO)) {
// 拒否した場合
} else {
// 許可した場合
int MY_PERMISSIONS_RECORD_AUDIO = 1;
ActivityCompat.requestPermissions(this, new String[]{RECORD_AUDIO}, MY_PERMISSIONS_RECORD_AUDIO);
}
}

intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.JAPAN.toString());

mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
mRecognizer.setRecognitionListener(recognitionListener);

// 音声認識スタートボタン
Button button = (Button) findViewById(R.id.buttonView);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

// 音声テキスト初期化
if (!TextUtils.isEmpty(textView.getText())) {
textView.setText("");
}

// カウントダウンスタート
countDownTimer();
countDownTimer.start();

// レコーディングスタート
mRecognizer.startListening(intent);
}
});
}

private RecognitionListener recognitionListener = new RecognitionListener() {
@Override
public void onReadyForSpeech(Bundle bundle) {
Log.d("log:: ", "準備できてます");
}

@Override
public void onBeginningOfSpeech() {
Log.d("log:: ", "始め!");
}

@Override
public void onRmsChanged(float v) {
Log.d("log:: ", "音声が変わった");
}

@Override
public void onBufferReceived(byte[] bytes) {
Log.d("log:: ", "新しい音声");
}

@Override
public void onEndOfSpeech() {
Log.d("log:: ", "終わりました");
}

@Override
public void onError(int i) {
switch (i) {
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
resetText();
textView.setText("ネットワークタイムエラー");
break;
case SpeechRecognizer.ERROR_NETWORK:
resetText();
textView.setText("その外ネットワークエラー");
break;
case SpeechRecognizer.ERROR_AUDIO:
resetText();
textView.setText("Audio エラー");
break;
case SpeechRecognizer.ERROR_SERVER:
resetText();
textView.setText("サーバーエラー");
break;
case SpeechRecognizer.ERROR_CLIENT:
resetText();
textView.setText("クライアントエラー");
break;
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
resetText();
textView.setText("何も聞こえてないエラー");
break;
case SpeechRecognizer.ERROR_NO_MATCH:
resetText();
textView.setText("適当な結果を見つけてませんエラー");
break;
case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
resetText();
textView.setText("RecognitionServiceが忙しいエラー");
break;
case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
resetText();
textView.setText("RECORD AUDIOがないエラー");
break;
}
}

@Override
public void onResults(Bundle bundle) {
String key = SpeechRecognizer.RESULTS_RECOGNITION;
ArrayList<String> mResult = bundle.getStringArrayList(key);

String[] result = new String[0];
if (mResult != null) {
result = new String[mResult.size()];
}
if (mResult != null) {
mResult.toArray(result);
}

textView.setText(result[0]);

// テキスト比較
if (TextUtils.equals(result[0], "メリークリスマス")) {
Toast.makeText(MainActivity.this, "あなたもね!!", Toast.LENGTH_SHORT).show();
countDownTimer.cancel();
countTextView.setText("");
}
}

@Override
public void onPartialResults(Bundle bundle) {
}

@Override
public void onEvent(int i, Bundle bundle) {
}
};

private void resetText() {
countDownTimer.cancel();
countTextView.setText("やり直し!");
}

public void countDownTimer() {
if (countDownTimer != null) {
countDownTimer.cancel();
count = 5;
}

countDownTimer = new CountDownTimer(MILLIS_IN_FUTURE, COUNT_DOWN_INTERVAL) {
public void onTick(long millisUntilFinished) {
String countString = getString(R.string.count_string, count);
countTextView.setText(countString);
count--;
}

public void onFinish() {
countDownTimer.cancel();
countTextView.setText(String.valueOf("やり直し?"));
}
};
}

@Override
public void onDestroy() {
super.onDestroy();
try {
countDownTimer.cancel();
} catch (Exception e) {
Log.e("EXCEPTION LOG ", "message:: " + e.getMessage());
}
countDownTimer = null;
}

}



結果

こちらが実行結果になります!

スクリーンショット 2017-12-09 10.27.39.png

すごく雑な感じなのですが、なんとなく返事をもらうことができました…!

体育会係の部活とか、スポーツはやってなくて「返事だけはイイ」で参加させて頂いたのですが

コード書いててとても楽しかったです!

それではまだ少し早いのですが皆さん、


メリークリスマス!


参照

https://developer.android.com/reference/android/speech/SpeechRecognizer.html

https://techbooster.org/android/application/14927/