[Unity] Android・iOSでネイティブの音声テキスト認識を実装する

# はじめに
UnityでAndroid、iOSのネイティブ音声テキスト認識のサンプルを作成しました。
実装方法などの忘却録。

#### Android
https://developer.android.com/reference/android/speech/SpeechRecognizer?hl=ja

#### iOS
https://developer.apple.com/documentation/speech/sfspeechrecognizer

#### Apple公式のサンプル

https://developer.apple.com/documentation/speech

## 使用環境
macOS Big Sur 11.6.1
Unity 2021.1.26f1
Android Studio 4.0.1
Swift5.0

### Android Native Pluginの作り方
Android Pluginのmodule作成の基本的な作り方をまとめていますので、参考までに。

https://qiita.com/atsutama/items/28744b1a29e79184c3fc

### iOS Native Pluginの作り方
iOS Pluginのmodule作成の基本的な作り方をまとめていますので、参考までに。

https://qiita.com/atsutama/items/3c8fe716c2667be6025f

## Androidの実装について
UnitySendMessageを使う際には「jar」ファイルをインポートする必要がありますので、下記で確認出来ます。
この設定をしておかないとコードを書いた時にimportエラーが出ます。

https://qiita.com/atsutama/items/28744b1a29e79184c3fc#unity%E6%A9%9F%E8%83%BD%E3%82%92android%E3%81%8B%E3%82%89%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E6%BA%96%E5%82%99

#### UnitySendMessageの引数説明
`UnitySendMessage("GameObject名","関数名","引数");`

- 第一引数にGameObject名、ここでは`callbackTarget`でUnityから指定してます。
- 第二引数に関数名、ここでは`callbackMethod `でUnityから指定してます。
- 第三引数にUnity側で受け取る文字列を指定しています。

また、音声認識を行うために必要な`SpeechRecognizer`クラスが**<font color="Red">メインスレッド</font>**でしか動作しない。

#### NativeSpeechRecognizer.java
https://github.com/atsutama2/AndroidNativePluginTest/blob/main/NativeSpeechRecognizer/src/main/java/jp/co/test/nativespeechrecognizer/NativeSpeechRecognizer.java

## iOSの実装について
「ビルド周りのEditor拡張」が必要です。
また、下記の2点をinfo.plistに追加しないとクラッシュしますので、注意が必要です。
こちらをビルド時に追加するので`PostProcessor.cs`で指定しています。

```plist:info.plist
<key>NSMicrophoneUsageDescription</key>
<string>音読音声の認識にマイクを使用します</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>音読音声の認識に音声認識を利用します</string>
```

#### PostProcessor.cs
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Editor/PostProcessor.cs

#### NativeSpeechRecognizer.swift
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Plugins/iOS/NativeSpeechRecognizer.swift

#### NativeSpeechRecognizer.mm
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Plugins/iOS/NativeSpeechRecognizer.mm


## Unity側のコード

#### ランタイムパーミッション要求が必要
音声認識で使用するマイクパーミッションの許可を取得しないといけません。
コードはこちらを参考にさせて頂きました。

https://qiita.com/utibenkei/items/65b56c13f43ce5809561#%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%91%E3%83%BC%E3%83%9F%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E8%A6%81%E6%B1%82%E3%81%AE%E4%BE%8B

最初にマイクが許可されているかを調べ、無ければ権限をリクエストします。

```c#
#if UNITY_IOS
    yield return Application.RequestUserAuthorization(UserAuthorization.Microphone);
    if (Application.HasUserAuthorization(UserAuthorization.Microphone)) {
        
    } else {
        Debug.Log("[iOS] Microphone not found");
    }
#endif

#if UNITY_ANDROID
    // マイクパーミッションが許可されているか調べる
    if (!Permission.HasUserAuthorizedPermission (Permission.Microphone)) {
        // 権限が無いので、マイクパーミッションのリクエストをする
        yield return RequestUserPermission (Permission.Microphone);
    } else {
        Debug.Log("[Android] Microphone not found");
    }
#endif
```

こちら`Microphone.devices`で[マイクデバイスの一覧](https://docs.unity3d.com/ja/2018.4/ScriptReference/Microphone-devices.html)の取得をしています。
イヤホンの時もありますね。

```c#
foreach (var device in Microphone.devices)
{
    Debug.Log("Name: " + device);
    _text.text = _text.text+"\n " + device;
}
```

#### NativeSpeechRecognizerView.cs
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Scripts/NativeSpeechRecognizerView.cs

また、`Disable Unity Audio`にチェックが入っているとマイクデバイスが取得出来ません。
※ ここをチェックを入れるとUnityのデフォルトのオーディオ機能を無効化できます。
`Edit`→`ProjectSettings`→`Audio`→`Disable Unity Audio`です。
[Audioを参考](https://docs.unity3d.com/ja/2018.4/Manual/class-AudioManager.html)
![ 2021-11-17 20.44.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1022988/b02e6688-8a48-b1a1-cf39-7813f9ef6470.png)

## AndroidManifestの変更
オーディオのパーミッションの許可が必要です。
`android.permissionn.RECORD_AUDIO`
また、オンラインで音声入力をしたいので、`android.permissions.INTERNET`を許可する必要があります。

#### AndroidManifest.xml
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Plugins/Android/AndroidManifest.xml.DISABLED

## 成果物
ビルドしてもらい実機で確認可能です。該当Sceneはこちら。

#### SpeechRecognitionTestScene.unity
https://github.com/atsutama2/NativePluginTest/blob/main/Assets/Scenes/SpeechRecognitionTestScene.unity

AndroidStudio Logcatでは下記のようになります。
(Gif画像あり)
![logcat.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1022988/bf70fbdb-9611-32e9-ff16-7baccc6dbd11.gif)


https://github.com/atsutama2/AndroidNativePluginTest

https://github.com/atsutama2/NativePluginTest

## 参考文献

https://dev.classmethod.jp/articles/try-ios10-speech-recognizer/

https://qiita.com/takashings/items/8e167767fad1e4df3fea

https://qiita.com/mtfum/items/d842c8f5a0e5b99fa4ad

https://qiita.com/shirahama_manabu/items/09676df4073102a1aeba

https://qiita.com/mishimay/items/71304f0aa2a313ad93ac