Ti ringraziamo per la visita. Questa pagina è per il momento disponibile solo in inglese.

Step 6: Create and Deploy Lambda Package (VSK FTV)

Now that you have your app running on Fire TV, you need to update the Lambda function with capabilities to pass the directives received from Alexa along to your app. You can use Amazon Device Messaging (ADM) to pass messages to your app.

Sample App Instructions

Even if you're working with the sample Fire TV app, you must still complete all the tasks described in this topic.

About the Lambda Deployment Package

In Step 1.3: Create the Lambda Function for Your Video Skill (a sub-task within "Step 1: Create Your Video Skill and Lambda Function"), you copied some basic Lambda code into the Lambda editor to configure your Lambda function. However, you will need to develop your Lambda code with much more functionality in order to handle the directives received from the Video Skill API. In this step, you'll use a more robust Lambda function that has contains ADM configuration.

Step 6.1: Create a Lambda Deployment Package

In this step, you'll start with an index.js file inside a Node JS application. This file includes sample Lambda code for a Video Skill API integration with your Fire TV app, including responses for Discovery, Search and Play, Fast-forward, Channel Change, and other directive types. It is similar to the basic Lambda code you copied earlier but with more logic, including ADM configuration. You will use this index.js code as a starting point but then later add your own logic.

You need to update this Lambda function with a client secret, client ID, and registration ID. You will use a Node JS application to generate the function as a Lambda deployment package (packaged as a zip file), which you will then upload into AWS Lambda. Later, you will customize this function with the logic needed to handle the incoming directives and pass them along to your app for processing.

To finalize your Lambda function:

  1. Download the sample-nodejs-vsk-with-adm project and unzip the file.
  2. Inside the sample-nodejs-vsk-with-adm folder, open the index.js in a text editor.
  3. Enter the values of CLIENT_ID and CLIENT_SECRET that you retrieved in Step 5: Sign Your App and Configure a Security Profile.

    const CLIENT_ID = '<enter client id>';
    const CLIENT_SECRET = '<enter client secret>';
    
  4. Retrieve the ADM Registration ID from the initializeADM() method in your app. (This function was covered in Step 3.4: Initialize a Down-Channel Service when you integrated the Alexa Client Library.)

    To get the Registration ID, if your app is currently running, expand Logcat in Android Studio, select your device and app, select Verbose, and filter on the text ADM registration Id. If you don't get a match, stop and re-run your app. When your app starts up, you will see the Registration Id in Logcat. Save this value in a convenient spot, as you will need it in the next step.

    Getting the ADM Registration ID in Logcat
    Retrieving the Registration ID in Logcat
  5. In the index.js file of the sample-nodejs-vsk-with-adm application, enter the registration ID value (that you retrieved in the previous step) for the admRegistrationId :

    var admRegistrationId = '<enter app ADM registration id>';
    

    Your Lambda function will send messages to your app through ADM. The registration ID is required to authorize the communication to your app.

  6. Save the file.
  7. If you don't already have Node and npm, install them. You can check whether you have node by running node -v and npm by running npm -v.
  8. Open a terminal window and browse to the directory that contains the sample-nodejs-vsk-with-adm app. For example:

    cd /Users/<your username>/skills/sample-nodejs-vsk-with-adm/
    
  9. Run command npm install. This creates a folder called node_modules (if not already present) and adds all the dependent packages in it.

    npm install
    

    Don't worry if you see warnings such as added 86 packages from 130 contributors and audited 115 packages in 3.165s found 4 vulnerabilities (3 moderate, 1 high).

  10. Run command zip -r sample-nodejs-vsk-with-adm.zip . to create a zip file with all the Lambda code packaged together. (On Windows, you can also right click on the folder in Windows Explorer and choose Send To -> Compressed (Zipped) Folder.)

    zip -r sample-nodejs-vsk-with-adm.zip .
    

    You will now see a package called sample-nodejs-vsk-with-adm.zip in this directory. You will upload this package in the next step.

Step 6.2: Upload the Lambda Package into AWS Lambda

In this step you will upload the zip file you generated in the previous section (Step 6.2: Create a Lambda Package) into your Lambda function in AWS.

  1. Sign in to https://aws.amazon.com.
  2. Click Services in the upper-left menu, and under "Compute" click Lambda.
  3. Click on the function name that you created earlier (in Step C: Create the Lambda Function for Your Video Skill).
  4. Under Function Code, change Code entry type to Upload a .zip file.
  5. Click Upload and select the sample-nodejs-vsk-with-adm.zip zip file that you created in the previous section (Step 6.1: Create a Lambda Package).
  6. Click Save.

Step 6.3: Test Your Video Skill with Fire TV app

To make sure your app is receiving the directives from your Lambda function, do a short test. Say to your Echo, Alexa, play 'video name' or Alexa, find 'video name' (replacing video name with a title from IMDb, such as "Bosch").

With Logcat open and your Fire TV app running, the ADM message handler will show that ADM has received the directive (filter for the title you searched for):

Check your ADM message handler in your app to see if you have received the directive.
Check your ADM message handler in the app to see if you have received the directive. Filter on the media title you searched for.

Exactly what gets delivered to your app depends how you coded your ADM integration in Step 4: Integrate Amazon Device Messaging (ADM).

For example, the message delivered for "Play Bosch" might look as follows:

{
  "directive": {
    "payload": {
      "entities": [
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
          "value": "Bosch",
          "externalIds": {
            "avc_vending_de": "amzn1.dv.gti.e0a9f6b7-ca7e-dc0c-c80e-f5801c580da8",
            "ENTITY_ID": "amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
            "avc_vending_us": "amzn1.dv.gti.56a9f78c-4cfe-36f0-663d-9104c6dd6595",
            "asin_row_na": "B01M32CYV3",
            "asin_row_fe": "B01MCYRKGY",
            "avc_vending_jp": "amzn1.dv.gti.fea9f575-39fd-7a77-622b-a400f9b511f8",
            "asin_us": "B00S45ZDVE",
            "avc_vending": "amzn1.dv.gti.8cac011f-78c3-114b-b3f8-246a48f23ec0",
            "asin_roe_eu": "B01MCYRQHG",
            "imdb": "tt3502248",
            "ontv": "SH018737530000",
            "asin_gb": "B00IGQC64I",
            "asin_row_eu": "B01MDRHYR2",
            "asin_jp": "B014QF5HMU",
            "avc_vending_gb": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
            "tms": "SH018737530000",
            "cravetv": "m32254",
            "asin_de": "B00ZWBWZXW",
            "gti": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
            "ontv_de": "SH026719310000"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
          "value": "Bosch",
          "externalIds": {
            "ENTITY_ID": "amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
            "imdb": "tt2773036"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad",
          "value": "Bosch",
          "externalIds": {
            "gvd": "GN2EAWZBASRC1PJ",
            "ENTITY_ID": "amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
          "value": "Bosch",
          "externalIds": {
            "ENTITY_ID": "amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
            "tms": "SH018739470000",
            "ontv_gb": "SH018739470000"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202",
          "value": "Bosch",
          "externalIds": {
            "gvd": "GN794XKHCHGKGJZ",
            "ENTITY_ID": "amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202"
          }
        }
      ]
    },
    "header": {
      "payloadVersion": "3",
      "messageId": "20d83e2d-6b20-4590-92ee-f252c2f607a9",
      "namespace": "Alexa.RemoteVideoPlayer",
      "name": "SearchAndPlay",
      "correlationToken": "cf662810-879e-4d8f-afb7-7488b778cd35"
    },
    "endpoint": {
      "cookie": {

      },
      "endpointId": "VSKTV",
      "scope": {
        "token": "452d41e7-8e4a-71ed-e8fb-dd31b126bf2e",
        "type": "BearerToken"
      }
    }
  }
}
Sample App Instructions

If you're working with the sample Fire TV app, note that three open-source videos are integrated into the catalog. You can say "Alexa, watch Big Buck Bunny" and the app will open and play it. You can say "Alexa, watch Cosmos Laundromat" and the app will open and play. Finally, you can say "Alexa, watch Tears of Steel" and the app will open and play. The following screenshot shows the three videos integrated.
Videos available in the sample app
Videos available in the sample app

The Full Interaction Viewed in Cloudwatch Logs

To get a better understanding of the interaction so far, let's open up the logs in Cloudwatch to see the full communication that's taking place. To view your logs in Cloudwatch:

  1. In AWS, go to Cloudwatch and click Logs in the left sidebar.
  2. Select your Lambda function.
  3. Find the latest log stream.
  4. Select the text radio button to expand the details.
  5. Find a log that indicates the beginning of the worfklow, such as Lambda was invoked by Alexa.

    Examining logs in Cloudwatch
    Examining logs in Cloudwatch

    For more information on accessing Cloudwatch, see Step 2.2: View the Directives Sent to Cloudwatch.

Your Cloudwatch logs should look something like this. See the inline comments for explanations of what each log message means.

START RequestId: 6a2b...c488 Version: $LATEST
# The log starts

2019-05-01T19:29:17.766Z	6a2b...c488	Lambda was invoked by Alexa
# The customer said a command to an Alexa-enabled Fire TV device ("Play Bosch"). The
# utterance was parsed in the cloud by Alexa and a directive was generated. Through the
# Video Skill API, Alexa reaches out to your Lambda function with the directive.

2019-05-01T19:29:17.766Z	6a2b...c488	Event:
{
    "directive": {
        "payload": {
            "entities": [
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
                    "value": "Bosch",
                    "externalIds": {
                        "avc_vending_de": "amzn1.dv.gti.e0a9f6b7-ca7e-dc0c-c80e-f5801c580da8",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
                        "avc_vending_us": "amzn1.dv.gti.56a9f78c-4cfe-36f0-663d-9104c6dd6595",
                        "asin_row_na": "B01M32CYV3",
                        "asin_row_fe": "B01MCYRKGY",
                        "avc_vending_jp": "amzn1.dv.gti.fea9f575-39fd-7a77-622b-a400f9b511f8",
                        "asin_us": "B00S45ZDVE",
                        "avc_vending": "amzn1.dv.gti.8cac011f-78c3-114b-b3f8-246a48f23ec0",
                        "asin_roe_eu": "B01MCYRQHG",
                        "imdb": "tt3502248",
                        "ontv": "SH018737530000",
                        "asin_gb": "B00IGQC64I",
                        "asin_row_eu": "B01MDRHYR2",
                        "asin_jp": "B014QF5HMU",
                        "avc_vending_gb": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
                        "tms": "SH018737530000",
                        "cravetv": "m32254",
                        "asin_de": "B00ZWBWZXW",
                        "gti": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
                        "ontv_de": "SH026719310000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
                    "value": "Bosch",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
                        "imdb": "tt2773036"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad",
                    "value": "Bosch",
                    "externalIds": {
                        "gvd": "GN2EAWZBASRC1PJ",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
                    "value": "Bosch",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
                        "tms": "SH018739470000",
                        "ontv_gb": "SH018739470000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202",
                    "value": "Bosch",
                    "externalIds": {
                        "gvd": "GN794XKHCHGKGJZ",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202"
                    }
                }
            ]
        },
        "header": {
            "payloadVersion": "3",
            "messageId": "20d83e2d-6b20-4590-92ee-f252c2f607a9",
            "namespace": "Alexa.RemoteVideoPlayer",
            "name": "SearchAndPlay",
            "correlationToken": "cf662810-879e-4d8f-afb7-7488b778cd35"
        },
        "endpoint": {
            "cookie": {},
            "endpointId": "VSKTV",
            "scope": {
                "token": "452d41e7-8e4a-71ed-e8fb-dd31b126bf2e",
                "type": "BearerToken"
            }
        }
    }
}

# This is a SearchAndPlay directive generated by Alexa specifying the content that your
# app should play. The content specified is "Bosch". Right now the payload contains all
# instances of the title across all catalogs. In later stages of the documentation, you'll
# perform an auto-pairing step that pairs the payload to your catalog only.

2019-05-01T19:29:17.766Z	6a2b...c488	Context: [object Object]

2019-05-01T19:29:17.766Z	6a2b...c488	Directive received from
Alexa: [object Object]
# The directive was received by your Lambda function.

2019-05-01T19:29:17.859Z	6a2b...c488	Got Access Token Type:bearer
Expires In:3600
# ADM gets an accessToken using your credentials. If it succeeds, the Lambda
# function calls the sendMessageToDevice() function. If this is unsuccessful,
# no access token is granted.

2019-05-01T19:29:17.859Z	6a2b...c488	Calling device...
# ADM calls the sendMessageToDevice() function to send the directive to your app, identifying it by way of the API key. ADM uses
# the request module for sending the directive. You can read more about ADM documentation
# headers here: https://developer.amazon.com/docs/adm/request-access-token.html.

2019-05-01T19:29:17.932Z	6a2b...c488	Response from the app:
{
    "registrationID": "amzn1.adm-registration.v3.Y29tLmFtYXpvbi5EZXZpY2VNZXNzYWdpbmcuUmVnaXN0cmF0aW9u..."
}

# The Lambda function responds with the registration ID to confirm the communication.
# Although your Lambda sends back this confirmation to Alexa, your Lambda doesn't ever
# send messages back to Alexa that get parsed into any kind of speech that Alexa says to
# users.

2019-05-01T19:29:17.932Z	6a2b...c488	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": {}
    }
}

# Your Lambda function sends a "success" response back to Alexa, indicating the directive
# was received by the Lambda.

END RequestId: 6a2b...c488
# The directive has a request ID as shown.

REPORT RequestId: 6a2b...c488	Duration: 167.40 ms	Billed
Duration: 200 ms Memory Size: 128 MB	Max Memory Used: 80 MB
# The directive took this much time and memory to process.

Billed Duration: 600 ms Memory Size: 128 MB	Max Memory Used: 81 MB
# This is the duration you were billed for for running this process. Most Fire TV apps
# with video skills never rarely use more memory than what the 40GB free tier already provides
# provides (https://aws.amazon.com/lambda/pricing/)

Troubleshooting

If you run into trouble at this stage of the integration, see the following troubleshooting info.

Error: LWA#getToken() failed ... Register LWA authentication after 20 seconds

Error: LWA#authorize() errorAuthError cat= INTERNAL type=ERROR_SERVER_REPSONSE - com.amazon.identity.auth.device.AuthError: Error=invalid_scope error_description=An unknown scope was requested

Error: LWA authentication failed. Voice service will not be available!`

Error: RequestedScope shouldn't be null!!!! - null, but continuing anyway...Can't post event:EVENT_TYPE_DISCOVERY, LWA access token is not valid yet or Can't post event:EVENT_TYPE_DISCOVERY, LWA access token is not valid yet.`

The app fails due to the Login with Amazon association with your security profile. Make sure you complete Step 5: Sign Your App and Configure a Security Profile (which entails enabling Login with Amazon for your app). There are numerous details to check here, since the Login with Amazon integration has a variety of components interacting. Check the following:

  1. Make sure your security profile has the right package name.
  2. Make sure your APK that you uploaded in the Developer Console has the same package name as the security profile.
  3. Make sure your Lambda code uses the client ID and client secret from the security profile.
  4. Make sure the registration ID correct.

Next Steps

Go to the next step: Step 7: Interpreting and Reacting to Directives.