Twilio Videoで都度Roomの設定を行う方法

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズのTwilio事業部エバンジェリストの高橋です。

今回は、[Twilio Video](https://cloudapi.kddi-web.com/function/video/)で都度Roomの設定を行う方法について説明します。

Twilio Videoでは、Roomと呼ばれる会議室に対して、Participantと呼ばれる参加者が入室することで会議が行われます。
Roomには３種類のタイプ（Peer-to-Peer Room / Small Group Room / Group Room）が用意されています。どのタイプを使ったほうが良いかは以下のフローチャートを参考にします。
![whats_my_room_type.original.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/2c2885ca-c340-3c90-42df-f516abd464ee.png)

参加人数が2名なら`Peer-to-Peer Room`が最も性能が高く、３〜4名なら`Small Group Room`、5名以上なら`Group Room`を利用します。
ただし、End-to-Endでの暗号化が必須の場合は、`Peer-to-Peer Room`を使うしかありません（それ以外のタイプを選択した場合も、EndとTwilio間では暗号化がされています）。逆に録画が必要な場合は、`Peer-to-Peer Room`は使えません。
それぞれのRoomタイプや、録画の有無により料金が異なりますので、どのRoomタイプを使うかを選択することは重要です。

Roomタイプ|１参加者毎の料金（税込）|録画料金（税込）
:--|:--|:--
Peer-to-Peer Room|0.22917円/分|録画不可
Small Group Room|0.61111円/分|1.52778円/分
Group Room|1.52778円/分|1.52778円/分

※録画を行う場合には、上記以外にもデータ保管料と録画データダウンロード料が必要です。

## Roomタイプの選択方法

Twilio VideoのRoomタイプの決定には２つの方法があります。

- Ad-hoc：会議を開催する度に自動的にRoomを作成します
- REST API:APIを使って、事前にRoomを作成します

Twilioが提供している[QuickStart](https://github.com/twilio/video-quickstart-js/tree/master)や[OSSのビデオソリューション](https://github.com/twilio/twilio-video-app-react)などは、Ad-hocを利用しています。
Ad-hocでは、Roomは自動的に作成されるため、Roomタイプは管理コンソールで設定したデフォルト値（Room Topology）が適用されます。
![TwilioVideo_Room_Topology.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/c7ab8dbe-1bbd-eb84-943f-649d16b176bc.png)

一方、Ad-hocでは都度Roomタイプを変更したり、録画の有無を指定することができません。都度変更が必要な場合は、REST APIを使って事前にRoomを作成する必要があります。

# REST APIでRoomを作成する

会議に先立ち、REST APIを使ってRoomを事前に作成する場合は、Ad-hocとは以下の点が異なります。

- Roomを作成してから５分以内に誰も入室しない場合は、Roomは自動的に削除されます。
- 全員がRoomから退出した後、5分間はルームは存在し続けます。5分経過後、自動的に削除されます。

## REST APIのサンプル

入室までのタイムアウトがあるので、REST APIは最初の参加者が入室する直前に行うのが良いでしょう。入室するためには、アクセストークンの生成が必須なので、トークンを生成するタイミングでRoomを作ってしまうのが良さそうです。

以下のコードは、アクセストークンを作成する際に、同時にRoomを生成するサンプルです。
事前に会議に招待した人数によって、`Small Group Room`にするか、`Group Room`にするかを動的に判定しています。

```javascript:video-token.js
exports.handler = async function(context, event, callback) {
    const response = new Twilio.Response();
    response.appendHeader('Access-Control-Allow-Origin', '*');  // CORS対策

    // パラメータのチェック
    const IDENTITY = event.identity || '';  // ユーザID
    if (IDENTITY === '') callback(new Error(`Parameter 'identity' was not set.`));

    const roomName = event.room || '';  // ルーム名
    if (roomName === '') callback(new Error(`Parameter 'room' was not set.`));

    const attendeesCount = event.attendees || 0;    // 会議に招待した人数
    if (attendeesCount === 0) callback(new Error(`Parameter 'attendees' was not set.`));

    const ACCOUNT_SID = 'AC'; // TwilioのAccountSid
    const API_KEY = ''; // Twilio VideoのAPI Key
    const API_SECRET = ''; // Twilio VideoのAPI Secret

    const RECORDING = false;    // 録画
    const ROOM_TYPE = attendeesCount > 4 ? 'group' : 'group-small'; // Roomタイプ
    const MAX_PARTICIPANTS = attendeesCount > 4 ? 50 : 4; // 最大参加者数（Group Roomは50名まで）

    // Roomを生成
    const client = require('twilio')(API_KEY, API_SECRET, {accountSid: ACCOUNT_SID});
    await client.video.rooms.list({
        uniqueName: roomName,
    })
    .then(rooms => {
        console.log('rooms.length: ', rooms.length);
        if (rooms.length === 0) {
            // 開催中のRoomがないので生成
            return client.video.rooms.create({
                maxParticipants: MAX_PARTICIPANTS,
                recordParticipantsOnConnect: RECORDING,
                type: ROOM_TYPE,
                uniqueName: roomName,
                mediaRegion: 'jp1',
            });
        } else {
            return null;
        }
    })
    .then(room => {
        if (room) {
            console.log(`Room created. ${room.sid}`);
        } else {
            console.log(`Room was exist.`);
        }
    })
    .catch(error => {
        callback(new Error(`Room create error: ${error}`));
    });

    // アクセストークンの作成
    const AccessToken = Twilio.jwt.AccessToken;
    const VideoGrant = AccessToken.VideoGrant;

    const videoGrant = new VideoGrant({
        room: roomName
    });

    const accessToken = new AccessToken(
        ACCOUNT_SID,
        API_KEY,
        API_SECRET
    );

    accessToken.addGrant(videoGrant);
    accessToken.identity = IDENTITY;

    response.appendHeader('Content-Type', 'application/json');
    response.setBody({
        token: accessToken.toJwt()
    });
    callback(null, response);
};
```

最初の参加者がRoomを生成するので、二人目以降の参加者がアクセストークンを生成する時は、すでにRoomが生成されているかを確認しています。
すでにRoomが存在するかを確認するには、[RoomをリストするAPI](https://www.twilio.com/docs/video/api/rooms-resource#linkcode)を利用します。ただし、このAPIの実行が非同期で実行されると、その後の処理が先に行われてFunctionが終了してしまうので、`async/await`でRoomの生成を実行するところがポイントです。

# まとめ

今回は、Twilio VideoのRoomをRest APIで生成する方法を説明しました。
記事の中にも書きましたが、REST APIでRoomを生成した場合、全員が退出してから５分経過しないとルームが閉じません。Twilio Videoを使った課金サービスなどを検討している方にとっては、正確なRoomの開催時間で課金をしたいケースも少なくないため、Ad-hocでの動作と同じように、全員が退出したタイミングでRoomが閉じられたほうが良いケースもあるでしょう。
こちらについては、[次回の記事](https://qiita.com/mobilebiz/items/8666058c3df1d0515fae)でご紹介します。

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilioは音声通話、メッセージング（SMS/チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウドAPIサービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。