Before we begin
This blog post is part two of a two-part series aiming to excite and enable developers to build and learn how to use the Amazon Interactive Video Service (Amazon IVS) Timed Metadata feature. You should complete the steps in part one of this series to successfully complete this tutorial. The third step in part one (Set up the web page player) may be skipped as the AWS CloudFormation template in this part replaces the work done in that step. The Amazon IVS channel and Python script are required and not covered in this half of the tutorial.
In this walk-through, you will build a full end-to-end working demonstration of an Amazon IVS live stream that provides a fully interactive experience for viewers. I designed this walk-through as a bare bones demonstration of the technology developer can learn how the functionality works. While the underlying services such as Amazon IVS are highly scalable and secure, the design of this demo is not intended for production use.
If you are looking for a starter kit for your production workflow, please check out this blog post about setting up streaming for Amazon IVS. But, if you would like to create a sandbox to learn how the Timed Metadata feature works, this blog post series is for you. Part one focuses on the Timed Metadata feature, while part two looks at the underlying infrastructure needed to create a fully interactive experience.
- Linux/Unix environment (Apple OS X was used to create this demo)
- Python 3.x
- boto3 module
Part one of this series detailed how to deliver questions to the user but not how to collect the answers. In part two, you will create a backend to collect those responses with a modified version of the web page from part one to see the results.
You will notice on the player web page that I have chosen to display the data in the same interface. You may want to create other views, but I wanted to keep this example straightforward. To get these results, I used a single Amazon API Gateway endpoint as well as an AWS Lambda function to change the behavior depending on the URL path provided. You could easily have multiple Lambda functions and API Gateway endpoints that do this; in this example, I maintain a single Lambda function to keep the AWS CloudFormation template lean and easy to follow. The web page interface uses jQuery to communicate with the API Gateway endpoint and Bootstrap to help keep the interface clean.
Overview of Solution
Step 1. Complete steps in part one
If you have not completed the steps in the previous blog post in this series, do so before moving forward with this tutorial. The player.html file is not needed for this part of the walk-through. Another version of that file is automatically configured with the API Gateway URL and Amazon IVS playback URL during the CloudFormation template deployment.
Three things that you will carry over from the previous blog post are:
- The Amazon IVS channel playback URL
- Python file – You can re-download the Python script here
- facts.txt Text file – You can re-download the text document from here (or create your own)
Step 2. AWS CloudFormation template
Begin running the AWS CloudFormation template, and in the meantime, return this post to read about all the things this template creates.
Launch in US-EAST-1.
In the CloudFormation console, follow these steps:
- Confirm you are in the “N. Virginia” (aka us-east-1) region.
- Press Next.
- Paste the Amazon IVS channel playback URL into the PlaybackUrl.
- Press Next.
- No changes needed for “Configure stack options.”
- Press Next.
- Review the PlaybackUrl under Step 2: Specify stack details.
- Scroll to the bottom, read, and acknowledge the Capabilities section by checking the box at the bottom of the page.
- Press Create stack.
Step 3. Wait for AWS CloudFormation template to complete
While you wait for the template to complete, let’s go over what will run under the hood. If you are pressed for time, feel free to skip these explanations and jump to Step 4.
I previously sent Timed Metadata from the Python script to the Amazon IVS REST API where the video.js HTML5 player has a “PlayerEvent” listener waiting for the Timed Metadata event. When that Timed Metadata event occurred, I used jQuery to create dynamic HTML from that payload sent by the Python script. In addition to what we did in part one, this CloudFormation template is creating an Amazon DynamoDB database, a API Gateway REST API, a Lambda function, and a Amazon Simple Storage Service (Amazon S3) bucket, and uses Amazon CloudFront to create a fully interactive experience with your Amazon IVS channel.
Next, I will go into detail about why I configured each service the way I did. I learned a lot in the process of making this demo, and hope you learn from my experience as well.
Amazon DynamoDB Database
I configured the DynamoDB database using a “primary partition key“ (poll_id) and a ”primary sort key“ (requestor_id) and Global Secondary Index with a ”partition key“ (requestor_id) and ”sort key“ of timestamp_created. The poll_id (primary partition key) is a unique id identified for a poll question.
Next, I’m using the requestor_id (primary sort key) as a unique identifier for the requestor who is answering the poll question. Using this combination allows for easy retrieval of all answers for a specific question.
I also wanted to be able to get the poll_id for a specific requestor_id. This is where the GSI (Global Secondary Index) comes into play. DynamoDB GSI makes it easy to create a cloned table with different key and sort combinations. This allows you to grab data in a different manner than the way you put it into the database. Folks that have used SQL queries in the past may have noticed that NoSQL databases don’t allow you to query any column in a database. The GSI of DynamoDB lets you get similar results by planning out which key and sort you will use with incredibly quick query speeds. Choosing the Right DynamoDB Partition Key is a great blog post about other examples available in choosing the best key and sort for your environment.
Amazon API Gateway REST API
I configured API Gateway as a REST API with a Lambda Proxy Integration with Cross-Origin Resource Sharing (CORS) enabled. CORS is required to allow your HTML host to communicate with the API Gateway. When a web page tries to access a remote resource, it sends an OPTION command first to see if the API Gateway is allowed to communicate with this specific location the web page is hosted from. Even though I am allowing all origins to access this API Gateway location, I still need this in the configuration or the request will be denied by the web browser. This is a very important concept when it comes to securing web page communication, but it can be incredibly frustrating when trying to learn how to piece all of these services together.
Brush up on this documentation for more information about CORS. I ultimately end up having the method “ANY” point to the Lambda Function, and the “OPTIONS” method point to a “Mock” request with a response header that contains all the CORS info.
Note: I have not included any security for this API Gateway endpoint. Refer to this documentation to add security functionality if you are going to use any endpoint in future production.
AWS Lambda Function
The Lambda Function receives the information from API Gateway in the “event” variable because I am using the Lambda Proxy Integration. This includes data such as the JSON payload the web page will send, as well as the path string since I am using the proxy feature. This allows us to use a single Lambda Function for all the calls we will use.
- The /requestor-put path takes the information sent from the web page and formats it in a way that makes DynamoDB happy before sending it over.
- The /requestor-get path takes the requestor_id for the primary key and utilizes the GSI to get a list of all the entries that specific requestor has answered.
- The /poll-get path takes the poll_id for the primary key and returns a list of all the entries that contain the answers given for that specific poll.
Amazon S3 Bucket
The S3 bucket is created both store the player.html and contain a .json file that has the configuration of the Amazon IVS Playback URL and the API Gateway URL. In the previous blog post, you added the Amazon IVS Playback URL by manually editing the file. The CloudFormation template did this for you.
Amazon CloudFront Distribution
The CloudFront distribution is created to be placed between the S3 Bucket and the client. Though you can host files directly from an S3 bucket, it is a best practice to put a CloudFront distribution in front of the bucket. This adds a layer of security by not allowing direct access to the S3 bucket.
The HTML file
Enough time has passed now that the CloudFormation template should be ready. Let’s move on to using the webpage!
Step 4. Use the demo
Confirm that your Amazon IVS channel status is “Live” from the Amazon IVS console. Also, confirm the metadata.py script is running and giving a HTTPStatusCode of 204.
- Confirm the Status has changed to CREATE_COMPLETE.
- Go to the Outputs
- Click on the CloudFront URL for Website.
Like the interface in the previous blog post, you will notice each “Poll Question” appear at the top left. This time when you click on the button for the answer, the web page sends your answer to the API Gateway REST API URL. This invokes the Lambda Function and places your answer in the DynamoDB Database. Also, the web page automatically asks the API Gateway REST API for the results submitted by other clients and yourself. You can open additional windows or tabs of the same page and each will have a unique requestor_id. If you answer multiple questions, you will also see the history of questions for that user.
Take note that every window or tab you have open of this player.html has the “Poll Questions” appear at the exact same moment in the live stream. It is common for all Amazon IVS streams will be in sync due to its low-latency goodness. But, if any of the player instances are delayed from network congestion, the “Poll Questions” will appear with frame accuracy. This means that when you insert a “Timed Metadata” payload, it will not be early or late in reference to the live stream. Without the Time Metadata feature, it is not trivial to be frame accurate with metadata and video. You can be sure that the payload is in sync with the content of the video, which is great for asking questions to your audience or delivering accompanying information to give a rich experience outside of the user’s player.
Now you can take the knowledge you gained from this demo and create a feature-rich and interactive experience that engages your customers in a way they are not accustomed to during a traditional live-stream experience.
To avoid incurring future charges, delete the resources used in this tutorial:
- Stop streaming to Amazon IVS ingest.
- In the Amazon IVS Console, select the channel. Press the Delete button
- In the AWS CloudFormation console, select this deployment. Click the Delete button.