開発者コンソール

手順8: スキルをテストしてCloudWatchでログを確認する


手順8: スキルをテストしてCloudWatchでログを確認する

スキルのテストを実行して、AlexaからLambda関数に送信されるディレクティブを確認します。AlexaからLambda関数に送信されたディレクティブをCloudWatchで一覧表示して、やり取りを確認できます。Lambda関数がアプリに送信するレスポンスを確認するには、Android StudioでLogcatを開きます。

adbを使用してFire TVに接続する方法

ここまでの手順で、セキュリティプロファイルの構成が完了し、準備が整いました。この手順では、Fire TV対応アプリを実行し、すべてが正常に機能して承認が成功するかを確認します。Fire TVでアプリを実行する方法の詳細については、adbを使用してFire TVに接続するを参照してください。以下に、その方法を簡単に説明します。

  1. Fire TVで、[My Fire TV] > [開発者オプション] の順にクリックします。[ADBデバッグ][不明ソースからのアプリ] を有効にします。
  2. Fire TVで、[設定] から、[My Fire TV] > [バージョン情報] > [ネットワーク] の順にクリックします(一部のFire TVモデルでは、[My Fire TV] ではなく [デバイス] と表示される場合があります)。この画面に表示されるIPアドレスを書き留めます。
  3. コンピューターがFire TVと同じWi-Fiネットワークに接続されていることを確認します。
  4. ターミナルウィンドウを開き、次のコマンドを実行します。

    adb connect <ipaddress>:<port>
    

    <port>には、5555~5585の範囲でポート番号を指定できます。

    次に例を示します。

    adb connect 10.49.172.51:5555
    

    adbがFire TVに接続できない場合は、同じWi-Fiネットワークを使用していることを確認してください。同じWi-Fiネットワークを使用している場合は、ポートに競合が生じている可能性があるため、Fire TVを再起動してください([設定] > [My Fire TV] > [再起動])。

  5. Fire TVに正常に接続できたら、Android Studioを開き、[Run App] ボタンRun Appをクリックしてアプリを実行します。
  6. 接続先のFire TVデバイスを選択し、[OK] をクリックします。

    対象のFire TVデバイスを選択する
    対象のFire TVデバイスを選択する
  7. アプリが実行されていることを確認します。Android StudioでLogcatを開き、ログメッセージをモニタリングします。アプリが実行されていれば、セキュリティプロファイルは正しく構成されていることになります。サンプルアプリのホーム画面は次のようになります。

    サンプルアプリで使用するカタログに統合されている3つのオープンソースビデオ
    サンプルアプリで使用するカタログに統合されている3つのオープンソースビデオ

    アプリの画面が空白になる場合やその他の問題がある場合は、Logcatを開き、「Error」でフィルタリングします。 「Invalid API key」というエラーが表示された場合は、以前に構成したカスタムデバッグ署名鍵を使用してアプリに署名していることを確認してください。

Alexa、Lambda、Fire TV対応アプリ間のインタラクションモデル

これで必要なものがすべて揃ったので、ここで、これらのコンポーネントの連携について詳しく説明します。Alexa搭載デバイスに言ったフレーズは、(Alexa自然言語サービスを通じて)意味が解析され、ディレクティブに変換されます。ディレクティブは、ビデオスキルAPIを介してAlexaからLambdaに送信されて処理される情報ブロック(JSON形式)です。Fire TVで使用されるディレクティブは、APIリファレンスのセクションに記載されています。

AlexaからLambda関数に送信されたディレクティブはCloudWatchで表示できます。CloudWatchは、Lambda(およびその他のサービス)のモニタリングデータと運用データをログ、指標、イベントの形で収集するAWSサービスです。Lambda関数は、Alexaからディレクティブを受け取るたびに、ディレクティブやその他のイベントをログに記録できます。これらのログはCloudWatchで確認できます。

ビデオスキルを構成する際には、AlexaからLambda関数に送信されるディレクティブを理解し、想定されるレスポンスをアプリに実装することが重要です(また、Lambda関数は、ディレクティブの処理が成功したことを示す簡単な確認レスポンスをAlexaに返す必要があります)。

(Lambda関数は、Alexaにレスポンスは返しますが、ユーザーに向けたカスタム音声フィードバックを提供することはできません。ユーザーとのやり取りは、Alexaが処理します。Lambda関数が実行できるアクションは、APIリファレンスで指定されているアクションだけです)

Lambda関数は、ADMを通じてFire TV対応アプリに情報を渡します。サンプルアプリのLambda関数は、Alexaから受け取ったのと同じディレクティブをアプリにプッシュするだけです(Lambda関数をカスタマイズして、必要な情報をアプリに送信することができます)。 ADMからのメッセージを調べ、カタログと一致するメディア識別子を見つけて再生するロジックが、サンプルアプリには含まれています。受信メッセージは [Logcat] ペインで確認できます。このペインでは、検索したタイトルでフィルタリングすることができます。

アプリのADMメッセージハンドラーでディレクティブの受信を確認する
アプリのADMメッセージハンドラーでディレクティブの受信を確認する(検索したメディアタイトルで絞り込んだ状態)

発話のコンテキストと暗黙的/明示的なターゲット指定

さまざまなテストケースに進む前に、発話を指定できるコンテキストを覚えておいてください。発話を使用できる主なコンテキストには次の2つがあります。

  • 暗黙的なターゲット指定: コンテンツプロバイダーやアプリ名を指定しない音声コマンド。例:「『ビッグバックバニー』を見せて」
  • 明示的なターゲット指定: コンテンツプロバイダーやアプリ名を指定する音声コマンド。例:「Streamzで『ビッグバックバニー』を見せて」

さまざまな発話をテストする場合、明示的なターゲット指定は、スキルをライブアプリテストにプッシュした後でないと使用できません。Android Studioでアプリをサイドロードすると、Alexaはスキルの明示的なターゲット指定を処理できません。そのため、フォアグラウンドになるようにアプリを開く必要があります。

ただし、アプリが(バックグラウンドではなく)フォアグラウンドにある場合、「『ビッグバックバニー』を見せて」と発話すると、Alexaはすべてのカタログではなく、フォアグラウンドにあるカタログのアプリで一致するものを探します。アプリがフォアグラウンドにある間にコマンドを発話することは、明示的なターゲット指定と同等ですが、Androidからローカルでサイドロードしている場合でもサポートされます。

テスト発話による確認

Fire TVでアプリが実行されている状態で、「アレクサ、『ビッグバックバニー』を見せて」とEchoに話しかけてください。 Alexaが正しく聞き取れるように、少しだけ間を取りながら「ビッグ...バック...バニー」と発音してください(早口だと、「バッグスバニー」と認識されることがあります)。

Alexaは、「<ビデオスキル>でアレクサが有効になりました...<ビデオスキル>から『ビッグバックバニー』を取得しています」と応答します。 これにより、AlexaでFire TV対応アプリとビデオスキルが自動的にペアリングされたことがわかります。「ビッグバックバニー」のビデオの再生が始まります。

CloudWatchでのログの確認

ビデオスキルから受信したイベントとLambdaによって書き込まれたログを確認するには、CloudWatchを使用する必要があります。CloudWatchでログを表示するには、次の手順を実行します。

  1. AWSで、CloudWatchに移動し、左側のサイドバーで [ログ] > [ロググループ] を選択します。

  2. 作成したLambda関数をクリックします。

    現在のリージョンに関連するLambda関数のみが表示されます。したがって、Lambda関数が表示されない場合は、現在のリージョンが正しいことを確認してください。

  3. 関数のログのリストが表示され、最新のロググループが一番上に表示されます(Echoに向けてコマンドの発話を開始するまで、ログは表示されません)。

Lambdaログを見やすくするには、[テキスト] ラジオボタンをクリックします。

Lambda関数に移動してCloudWatchログにアクセスすることもできます。次のスクリーンショットに示すように、[モニタリング] タブをクリックし、[CloudWatchのログを表示] ボタンをクリックします。

Lambda関数画面にある、CloudWatchログへのリンク
Lambda関数画面にある、CloudWatchログへのリンク

CloudWatchに表示される全体のやり取りについて

以下のテスト発話に進む前に、サンプルのCloudWatchログについて詳しく説明します。SearchAndPlayディレクティブの場合、以下のようなCloudWatchログが得られます(これらは、サンプルのLambda関数の例です)。各ログメッセージの意味については、インラインコメントを参照してください。読みやすくするために、ここでは、リクエストIDを短縮表示しています(5351d...7376c)。

2019-11-22T02:38:56.315Z 5351d…7376c INFO Lambda was invoked by Alexa

ログは、Alexaのリクエストイベントから始まります。

Lambda関数が(この場合は、「トリガー」として機能するビデオスキルによって)呼び出されると、AWS Lambdaはhandler関数を呼び出してコードの実行を開始します。ランタイムは、handlerメソッドに3つの引数を渡します。

exports.handler = (event, context, callback) =>

各引数の内容は次のとおりです。

  • event: 呼び出し元の情報が含まれています。この場合、呼び出し元はAlexaディレクティブです。Alexaでは、Invokeを呼び出すときに、JSON形式の文字列としてこのディレクティブを渡します。
  • context: 呼び出し、関数、実行環境に関する情報が含まれています。
  • callback: レスポンスを送信するために非同期関数で呼び出すことができる関数です。

Lambdaの詳細については、Node.jsのAWS Lambda関数ハンドラーを参照してください。

2019-11-22T02:38:56.345Z 5351d…7376c INFO Context:

{
    "callbackWaitsForEmptyEventLoop": true,
    "functionVersion": "$LATEST",
    "functionName": "football_streamz_lambda",
    "memoryLimitInMB": "128",
    "logGroupName": "/aws/lambda/football_streamz_lambda",
    "logStreamName": "2019/11/22/[$LATEST]80890c82ad974631b9586cb4072e3558",
    "invokedFunctionArn": "arn:aws:lambda:us-east-1:793895964098:function:football_streamz_lambda",
    "awsRequestId": "5351d...7376c"
}

contextを確認できるように、サンプルのLambda関数では、この情報をログに記録しています。

console.log("Context: " + JSON.stringify(context, null, 2));

contextには、Lambda関数を呼び出したイベントに関する情報が含まれています。コンテキスト情報は、呼び出されたLambda ARNとそれを呼び出した関数(ビデオスキル)を示す以外は、あまり役に立ちません。これをコメントアウトしようと考える開発者も少なくないと思います。サンプルアプリではコンテキストをログに記録する処理がコメントアウトされていないため、アプリに渡される情報を確認できます。ビデオスキルは、このLambda関数に接続したスマートホーム用トリガーとして機能します。

2019-11-22T02:38:56.345Z 5351d…7376c INFO Alexa Request: SearchAndPlay

{
    "directive": {
        "payload": {
            "entities": [
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.8a42b984-28c2-5c09-bd24-8d924e004d3f",
                    "value": "ビッグバックバニー",
                    "externalIds": {
                        "hawaii_us": "tt1254207",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.8a42b984-28c2-5c09-bd24-8d924e004d3f",
                        "imdb": "tt1254207",
                        "tms": "MV006850300000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.5ad5ba65-843b-5ac0-bf1d-668e5f7ff894",
                    "value": "ザ・ビッグ・マネー",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.5ad5ba65-843b-5ac0-bf1d-668e5f7ff894",
                        "tms": "MV010152170000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.de82b43b-3fbb-5550-872a-e85752ae5901",
                    "value": "ビッグバックポール",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.de82b43b-3fbb-5550-872a-e85752ae5901",
                        "tms": "8826242"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.4176eed9-eb18-546a-b934-314f50abe8db",
                    "value": "ビッグバックバニー",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.4176eed9-eb18-546a-b934-314f50abe8db"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.3cabe805-968e-5001-813c-f46b5b1069d7",
                    "value": "ビッグバックバニー",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.3cabe805-968e-5001-813c-f46b5b1069d7",
                        "tms": "SH023726740000"
                    }
                }
            ]
        },
        "header": {
            "payloadVersion": "3",
            "messageId": "c2ca519b-9582-4cbf-87ae-5aa9bbb0abb5",
            "namespace": "Alexa.RemoteVideoPlayer",
            "name": "SearchAndPlay",
            "correlationToken": "b762c130-fb10-4337-ae08-3659cb5d1b87"
        },
        "endpoint": {
            "endpointId": "1b8b8f648adcd730##amzn1-ask-skill-c90a4a61-0cda-4a6e-a797-8766abec6fcb##development##com-fireappbuilder-android-nature-streamz",
            "cookie": {
                "VSKClientVersion": "1.4.5",
                "deviceType": "AFF5OAL5E3DIU",
                "appPackageName": "com.fireappbuilder.android.nature.streamz",
                "deviceId": "G3J0TV00838703PE",
                "appName": "Alexa VSKを使用するFire TV対応サンプルアプリ",
                "applicationInstanceId": "amzn1.adm-registration.v3.Y29t...LmFtYX0"
            },
            "scope": {
                "token": null,
                "type": "BearerToken"
            }
        }
    }
}

ユーザーがAlexa搭載Fire TVデバイスにコマンド(たとえば、「『ビッグバックバニー』を見せて」)を発話しました。発話はAlexaによってクラウドで解析され、ディレクティブが生成されました。ビデオスキルAPIを通じて、AlexaからLambda関数にディレクティブが送信されます。このディレクティブには、カタログとAmazonプライムで一致するすべてのアイテム(amzn1.p11cat...で参照されるもの)が含まれます。

これはAlexaによって生成されたSearchAndPlayディレクティブであり、アプリで再生するコンテンツ(ここでは「ビッグバックバニー」)を指定しています。 Alexaは、ユーザーのリクエストに一致するタイトルをカタログ内で検索し、一致するエントリをexternalIds配列にリストします。Alexaは、一致したすべてのタイトルをLambda関数に送信し、アプリで再生するタイトルの決定をLambda関数に任せます。

2019-11-22T02:38:56.345Z 5351d…7376c INFO ADM Registration ID: amzn1.adm-registration.v3.Y29tLmFtYXp…

このケースでは、サンプルLambda関数はADM登録IDをコンソールに記録しています。必要な情報をLambda関数でログに記録し、CloudWatchで確認することができます。

2019-11-22T02:38:56.788Z 5351d…7376c INFO Got Access Token Type:bearer Expires In:3600

ADMは、認証情報を使用してaccessTokenを取得します。認証に成功すると、Lambda関数はsendMessageToDevice()関数を呼び出します。認証に失敗した場合、アクセストークンは付与されません。

2019-11-22T02:38:56.825Z 5351d…7376c INFO Calling device…

ADMはsendMessageToDevice()関数を呼び出して、APIキーで識別したアプリにディレクティブを送信します。ディレクティブの送信には、リクエストモジュールを使用します。ADMドキュメントヘッダーの詳細については、アクセストークンのリクエスト方法を参照してください。

2019-11-22T02:38:56.967Z 5351d…7376c INFO Response from the app:

{
    "registrationID": "amzn1.adm-registration.v3.Y29tLmFtYXpvbi5EZXZpY2VNZXN...hM1VCUFVnPT0"
}

Lambda関数は、通信を確認するために登録IDを返します(読みやすくするために、ここでは長い文字列を切り捨てています)。

2019-11-22T02:38:56.967Z 5351d…7376c INFO Sending SearchAndPlay response back to Alexa: :

{
    "event": {
        "header": {
            "messageId": "not-required",
            "correlationToken": "not-required",
            "name": "Response",
            "namespace": "Alexa",
            "payloadVersion": "3"
        },
        "endpoint": {
            "scope": {
                "type": "DirectedUserId",
                "directedUserId": "not-required"
            },
            "endpointId": "not-required"
        },
        "payload": {}
    }
}

Lambda関数がAlexaに成功レスポンスを返し、ディレクティブを受信したことを知らせます。

END RequestId: 5351d…7376c

ディレクティブのリクエストIDです。やり取りが終了しました。

REPORT RequestId: 5351d…7376c Duration: 673.60 ms Billed Duration: 700 ms Memory Size: 128 MB Max Memory Used: 102 MB Init Duration: 689.67 ms

ディレクティブの処理に要した時間とメモリです。この処理で請求対象となる実行時間です。ビデオスキルを使用するFire TV対応アプリで、 「1か月に100万件のリクエストおよび400,000GB/秒のコンピューティング時間」の無料利用枠を超えるメモリを使用することはほとんどありません。 詳細については、AWS Lambda料金を参照してください。

サンプルアプリのディレクティブ

CloudWatchログ(サンプルLambda関数によってログに記録される情報)の読み取り方法がわかったので、次はテストを実行します。このセクションでは、Alexaに4つの異なる発話を保存し、アプリの動作とCloudWatchに記録されるログを確認します。アプリの明示的なターゲット指定はまだ利用できないため、サンプルアプリを起動してフォアグラウンドに移動してから各発話を行う必要があります。

サンプルアプリは4つのディレクティブを処理できます。サンプルアプリで、com.amazon.android.tv.tenfoot.receiver.TenFootADMessageHandler#onMessage(80行目から)を見ると、ADMから受信したメッセージをサンプルアプリが処理するロジックを確認できます。このLambda関数のサンプルコードでは、Lambda関数はAlexaから受け取ったのと同じディレクティブを渡すだけである点に注意してください。その後、アプリはペイロードを照会し、カタログでメディアを検索します。

Lambda関数には、アプリにとって有用なプロセスをコーディングすることができます。たとえば、別のワークフローとして、Lambda関数で独自の処理を実行して正しいメディア識別子を見つけ、必要に応じて、その結果をアプリに送信できます。

SearchAndDisplayResultsディレクティブ

サンプル発話: サンプルアプリを起動して、「アレクサ、『ビッグバックバニー』を探して」と言います。

レスポンス: 「<ビデオスキル名>から『ビッグバックバニー』を取得しています」という応答後、アプリが検索画面に切り替わり、「ビッグバックバニー」というテキストが検索されます。

AlexaがLambda関数に送信するディレクティブSearchAndDisplayResults

SearchAndPlayディレクティブ

サンプル発話: サンプルアプリを起動して、「アレクサ、『ビッグバックバニー』を見せて」と言います。

レスポンス: 「<ビデオスキル名>から『ビッグバックバニー』を取得しています」という応答後、 「ビッグバックバニー」のビデオが再生されます。

AlexaがLambda関数に送信するディレクティブSearchAndPlay

PlaybackController - Pauseディレクティブ

サンプル発話: サンプルアプリが起動していない場合は起動し、「ビッグバックバニー」を再生します。その後、「アレクサ、一時停止して」と言います。

レスポンス: Alexaは何も応答せず、ビデオが一時停止されます。

AlexaがLambda関数に送信するディレクティブPlaybackController: Pause

PlaybackController - Playディレクティブ

サンプル発話: 前のシナリオで「ビッグバックバニー」を一時停止した状態で、「アレクサ、再生して」と言います。

レスポンス: Alexaは何も応答せず、ビデオの再生が再開されます。

AlexaがLambda関数に送信するディレクティブPlaybackController: Play

次のステップ

AlexaディレクティブとLambda関数の動作を理解できたので、次は独自のコンテンツおよびサービス用にLambda関数をカスタマイズします。手順9: Alexaディレクティブを解釈して応答するに進みます。

(問題が発生して続行できない場合は、トラブルシューティングを参照してください)