AndroidでAmazon Chime SDKを使ってみた（サーバー構築編）

# はじめに

わけあってビデオチャットを作る方法を調べてみようと思ったので、今回は**Amazon Chime SDK**を使って見ることにしました。

# Amazon Chimeとは

[Amazon Chime](https://aws.amazon.com/jp/chime/)はAmazonが提供するビデオチャットのサービスです。AWSのセミナーなどでたまに使われているのを見ますね（そらそうか）。このAmazon Chimeそのものは単なるビデオチャットチャットのアプリケーションであるのですが、[Amazon Chime SDK](https://aws.amazon.com/jp/chime/chime-sdk/)を使うとAmazon Chimeの機能を盛り込んだアプリを作ることができます。
このSDKは、[Android](https://github.com/aws/amazon-chime-sdk-android)、[iOS](https://github.com/aws/amazon-chime-sdk-ios)、[JavaScript](https://github.com/aws/amazon-chime-sdk-js)それぞれが公開されています。今回は、Androidで作成するのでAndroid向けのSDKを使用します。このSDKを用いることで、WebRTCなどの通信周りのことを意識せずにビデオチャットアプリケーションを実装することができます。基本的に今回の実装は[公式のデモアプリ](https://github.com/aws/amazon-chime-sdk-android#running-the-demo-app)をベースに行っています。

# サーバーの構築

まずはサーバーを構築します。ここで構築するサーバーの役割は、WebRTCとは別で主には**ルームの作成・削除**や**参加者の登録・解除**などの管理を行うためのシステムを実装します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209689/5e0cf3f3-1f47-6fbf-90cc-381d6e2b2714.png)

構築したのは↑のようなサーバーです。[ソースコードはこちら](https://github.com/ufoo68/chime-backend-cdk)で公開しています。[公式のサンプル](https://github.com/aws/amazon-chime-sdk-js/tree/master/demos/serverless)から、ルームの作成と削除を行うAPIを実装したものをaws-cdkを使って構築してみました。**join**というlambdaでルームの作成を行って、**leave**というlambdaでルームの削除を行っています。このAPIを使って以下の２つの情報を登録します。

- `title`:ルームのID
- `name`:参加者名

# APIの実装

コードはこんな感じです。

```typescript
import { APIGatewayEvent } from 'aws-lambda'
import * as aws from 'aws-sdk'
import { v4 as uuidv4 } from 'uuid'

const dynamo = new aws.DynamoDB()
const chime = new aws.Chime()

const tableName = process.env.TABLE_NAME ?? ''

type JoinEvent = {
  title: string
  name: String
}

type LeaveEvent = {
  title: string
}

export const join = async ({ body }: APIGatewayEvent) => {
  const { title, name }: JoinEvent = JSON.parse(body ?? '{}')
  if (!title || !name) {
    return response(400, 'application/json', JSON.stringify({ error: 'Need parameters: title, name, region' }))
  }
  let meeting = await getMeeting(title)
  if (!meeting) {
    meeting = await chime.createMeeting({
      ClientRequestToken: uuidv4(),
      ExternalMeetingId: title.substring(0, 64),
    }).promise()
    await putMeeting(title, meeting)
  }
  const attendee = (await chime.createAttendee({
    MeetingId: meeting.Meeting.MeetingId,
    ExternalUserId: `${uuidv4().substring(0, 8)}#${name}`.substring(0, 64),
  }).promise())

  return response(200, 'application/json', JSON.stringify({
    JoinInfo: {
      Meeting: meeting,
      Attendee: attendee,
    },
  }, null, 2))
}

export const leave = async ({ body }: APIGatewayEvent) => {
  const { title }: LeaveEvent = JSON.parse(body ?? '{}')
  const meeting = await getMeeting(title)

  await chime.deleteMeeting({ MeetingId: meeting.Meeting.MeetingId }).promise()
  await dynamo.deleteItem({
    TableName: tableName,
    Key: {
      title: {
        S: title,
      },
    },
  }).promise()
  return response(200, 'application/json', JSON.stringify({}))
}

const getMeeting = async (title: string) => {
  const result = await dynamo.getItem({
    TableName: tableName,
    Key: {
      title: {
        S: title,
      },
    },
  }).promise()
  return result.Item ? JSON.parse(result.Item?.data?.S ?? '{}') : null
}

// Stores the meeting in the table using the meeting title as the key
const putMeeting = async (title: string, meeting: any) => {
  await dynamo.putItem({
    TableName: tableName,
    Item: {
      title: { S: title },
      data: { S: JSON.stringify(meeting) },
      ttl: {
        N: `${Math.floor(Date.now() / 1000) + 60 * 60 * 24}`,
      },
    },
  }).promise()
}

const response = (statusCode: number, contentType: string, body: any) => {
  return {
    statusCode: statusCode,
    headers: {
      'Content-Type': contentType,
      'Access-Control-Allow-Headers': 'Content-Type',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
    },
    body: body,
    isBase64Encoded: false,
  }
}

```

[aws-sdk](https://www.npmjs.com/package/aws-sdk)を用いて実装しています。`chime.createMeeting()`でルームの作成を行って、`chime.createAttendee()`でルームにユーザーを登録します。
同じルームIDのものを作成しないために、DynamoDBを用いて各ルームIDの情報を一時保存しています。

# さいごに

ここまでがサーバーの構築です。次からはアプリの実装について説明していきます。