Amazon IVS リアルタイムストリーミング機能|視聴環境をカスタマイズしてみた!

2024.05.14

こんにちは坂齊です!
前回のコラムではIVSリアルタイムストリーミング機能の視聴までの処理を確認しました。

Amazon IVSリアルタイムストリーミング機能|視聴までの処理を見てみよう! | DevelopersIO

今回は独自の配信視聴基盤を作る一歩目として、デモ環境の視聴画面をカスタマイズしてみた内容をご紹介します。

ゴール

本コラムのゴールです。

  • マイクとカメラの許可をせずに視聴を開始する!
  • トークンを自動払い出しに!(Python版)

デモ環境:https://codepen.io/amazon-ivs/pen/ZEqgrpo

余談ですが、『マイクとカメラの許可をせずに視聴を開始する!』をなぜ取り組んだかというと、デモ環境デフォルトの状態では、Tokenを入力して『Join』を押すと映像視聴にあたって、下記のようにカメラとマイクの仕様を許可する必要が出てしまいました。
配信側がマイクとカメラを許可する必要があるのはわかるのですが、視聴者側はいらないのでは?と感じたためです。

準備

※すでにデモ環境で配信をされている方向けとなります、IVSのステージ作成などはこちらをご確認ください
※デモ環境は2024年4月時点の環境を利用しています
※codepenを使いこなせず下記方法をとっておりますが、あくまで一例です

  • デモ環境をローカルにコピーデモ環境にはHTML/CSS/JavaScriptのファイルがあります、それぞれ下記のように命名します。 以降の説明で利用するだけで、任意のファイル名で問題ないです。

    • index.html
    • style.css
    • script.js
  • index.htmlの中にstyle.jsを読みに行くコードを記載
    <body>
        <!-- 中略 -->
        <!-- bodyの最後に下記を記載 -->
      <script src="./script.js"></script>
    </body>
    
  • ローカルのindex.htmlをEdgeで開く方法は、トークンの払い出し時にCORSエラーとなりました。 検証時はXAMPPやReact、S3などをうまく利用しましょう。

マイクとカメラの許可をせずに視聴を開始する!

下記を変更していきましょう。

①joinStage関数内変更

変更前

  // Retrieve the User Media currently set on the page
  localCamera = await getCamera();
  localMic = await getMic();

  // Create StageStreams for Audio and Video
  cameraStageStream = new LocalStageStream(localCamera.getVideoTracks()[0]);
  micStageStream = new LocalStageStream(localMic.getAudioTracks()[0]);

変更後

  cameraStageStream = "just-looking-camera"
  micStageStream = "just-looking-mic"

②init関数

変更前

const init = async () => {
  joinButton.addEventListener("click", async () => {
    try {
      // Prevents issues on Safari/FF so devices are not blank
      await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    } catch (e) {
      // ignore
    }

    joinStage();
  });

変更後

const init = async () => {
  joinButton.addEventListener("click", async () => {
    joinStage();
  });

色々と調べた結果、MediaDevices.getUserMedia() メソッドが、MediaStream を生成するメディア入力を使用する許可をユーザーに求めていたようです。一旦削除して、joinStage内の定義も変えておきました。

MediaDevices: getUserMedia() メソッド - Web API | MDN

トークンを自動払い出しに!(Python版)

トークンの自動払い出しはとてもシンプルでAPI・Lambdaで完結することができます。本コラムではポイントをご紹介します。

※視聴者トークンを受け取ってから映像を視聴するロジックはこちらをご参照ください。

Lambdaで配信者トークンを払い出す

今回はPythonでIVSのステージのトークンを払い出す方法を探しました。
利用するのは、boto3のcreate_participant_tokenです。

create_participant_token - Boto3 1.34.101 documentation

例をご紹介します。検証の為とてもシンプルに書いています、実案件時はDynamoDBや環境変数をご活用ください。

import json
import boto3

client = boto3.client('ivs-realtime')

def lambda_handler(event, context):
    stage_arn = "arn:aws:ivs:ap-northeast-1:xxxxxx:stage/xxxxxx" 
    response = client.create_participant_token(
        capabilities=['SUBSCRIBE'],
        duration=10,
        stageArn= stage_arn,
        userId='test'
    )
    token = response["participantToken"]["token"]

フロントのポイント

index.html

<body>内に記載されているトークンの入力欄は不要です。

style.js

  • ブラウザが読み込まれたらAPIにリクエストを投げるようにJavaScriptを記載しましょう 参考:JavaScriptでAPIを利用 https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
  • init関数は、joinボタンを押したときにjoinStage関数を動かしていた関数の為不要です。
  • joinButton、leaveButtonに関する記述は不要です。 映像視聴に影響はないですが、記載したままにするとコンソールにエラーが表示されます。

    let joinButton = document.getElementById("join-button");   //不要
    let leaveButton = document.getElementById("leave-button"); //不要
    // 中略
    
      stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {
        connected = state === ConnectionState.CONNECTED;
    
        if (connected) {
          joining = false;
          joinButton.style = "display: none";       //不要
          leaveButton.style = "display: inline-block";   //不要
        }
      });
    
    
  • トークンはAPI経由で取得するので、joinStageに記載されている『const token = document.getElementById("token").value;』は不要です。

最後に

色々と変更箇所が多くわかりづらかったかもしれません。実は提供されているデモ環境では、init関数で、ビデオと音声情報を取得してjoinStage関数を動かしていました。
本コラムをまとめると、init関数ではなく、ブラウザにアクセスしたらトークンを払い出すAPIをたたいてjoinStage関数を動かすようにすることで、今回ゴールとした『トークンを自動払い出しに!』『マイクとカメラの許可をせずに視聴を開始する』状態にすることができました!
本コラムがどなたかのお役に立てれば幸いです!