rksoftware

Visual Studio とか C# とかが好きです

Xamarin Android で音声認識をする

Xamarin.Android で音声認識の API を使ってみました。
早速ですがコードです。

using Android.App;
using Android.Widget;
using Android.OS;
using System.Linq;

namespace SpeechRecognizer
{
    [Activity(Label = "SpeechRecognizer", MainLauncher = true)]
    public class MainActivity : Activity
    {
        private static int _requestCode { get; } = 1;

        private TextView _text;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // ドダイ
            var parent = new LinearLayout(this) { Orientation = Orientation.Vertical, };
            SetContentView(parent);

            // ボタン
            var button1 = new Button(this) { Text = "風の気持ちで語りかける(Activityあり)", TextSize = 24, };
            parent.AddView(button1);
            var button2 = new Button(this) { Text = "風の気持ちで語りかける(Activityなし)", TextSize = 24, };
            parent.AddView(button2);

            // テキスト
            var text = _text = new TextView(this) { TextSize = 24, };
            parent.AddView(text);

            // ボタン
            button1.Click += (sender, e) => StartSpeechRecognizerActivity(this);
            button2.Click += (sender, e) => StartSpeechRecognizerListening(this);
        }

        // 音声認識の Activity を表示しないパターン (<uses-permission android:name="android.permission.RECORD_AUDIO" />が必要)
        protected void StartSpeechRecognizerListening(Activity con)
        {
            var intent = new Android.Content.Intent(Android.Speech.RecognizerIntent.ActionRecognizeSpeech);
            intent.PutExtra(Android.Speech.RecognizerIntent.ExtraLanguageModel, Android.Speech.RecognizerIntent.LanguageModelFreeForm);

            var recognizer = Android.Speech.SpeechRecognizer.CreateSpeechRecognizer(con);

            recognizer.Results += (sender, e) =>
            {
                var values = e.Results.GetStringArrayList(Android.Speech.SpeechRecognizer.ResultsRecognition);
                _text.Text = values == null ? "(null)" : string.Join(", ", values.ToArray());
            };

            recognizer.StartListening(intent);
        }

        // 音声認識の Activity を表示するパターン
        protected void StartSpeechRecognizerActivity(Activity con)
        {
            var intent = new Android.Content.Intent(Android.Speech.RecognizerIntent.ActionRecognizeSpeech);
            intent.PutExtra(Android.Speech.RecognizerIntent.ExtraLanguageModel, Android.Speech.RecognizerIntent.LanguageModelFreeForm);
            intent.PutExtra(Android.Speech.RecognizerIntent.ExtraPrompt, "風の気持ちで語りかけてください");

            con.StartActivityForResult(intent, _requestCode);
        }

        // 標準の音声認識の Activity の結果が帰ってくる
        protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent data)
        {
            if (_requestCode != requestCode) return;
            if (Result.Ok != resultCode) return;

            var values = data.GetStringArrayListExtra(Android.Speech.RecognizerIntent.ExtraResults);
            _text.Text = values == null ? "(null)" : string.Join(", ", values.ToArray());

            base.OnActivityResult(requestCode, resultCode, data);
        }
    }
}

コードは基本的に、Android での情報を参考にしています。次の記事に非常にお世話になりました。

二つの方式

このコードを動かすと、次のように二つのボタンがあります。

音声認識には大きく二つの方式があり、それぞれのボタンが対応しています。

Android の音声認識用の Activity を表示する

音声認識中に、標準の UI が表示される方式です。
・ボタンを押すと音声認識中とわかる標準の UI が表示され...

・認識した文言を表示します。

私はこちらの方が好きですが、アプリの仕様を決める方にはもう一方の方式が人気ありそうです。

Android の音声認識用の Activity を表示しない

音声認識中に、標準の UI が表示されない方式です。
・ボタンを押すと UI 上は何も起きず...

・Android に語りかけると認識した文言を表示します。

音声認識中とわかる標準の UI は表示されませんが、逆に音声認識中に自由な UI を表示できます。
例えば、イルカや羊を表示するなどしたい場合はこちらの方式を使うことになります。私のおススメはイルカです。

permission

・Activity を表示しないパターンの場合は、RECORD_AUDIO の permission が必要です。
・表示するパターンでは permission は不要でした。

結果の文言はリストで複数返ってくる

音声の候補はすべてリストで返ってくる。これにより同音異義語や活舌が悪かった場合などにも対応できます。
上記の例でも「うまいうますぎる」と語り掛けたのですが、「甘い甘すぎる」かもしれないと認識して両方を候補として返してくれています。

「甘い甘すぎる」が何なのかはよくわかりませんが...。

文字の表記の違いも OK

同じ音で日本語の漢字等の表記の違いも候補としてリストで返してくれます。
次の例では「かすみがせきえき」で「霞ヶ関駅(埼玉県)」と「霞ケ関駅(東京都)」の両方を候補として返してくれています。

これにより例えば 東京国際大学(最寄り駅「霞ヶ関駅(埼玉県)」)へ行きたいユーザーに間違えて「霞ケ関駅(東京都)」へのルートを案内してしまうといった不幸な事故が防げますね。