開発者コンソール

手順9: Alexaディレクティブを解釈して応答する

手順9: Alexaディレクティブを解釈して応答する

この手順では、処理するディレクティブに合わせて、Lambda関数のコードをカスタマイズします。ここでは、サンプルアプリを使用せず、実際のアプリで作業することを想定しています。

サポートする機能の宣言

Alexaが送信するディレクティブは、Alexa Client Libraryの構成で宣言した機能とLambda関数のコードに応じて異なります。次の例では、Alexaはすべてのディレクティブを送信します。

// スキルでサポートされている機能のリストを作成します。
List<String> capabilities = new ArrayList<>();
capabilities.add(AlexaClientManager.CAPABILITY_REMOTE_VIDEO_PLAYER);
capabilities.add(AlexaClientManager.CAPABILITY_PLAY_BACK_CONTROLLER);
capabilities.add(AlexaClientManager.CAPABILITY_SEEK_CONTROLLER);
capabilities.add(AlexaClientManager.CAPABILITY_CHANNEL_CONTROLLER);
capabilities.add(AlexaClientManager.CAPABILITY_RECORD_CONTROLLER);
capabilities.add(AlexaClientManager.CAPABILITY_VIDEO_RECORDER);
capabilities.add(AlexaClientManager.CAPABILITY_KEYPAD_CONTROLLER);

すべての機能を宣言する場合、Lambda関数側で受信するディレクティブをすべて処理する必要があります(詳細については、手順3: Alexa Client Libraryを統合するを参照してください)。 次の表に、宣言できるすべての機能を示します。

Alexa Client Libraryの機能 ディレクティブの機能 ディレクティブ
CAPABILITY_CHANNEL_CONTROLLER Alexa.ChannelController ChangeChannel
CAPABILITY_REMOTE_VIDEO_PLAYER Alexa.RemoteVideoPlayer SearchAndDisplayResults
SearchAndPlay
CAPABILITY_PLAY_BACK_CONTROLLER Alexa.PlaybackController Pause
Play
Stop
Resume
Next
Previous
FastForward
Rewind
StartOver
CAPABILITY_SEEK_CONTROLLER Alexa.SeekController AdjustSeekPosition
CAPABILITY_KEYPAD_CONTROLLER Alexa.KeypadController SendKeystroke

アプリのコードに機能を指定するだけでなく、Lambdaコードにもこれらの機能を指定する必要があります。Lambda関数はDiscoverディレクティブを受信すると、Discover.Responseを送り返して、スキルでサポートしている機能を指定する必要があります。たとえば、以下はDiscoverディレクティブに対する応答例です。

{
  "event": {
    "header": {
      "namespace":"Alexa.Discovery",
      "name":"Discover.Response",
      "payloadVersion":"3",
      “messageId”:“2aa731f1-b6dd-471c-98fe-3ac5fa5d6554”
    },
    "payload": {
        "endpoints": [
            {
                "capabilities": [
                    {
                        "interface": "Alexa.RemoteVideoPlayer",
                        "type": "AlexaInterface",
                        "version": "1.0"
                    },
                    {
                        "type": "AlexaInterface",
                        "interface": "Alexa.PlaybackController",
                        "version": "3",
                        "supportedOperations" : ["Play", "Pause", "Stop", "StartOver", "Next", "Previous", "Rewind", "FastForward"]
                    }
                    {
                        "interface": "Alexa.SeekController",
                        "type": "AlexaInterface",
                        "version": "1.0"
                    },
                    {
                        "interface": "Alexa.ChannelController",
                        "type": "AlexaInterface",
                        "version": "1.0"
                    },
                      {
                        "interface": "Alexa.KeypadController",
                        "type": "AlexaInterface",
                        "version": "3",
                        "keys": [
                          "INFO", "MORE", "SELECT",
                          "UP", "DOWN", "LEFT", "RIGHT",
                          "PAGE_UP", "PAGE_DOWN", "PAGE_LEFT", "PAGE_RIGHT"
                        ]
                      }  
                ]
              }
          ]
       }
  }
};

詳細については、Discoveryインターフェースを参照してください。簡潔に言うと、スキル機能の検出はアプリとLambdaの両方で行われます。

上記の各ディレクティブの実装と処理の詳細については、APIリファレンスドキュメントを参照してください。Alexaでは、受信するディレクティブごとに特定のレスポンスとアクションを想定しています。

ビデオスキルAPIの全機能を実装したアプリはほとんどありません。たとえば、アプリにチャンネルがない場合、チャンネル変更の機能は不必要かもしれません。また、アプリに録画機能がない場合、録画機能の実装は必要ないと考えられます。

ディレクティブ処理のカスタマイズ

firetv-lambdaプロジェクトのindex.jsファイルを再度開きます(手順6: Lambdaパッケージを作成・デプロイするを参照)。このindex.jsファイルのカスタムロジック用のプレースホルダーに記述する必要があります。たとえば、次のようなインラインコメントがあります。

// ディレクティブを処理する独自のロジックをここに記述
// ディレクティブをLambda関数からアプリに送信するためのコードをここに記述

各コメントでは必要なロジックが説明されているので、そのディレクティブを処理するロジックを記述します。各ディレクティブとそのペイロード、想定されるアクション、レスポンスの詳細については、APIリファレンスを参照してください。

ディレクティブをLambda関数で受信し、それをADM経由でアプリに送信する方法をお勧めします。それ以降の処理は、すべてアプリ内で実行可能です。サンプルアプリでも、この方法でディレクティブを処理しています。

たとえば、サンプルアプリのTenFootApp.javaを開くと、119行目に以下のコードがあり、ここでADM経由でアプリに送信されたディレクティブを処理しています。

if (directive != null) {
       String directiveName = directive.getDirective().getHeader().getName();
       if ("SearchAndPlay".equals(directiveName)) {

           Content playContent = null;
           String directivePayload = directive.getDirective().getPayload().getEntities().get(0).getValue().toLowerCase();

           List<ContentContainer> containers = browser.getContentLoader().getRootContentContainer().getContentContainers();
           for(ContentContainer container : containers) {
               if(null != playContent) break;
               for(Content c : container.getContents()) {
                   // 最初のペイロードエンティティのみをチェックします
                   if(c.getTitle().toLowerCase().contains( directive.getDirective().getPayload().getEntities().get(0).getValue().toLowerCase() )) {
                       playContent = c;
                       break;
                   }
               }
           }

           // ディレクティブペイロードに一致するコンテンツが見つかったらビデオを再生します
           if (playContent == null) {
               playContent = containers.get(0).getContents().get(0);
           }
           if(null != playContent) {
               browser.switchToRendererScreen(playContent, ContentBrowser.CONTENT_ACTION_WATCH_FROM_BEGINNING);
           } else {
               // コンテンツを検索します
               searchForContent(app, browser, directivePayload);
           }

       } else if ("SearchAndDisplayResults".equals(directiveName)) {
           String directivePayload = directive.getDirective().getPayload().getEntities().get(0).getValue().toLowerCase();
           searchForContent(app, browser, directivePayload);
       } else if ("Pause".equals(directiveName)) {
           try {
               PlaybackActivity playbackActivity = (PlaybackActivity) app.getCurrentActivity();
               if(playbackActivity.isPlaying()) {
                   playbackActivity.runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           playbackActivity.pause();
                       }
                   });
               }
           } catch (Exception castE) {
               Log.e(TAG, "PlayBackActivityにキャストできませんでした。");
               return;
           }

       }  else if ("Play".equals(directiveName) ) {
           try {
               PlaybackActivity playbackActivity = (PlaybackActivity) app.getCurrentActivity();
               playbackActivity.runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       playbackActivity.play();
                   }
               });
           } catch (Exception castE) {
               Log.e(TAG, "PlayBackActivityにキャストできませんでした。");
               return;
           }

       }

   }

}

/**
* @param searchQuery - ディレクティブのテキストを検索します
*/
private void searchForContent(TenFootApp app, ContentBrowser browser, String searchQuery) {

   browser.switchToScreen(ContentBrowser.CONTENT_SEARCH_SCREEN);
   // 画面が切り替わるまで最大2秒待ちます
   for(int i = 0; i < 5; i++)  {
       Activity newActivity = app.getCurrentActivity();
       if(newActivity instanceof ContentSearchActivity) break;
       try {
           Thread.sleep(400);
       } catch (InterruptedException e) {
           return;
       }

   }

   ContentSearchActivity searchActivity = (ContentSearchActivity) app.getCurrentActivity();

   searchActivity.runOnUiThread(new Runnable() {
       @Override
       public void run() {
           searchActivity.getmFragment().setSearchQuery(searchQuery, true);
       }
   });
}

}

この実装コードでは、entities配列の最初の項目からペイロードを取得し、使用可能な場合はそのペイロードを再生します。使用可能でない場合はコンテンツを検索します。index.jsファイルには、Lambda関数をカスタマイズするためのヒントと手順を示すその他のインラインコメントもあります。

Lambdaコードを更新する場合、Alexaへのレスポンスは変更せず、ディレクティブの処理/送信部分のみコーディングしてください。また、Lambda関数からアプリにディレクティブを送信する必要はありますが、アプリからLambda関数には、シンプルな成功レスポンス以外のメッセージを返さないようにしてください。Lambda関数からの成功レスポンスは、Lambda関数がメッセージを受信したことを示すもので、アプリによる受信を示すものではありません。

仕上がったLambdaのアップロード

前のセクションで指定したディレクティブを処理するロジックを記述したら、Lambdaデプロイパッケージを作成するの手順(zip-r firetv-lambda.zipの実行)を繰り返して、生成されたzipファイルをAWSのLambdaにアップロードします。本番環境で使用する際は必ず事前にコードをテストし、検証してください。

次のステップ

次の 手順10: ライブアプリテストにアプリをプッシュするに進みます。

問題が発生して続行できない場合は、クラウド側の統合に関するトラブルシューティングを参照してください。