【Unity】Androidで音声認識を使う 
2017/12/11 Mon [edit]
今回はプラグイン内に入っている音声認識を改めて Unity 側のコードを中心に書いてみよう。大まかにはダイアログを表示する方法と、自分でUIなどを用意し、コールバックメソッドを使って実装していく方法がある。用途によって使い分けるのも良いだろう。
プラグインの内部的なコード(Java)を知りたい場合は以前の記事を参照して欲しい。プラグイン自体のセットアップからはじめる場合も以前の記事を参照。
|
■音声認識する際の AndroidManifest.xml について
■ダイアログを使用した音声認識の利用方法
■コールバックを実装した音声認識の利用方法
●音声認識の主なエラー
●音声認識を中断する
■ユニティちゃんと音声認識でじゃんけん(Android 版デモ)
(※) Unity 5.6.3p1 / AndroidStudio 2.3.3 / Windows10(x64) / Galaxy S7 Edge (Android 7.0) で確認
■音声認識する際の AndroidManifest.xml について
※Android11 以降では音声認識(SpeechRecognizer)に専用パーミッションが必要になったようです。
プラグインのセットアップにも書いてあるが、ここではもう少し詳細に解説しておこう。Googleの音声認識など別のアプリケーションから結果を受け取る際には Unity で通常使われるアクティビティ「UnityPlayerActivity」をオーバーライドした、「ReceiveResultsOnUnityPlayerActivity」(他のアプリケーションから結果を受信するアクティビティ:プラグイン内に入っている)または「FullPluginOnUnityPlayerActivity」(プラグイン機能のすべてが入っている)を使う必要がある。これらのアクティビティ(Activity)はこのプラグイン独自のアクティビティで、他のアプリケーションから何らかのメッセージを受信できるコードが含まれている(Java コードは以前の記事に掲載してある)。インポートした「Assets/Plugins/Android/」にはマニフェストファイルのテンプレとして「AndroidManifest-Speech~.xml」または「AndroidManifest-FullPlugin~.xml」が含まれているので、これらの中から適切なものを選んで(「縦置き・横置き」とか「API Level」とか)、「AndroidManifest.xml」にリネームしてビルドすることで利用することが可能になる。

なお、ダイアログを表示せず、音声認識のコールバックイベントを実装して結果を受信するなら、オーバーライドしたアクティビティを使う必要はない。具体的には例えば、後述する「StartSpeechRecognizer()」を使って音声認識の音声待機・開始・結果取得・エラーのコールバックを実装するなら、これらマニフェストファイルは必要ない(Unity がデフォルトのマニフェストファイルを用意してくれる)。Unity ではキャラなどを出したいことも多いと思うので、少し大変だが、コールバックイベントを実装していく方法はオススメだ。
(※) 音声認識にはマニフェストファイルに録音パーミッション "RECORD_AUDIO" が必要(「AndroidManifest-Speech~.xml」または「AndroidManifest-FullPlugin~.xml」には含まれている)。
(※) 独自のマニフェストファイルでビルドすると警告「Unable to find unity activity in manifest. You need to make sure orientation attribute is set to sensorPortrait manually.」が出るが、「UnityPlayerActivity」以外のアクティビティを使うと出るものなので気にしなくて良い(orientation=画面回転はUnity側のアプリの設定に合わせた方が良い)。
■ダイアログを使用した音声認識の利用方法

サンプルシーン「SpeechRecognizerTest」には2つの方法が含まれているが、こちらは「Speech Dialog」のボタンを押したとき出てくる Googleの音声認識ダイアログを利用する方法だ。簡単に言えば、このダイアログは別のアプリケーションであって、それを呼び出して結果だけを受け取る方法であり、音声認識中の待機や開始、失敗(エラー)のときなどは任せっきりで、結果を受け取るだけなので実装は非常に楽だ。しかし、前述した「別のアプリケーションから結果を受け取る特別なアクティビティ」が必要なのと、ダイアログの性質上、画面にオーバーレイで重ねられて表示されるので、Unity でキャラなどが表示されている場合見えなくなってしまうのがデメリットだ。なので、InputField の文字入力の代わりに使うなど、見た目を気にする必要がないときに利用する方が良いだろう(受信する結果などは後述するコールバックの方法と何ら変わりはない)。
それでは、音声認識のダイアログを呼び出す所からやってみよう。
●Unity から音声認識ダイアログを呼び出す
using FantomLib;
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidPlugin.ShowSpeechRecognizer(callbackGameObject, resultCallbackMethod, message);
#endif
●引数
callbackGameObject | 音声認識が成功した際、結果をコールバックするヒエラルキーにある GameObject の名前。 |
---|---|
resultCallbackMethod | 音声認識が成功した際、結果をコールバックするメソッドの名前(callbackGameObject 内)。引数に string 型を1つとる。 |
message | ダイアログに表示されるメッセージ文字列。省略すると(=空文字("")) "なんでも話してみてください" になる(システム/バージョンによるかも)。 |
認識された音声は "候補1\n候補2\n候補3" のように改行区切り("\n") でヒエラルキーにある GameObject(callbackGameObject)にあるメソッド(resultCallbackMethod)の引数(string 型)として1つづきの文字列として送られてくる。メソッドの名前は任意だが、シグニチャが違っていると無視されてしまうので気をつけよう。例えば結果のコールバックメソッドの名前を "OnResult" と名付けたとすると、以下のように書けば、認識された1つ1つの候補が列挙できる。
●音声認識された文字列を受信するコード
private void OnResult(string result)
{
string[] words = result.Split('\n');
foreach (var item in words)
{
Debug.Log(item); //各候補の文字列
}
}
ここでは foreach で認識された各候補を表示しているだけだが、ここであらかじめ作っておいた辞書などと照合して処理を分岐したり、プラグインの選択ダイアログを使ってユーザーに絞り込んで貰って、文字列を InputField に代入して利用するなどでも良いだろう。
サンプルコード「SpeechRecognizerTest.cs」では「ShowSpeechRecognizer()」「ResultSpeechRecognizer()」になるので、コピペなどして使えば難しくはないだろう。シーン「SpeechRecognizerTest」内で「Web Search」のチェックをオンにしたときには選択ダイアログが出るようにしてあるので、絞り込みをしたいときはこの辺りをまるっとコピペすれば簡単に使えると思う。
■コールバックを実装した音声認識の利用方法

こちらは前述のダイアログを使用した方法とは異なり、Unity でダイアログを介さずに音声認識の結果やエラーなどを受信する方法となる。サンプルシーン「SpeechRecognizerTest」では「Speech Here」のボタンを押したときがそれだ。少し大変かも知れないが、ダイアログを使うより自由度は高いので、Unity などビジュアルが中心のコンテンツには合っている(ビジネスツールみたいなものは、かえってダイアログを出したほうがわかりやすい気がする)。「一択彼女(加藤恵)」みたいなアプリも内部的には同じものを使ってると思う(このプラグインとは関係ないです)。ちなみに音声認識中の "ピロ♪" という音は消せないそうだ。
なお、こちらのコールバックを実装する方法では前述した特別なアクティビティは必要ないが、録音パーミッション("RECORD_AUDIO")だけは必要だ。
それではダイアログなしの音声認識を開始するコードを書いてみよう。また未確認だが、機種によって微妙に挙動が異なるとの話もあるので、実機があるのなら色々テストしておいた方が良いかも知れない。
●Unity からコールバックを実装した音声認識を開始する
using FantomLib;
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidPlugin.StartSpeechRecognizer(callbackGameObject, resultCallbackMethod, errorCallbackMethod,
readyCallbackMethod, beginCallbackMethod);
#endif
●引数
callbackGameObject | 音声認識の結果やエラーなどをコールバックするヒエラルキーにある GameObject の名前。 |
---|---|
resultCallbackMethod | 音声認識が成功した際、結果をコールバックするメソッドの名前(callbackGameObject 内)。引数に string 型を1つとる(結果が返る)。 |
errorCallbackMethod | 音声認識が失敗した際、エラーをコールバックするメソッドの名前(callbackGameObject 内)。引数に string 型を1つとる。主なエラーは以下を参照。 |
readyCallbackMethod | 音声認識が開始され、声の待機をはじめたときコールバックするメソッドの名前(callbackGameObject 内)。UI などを変化させて音声認識がオンになった状態がユーザーにわかるようにしてあげると良い。引数に string 型を1つとる。値は必ず "onReadyForSpeech" になる。タイミングをとるためだけのコールバック。省略可。 |
beginCallbackMethod | 音声認識が開始→待機から、はじめの声がマイクに入ったときコールバックするメソッドの名前(callbackGameObject 内)。UI などを変化させて認識中であることをユーザーにわかるようにしてあげると良い。引数に string 型を1つとる。値は必ず "onBeginningOfSpeech" になる。タイミングをとるためだけのコールバック。省略可。 |
コールバックは色々あって大変なのだが、特に重要なものは結果(resultCallbackMethod)とエラー(errorCallbackMethod)のコールバックだ。以下に例を載せておこう。
例えば結果のコールバックメソッド(resultCallbackMethod)の名前を "OnResult" と名付けたとすると、以下のように書けば、認識された1つ1つの候補が列挙できる。
●音声認識された文字列を受信するコード
private void OnResult(string result)
{
string[] words = result.Split('\n');
foreach (var item in words)
{
Debug.Log(item); //各候補の文字列
}
}
認識された音声は "候補1\n候補2\n候補3" のように改行区切り("\n") でヒエラルキーにある GameObject(callbackGameObject)にあるメソッド(resultCallbackMethod)の引数(string 型)として1つづきの文字列として送られてくる。メソッドの名前は任意だが、シグニチャが違っていると無視されてしまうので気をつけよう。
ここでは foreach で認識された各候補を表示しているだけだが、ここであらかじめ作っておいた辞書などと照合して処理を分岐したり、プラグインの選択ダイアログを使ってユーザーに絞り込んで貰うのも良いだろう。
次にエラー時のコールバックメソッド(errorCallbackMethod)の名前を "OnError" と名付けたとすると、以下のように書けば、エラーでの分岐ができる。
●音声認識で失敗したときのエラーを受信するコード
private void OnError(string errmes)
{
switch (errmes) {
case "ERROR_NO_MATCH":
Debug.Log("認識失敗");
break;
case "ERROR_SPEECH_TIMEOUT":
Debug.Log("タイムアウト");
break;
case "ERROR_NETWORK":
Debug.Log("ネットワークに繋がらない");
break;
case "ERROR_AUDIO":
Debug.Log("録音パーミッションがない");
break;
・・・(略)・・・
}
}
引数で返ってくる値はエラーコードの文字列となる。エラーコードは公式のデベロッパーサイトも参照して欲しいが主に以下のものが出ると考えて良いだろう。
●音声認識でよく出るエラー
ERROR_NO_MATCH | 音声認識できなかったときに出るエラー。1音のような短いときや、声量が小さすぎるとき、周りの騒音が邪魔で聴き取れないときなどに出やすい。 |
---|---|
ERROR_SPEECH_TIMEOUT | 音声認識が開始→待機中に時間切れしたときに出るエラー。周りの騒音が邪魔で聴き取れないときなどにも出ることがある。 |
ERROR_NETWORK | 認識された語句をネットワーク上のデータベースと照合する際に接続できなかったときのエラー。他のアプリがネットワークを専有してたり、何からの理由でネットワークがブロックされているときにも出る。 |
ERROR_AUDIO | マニフェストファイル(AndroidManifest.xml)に録音パーミッション("RECORD_AUDIO")が無いときに出るエラー。パーミッションタグを挿入して再ビルドするしかない。 |
他のエラーは以下を参照。
・SpeechRecognizer
その他には音声認識の起動のコールバック(readyCallbackMethod)、声の取得開始(beginCallbackMethod)があるが、それぞれ必ず "onReadyForSpeech", "onBeginningOfSpeech" の文字列が返る。これらはタイミングをとるためのコールバックなので、ここで UI を変化させたり、アニメーションを開始したりすると良いだろう。
これらのサンプルコードは「SpeechRecognizerTest.cs」の「StartSpeechRecognizer()」「OnReady」「OnBegin」「OnResult」「OnError」とほぼ同じだ。コピペして中身だけ入れ替えれば簡単に利用できるだろう。
もう1つ、中断する方法を書いておこう、これはリリース(オブジェクト解放)と同じものになる。未確認だが、この中断の挙動が実機の機種によって微妙に違うという話を見たので、使う際は気をつけた方が良いかも知れない。基本的にこの音声認識は放っておいても認識失敗("ERROR_NO_MATCH")かタイムアウト("ERROR_SPEECH_TIMEOUT")で停止するので、必要ないなら中断機能を付けないのも手だ。ともあれ、とりえあず例を載せておこう。といっても音声認識のオブジェクトをリリースするだけだ。
●音声認識を中断・リリースする
using FantomLib;
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidPlugin.ReleaseSpeechRecognizer();
#endif
内部的なコード(Java)には「SpeechRecognizer.destroy()」を使っている。他にも「SpeechRecognizer.cancel()」とか「SpeechRecognizer.stopListening()」も試してみたが、なぜか私の環境(Galaxy S7 Edge)では上手く行かなかった。この辺りが「停止は機種によって微妙に挙動が違う」と言われる所以なのかも知れない。なので確実に停止させるためには、オブジェクトをリリースするのが一番と考えてこの方法のみを実装してある。
中断のサンプルは「SpeechRecognizerTest.cs」の「StopSpeechRecognizer()」になるが、同時に UI を止めているくらいで、それほど見る必要もないかも知れない。
■ユニティちゃんと音声認識でじゃんけん(Android 版)
せっかくなので、このプラグインを使って音声認識でじゃんけんゲームを作ってみた。音声認識の箇所はパッケージに入っている「Assets/_Test/Scripts/SpeechRecognizerTest.cs」をほぼそのまま使っている。具体的には、受け取った結果は改行("\n")で連結されてくるのでそれを分割し、それらの最初の1文字でグー、チョキ、パーを判定する処理(いくつか候補をデータ化してある)を追加しただけだ。
(※) Unity 2017.1.1f1 / Windows10(x64) でビルド。Galaxy S7 Edge (Android 7.0) で確認。
|


Android 4.2以上
※「提供元不明アプリのインストール」許可が必要です。
じゃんけん自体のアルゴリズム・作成方法を知りたければ以下の書籍を参考にすると良いだろう。アイコンがそっくりなのは、実際にこの本を以前読んでいたためである(笑)(※アプリ内のアイコンは新たに作ったものです)。また音声認識は以下の本も参考にしている(※ただし少し古い。実際のビルドは AndroidStudio 2.3.3 でやった)。なのでこのサンプルは2つをミックスしただけとも言える(笑)。
(じゃんけん画像素材)
・LiveMaker 指南番
※この記事のUnityアセットはプラグインとして配布されています。
※とりあえず試してみたい方は、最新版をビルドした apk デモをダウンロードできます。動作確認にもどうぞ。


Android 4.2以上
※「提供元不明アプリのインストール」許可が必要です。
(関連記事)
【Android】【Java】音声入力(音声認識)で文字列を取得する
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】Androidのテキスト読み上げ(TextToSpeech)を使う
【Unity】Androidでカスタマイズしたダイアログを動的生成できるプラグインを作ってみた
【Unity】Androidでスライダーで設定を変更するダイアログを使う
【Unity】Androidでスイッチで設定を変更するダイアログを使う
【Unity】Androidの選択ダイアログを使う
【Unity】Androidで日付・時刻選択ダイアログ(DatePicker, TimePicker)を使う
【Unity】Androidで数値・半角英数・パスワード入力ダイアログを使う
【Unity】Androidでテキスト入力ダイアログを使う

- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/284-66346cfa
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |