Unity製Androidアプリで音声認識をする方法

Unity製Androidアプリで音声認識をする方法、意外にハマってしまったので自分用メモも兼ねてまとめておきます。
Unity4.5時代に書いた記事をQiitaで書き直してるのでもしかしたら古いかも。

概要
-----
JavaNativePluginを使ってAndroidの機能である音声認識機能を呼び出します。

JavaNativePluginで呼び出すには2種類ありまして…
・Activityを上書きせず、単純にJavaコードを呼び出す方法
・Activityを上書きする方法
があります。

ざっくり説明すると、前者は「Androidとは関係なく単純にJavaクラスをUnityスクリプトから利用したい場合有用」後者は「Pluginを通じてAndroidOSの機能を利用する場合に有用で、特にメインスレッドから呼び出さなくてはいけない機能を使う場合はこちらを使う必要があります。」
（詳細参照：http://blog.imho.jp/2012/05/unity-android-java-plugin.html）

このとき大事なのは、
**音声認識を行うために必要なSpeechRecognizerクラスがメインスレッドでしか動作しないということです**
　
ということで**アセットなどを使わず**、Activityを上書きする方法を用いて音声認識をする方法をご紹介したいと思います。

流れ
-----
・音声認識のためのコード(Java)を書く。
・JARファイルにしてUnityのPluginファイルにいれる。
・Javaコードを呼び出すUnityコードを書く。
・AndroidManifest.xmlを書き加える。
・Build

音声認識のためのコード(Java)を書く。
-----
(参考：http://www.unitymanual.com/7096.html)
ただ、このコードをそのまま写経すると、永遠に音声認識機能が呼び出される感じなので改善しましょう。
まず、onCreateメソッドを

```UnityTestActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mContext = this;
    str = "";
    registerBroadcastReceiver();
    mBroadcastReceiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context,Intent intent){
            String action = intent.getAction();
            Log.i(action,action);
             
            if(action.equals(ACTION_NAME)){
                SpeechRecognizer sr2;
                sr2 = SpeechRecognizer.createSpeechRecognizer(mContext);
                sr2.setRecognitionListener(new listener());
                sr2.startListening(new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS));
            }
        }
    };
   registerBroadcastReceiver(); 
}
```
として、次に新たにmyRecogStart()というメソッドを作ります。

```UnityTestActivity.java
public void myRecogStart(){
    Intent mIntent = new Intent(ACTION_NAME);
    sendBroadcast(mIntent);
}
```
このmyRecogStart()メソッドを呼び出すことで、Broadcastに音声認識を開始するIntentを送信し、Broadcastがそれを受け取ったら音声認識開始！となります。


**(注意)**

```UnityTestActivity.java
public void MyRecogStart(){
        sr = SpeechRecognizer.createSpeechRecognizer(mContext);
    sr.setRecognitionListener(new listener());
    sr.startListening(new　Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS));    
    }
```
のようにIntentを使わず直接SpeechRecognizerを呼びだそうとすると” java.lang.RuntimeException: SpeechRecognizer should be used only from the application’s main thread”エラーが発生するのでやめましょう。


コードはGistにおいておきます。
https://gist.github.com/NegishiTakumi/ba7d678a13b85317db48

JARファイルにしてUnityのPluginファイルにいれる
---
参考にしました=> http://qiita.com/relzx/items/a35f7ab6dbacb48f7e26

あとはUnityのAssets/Plugin/Androidフォルダに作ったjarファイルを入れておくだけです。
このときjarファイルの名前は特に指定は無いと思います。
「jarファイルにするJavaファイルのpackage名」と「Unityのプロジェクトのパッケージ名を同一にする」のだけ気をつけてください。


Javaコードを呼び出すUnityコードを書く
-----
適当なMonoBehaviourを継承したコードに書きます。

```SpeechRecogTest.cs
using UnityEngine;
using System.Collections;
 
public class SpeechRecogTest : MonoBehaviour
{
    private string stringToEdit = "";
 
    private void OnGUI()
    {
        var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        var jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
 
        stringToEdit = jo.Call<string>("getStr");
        if (GUI.Button(new Rect(0, 200, 800, 100), stringToEdit))
        {
            if (Application.platform == RuntimePlatform.Android)
            {
                jo.Call("MyRecogStart");
 
            }
        }
    }
}
```
これを空のGameObjectにアタッチするだけでOKです。
　
Unityにおける通常のJavaコードの呼び出しならば、
`
var hoge = new AndroidJavaObject("パッケージ名.クラス名");
hoge.Call("メソッド名");
`
でいいんですが、
**今回はActivityを上書きする方法なので、com.unity3d.player.UnityPlayerを呼び出して、currentActivityを呼び出しています**。

AndroidManifest.xmlを書き換える
-----
AndroidManifest.xmlを書き換えます。
目的としては…
**・Activityの上書き
・permissionを書き加える**
の2点です。
　
書き換えると言っても普通にUnityだけでAndroidアプリ作るだけだと、あまりお目にかかることのないAndroidManifest.xmlですが、ちゃんと存在します。

Unityプロジェクトを作ると、Assetsディレクトリと同じ階層にTempというフォルダができていると思います。
そのTempからTemp/StagingAreaにAndroidManifest.xmlというのが見つかると思います。
それをVisualStudioなりnotepad.exeなりで開いて、


**Activityの上書きをする。**
`android:name="com.unity3d.player.UnityPlayerNativeActivity"`
を
`android:name=".MainActivity"`
にします。この.MainActivityというのは、最初に作ったJavaファイルのクラス名です。
これで、Activityの上書きができます。


**permissionを書き加える。**
`<uses-permission android:name="android.permission.RECORD_AUDIO" />`
を書き加えるだけです。簡単！！
　
そしてこれをUnityのAssets/Plugins/Android以下に配置しておくとビルド時に書き換えたManifestを参照してくれるようになります。


ビルド
----
あとは、実機にBuildして、お終いです。ちなみに音声認識の技術は以下で使われています。

<script type="text/javascript" src="http://ext.nicovideo.jp/thumb_watch/sm25705025?w=490&h=307"></script><noscript><a href="http://www.nicovideo.jp/watch/sm25705025">【ニコニコ動画】初音ミクといつでも一緒にいられるアプリ作ってみた</a></noscript>

その他気づいたこと
-----
EclipseのLogcatという開発時のデバッグログ用のビューがあると思いますが、あれってJavaのLog.d(tag,hoge)以外にもUnityの方のソースコードでDebug.Log(hoge)も出力できるんですね。

音声認識を利用するアプリ開発してて非常に便利でした。
今後NativePluginが絡んでくるものを作ろうとした時にはほぼ必須みたいな感じですね。

-----
元記事：
http://negipoyoc.com/?p=116