Azure
Xamarin
Xamarin.Forms
CognitiveServices

Xamarin.FormsとCognitive Servicesで話者識別をやってみる

はじめに

この投稿は Xamarin Advent Calendar 2017 の 17 日目の記事です。

Cognitive Servicesでは、様々なAPIが提供されています。
しかしながら「Speaker Recognition API」については、あまり日本国内で話を聞くことはありません。
そこで、 Xamarin.Forms と Speaker Recognition API で、サクッと話者識別アプリを使ってみようと思いました!

が、間に合いませんでした・・・

ということで、、、Speaker Recognition APIのご紹介や、Xamarin.Formsではこうやって使えます。
というご紹介ができればと思います!
色々と実験したので、その結果も共有します。

Speaker Recognition API

公式のAPI Referenceはこちらです。

話者認証 (Speaker Verification)

これは「パスワードの代わりに音声を使用する」ことができるものです。
Xamarinで作るモバイルアプリにも、この機能を簡単に実装できます。
ただし、まだ、日本語に対応していません。

事前に指定された10種類の英語のフレーズから、どれかを選び、それを読み上げて登録します。
このため、日本語に対応していなくても使えそうな気がしますが、
残念ながらノンネイティブな発音では、そもそも認識をしてくれないケースが多かったです。

ちなみに、日本語ネイティブの人の発音で最も認識率が高かったのは、
my name is unknown to you
でした。
推測ですが、以下が理由かなと思っています。
- LやRが含まれていない。
- my name is は、そのイントネーションに慣れている人が多い。

話者識別 (Speaker Identification)

これは「今、誰が話しているか」を識別することができるものです。
Xamarinで作るモバイルアプリにも、この機能を簡単に実装できます。
残念ながら、こちらもまだ、日本語に対応していません。

ただ、こちらについては、日本語でもそれなりの精度が出るようなので、
アプリに組み込んでも面白いかなと思います。

話者識別アプリをXamarin.Formsで作ってみる!

こんな感じものを作ってみます

  1. ユーザを指定して登録
  2. ユーザを指定して音声を登録
  3. 登録した誰かが話す
  4. 誰が話をしたか表示する

スクリーンショット

1. ユーザをユーザ名を指定して登録

Speaker Recognition APIにLocaleを指定してPOSTします。
登録が成功すると、JSONでユーザのIdentificationProfileId(GUID)が帰ってきます。
IdentificationProfileIdは、こちらで指定できないので、帰ってきた結果とユーザ情報などを紐づける必要があります。

        public async Task<string> CreateProfile()
        {
            var client = new HttpClient();

            //SubscriptionKeyはAzureの管理ポータルから確認可能。
            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{SubscriptionKey}");

            var uri = "https://westus.api.cognitive.microsoft.com/spid/v1.0/identificationProfiles";

            HttpResponseMessage response;

            // Localeはja-jpが使えないので en-us にする。
            byte[] byteData = Encoding.UTF8.GetBytes("{\"locale\":\"en-us\"}");

            using (var content = new ByteArrayContent(byteData))
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                response = await client.PostAsync(uri, content);
            }

            //JSONでIdentificationProfileId(GUID)が帰ってくるので受け取ってパースする。
            var responceContent = await response.Content.ReadAsStringAsync();
            var deserializedResponse = JsonConvert.DeserializeObject<IdentificationProfileId>(responceContent);

            return deserializedResponse.Id;
        }

2. ユーザを指定して音声を登録

identificationProfileId を指定して、wavファイルをPOSTします。
ここでは、Xamarin.Formsで簡単にwavを録音できる
Audio Recorder plugin for Xamarin and Windows」を使ってみました。
ここ以降作りかけなので、そのままでは動きません。(ごめんなさい)

        //作りかけです。。。
     public async Task<string> CreateEnrollment(string identificationProfileId)
        {

            var recorder = new AudioRecorderService
            {
                StopRecordingOnSilence = true,
                StopRecordingAfterTimeout = true,
                TotalAudioTimeout = TimeSpan.FromSeconds(15)
            };

            var recordTask = await recorder.StartRecording();
            var audioFile = await recordTask;

            var client = new HttpClient();

            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{SubscriptionKey}");

            var uri = $@"https://westus.api.cognitive.microsoft.com/spid/v1.0/identificationProfiles/{identificationProfileId}/enroll?shortAudio=true";

            HttpResponseMessage response;

            var byteData = new byte[audioFile.Length];
            //結局、DependencyServiceを使わないと、iOSのストレージにアクセスできないじゃん(´;ω;`)

            using (var content = new ByteArrayContent(byteData))
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");

                response = await client.PostAsync(uri, content);
            }

            var responceContent = await response.Content.ReadAsStringAsync();

            return responceContent;
        }

3. 登録した誰かが話す

2.と同じ要領で、対象となるidentificationProfileId を指定(10IDまで)して、wavファイルをPOSTします。
これで、下記のような結果(抜粋)が帰ってきます。
Confidenceとして、信頼度も帰ってきます。
日本語でも動作しました∩(´∀`)∩

    "IdentifiedProfileId": "0e1e82c8-32b1-45b0-8989-fe61efc95ead",
    "Confidence": "High"

4. 誰が話をしたか表示する

3.で IdentifiedProfileIdが帰ってきているので、それに基づいて表示するだけですね。

おわりに

間に合わなくて申し訳ございません(´;ω;`)

Speaker Recognition API は、Xamarinでも簡単に使えるので、
アイデア次第で、モバイルアプリに話者識別を組み込んだ楽しいものが作れそうですね!