読者です 読者をやめる 読者になる 読者になる

(4-1) UnityでBing Speech to Text API(Android用)を使う方法

Unity Android

以前紹介した、MicrosoftのBing Speech To TextをUnityで使えるようにしてみました。

magicbullet.hatenablog.jp

ただ、Android nativeアプリ開発に不慣れだったこともあり、色々とつまづきました。

せっかくなので、修正過程を整理しておこうと思います。

実行した環境は以下です。

MacOS X 10.11.6
Android Studio 2.1.2

Windows10環境では試していませんが、Android Studioの話なので動くと思います。

=====

手順

1. Android Studio側の手順

1-1. Android Studioプロジェクトサンプルを入手し、動作確認

1-2. Module & Service化

1-3. ビルド

2章以降は別の記事に掲載
=====

1. Android Studio側の手順

1-1. Android Studioプロジェクトサンプルを入手し、動作確認

まずはMicrosoftが提供しているサンプルコードを入手します。

github.com

これをAndroid Studioで開きます。開いた後、下記の手順に従って、Androidスマートフォンで動くように設定します。

magicbullet.hatenablog.jp

この記事でも紹介しましたが、私の環境では、アプリインストール直後は、ほぼ必ず1,2回動作に失敗しました。
(Login Failedというエラーが出ます)

この場合、アプリの再インストールか再起動を繰り返してみてください。

1-2. Module & Service化

Microsoftが提供するサンプルコードは、アプリ(app)になっています。これだとUnityでアプリ化できないので、モジュール(library)に変更します。

アプリとモジュールの違いについては、下記を参照ください。また、以後は下記を確認済みとして解説します。

magicbullet.hatenablog.jp


以下、手順です。

[1] classes.jarを追加

以下のclasses.jarでctrl+cした後、Android Studioを開いてlibフォルダで、ctrl+pします。

Macの場合
/アプリケーション/Unity/PlaybackEngine/AndroidPlayer/Variations/mono/Release/Classes/classes.jar

Windowsの場合
C:\Program Files\Unity\Editor\Data/PlaybackEngines/AndroidPlayer/Varitations/mono/Release/Classes/classes.jar

classes.jarをドラッグ&ドロップすると、copyではなくmove扱いになって、Unityの本来のフォルダからclasses.jarが消えてしまうので注意してください。

コピーすると、Android Studio上ではこのように配置されます。

f:id:Takyu:20161106131058p:plain

メッセージウインドウが2回出ますが、どちらもOKを選択してください。


[2] build.gradleを修正

applicationではなくlibraryとしてビルドするため、先頭を変更します。

また、末尾(でなくてもよいですが)に、android.libraryVariants.all を使って、ビルド時の条件を追加します。

それ以外は元のMicrosoftのサンプルと同様です。下記のようになります。


gist1df4689cfea9d7484a04147b83e01c8b


[3] Unityと通信するためのI/Fクラスを追加

Project Viewにして、com.microsoft.CognitiveServicesExampleで右クリックし、New / Java Class を選択して、新しくクラスを追加します。

私の場合、クラス名をNativeBridgeとしました。

f:id:Takyu:20161106175735p:plain


[4] I/Fクラス NativeBridge.javaにbindServiceの機能を実装

色々試しましたが、最終的に元のMicrosoftの機能をService化することで、動作させることができました。

以下はNativeBridge側の機能です。

ざっくり説明すると、元の機能をServiceとして呼び出し、bindServiceによってUnity側のActivityとつなぎ、Service化した機能をUnityに渡しています。

bindServiceの書き方は少し複雑ですが、いくつか調べたところ、決まったフォーマットで書けばよいことがわかったので、それに倣って書きました。

下記はNativeBridge.javaの実装例です。


gist47c7cb56bd156593badcefcca2a80827

なお、これだけを書いた時点では多数のエラーが出ます。それはMainActivity.java側を変更していないためなので、この時点では無視して問題ありません。


[5] Activityクラスを修正

Serviceとして呼ぶためにActivityの記述を削除すること、およびUnityに音声認識結果を返すためにUnitySendMessage関数を仕込むこと、の2つが大きな修正目的です。

個別に説明すると相当多くなるので、ここでは主な修正箇所をざっと解説します。余力があればgithubで全体を公開します。


(2016/11/27 追記:Githubで公開しました。)

import

以下を追加。

import android.os.IBinder;

import android.util.Log;
import com.unity3d.player.UnityPlayer;

import android.content.Intent;

import android.app.Service;
import android.os.Binder;
bindService

以下を追加。

    public class MyServiceLocalBinder extends Binder {
        MainActivity getService() {
            return MainActivity.this;
        }
    }
    private final IBinder mBinder = new MyServiceLocalBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    @Override
    public void onRebind(Intent intent){}

    @Override
    public boolean onUnbind(Intent intent){
        //onUnbindをreturn trueでoverrideすると次回バインド時にonRebildが呼ばれる
        return true;
    }
元のサンプルコードでボタンやラジオボタンで処理が分かれる箇所

基本的に全てtrueで返し、ボタン関係の処理はコメントアウトします。

認識対象の言語

下記のようにgetDefaultLocaleメソッドを修正し、日本語対応させます。

    private String getDefaultLocale() {  return "ja-jp"; }
onCreateメソッドの削除

全てコメントアウトします。

StartButton_Clickメソッドの変更

このメソッドの中では、Activityを引数に持つメソッドを呼び出す箇所が何個かあります。

ただ、今回はServiceにしているので、Activityを引数に持たないようにします。

幸い、呼び出したいメソッドを調べるとActivityが引数にない場合の宣言もあるので、こっちを使います。

また、StartButton_Clickメソッドの引数はなしにしておきます。

onFinalResponseReceivedメソッドにUnitySendMessageを追加

このメソッドは、音声認識が完了すると呼ばれます。
そこで、ここにUnitySendMessageを挟むことで、認識結果の文字列をUnity側に送ることができます。

具体的には、

 for (int i = 0; i < response.Results.length; i++) {
                UnityPlayer.UnitySendMessage("TestObject","onCallBackShowResult",response.Results[i].DisplayText);
             //   this.WriteLine("[" + i + "]" + " Confidence=" + response.Results[i].Confidence +
             //           " Text=\"" + response.Results[i].DisplayText + "\"");
}

のように記述します。

1-3. ビルド

Terminalを開いて、

./gradlew :samples:SpeechRecoExample:clean :samples:SpeechRecoExample:assembleRelease

を実行します。

Terminalの場所については、下記の2-5を参照ください。

magicbullet.hatenablog.jp



ここまで実行すると、Android Studio側の対応が完了します。

Unity側は次回記載します。