IVS Timed Metadata

In this section we are going to be connecting AppSync to Amazon Interactive Video Services put metadata api. So when we create a question it will also send a request to IVS with the question id so we can sync the question coming up with the video.

  1. Navigate to the IAM Console - Policies. And select Create Policy.
  2. Select the JSON tab and paste the JSON below
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": "ivs:*",
                "Resource": "*"
            }
        ]
    }
    

    Should look something like this: policyCreate

  3. After you paste in the JSON select the Review policy button on the bottom of the page.
  4. Fill out the form with a new Name for the policy like IVS_AppSync_Policy and provide a description. And then click the Create policy. IVSAppSyncPolicyOverview
  5. Note down the name as you will need it for later!
  6. Navigate to the IAM Console - Roles. And select Create Role.
  7. For the trust entity we are going to select AppSync from the list and then click the bottom Next Permissions button at the bottom. appsyncChooseRole
  8. Select the defaults and click Next: Tags, then finally Next Review.
  9. Fill out the form with a new Name for the role like IVS_AppSync_Role and provide a description. And then click the Create Role. createRole
  10. Now you should be sent back to Role page. Search for the Role you just created, and select it.
  11. Click the Attach policies button. This should open a searchable list for all the policies we have. attachPolicies
  12. Search for the policy you create before (i.e. IVS_AppSync_Policy). And select the checkbox next to it. searchRole
  13. Click the Attach policy at the bottom of the page and you should now see the policy attached to your Role.
  14. Staying on that page copy down the Role arn at the top of the page. It should look like: arn:aws:iam::<accountNumber>:role/ivs_appsync_role. roleARN
  15. Now that we have all the info we need we can now add a new Data Source to AppSync that can call the IVS API. AppSync Data Sources are a mapping from the API to the data sources behind AppSync. We already have two Data Sources configured for us. One that connects to our Question database and the other that connects to our Answer database. We will be creating a new Data Source that is a HTTP datasource. A HTTP data source allows us to call HTTP endpoints to request or send data. We will be using it to call the IVS API and send some time metadata.
  16. To do so we will be using the AWS CLI.
  17. Find the file called http_datasource.json in the root directory of the project. It should look something like this:
    {
        "endpoint": "https://ivs.us-west-2.amazonaws.com/",
        "authorizationConfig": {
            "authorizationType": "AWS_IAM",
            "awsIamConfig": {
                "signingRegion": "us-west-2",
                "signingServiceName": "ivs"
            }
        }
    }
    
  18. Double check the endpoint is correct (the region may need to be updated if you are not in us-west-2)
  19. Now we will need to get a few values. First we need our role arn we copied down earlier. Paste that somewhere for safe keeping.
  20. Next we will need the API_ID, this can be found by opening up the file: ./amplify/backend/amplify-meta.json and finding the api secion and locating the GraphQLAPIIdOutput dictionary value. This should have an ID next to it.
  21. Now in the terminal (same directory as the http_datasource.json file). Run this command, replacing API_ID and ROLE_ARN with your respective values.
    aws appsync create-data-source --api-id API-ID \
                               --name IVS \
                               --type HTTP \
                               --http-config file://./http_datasource.json \
                               --service-role-arn ROLE-ARN
    
  22. You should see an output like this:
    {
        "dataSource": {
            "dataSourceArn": "",
            "name": "IVS",
            "type": "HTTP",
            "serviceRoleArn": "",
            "httpConfig": {
                "endpoint": "https://ivs.us-west-2.amazonaws.com/",
                "authorizationConfig": {
                    "authorizationType": "AWS_IAM",
                    "awsIamConfig": {
                        "signingRegion": "us-west-2",
                        "signingServiceName": "ivs"
                    }
                }
            }
        }
    }
    
  23. Woooooh now we will have a new AppSync data source!
  24. We are going to need to now configure AppSync to send the data to our data source. For this we will need a Channel ARN. (To get the Channel ARN again if you lost it you can simply run amplify video get-info. If it prompts yout to overwrite the exports file you can say yes).
  25. Open the AppSync console
  26. Select the API that contains your project name. Mine is unicornliveworkshop-dev.
  27. Now navigate to the Functions on the left hand side. We are going to create a function, that calls our Lambda function. AppSync function are resolvers that can be reused between multiple pipeline resolvers.
  28. Select Create function, and fill it out like below: appsyncfunction
  29. Scroll down to find the Request Mapping Template. Replace the code inside the box with the code below. We are going to be using the /PutMetadata api to send Metadata changes. Reminder: Replace channelArn with your Channel Arn from the step above
    #set( $body = {} )
    #set( $body.channelArn = 'REPLACE_ME' )
    #set( $body.metadata = $context.prev.result.id )
    
    {
        "version": "2018-05-29",
        "method": "POST",
        "resourcePath": "/PutMetadata",
        "params":{
            "body":$util.toJson($body),
        }
    }
    
  30. Double check you replaced the ARN It shouldn’t say 'REPLACE_ME'
  31. Scroll down again and replace the response mapping template with the one below. Here we are just forwarding the results from the previous function to the next step.
    ## Raise a GraphQL field error in case of a datasource invocation error
    #if($ctx.error)
      $util.error($ctx.error.message, $ctx.error.type)
    #end
    $util.toJson($context.prev.result)
    
  32. Select the Create Function button at the top.
  33. Now that we have a new function we now need to add that to our application. Navigate to the Schema section the top left side.
  34. On the right side you should see a Schema and a Resolvers section on your page. On the resolvers section use the Search bar and type in mutation to filter your search down to just the mutations. createQuestion
  35. We are going to be editing the Mutation resolver for createQuestion.
  36. On this new page you will be given an editor to edit the resolver. There is also a button to convert this resolver into a pipeline resolver. Click that button and confirm. appsyncconvert
  37. Now you have a pipeline resolver that you will need to add the function we created earlier. Click on the Add function dropdown and select the function. It should append the function we created to the bottom of the pipeline resolver. We have now successfully added Interactive Video Service’s Timed Metadata API to AppSync. addFunction
  38. Go to the top of the page and click the Save Resolver button.
  39. Now that we are syncing with Interactive Video Service Timed Metadata we need to make the client aware of this Metadata. Navigate to src/components/Video/index.jsx
  40. We are first going to add an action to the invoke the callback from the parent view. This takes advantage of the unique player technology that is provided by Interactive Video Service. Place this code in Location 13
    this.player.getIVSPlayer().addEventListener(PlayerEventType.TEXT_METADATA_CUE, (metadata) => {
      parentCallback(metadata.text);
      console.info(metadata.text);
    });
    
  41. Now that we call our callback to our parent view we can now show our questions to all our users. To set this up go to the src/components/Game/index.jsx
  42. We now need to add some code to our parent callback. Place this code in Location 14
    const { drawInfo } = this.state;
    let questionId = '';
    if ('onCreateQuestion' in drawInfo) {
      questionId = drawInfo.onCreateQuestion.id;
    }
    if (childData === questionId) {
      this.setState({
        modalVisible: true,
      });
      setTimeout(() => {
        this.setState({
          modalVisible: false,
        });
      }, 10000);
    }
    
  43. Now whenever we receive a question we will draw the modal view!