はじめに

Amazon Chime SDK を使用してチャットルームを実装する方法をまとめました。ここでは、サーバー側でチャンネルの作成とユーザーの登録を行ない、フロント側でチャンネルへ接続するところまでを記載しています。ソースはチャットルームを用意するための基本となる部分の記載のみとなるので、環境などに応じて適宜実装が必要になります。

Amazon Chime SDK とは

メッセージング、音声、ビデオ、および画面共有機能をウェブアプリケーションやモバイルアプリケーションにすばやく追加するために使用できるリアルタイム通信コンポーネントのセットです。Amazon Chime SDK を使用して、音声や動画を送受信したり、コンテンツを共有したりできるリアルタイムメディアアプリケーションを構築できます。
また、Amazon Chime SDK には、Amazon Chime SDK messaging と Amazon Chime SDK meetings が存在し用途が異なります。

Amazon Chime SDK messaging
テキスト主体のチャット機能のサービス
Amazon Chime SDK meetings
動画ベースでのチャット、画面共有等の機能のサービス

チャット機能はどちらも備えていますが、Amazon Chime SDK messaging の方はテキストチャットに特化して実装しやすいため、この2つを使い分けます。

目的・やりたいこと

2人以上で各 PC (スマホ)のブラウザでやりとりができるチャットルームを実装することを目的としています。サーバー側でチャンネルを作成し、クライアント側のブラウザでチャットルームの操作を行なうようにします。

事前準備

Amazon Chime SDK には、Amazon Chime SDK messaging と Amazon Chime SDK meetings があり、今回この2つを使ってチャットルームを実装します。Amazon Chime SDK messaging はメッセージ機能を実装するため、Amazon Chime SDK meetings は通話機能、画面共有機能等を実装するために使用します。
Amazon Chime SDK messaging は認証が必要なため実施用の IAM を用意します。

AppInstance の作成と AppInstanceArn の取得

CLI で下記コマンドを実行すると AppInstanceArn の値が取得されるので、DB や config ファイルなどに保持しておきます。

aws chime-sdk-identity create-app-instance --region us-east-1 --name [任意の環境名]

サーバー側での事前処理

サーバー側で Chime Meeting の作成とユーザーの登録を行ないます。

use Aws\Chime\ChimeClient;

//ChimeClientクラス用意
//リージョンは使える箇所が限られているのでドキュメントを要確認
$options = ['version' => 'latest', 'region' => 'ap-northeast-1'];
$client = new ChimeClient($options);

//meetingオプション設定
$meetOptions = [
    'ClientRequestToken' => 'unique-a', //ユニークになるような値にする
    'MediaRegion' => 'ap-northeast-1',
    'ExternalMeetingId' => 'unique-b', //ユニークになるような値にする
    'Attendees' => [
        [
        'ExternalUserId' => 'user1', //ユーザーIDを設定する
        ],
        [
        'ExternalUserId' => 'user2', //2人目(相手)のユーザーIDを設定する
        ],
    ],
];
//meeting作成
$response = $client->createMeetingWithAttendees($meetOptions);

//meeting接続情報
$config = array(
    'Meeting' => $response['Meeting'],
    'Attendees' => $response['Attendees'],
    'Errors' => $response['Errors'],
);
//取得した接続情報はクライアント側へ渡すためJSON形式などで保持しておく(※①)
$jsonJoinConfig = json_encode($config);

続いてChime Messagingの作成を行います。Messagingでは、ユーザーの作成、チャットチャンネルの作成、ユーザーをチャンネルへ登録、が必要となります。

use Aws\Chime\ChimeClient;

//ChimeClientクラス用意
//リージョンは使える箇所が限られているのでドキュメントを要確認
$options = ['version' => 'latest', 'region' => 'us-east-1'];
$client = new ChimeClient($options);

// Messaging用ユーザー1作成
$options_1 = [
    'AppInstanceArn' => $instanceArn, //事前準備で用意したAppInstanceArnを設定する
    'AppInstanceUserId' => 'unique-c', //ユニークになるようなIDを設定する
    'ClientRequestToken' => 'unique-d', //ユニークになるような値にする
    'Name' => 'user1', //ユーザー名を設定する
];
$appInstanceUserArn1 = $client->createAppInstanceUser($options_1);

// Messaging用ユーザー2作成
$options_2 = [
    'AppInstanceArn' => $instanceArn, //事前準備で用意したAppInstanceArnを設定する
    'AppInstanceUserId' => 'unique-e', //ユニークになるようなIDを設定する
    'ClientRequestToken' => 'unique-f', //ユニークになるような値にする
    'Name' => 'user2', //ユーザー名を設定する
];
$appInstanceUserArn2 = $client->createAppInstanceUser($options_2);


// Messaging用チャットチャネル作成
$channelOptions = [
    'AppInstanceArn' => $instanceArn, //事前準備で用意したAppInstanceArnを設定する
    'ClientRequestToken' => 'unique-g', //ユニークになるような値にする
    'ChimeBearer' => $appInstanceUserArn1['AppInstanceUserArn'], //チャンネルのオーナーになるユーザーのArnを設定する
    'Name' => 'TestChannel', //チャンネル名を設定する
];
$channelArn = $client->createChannel($channelOptions);

// 作成したユーザーを作成したチャネルへ登録
$channelMemberOptions = [
    'ChannelArn' => $channelArn['ChannelArn'],
    'ChimeBearer' => $appInstanceUserArn1['AppInstanceUserArn'],
    'MemberArn' => $appInstanceUserArn2['AppInstanceUserArn'],
    'Type' => 'DEFAULT',
];
$client->createChannelMembership($channelMemberOptions);

//接続に必要な情報をまとめておく
$msgConfig = array(
    'AppInstanceArn' => $instanceArn,
    'AppInstanceUserArn' => array(
        array('AppInstanceUserArn' => $appInstanceUserArn1['AppInstanceUserArn']),
        array('AppInstanceUserArn' => $appInstanceUserArn2['AppInstanceUserArn']),
    ),
    'ChannelArn'      => $channelArn['ChannelArn'],
    'accessKeyId'     => xxxxxxxxxxxxxxxxxxxx, //IAMのaccessKeyId
    'secretAccessKey' => xxxxxxxxxxxxxxxxxxxx, //IAMのsecretAccessKey
);

//クライアント側へ渡すためJSON形式などで保持しておく
$jsonMsgConfig = json_encode($msgConfig);

クライアント側での処理

クライアント側では、サーバ側で生成した接続情報を元に amazon-chime-sdk-js を使用して実装します。

import {
  ConsoleLogger,
  LogLevel,
  DefaultDeviceController,
  MeetingSessionConfiguration,
  MeetingSessionStatusCode,
  DefaultMeetingSession,
  DefaultModality,
  DefaultVideoTile,
  AudioProfile,
} from "amazon-chime-sdk-js";
const logger = new ConsoleLogger('MT', LogLevel.DEBUG);

// -- 初期設定 --
const meetingResponse = xxxxxxxxxxxxxxxxx; //※①のサーバ側で生成したMeeting情報のJSON
const deviceController = new DefaultDeviceController(logger);
const configuration = new MeetingSessionConfiguration(meetingResponse, attendeeResponse);
const meetingSession = new DefaultMeetingSession(configuration, logger, deviceController);

// ビデオチャット用オブザーバー(各イベント発生時の処理などを記載する)
// 参考:https://aws.github.io/amazon-chime-sdk-js/interfaces/audiovideoobserver.html#audiovideodidstartconnecting
const av_observer = {
  audioVideoDidStart: () => {
  },
  audioVideoDidStop: sessionStatus => {
  },
  audioVideoDidStartConnecting: reconnecting => {
  },
};
// ビデオチャット用デバイス管理オブザーバー(各イベント発生時の処理などを記載する)
// 参考:https://aws.github.io/amazon-chime-sdk-js/interfaces/devicechangeobserver.html#audioinputschanged
const av_device_observer = {
  audioInputsChanged: freshAudioInputDeviceList => {
  },
  audioOutputsChanged: freshAudioOutputDeviceList => {
  },
  audioInputMuteStateChanged: (device, muted) => {
  },
};

// ビデオチャットの送受信用オブザーバーを登録
meetingSession.audioVideo.addObserver(av_observer);
meetingSession.audioVideo.addDeviceChangeObserver(av_device_observer);
// 開始処理
meetingSession.audioVideo.start();
import {
  ChimeSDKMessagingClient,
  SendChannelMessageCommand,
  ListChannelMessagesCommand,
} from '@aws-sdk/client-chime-sdk-messaging';
import {
  ConsoleLogger,
  DefaultMessagingSession,
  LogLevel,
  MessagingSessionConfiguration,
} from 'amazon-chime-sdk-js';
const logger = new ConsoleLogger('MT', LogLevel.DEBUG);

// -- 初期設定 --
const client = new ChimeSDKMessagingClient({
  region: 'us-east-1',
  credentials: {
    accessKeyId: xxxxxxxxxxxxxxxxxxxx, //IAMのaccessKeyId
    secretAccessKey: xxxxxxxxxxxxxxxxxxxx, //IAMのsecretAccessKey
  }
});
const sessionId = undefined;
const messagingConfiguration = new MessagingSessionConfiguration(userArn, sessionId, undefined, client);
const messagingSession = new DefaultMessagingSession(messagingConfiguration, logger);

// テキストチャット用オブザーバー(各イベント発生時の処理などを記載する)
const observer = {  
  // Chime Messagingサーバーから受け取ったデータの処理はすべてここで定義する
 // 参考:https://aws.github.io/amazon-chime-sdk-js/interfaces/messagingsessionobserver.html
  messagingSessionDidStart: () => {
  },
  messagingSessionDidStartConnecting: reconnecting => {
  },
  messagingSessionDidStop: event => {
  },
  messagingSessionDidReceiveMessage: message => {
  },
};

// テキストチャット開始処理
messagingSession.addObserver(observer);
messagingSession.start();

上記の準備後は、各オブザーバーの設定箇所に処理を実装していきます。
例えばメッセージの送信は SendChannelMessageCommand クラスを使用することで送信ができます。メッセージの履歴は ListChannelMessagesCommand クラスで取得できるので、オブザーバー設定の messagingSessionDidReceiveMessage でメッセージを受信したら履歴を表示するなどの処理を入れることで、チャットルームのような実装ができます。
ただ、Amazon Chime SDK messaging と Amazon Chime SDK meetings の2つには互換性があるわけではなく、各々のユーザーやチャンネルは別々の扱いとなるので、管理に注意しながら1つのチャットルームのように見せる必要があります。

また、今回はユーザ認証など記載していませんが、認証されたユーザのみ入室(ログイン)できるような処理を必要に応じて追加する必要があります。

まとめ

Amazon Chime SDK を使用してチャットルームを実装しました。今回はシンプルなチャットルームを用意するための基本となる部分の記載のみとなりますが、リモート会議などで使用するビデオ通話や画面共有などの機能も実装することができ、要件に応じてカスタムできるところが魅力だと思います。