<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Donnie Prakoso</title>
    <description>The latest articles on Forem by Donnie Prakoso (@donnieprakoso).</description>
    <link>https://forem.com/donnieprakoso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F181326%2F2337898d-c9cb-4687-a6f3-594dc73ff622.jpg</url>
      <title>Forem: Donnie Prakoso</title>
      <link>https://forem.com/donnieprakoso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/donnieprakoso"/>
    <language>en</language>
    <item>
      <title>Let's Build Serverless Apps. Wait, Why?</title>
      <dc:creator>Donnie Prakoso</dc:creator>
      <pubDate>Mon, 20 Jun 2022 07:16:57 +0000</pubDate>
      <link>https://forem.com/awscommunity-asean/lets-build-serverless-apps-wait-why-2f2i</link>
      <guid>https://forem.com/awscommunity-asean/lets-build-serverless-apps-wait-why-2f2i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is part of the AWS Community ASEAN content. All presentations and ready-to-deploy codes used in this talk are available at &lt;a href="https://github.com/aws-community-asean/community-content" rel="noopener noreferrer"&gt;AWS Community ASEAN Content Repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Beside containers, serverless technology is something I consider an integral part of modern application development. When I ask developers about "what is serverless?", the perception mostly refers to the definition of "no server". While this is not wrong, it is not entirely true.&lt;/p&gt;

&lt;p&gt;Serverless is an operating model. &lt;/p&gt;

&lt;p&gt;With serverless, we delegate various activities that do not provide value to our business to other parties. By delegating these things, we can focus on improving business logic and not worrying about infrastructure. At the end, serverless enables us to have less code, less liability, better integration, better application, more focus, more values to deliver. These are what I think the real values for developers.&lt;/p&gt;

&lt;p&gt;Looking back on some of the past speaking engagements, I often get the opportunity to explain how we can build a particular solution using the AWS serverless services. Recently, I've realized that I haven't done much at explaining the "why" or various logical reasons for using serverless. And finally I decided to make this content.&lt;/p&gt;

&lt;p&gt;Now that we've set the context, let's dive "why" using AWS serverless services might be a good approach for you:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason #1: No Server Management
&lt;/h3&gt;

&lt;p&gt;The main reason why using serverless gives you an advantage is that there is no server management. This means that there is no need for patching, retiring aging hardware, and performing day-to-day operations or maintenance.&lt;/p&gt;

&lt;p&gt;The most classic example is AWS Lambda. AWS Lambda is a service where we can run a function without the need to manage hardware. At minimum, all we need to do is upload or write our business logic to AWS Lambda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide10.png" alt="Anatomy of AWS Lambda Function"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like normal functions, we can integrate with various databases, or interact with HTTP API endpoints. To trigger, we can integrate with a variety of other AWS services — such as HTTP API requests with Amazon API Gateway, or when an object is uploaded into Amazon S3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide9.png" alt="How Lambda Function Works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For those who use containers, you can also use AWS Fargate — a serverless containers compute engine — which you can use to run your apps. Both of these options free you from provisioning to maintaingin your servers, and you can allocate focus, effort and time to what is more important: building features for your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason #2: Get to Market, Fast and Secure
&lt;/h3&gt;

&lt;p&gt;One of the misconceptions about serverless is that serverless is synonymous with AWS Lambda. The fact is, AWS Lambda is a just one layer of AWS serverless services. &lt;/p&gt;

&lt;p&gt;If we refer to serverless as an operational model, in practice serverless can be applied to any layer. For example, for computing, we can use AWS Lambda and AWS Fargate. For databases, we can use Amazon DynamoDB as well as Amazon Aurora Serverless. For integration from service to service, we can use Amazon EventBridge, and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide12.png" alt="Serverless is More Than Compute"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing that is not less important is that each serverless service is rich in features that are difficult for us to replicate if we build it manually. Take for example when you want to monetize your API. You need to build a limit for different tiers, for example a maximum of 100 RPS with a limit of 5,000 requests per day for plan A, and 200 RPS with a limit of 10,000 requests per day for plan B. You can use the &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html" rel="noopener noreferrer"&gt;usage plan&lt;/a&gt; feature that you can use, directly within Amazon API Gateway.&lt;/p&gt;

&lt;p&gt;The point is that by using the features of the serverless service, you can get your apps to market faster.&lt;/p&gt;

&lt;p&gt;But even though we can deliver our apps faster to the market, we certainly need to think about security. Before the era of cloud computing, this was an option for me, to deliver apps quickly, or prioritize security which usually slows down apps delivery. Now these two are not an option, and we can do it at the same time.&lt;/p&gt;

&lt;p&gt;The diagram below describes how we can maintain security of AWS Lambda to access Amazon CloudWatch and Amazon DynamoDB using the IAM Role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide13.png" alt="IAM Role for AWS Lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although your code runs fine, if you don't have an IAM role to access DynamoDB, it won't work. This is one example where we can run applications more secure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason #3: Effective Scaling and Cost Efficient
&lt;/h3&gt;

&lt;p&gt;Before the era of cloud computing, to run services and apps, I needed a fixed number of servers, and of course this approach is not effective and cost efficient. Cloud computing changed all of this by introducing auto scaling. There are two types of scaling, namely horizontal and vertical scaling scaling. Horizontal scaling basically means adding a number of compute engines to your fleet. Vertical scaling is more about adding power, such as CPU or RAM to the existing machines in your pool.&lt;/p&gt;

&lt;p&gt;With serverless, the effort expended on handling requests is made easier by auto scaling. Here I take an example of auto scaling for a database using Amazon DynamoDB.&lt;/p&gt;

&lt;p&gt;Let's be straight here, database workloads are difficult to predict and database scaling is a very challenging thing. Most of the startups I used to be involved with were in the Media and Entertainment industry. Read consumption for the database is higher between 8-10am, 1-3pm, and 6-9pm and handles approximately 1 million requests during those hours. Outside of those hours, the requests are significantly reduced. In other words, the capacity of a database to handle requests is not the same as a high traffic hours.&lt;/p&gt;

&lt;p&gt;Then, I gave myself another thought on database. When I switched from self-managed MySQL to Amazon DynamoDB, I benefited from auto scaling. I can define the scaling configuration for read capacity, and different configuration for write capacity.&lt;/p&gt;

&lt;p&gt;The image below is an illustration of how auto scaling from Amazon DynamoDB works. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide15.png" alt="DynamoDB and Auto Scaling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The red line is provisioned capacity and the blue line indicates actual consumption based on item size. Here we can see that provisioned capacity adjusts the utilization rate to support application performance. In addition, this also reduces the cost that I need to pay because capacity is not fixed all the time, and adjusts to requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason #4: Flexible and Seamless Integrations
&lt;/h3&gt;

&lt;p&gt;Serverless services on AWS are built with a specific purpose — Amazon DynamoDB as database, Amazon S3 as object storage, Amazon EventBridge as event bus. I'd like to think them somewhat like a Lego, building blocks. This provides flexibility for developers to build architectures using appropriate services. &lt;/p&gt;

&lt;p&gt;Due to its modular characteristics, it makes it easier to build functionality for an application. We can be more flexible on building applications from very simple to sophisticated architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FWorkshop-REST%2520API-Page-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FWorkshop-REST%2520API-Page-2.png" alt="Simple architecture of Serverless REST API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"But if we are adopting various services, that also means we also need to work on more integration." That's right. The more services that we use, the more integration is needed. &lt;/p&gt;

&lt;p&gt;Fortunately, AWS serverless services have seamless integration, which means we can integrate easily because the integration features are built-in. Take the example here on AWS Lambda, you can easily do the integration by configuring them in the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide19.png" alt="AWS Lambda — Trigger Configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also find the same thing in other serverless services, for example AWS Step Functions — one of my favorite services because it can easily create visual workflows for distributed applications. With AWS Step Functions, we can define workflow flows and seamless integration with AWS Lambda by simply defining the ARNs from AWS Lambda. &lt;/p&gt;

&lt;p&gt;Below is an example of how we can implement distributed transactions using state machine with AWS Step Functions using &lt;a href="https://copilot.rocks/implementing-architectural-patterns/20-implementing-saga-pattern/" rel="noopener noreferrer"&gt;Amazon ECS and AWS Fargate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fstepfunctions_graph%2B%25281%2529.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fstepfunctions_graph%2B%25281%2529.png" alt="State machine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason #5: Faster Response with Events
&lt;/h3&gt;

&lt;p&gt;AWS Lambda was first launched in late 2014 as an event-driven function. Triggering by event was something new and a bit unusual at the time, but as we move our workloads into cloud, the adoption of leveraging event increased. &lt;/p&gt;

&lt;p&gt;Event itself is not something entirely new. Events can take any form, from changes in the state of a system — such as when data is entered into a database — to custom events — such as in the context of e-commerce, when a customer places an order.&lt;/p&gt;

&lt;p&gt;By leveraging events, our applications can now respond to various kinds of events generated by the system, or the services we have. For example, below is a near real-time response by AWS Lambda to data changes that occur in Amazon DynamoDB. This feature is called DynamoDB Streams, where our system now has the ability to capture a time-ordered sequence of item-level modifications in any DynamoDB table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide21.png" alt="DynamoDB Streams"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leveraging events is becoming more adopted in recent years, and formally defined in Event-driven architecture. Event-driven architecture is a paradigm in building architecture by using production and consumption to respond to an event. &lt;/p&gt;

&lt;p&gt;Another example how serverless could help you is the implementation of choreography in microservices using Amazon EventBridge as a serverless event bus. By using Amazon EventBridge, we can easily define rules to route to which service we need to send data. This gives us the advantage of decoupling between services so they can run their processes independently and scale according to requests. &lt;/p&gt;

&lt;p&gt;Below is an example on how you can build choreography for microservices in context of e-commerce application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FSlide24.png" alt="Implementing Event-Driven Architecture with Amazon EventBridge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up!
&lt;/h3&gt;

&lt;p&gt;At this point, you already understand some of the reasons to consider whether serverless can be your development system approach. Serverless architecture can be used in almost all cases, starting from building a simple serverless API, IT automation, streaming data processing to implementing microservices. &lt;/p&gt;

&lt;p&gt;Although this requires a change in perspective from developing with a traditional approach, but from my experience coupled with the development of features for AWS serverless services, the serverless approach will provide significant advantages in the long run.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And also, you can use presentations and ready-to-use code for this talk. All materials have been collected for you on the &lt;a href="https://github.com/aws-community-asean/community-content" rel="noopener noreferrer"&gt;AWS Community ASEAN Content Repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Happy building!🤘🏻&lt;br&gt;
—Donnie&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Live Video Authorization with Private Channel on Amazon IVS</title>
      <dc:creator>Donnie Prakoso</dc:creator>
      <pubDate>Mon, 09 May 2022 04:24:10 +0000</pubDate>
      <link>https://forem.com/awscommunity-asean/live-video-authorization-with-private-channel-on-amazon-ivs-3k5n</link>
      <guid>https://forem.com/awscommunity-asean/live-video-authorization-with-private-channel-on-amazon-ivs-3k5n</guid>
      <description>&lt;p&gt;You can use the Private Channel feature to restrict video playback access using Amazon IVS. In this article, we will build a simple website, serverless API, and JWT signing to implement the Private Channel feature in Amazon IVS. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PfRZz2KIebQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Github Repository for Demo(s)
&lt;/h4&gt;

&lt;p&gt;Code for this article is available at &lt;a href="https://github.com/donnieprakoso/demo-ivs/tree/main/2-private-channel" rel="noopener noreferrer"&gt;github.com/donnieprakoso/demo-ivs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In the previous article, we learned how we can build interactive live videos using Amazon IVS. Running live streaming is now much easier and simpler, without worrying about scalability and low latency.&lt;/p&gt;

&lt;p&gt;However, there are some use cases where you need to protect your content. In this situation, you need an authorization mechanism to allow only certain viewers — such as those already logged into your app — to access the live video and deny access to viewers who are not registered in your system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Controlling Access with Private Channel on IVS
&lt;/h2&gt;

&lt;p&gt;The Private Channel feature is one of the features within Amazon IVS that you can use to implement this use case. With the Private Channel feature, you have the flexibility to control access for playback by using a JWT (JSON Web Token) as part of the mechanism to authorize playback.&lt;/p&gt;

&lt;p&gt;By using the Private Channel feature, you can restrict access to playback or broadcasting of live video streaming. For example, you can run live video streaming for a virtual conference that can only be accessed by logged-in users. With this, you can provide additional value for your existing customers.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Are Going To Build
&lt;/h2&gt;

&lt;p&gt;In this article, we will build a simple application to demonstrate how we can implement a Private Channel with Amazon IVS. The diagram below describes the set of application architectures that we will build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-arch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-arch.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we will do provisioning for the IVS channel. The main difference between provisioning IVS channels in this tutorial and the previous one is that in this tutorial we will enable authorization mode.&lt;/p&gt;

&lt;p&gt;Then, we will do video ingesting. In this tutorial, we will use FFMPEG to send videos to the IVS channel.&lt;br&gt;
After that, we will run the webserver to host live video from the IVS channel on a web page. There are 2 buttons in this tutorial — as you can already see in the "Demo Preview" video above. The first button is to run IVS without a token — which will fail for sure. The second button is to run IVS with a token.&lt;/p&gt;

&lt;p&gt;The next question is, how do we get the tokens? We will get this token from the AWS Lambda function which will perform the signing request and return the token in the form of a JWT. We can then use this token as one of the parameters in the IVS Playback URL, to gain access to video playback from IVS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;This tutorial uses the following requirements and please make sure that your development environment satisfies all requirements described below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Versions&lt;/th&gt;
&lt;th&gt;Where to get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS CDK&lt;/td&gt;
&lt;td&gt;2.17.0&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/aws/aws-cdk" rel="noopener noreferrer"&gt;github.com/aws/aws-cdk&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;3.8.13&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.python.org/downloads/release/python-3813/" rel="noopener noreferrer"&gt;python.org/downloads/release/python-3813/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg&lt;/td&gt;
&lt;td&gt;4.4&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ffmpeg.org/download.html" rel="noopener noreferrer"&gt;ffmpeg.org/download.html&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sample videos&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;a href="https://peach.blender.org/download/" rel="noopener noreferrer"&gt;peach.blender.org/download/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;curl&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;a href="https://curl.se/" rel="noopener noreferrer"&gt;https://curl.se/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 0: Clone Github repo
&lt;/h3&gt;

&lt;p&gt;If you'd like to do this tutorial, you can clone this repo: &lt;a href="https://github.com/donnieprakoso/demo-ivs" rel="noopener noreferrer"&gt;github.com/donnieprakoso/demo-ivs&lt;/a&gt;. Otherwise, carry on reading this tutorial if you'd like to get big pictures of how everything works.&lt;/p&gt;

&lt;p&gt;To clone the Git repo, you can run this command on your development environment:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git clone github.com/donnieprakoso/demo-ivs


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We will use the &lt;code&gt;2-private-channel&lt;/code&gt; module inside the repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create ECDSA Private/Public Key Pair
&lt;/h3&gt;

&lt;p&gt;Private channels with Amazon IVS work using the Private/Public Key Pair mechanism. We will upload the public key into IVS and we will use the private key to perform signing requests with the AWS Lambda function. The diagram below explains how this mechanism works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-public-private.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-public-private.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To generate Public/Private key pair, we can use the openssl tool which is generally already installed on Linux. Here's the command to generate the private key:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/keypair/&lt;/span&gt;
openssl ecparam &lt;span class="nt"&gt;-name&lt;/span&gt; secp384r1 &lt;span class="nt"&gt;-genkey&lt;/span&gt; &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; private.pem


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And to generate the public key, we can use the private key with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/keypair/&lt;/span&gt;
openssl ec &lt;span class="nt"&gt;-in&lt;/span&gt; private.pem &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; public.pem


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you successfully ran the commands, we can see the files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/keypair/&lt;/span&gt;
dev&amp;gt; tree
&lt;span class="nb"&gt;.&lt;/span&gt;
├── private.pem
└── public.pem


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 2: Deploy CDK App
&lt;/h3&gt;

&lt;p&gt;In this step, you only need to run the &lt;code&gt;cdk deploy&lt;/code&gt; command in the &lt;code&gt;cdk&lt;/code&gt; folder. However, before we move on to deployment, let's first evaluate 2 important things: 1) an overview of the CDK app and 2) using the Lambda function for signing JWT.&lt;/p&gt;
&lt;h4&gt;
  
  
  CDK App Overview
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-cdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-cdk.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first thing defined in the CDK app is the AWS Secrets Manager. In this tutorial, we will use the Secrets Manager to store the private key that we generated in the previous step.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 python
private_key_secret = secrets_manager.Secret(self, "{}-secret-private-key".format(id),
                    secret_name="{}-secret-private-key".format(
                        en)
                    )



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In addition, we will also upload the public key into Amazon IVS to be used as a playback key. The code snippet below defines how we can do this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 python
public_key_pair_file = self.node.try_get_context(
    "publicKeyPair")

public_key_pair_string = ""
with open(public_key_pair_file, 'r') as f:
    public_key_pair_string = f.read()

playback_key = ivs.CfnPlaybackKeyPair(
    self, "{}-keypair".format(id), name="{}-keypair".format(id), public_key_material=public_key_pair_string)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, we can define the IVS channel and notice the &lt;code&gt;authorized&lt;/code&gt; parameter which has the value &lt;code&gt;True&lt;/code&gt;. This defines an IVS channel that requires authorization to be able to perform playback.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 python
# File: 2-private-channel/cdk/app.py

        ivs_channel = ivs.CfnChannel(self, "{}-channel".format(id),
                                     authorized=True,
                                     latency_mode="LOW",
                                     name=id,
                                     recording_configuration_arn="",
                                     type="STANDARD"
                                     )


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The rest of the CDK application is defining AWS Lambda functions and integration with Amazon API Gateway. For details, you can see the source code on Github.&lt;/p&gt;

&lt;h4&gt;
  
  
  AWS Lambda Function for Signing JWT
&lt;/h4&gt;

&lt;p&gt;To get a token as playback authorization, we need to do a signing request with the public key. In this tutorial, we will implement an API with Amazon API Gateway and AWS Lambda function to perform signing requests with JWT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-lambda-sign.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-lambda-sign.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code below shows how we can use the AWS Secrets Manager to retrieve the private key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 python
# File: 2-private-channel/lambda-functions/sign-requests/app.py

def get_private_key(secret_id):
    client = boto3.client('secretsmanager')
    response = client.get_secret_value(
        secretId=secret_id,
    )
    if not response:
        return None
    if "SecretString" not in response:
        return None
    else:
        return response['SecretString']


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After getting the private key, we can now form the JWT using the ECDSA signature and the SHA-384 hash.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 python
# File: 2-private-channel/lambda-functions/sign-requests/app.py

def sign_request(private_key, channel_arn):
    payload = {
        "aws:channel-arn": channel_arn,
        "aws:access-control-allow-origin": "*",
        "exp": datetime.now() + timedelta(days=3)}
    encoded = jwt.encode(payload, private_key, algorithm="ES384")
    return encoded


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The token is in base64 form and if you decoded the token, the JWT will have the following headers:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES384"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In addition, JWT will also have a payload that stores information &lt;code&gt;channel-arn&lt;/code&gt; and also origin access &lt;code&gt;*&lt;/code&gt; which means it can be accessed from any website. If you want to restrict only loading from your website, then you need to change it to your domain name. In addition, I also added &lt;code&gt;exp&lt;/code&gt; — expiration time — as part of the JWT claim which indicates that this token should not be processed after the specified time has passed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aws:channel-arn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;channel_arn&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aws:access-control-allow-origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;timestamp&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  App Deployments
&lt;/h4&gt;

&lt;p&gt;Now you understand the main components of this CDK app. The next step is to run &lt;code&gt;cdk deploy&lt;/code&gt; to deploy the app.&lt;/p&gt;

&lt;p&gt;In this app, it uses &lt;code&gt;context&lt;/code&gt; to get the file path for your public key pair. Below is an example on how to run the &lt;code&gt;cdk deploy&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/cdk/&lt;/span&gt;

cdk deploy &lt;span class="nt"&gt;--context&lt;/span&gt; &lt;span class="nv"&gt;publicKeyPair&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_PUBLIC_KEY_FOLDER&amp;gt;/public.pem
Synthesis &lt;span class="nb"&gt;time&lt;/span&gt;: 7.4s

demo2-private-channel: deploying...
&lt;span class="o"&gt;[&lt;/span&gt;0%] start: Publishing c713b4752fe62d1d6d6c8a9cacd2e576039cd0c7697ea0bf0317b41aa6ec8f40:XXXXXXXXXXXXXX-us-east-1
&lt;span class="o"&gt;[&lt;/span&gt;100%] success: Published c713b4752fe62d1d6d6c8a9cacd2e576039cd0c7697ea0bf0317b41aa6ec8f40:XXXXXXXXXXXXXX-us-east-1

 demo2-private-channel &lt;span class="o"&gt;(&lt;/span&gt;no changes&lt;span class="o"&gt;)&lt;/span&gt;

Deployment &lt;span class="nb"&gt;time&lt;/span&gt;: 8.32s



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After the deployment is complete, you will get the following output. You will need the output below, so make sure you save it for later use.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/cdk/&lt;/span&gt;

Outputs:
demo2-private-channel.demo2privatechannelapigatewayEndpoint7F53E47C &lt;span class="o"&gt;=&lt;/span&gt; https://XXXXXXXXXXXXXX/prod/
demo2-private-channel.demo2privatechanneloutputapigateway &lt;span class="o"&gt;=&lt;/span&gt; https://XXXXXXXXXXXXXX/prod/
demo2-private-channel.demo2privatechanneloutputchannelarn &lt;span class="o"&gt;=&lt;/span&gt; arn:aws:ivs:us-east-1:XXXXXXXXXXXXXX:channel/XXXXXXXXXXXXXX
demo2-private-channel.demo2privatechanneloutputchannelingest &lt;span class="o"&gt;=&lt;/span&gt; XXXXXXXXXXXXXX.global-contribute.live-video.net
demo2-private-channel.demo2privatechanneloutputchannelplayback &lt;span class="o"&gt;=&lt;/span&gt; https://XXXXXXXXXXXXXX.us-east-1.playback.live-video.net/api/video/v1/us-east-1.XXXXXXXXXXXXXX.channel.XXXXXXXXXXXXXX.m3u8
demo2-private-channel.demo2privatechanneloutputsecretmanagerarn &lt;span class="o"&gt;=&lt;/span&gt; arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXXXX:secret:demo2-private-channel-secret-private-key-XXXXXXXXXXXXXX
demo2-private-channel.demo2privatechanneloutputstreamkey &lt;span class="o"&gt;=&lt;/span&gt; XXXXXXXXXXXXXX

Total &lt;span class="nb"&gt;time&lt;/span&gt;: 15.72s


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 3: Post Deployment — Deploy CDK
&lt;/h3&gt;

&lt;p&gt;At this point, you have a ready-to-use architecture for Private Channel implementation with IVS. After deployment, you need to import the private key into the AWS Secrets Manager. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-uploadtosecrets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-uploadtosecrets.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To import the private key, we first need to convert it into base64 form.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/keypair/&lt;/span&gt;
&lt;span class="nb"&gt;base64 &lt;/span&gt;private.pem &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; encoded-private.pem


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that, we can import the private key into AWS Secrets Manager using &lt;code&gt;--secret-id&lt;/code&gt; which we got in the output of CDK. Note that you also need to define the &lt;code&gt;--region&lt;/code&gt; parameter to define the region where you are deploying your app — in this case, I used &lt;code&gt;us-east-1&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/keypair/&lt;/span&gt;
dev&amp;gt; aws secretsmanager put-secret-value &lt;span class="nt"&gt;--secret-id&lt;/span&gt; arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXXXX:secret:demo2-private-channel-secret-private-key-XXXXXXXXXXXXXX &lt;span class="nt"&gt;--secret-string&lt;/span&gt; file: //encoded-private.pem &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"ARN"&lt;/span&gt;: &lt;span class="s2"&gt;"arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXXXX:secret:demo2-private-channel-secret-private-key-XXXXXXXXXXXXXX"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"demo2-private-channel-secret-private-key"&lt;/span&gt;,
    &lt;span class="s2"&gt;"VersionId"&lt;/span&gt;: &lt;span class="s2"&gt;"XXXXXXXXXXXXXX"&lt;/span&gt;,
    &lt;span class="s2"&gt;"VersionStages"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"AWSCURRENT"&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 4: Adjusting Variables for Web and Video Ingestion Script
&lt;/h3&gt;

&lt;p&gt;Now we need to adjust the variables for the web and video ingestion script.&lt;/p&gt;

&lt;p&gt;For the web, we need to change the location of the playback URL in the &lt;code&gt;index.js&lt;/code&gt; file so that the Amazon IVS player knows the URL location for the video playback. You need to change this URL playback manually for 2 functions, namely &lt;code&gt;playWithoutToken()&lt;/code&gt; and &lt;code&gt;playWithToken()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// File: 2-private-channel/web/index.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;playWithoutToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PLAYBACK_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;PLAYBACK_URL&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;playWithToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PLAYBACK_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;PLAYBACK_URL&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;




&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Apart from that, we also need to change the variables in the video ingestion script, which you can find at &lt;code&gt;2-private-channel/video-stream/stream-video.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;STREAM_URL&lt;/code&gt; variable, you will need the &lt;code&gt;channel_ingest&lt;/code&gt; and &lt;code&gt;stream_key&lt;/code&gt; variables which you found when you deployed the CDK app in step 2.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# File: 2-private-channel/video-stream/stream-video.sh&lt;/span&gt;
&lt;span class="nv"&gt;TEST_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR VIDEO FILEPATH&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;STREAM_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rtmps://&amp;lt;YOUR_CHANNEL_INGEST&amp;gt;:443/app/&amp;lt;YOUR_STREAM_KEY&amp;gt;"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 5: Test!
&lt;/h3&gt;

&lt;p&gt;Now we have everything we need for testing. Before that, we need to make sure that our API is running properly.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;apigateway&lt;/code&gt; variable from step 2 — which is the API URL of the Amazon API Gateway — we can test our API by doing a &lt;code&gt;GET&lt;/code&gt; request with the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET https://&amp;lt;URL_API_ENDPOINT&amp;gt;/sign


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we will get the following output.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT_TOKEN_EXAMPLE"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To finish testing, we need to run a webserver for serving HTML pages and ingesting video to the Amazon IVS channel.&lt;/p&gt;

&lt;p&gt;To run the webserver in Python, you can use the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/web/&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 8080


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, you can access the website by visiting &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And to run the video ingestion script, you need to run the following command to make the script executable:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-ingestvideo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-privatechannel-ingestvideo.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/video-stream/&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x stream-video.sh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To run the script, you can use the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Working directory: 2-private-channel/video-stream/&lt;/span&gt;
./stream-video.sh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And with this command, we are now ingesting the video to the IVS channel.&lt;/p&gt;

&lt;p&gt;Now, when we open the web &lt;code&gt;http://localhost:8080&lt;/code&gt;, there are two buttons available. When you click &lt;code&gt;Play without Token&lt;/code&gt;, video playback will not be successful because this channel requires authorization with a playback key.&lt;/p&gt;

&lt;p&gt;TODO: ADD Screenshot&lt;/p&gt;

&lt;p&gt;And when you click &lt;code&gt;Play with Token&lt;/code&gt;, you will see your video is running fine because the playback URL has been added to the token that we get from the API.&lt;/p&gt;

&lt;h4&gt;
  
  
  Congrats! 🥳
&lt;/h4&gt;

&lt;p&gt;Now you can implement private channels with Amazon IVS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Cleanup
&lt;/h3&gt;

&lt;p&gt;Don't forget to remove all resources once you're done with the tutorial. To do cleanup, do the following steps:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cd cd&lt;/span&gt;/
cdk destroy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Choose "Yes" and CDK will remove all resources created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up!
&lt;/h2&gt;

&lt;p&gt;I was quite surprised by how easy it is to implement access control restrictions for video playback using Amazon IVS. The token mechanism, using JWT signing and public/private keys, can be implemented in various authentication and authorization approaches.&lt;/p&gt;

&lt;p&gt;And that's a wrap! Hope you enjoyed this tutorial and if you have any questions, please leave your comments.&lt;/p&gt;

&lt;p&gt;Happy building!🤘🏻&lt;br&gt;
— Donnie&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>lambda</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build Interactive Live Video Apps with Amazon IVS</title>
      <dc:creator>Donnie Prakoso</dc:creator>
      <pubDate>Mon, 25 Apr 2022 02:52:20 +0000</pubDate>
      <link>https://forem.com/awscommunity-asean/build-interactive-live-video-apps-with-amazon-ivs-40c1</link>
      <guid>https://forem.com/awscommunity-asean/build-interactive-live-video-apps-with-amazon-ivs-40c1</guid>
      <description>&lt;p&gt;Live streaming is becoming more popular than before as we explore new ways to connect during the restriction in a pandemic situation. In this article, I'll show you how to build your streaming channel using Amazon IVS, so you can host them on your website or applications. Adding a bit of fun, I'll also show you how to add an interactive element to your live streaming to engage your audiences even more.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gXQc3X1fGx0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Github Repository for Demo(s)
&lt;/h4&gt;

&lt;p&gt;Code for this article is available at &lt;a href="https://github.com/donnieprakoso/demo-ivs/tree/main/1-stream-channel-timed-metadata" rel="noopener noreferrer"&gt;github.com/donnieprakoso/demo-ivs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Challenges on Running Live Streaming Platform
&lt;/h2&gt;

&lt;p&gt;As we are constantly improving how we deliver information — especially in the current situation — live streaming has become one of the solutions. The idea of disseminating real-time information to (practically) unlimited audiences is one reason for running live streaming.&lt;/p&gt;

&lt;p&gt;If we want to live stream into video platforms, i.e. YouTube, Vimeo, we can easily setup our OBS and start streaming. But, there's a case if you want to provide more seamless experience with your business, or to add features that aren't available in the video platform, you will need to host the live stream on your website. &lt;/p&gt;

&lt;p&gt;The biggest challenge in this case is the complexities of managing infrastructure to deliver low-latency videos. Not to mention how hard it is to bring interactivity into the stream. I'm not talking about greeting every viewer who joined the live stream. I'm talking about getting their responses to any questions in real-time.&lt;/p&gt;

&lt;p&gt;Wouldn't it be great if we can interact with our viewers? If only we can show some a popup dialog right in the stream and viewers can select the options without having to go to external apps or websites.&lt;/p&gt;

&lt;p&gt;Or, in the case of e-commerce live streaming, it would be easier for viewers to shop with the presented items on the stream. They just need to click the item, added into their cart, and proceed with checkout.&lt;/p&gt;

&lt;p&gt;Delivering the stream helps us to reach more audiences. Interactivity makes it live.&lt;/p&gt;




&lt;h2&gt;
  
  
  Here's Amazon IVS
&lt;/h2&gt;

&lt;p&gt;So, imagine that now you can set up your live stream channel with just several clicks. Even better, you can programmatically create the live stream channels for any number of the live stream that you'd like to deliver. These channels can also be embedded into your website or applications. You can also add quizzes, polling, or anything that requires feedback from your viewers.&lt;/p&gt;

&lt;p&gt;And the good news is, that those features are what you can expect from Amazon IVS. Amazon Interactive Video Service (IVS), is a managed live streaming solution to create interactive video experiences.&lt;/p&gt;

&lt;p&gt;Roughly speaking, this is how it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-1.png" alt="Working with Amazon IVS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, you need to create a channel in Amazon IVS. You will get a stream key and URL as output from this step.&lt;/p&gt;

&lt;p&gt;Second, you need to supply the stream key and URL to your favorite broadcasting channel. We have quite a few options — &lt;a href="https://obsproject.com/" rel="noopener noreferrer"&gt;OBS&lt;/a&gt;, &lt;a href="https://streamlabs.com/" rel="noopener noreferrer"&gt;Streamlabs&lt;/a&gt;, &lt;a href="https://www.xsplit.com/" rel="noopener noreferrer"&gt;XSplit&lt;/a&gt; — or you can even use an online live streaming studio such as &lt;a href="https://streamyard.com/" rel="noopener noreferrer"&gt;Streamyard&lt;/a&gt; or &lt;a href="https://restream.io/" rel="noopener noreferrer"&gt;Restream&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The third step is how you want to host the stream. You can use a website using SDK for Web or mobile applications — using SDK for iOS and Android — to host the stream.&lt;/p&gt;

&lt;p&gt;The fourth step is optional if you want to add interactivity. You can send metadata payloads into the stream, and your website or mobile apps can receive and process it accordingly.&lt;/p&gt;

&lt;p&gt;And that's it. You don't need to provision any infrastructures or expertise to run and scale the live streaming platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Are Going to Build
&lt;/h2&gt;

&lt;p&gt;If you like what you read so far, the next part will help you to get started. We are going to build a live stream video channel, serve the live stream on a website and send real-time metadata into the stream.&lt;/p&gt;

&lt;p&gt;There are 4 main steps in this tutorial.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-2.png" alt="Steps in This Tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Step 1: Provision the Amazon IVS channel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Step 2: Broadcast a video. In this tutorial, I'm going to use the VLC app to ingest the video into Amazon IVS. You can also use OBS or other broadcasting tools, as long as it supports RTMP protocols.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Step 3: Run and host a website to serve the live video stream. A quick note in this tutorial, we are going to use a local website. In practice, you can host your website in other AWS services, such as AWS Amplify.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Step 4: Once everything is set up properly, the last step is to send metadata to demonstrate how we can add interactivity to the live stream.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;This tutorial uses the following requirements and please make sure that your development environment satisfies all requirements described below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Where to get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS CDK&lt;/td&gt;
&lt;td&gt;2.17.0&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/aws/aws-cdk" rel="noopener noreferrer"&gt;github.com/aws/aws-cdk&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;3.8.13&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.python.org/downloads/release/python-3813/" rel="noopener noreferrer"&gt;python.org/downloads/release/python-3813/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg&lt;/td&gt;
&lt;td&gt;4.4&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ffmpeg.org/download.html" rel="noopener noreferrer"&gt;ffmpeg.org/download.html&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sample video&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;a href="https://peach.blender.org/download/" rel="noopener noreferrer"&gt;peach.blender.org/download/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 0: Clone Github repo
&lt;/h3&gt;

&lt;p&gt;If you'd like to do this tutorial, you can clone this repo: &lt;a href="https://github.com/donnieprakoso/demo-ivs" rel="noopener noreferrer"&gt;github.com/donnieprakoso/demo-ivs&lt;/a&gt;. Otherwise, carry on reading this tutorial if you'd like to get big pictures of how everything works.&lt;/p&gt;

&lt;p&gt;To clone the Git repo, you can run this command on your development environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone github.com/donnieprakoso/demo-ivs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Provision IVS Channel with AWS CDK
&lt;/h3&gt;

&lt;p&gt;In this step, we are going to provision the IVS channel with AWS CDK. This tutorial uses AWS Cloud Development Kit (CDK) to provide consistent deployment between this tutorial and yours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-1.png" alt="Provision IVS Channel with AWS CDK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Code Overview&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;cdk/app.py&lt;/code&gt; code is the main file to provision your IVS channel. Below is the redacted version of the source code, to point out important parts you need to understand.&lt;/p&gt;

&lt;p&gt;First, we need to configure the channel. The code below uses the L1 construct of IVS. This channel uses the basic configuration of the IVS channel, without auto-record enabled to Amazon S3 bucket. Noticed that the &lt;code&gt;authorized&lt;/code&gt; parameter is set to false, which translates to disabling playback authorization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ivs_channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}-channel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="n"&gt;authorized&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="n"&gt;latency_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;demo-ivs-metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="n"&gt;recording_configuration_arn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STANDARD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the channel configured, we need to configure the stream key so we can ingest video into the channel. To pair with the channel, we pass the IVS channel ARN into the &lt;code&gt;channel_arn&lt;/code&gt; parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ivs_stream_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnStreamKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}-streamkey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="n"&gt;channel_arn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ivs_channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the channel and stream key configured, the next step is to define and instantiates the IVS stack to produce the AWS CloudFormation template. Noticed that we are injecting the account using the environment variable &lt;code&gt;CDK_DEFAULT_ACCOUNT&lt;/code&gt; and using the &lt;code&gt;us-east-1&lt;/code&gt; region.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CDK_DEFAULT_ACCOUNT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="nc"&gt;IvsChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;demo1-ivs-metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;synth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Deployment&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To deploy the IVS stack using CDK, follow these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;1-stream-channel-timed-metadata/cdk  
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt  
cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will deploy the IVS channel and you'll see the output below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Outputs:  
demo1-ivs-metadata.demo1ivsmetadataoutputchannelarn &lt;span class="o"&gt;=&lt;/span&gt; arn:aws:ivs:us-east-1:XXXXXXXXXX:channel/XXXXXXXXXX  
demo1-ivs-metadata.demo1ivsmetadataoutputchannelingest &lt;span class="o"&gt;=&lt;/span&gt; XXXXXXXXXX.global-contribute.live-video.net  
demo1-ivs-metadata.demo1ivsmetadataoutputchannelplayback &lt;span class="o"&gt;=&lt;/span&gt; https://XXXXXXXXXX.us-east-1.playback.live-video.net/api/video/v1/us-east-1.XXXXXXXXXX.channel.XXXXXXXXXX.m3u8  
demo1-ivs-metadata.demo1ivsmetadataoutputstreamkey &lt;span class="o"&gt;=&lt;/span&gt; XXXXXXXXXX  
Stack ARN:  
arn:aws:cloudformation:us-east-1:XXXXXXXXXX:stack/demo1-ivs-metadata/XXXXXXXXXX  

✨  Total &lt;span class="nb"&gt;time&lt;/span&gt;: 15.72s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the information and credential that you can use to start hosting your live stream. Take note of these pieces of information, as we need them in the next steps.&lt;/p&gt;

&lt;p&gt;Quick overview of these variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;channelarn&lt;/code&gt; is the ARN of your IVS channel. This is required to programmatically interact with your channel.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;channelingest&lt;/code&gt; is the variable to ingest video into your channel.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;channelplayback&lt;/code&gt; is the variable you need to pass into your website so it could play the video&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;streamkey&lt;/code&gt; is the key to initiating a live stream. Remember to store your stream key in a safe place as anyone who has the stream key can ingest the video stream into the channel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Ingest video with FFMPEG
&lt;/h3&gt;

&lt;p&gt;In this step, we are going to ingest video into the IVS channel. Once we have successfully ingested video into IVS channel, our website can start playing the video using the playback URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-2.png" alt="Ingest Video with FFMPEG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To ingest video into the IVS channel, you can use OBS, XSplit, or other broadcasting. In this tutorial, to simplify the demo, we are going to use FFMPEG to stream a video into the IVS channel.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Configure Ingest Endpoint&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Before we run the FFMPEG command, we need to configure a few variables on &lt;code&gt;video-stream/stream-video.sh&lt;/code&gt; file. You will need two variables: 1) &lt;code&gt;channelingest&lt;/code&gt; and 2) &lt;code&gt;streamkey&lt;/code&gt;, which you already obtained from deployment with CDK. Also, you need to have a video to ingest into your channel. A good starting point that you can use to test is "Big Buck Bunny" — which you can download from &lt;a href="https://peach.blender.org/download/" rel="noopener noreferrer"&gt;peach.blender.org/download/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have the required variables, you need to change the following lines on &lt;code&gt;video-stream/stream-video.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TEST_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VIDEO_FILEPATH&amp;gt;.mp4"&lt;/span&gt;  
&lt;span class="nv"&gt;STREAM_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rtmps://&amp;lt;YOUR_CHANNEL_INGEST&amp;gt;:443/app/&amp;lt;YOUR_STREAM_KEY&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Run ffmpeg&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You also need to run the following command to make the script executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x stream-video.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the script, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./stream-video.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, it will start ingesting the video into your IVS channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Play Video Stream on Website
&lt;/h3&gt;

&lt;p&gt;At this stage, we already have the IVS channel created and configured with the stream key, and ingesting the video into IVS channel. The next part is to run the website to host the live video stream. With IVS, you can host your live stream on a website or mobile application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-3.png" alt="Play video on website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we use a website to host the live streaming by running the webserver on &lt;code&gt;localhost&lt;/code&gt;. In practice, you will need to deploy the website so it can be accessible to your users. There are various ways to do this, two of my favorites approach are hosting it as a static website using AWS Amplify, or you can use Amazon ECS and AWS Fargate to host the dynamic website.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Configure Variables&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The website needs to have the playback URL to identify where it should retrieve the video stream. To do this, get your playback URL variable from the CDK output and open &lt;code&gt;web/index.js&lt;/code&gt;, and change the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PLAYBACK_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://XXXXXXXXXX.us-east-1.playback.live-video.net/api/video/v1/us-east-1.XXXXXXXXXX.channel.XXXXXXXXXX.m3u8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Run Webserver&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Once you have your app configured, the next step is to run the webserver to host the web page.&lt;/p&gt;

&lt;p&gt;Again, there are various ways to do this, and as we are working on Python, the easiest way is to run the following command to run the webserver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;web/  
python &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open your browser and point the URL to &lt;code&gt;http://localhost:8080&lt;/code&gt;. You will find a page below and watch the video ingested from IVS playing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FScreenshot%2B2022-04-14%2Bat%2B11.13.23%2BPM%2B%25281%2529.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FScreenshot%2B2022-04-14%2Bat%2B11.13.23%2BPM%2B%25281%2529.png" alt="Demo Preview: Check live stream from web browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you can see a similar page like this, Congrats! You just successfully integrate your IVS channel and your web page. If you don't, let me know in the comments below so I can help you out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Sending Timed Metadata
&lt;/h3&gt;

&lt;p&gt;In previous steps, we configured and ingested live video, and host a website to playback the video. These steps are the starting point for you to run a live streaming platform.&lt;/p&gt;

&lt;p&gt;Now, we'd like to take it to the next level by adding an interactive element to your live stream. The key to interactivity is the ability to send out a message (or payload) into the live video stream. With IVS, you can send this message as timed metadata. In short, timed metadata is data about other data equipped with timestamps that are sent simultaneously to every viewer in any channel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fivs-3-4.png" alt="Send Timed Metadata"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The implementation of timed metadata isn't as complicated as its definition, and in this step, I'll explain how you can implement it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generator (App) Code Overview
&lt;/h4&gt;

&lt;p&gt;The main application to send timed metadata into the IVS channel is located at &lt;code&gt;timed-metadata/app.py&lt;/code&gt;. In this generator app, the payload we are going to send into the stream is a JSON data with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="nl"&gt;"current_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2022-Apr-14-153617"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Question : 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
           &lt;/span&gt;&lt;span class="nl"&gt;"answers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;  
                &lt;/span&gt;&lt;span class="s2"&gt;"True"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
                &lt;/span&gt;&lt;span class="s2"&gt;"False"&lt;/span&gt;&lt;span class="w"&gt;  
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just an example of a payload and all payloads are populated by the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%Y-%b-%d-%H%M%S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Question : {}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;False&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
            &lt;span class="p"&gt;]&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the payload, we can send it to particular IVS channel by calling &lt;code&gt;put_metadata&lt;/code&gt; API from IVS. Following lines show how to send metadata into IVS channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
                &lt;span class="n"&gt;channelArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;channel_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the request is successfully sent, the stream will receive the following metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;startTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.458&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;endTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.458&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'TextMetadataCue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;description:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"current_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-Apr-14-153617"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Question : 8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"answers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"True"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"False"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this data, you can build your interactive element by processing the metadata received on the &lt;code&gt;text&lt;/code&gt; property.&lt;/p&gt;

&lt;h4&gt;
  
  
  Receiver (Web) Code Overview
&lt;/h4&gt;

&lt;p&gt;In the previous step, we evaluated the generator app to send the timed metadata. We still need to receive the timed metadata on our web page. Let's review how we can instantiate the IVS player and how to receive the metadata.&lt;/p&gt;

&lt;p&gt;The web page itself is built with 2 files: &lt;code&gt;web/index.html&lt;/code&gt; and &lt;code&gt;web/index.js&lt;/code&gt;. The main logic to consume the timed metadata is on &lt;code&gt;web/index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first thing that you need to configure on this file is the &lt;code&gt;PLAYBACK_URL&lt;/code&gt;. Simply replace the variable value with the value you obtained from CDK deployment outputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PLAYBACK_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://XXXXXXXXXX.us-east-1.playback.live-video.net/api/video/v1/us-east-1.XXXXXXXXXX.channel.XXXXXXXXXX.m3u8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for the IVS player, I'm using VideoJS integration, and the following lines show how to instantiate the player:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;videojs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon-ivs-videojs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
      &lt;span class="na"&gt;techOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AmazonIVS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
    &lt;span class="p"&gt;},&lt;/span&gt;  
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
      &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PLAYBACK_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To receive the timed metadata, we need to add &lt;code&gt;event_listener&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIVSPlayer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PlayerEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEXT_METADATA_CUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn_metadata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we invoke the &lt;code&gt;fn_metadata&lt;/code&gt; function whenever the player receives timed metadata from IVS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sending Timed Metadata
&lt;/h4&gt;

&lt;p&gt;To demonstrate sending metadata into the stream, you will need your IVS channel ARN. Once you have the channel ARN, you can pass it as input to the &lt;code&gt;timed-metadata/app.py&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;To send the metadata, you can run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python app.py arn:aws:ivs:us-east-1:XXXXXXXXXX:channel/XXXXXXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;To stop the application, you need to press &lt;code&gt;Ctrl-C&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you successfully run the application, it will send the metadata into the IVS channel and it will be received by the web page. If you go to the web page, it will show the timed metadata on the right column.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fscreenshot-metadata%2B%25281%2529.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2Fscreenshot-metadata%2B%25281%2529.png" alt="Demo Preview: Website receives timed metadata"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Next?
&lt;/h3&gt;

&lt;p&gt;You're probably wondering, what you can do with this metadata. This metadata is the raw form for adding interactivity. You can add pop-up dialog for running quizzes like the screenshot below using the metadata payload you configure from your application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FScreenshot%25202022-04-20%2520at%25207.53.34%2520PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdsc.cloud%2F2c5cc2%2FScreenshot%25202022-04-20%2520at%25207.53.34%2520PM.png" alt="Demo Preview: Pop-up dialog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Cleaning up
&lt;/h3&gt;

&lt;p&gt;Don't forget to remove all resources once you're done with the tutorial. To do cleanup, do the following steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;cdk/  
cdk destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose "Yes" and CDK will remove all resources created.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In conclusion, I found it's easy to run low-latency live streaming with Amazon IVS. Equipped with a timed metadata feature, it provides a simple way to add interactive elements with viewers and take your live streaming experience to the next level.&lt;/p&gt;

&lt;p&gt;I hope this tutorial provides you with a good understanding of how Amazon IVS works. In the next post, I'll cover how to restrict playback access with authorization for a private channel.&lt;/p&gt;

&lt;p&gt;Happy building!🤘🏻&lt;br&gt;
— Donnie&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
    </item>
  </channel>
</rss>
