JavaScriptでAmazon Chime SDKを動かしてみる

Amazon Chime SDKの動作を確認するクライアントサイドをJavaScriptで実装してみたいと思います。

事前準備

サーバサイド

サーバサイドにて、ミーティング(meeting)と参加者(attendee)を作成して、クライアントサイドへ渡してあげる必要があります。 以下などを参考に、サーバサイドを実装してください。

gsol.hatenablog.com

Amazon Chime SDKダウンロード

以下READMEを参考に、Amazon Chime SDKをダウンロードしてください。

https://github.com/aws/amazon-chime-sdk-js/tree/master/demos/singlejs

実装内容

<html lang="ja">
<head>
  <script src="aws/amazon-chime-sdk.min.js"></script>
  <script type="text/javascript">
    var logger = '';
    var deviceController = '';
    var configuration = '';
    var meetingSession = '';
    
    // Meeting参加
    function addMeeting() {
      // サーバサイドにてミーティングと参加者を作成し、クライアントサイドで受け取る
      var meeting = {XXXX};
      var attendee = {XXXX};
      (async () => {
        logger = new ChimeSDK.ConsoleLogger('MyLogger', ChimeSDK.LogLevel.ERROR);
        deviceController = new ChimeSDK.DefaultDeviceController(logger);
        console.log('deviceController', deviceController);
             
        // ミーティングセッション作成
        configuration = new ChimeSDK.MeetingSessionConfiguration(meeting, attendee);
        console.log('configuration', configuration);
        meetingSession = new ChimeSDK.DefaultMeetingSession(configuration, logger, deviceController);
        console.log('meetingSession', meetingSession);

        // 入出力デバイス取得(ブラウザはマイクとカメラの許可を求める)
        const audioInputDevices = await meetingSession.audioVideo.listAudioInputDevices();
        console.log('audioInputDevices', audioInputDevices);
        const audioOutputDevices = await meetingSession.audioVideo.listAudioOutputDevices();
        console.log('audioOutputDevices', audioOutputDevices);
        const videoInputDevices = await meetingSession.audioVideo.listVideoInputDevices();
        console.log('videoInputDevices', videoInputDevices);

        meetingSession.audioVideo.chooseVideoInputQuality(1280,720,3,1000);
        await meetingSession.audioVideo.chooseVideoInputDevice(videoInputDevices[0].deviceId);
        await meetingSession.audioVideo.chooseAudioInputDevice(audioInputDevices[0].deviceId);
        if (audioOutputDevices[0]) {
          await meetingSession.audioVideo.chooseAudioOutputDevice(audioOutputDevices[0].deviceId);
        }

        // オーディオ要素取得・バインド
        const audioElement = document.getElementById('audio-preview');
        meetingSession.audioVideo.bindAudioElement(audioElement);

        const videoElements = {}; // ビデオタイル要素
        for (let i = 0; i < 16; i++) {
          videoElements[i] = document.getElementById(`video-preview` + i);
        }
        const indexMap = {};

        const acquireVideoElement = tileId => {
          // 既にバインドされている場合、同要素を返却
          for (let i = 0; i < 16; i++) {
            if (indexMap[i] === tileId) {
              return videoElements[i];
            }
          }
          // バインド可能な要素を返却
          for (let i = 0; i < 16; i++) {
            if (!indexMap.hasOwnProperty(i)) {
              indexMap[i] = tileId;
              return videoElements[i];
            }
          }
          return;
        }
        if (!acquireVideoElement) {
          alert('利用可能なビデオ要素がありません。');
        };

        // observer設定
        const observer = {
          audioVideoDidStart: () => {
            console.log('Started');
          },
          // 映像要素取得・バインド
          videoTileDidUpdate: tileState => {
            if (!tileState.boundAttendeeId) {
              return;
            }
            console.log('Start video');
            meetingSession.audioVideo.bindVideoElement(tileState.tileId, acquireVideoElement(tileState.tileId));
          }
        };

        // 出力開始
        meetingSession.audioVideo.addObserver(observer);
        meetingSession.audioVideo.start();
        meetingSession.audioVideo.startLocalVideoTile();

        document.getElementById('meetingId').value = meetingInfo.Meeting.MeetingId;
        document.getElementById('attendeeId').value = attendeeInfo.Attendee.AttendeeId;
       }) ();
    },
    error : function() {
      console.log('通信エラーです');
    }

    // Meeting退室
    function leaveMeeting() {
      // observer設定
      const observer = {
        audioVideoDidStop: sessionStatus => {
          const sessionStatusCode = sessionStatus.statusCode();
          if (sessionStatusCode === ChimeSDK.MeetingSessionStatusCode.Left) {
            alert('退室しました。');
          } else {
            alert('セッションが切れました。ステータスコード: ' + sessionStatusCode);
          }
        }
      };
    }
  </script>
</head>
<body>
  <div>
    video test<br>
    MeetingId : <input id="meetingId" value="" style="width:300px"/><br>
    AttendeeId : <input id="attendeeId" value="" style="width:300px"/>
    <br>
    <button type="button" value="" onclick="addMeeting()">参加</button>
    <button type="button" value="" onclick="leaveMeeting()">退室</button>
  </div>
  <video id="video-preview0" style="width:100%; height: 200px"></video>
  <video id="video-preview1" style="width:100%; height: 200px"></video>
  <video id="video-preview2" style="width:100%; height: 200px"></video>
  <video id="video-preview3" style="width:100%; height: 200px"></video>
  <video id="video-preview4" style="width:100%; height: 200px"></video>
  <video id="video-preview5" style="width:100%; height: 200px"></video>
  <video id="video-preview6" style="width:100%; height: 200px"></video>
  <video id="video-preview7" style="width:100%; height: 200px"></video>
  <video id="video-preview8" style="width:100%; height: 200px"></video>
  <video id="video-preview9" style="width:100%; height: 200px"></video>
  <video id="video-preview10" style="width:100%; height: 200px"></video>
  <video id="video-preview11" style="width:100%; height: 200px"></video>
  <video id="video-preview12" style="width:100%; height: 200px"></video>
  <video id="video-preview13" style="width:100%; height: 200px"></video>
  <video id="video-preview14" style="width:100%; height: 200px"></video>
  <video id="video-preview15" style="width:100%; height: 200px"></video>
  <audio id="audio-preview"></audio>
</body>
</html>

各メソッドなどは以下を参照してください。

https://aws.github.io/amazon-chime-sdk-js/

動作確認

ミーティング参加

f:id:sanok-gsol:20201130173256p:plain

ミーティング退出

f:id:sanok-gsol:20201130173311p:plain

注意点

ミーティングセッションの自動終了

生成したミーティングは、音声接続が無いまま5分経過すると自動的にセッションが終了します。 その他ミーティングのセッションが自動的に終了する場合がありますので、以下をご参照ください。

https://docs.aws.amazon.com/chime/latest/dg/mtgs-sdk-mtgs.html

ブラウザの制約

Chromiumをベースにしているブラウザ(Chrome、Edgeなど)では、「https」もしくは「localhost」にてアクセスしないと、「getUserMedia」メソッドが正常に動作しないため、 ビデオ映像や音声などが出力されません。 以下をご参照ください。

https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins