Twilio WebRTCハンズオン（CSSで見栄えをよくする編）

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

# はじめに

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

本記事は、以下の記事の内容の続編となります。ただし、以下の記事を実施していなくても大丈夫です。
[Twilio WebRTCハンズオン（WebRTC Go）CLI編](https://qiita.com/mobilebiz/private/a3e59f295f5e4c963638)

上記記事は、WebRTC を最低限の機能として実装するもので、見栄えなどは考慮されていません。実際の現場では、画面のサイズをあわせたり、参加者の数によってサイズも動的に変えたいなどの要望がでてきます。
そこで本記事では、CSS を使って映像のサイズを動的に変更したり、ボタンの見栄えを良くする方法について解説します。

すでに上記記事を実施している方は、前半部分については割愛することができますますので、[ソースコードの準備](#ソースコードの準備)から実施してください。

# 準備

## 環境
本記事を実施するにあたって、以下の環境が必要です。

- Twilio アカウント : [こちら](https://cloudapi.kddi-web.com/signup)から作成しましょう（トライアルアカウントでも OK です）
- Twilio CLI のセットアップ : [こちらの記事](https://qiita.com/mobilebiz/items/456ce8b455f6aa84cc1e)を参考にしてください
- Twilio CLI Serverless plugins : [こちらの記事](https://qiita.com/mobilebiz/items/fb4439bf162098e345ae)を参考にしてください
- VSCodeなどのエディタ

## Twilio 側の準備

### サブアカウントの作成

- Twilio 管理コンソールにログインします。
- **Dashboard** > **設定** > **サブアカウント** を選択します。

![WebRTCGoCLI_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b497ce6a-cb33-111e-5e23-e4af5ecee5d1.png)
- 赤い＋アイコンを押します。
- **わかりやすい名前**欄に、「WebRTC Go CLI」と入力して、**Create**ボタンを押します。

![スクリーンショット 2020-11-24 8.15.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/959e2205-2ecd-da17-214a-98d3b05fd72b.png)
- アカウント名の一覧に今作成した WebRTC Go CLI が表示されるので、そちらをクリックしてサブアカウントに移動します。
- 表示されたサブアカウントの**アカウントSID**と、**AUTHTOKEN**（View を押すと表示されます）を控えておきます。

![WebRTCGoCLI_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/a06ff5b2-73c4-c6e1-d5df-b433af935fc2.png)

## API キーの作成

- サブアカウントの **Dashboard** > **設定** > **API キー** を選択します。
- 赤い**新しい API キーを作成する**ボタンを押します。
- **わかりやすい名前**欄に、「Video」と入力して、**キータイプ**は「Standard」を選択し、**API キーを作成する**ボタンを押します。

![スクリーンショット 2020-11-24 8.26.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/fd603bc7-7eb1-5892-41c8-7c181a53aa17.png)
- 生成された SID（これが API Key になります）と、SECRET を控えておきます（<font color='red'>SECRET はこの画面でしか確認できません</font>）。

![WebRTCGoCLI_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/0be6af70-b3ea-c7a6-b65b-6ce177215fe1.png)
- **完了しました**にチェックを入れて、**終了**ボタンを押します。

## ソースコードの準備

この記事のソースコードは以下に準備してあります（ css ブランチ）。
https://github.com/mobilebiz/twilio-video-handson-webrtc-go/tree/css

```sh
$ git clone -b css https://github.com/mobilebiz/twilio-video-handson-webrtc-go.git
$ cd twilio-video-handson-webrtc-go
$ npm install 
```

## 環境変数の設定

ダウンロードしたフォルダの、`.env.sample` を `.env` にコピーしてご自分の環境に併せて編集します。

```sh
$ cp .env.sample .env
```

```text:.env
ACCOUNT_SID=先程控えておいた API Key（SK から始まる文字列）
AUTH_TOKEN=先程控えておいた API Secret（本当の AuthToken ではないので注意）

# Variables for function ".env"
# ---
MAIN_ACCOUNT_SID=先程控えておいたアカウント SID （AC から始まる文字列）
TWILIO_VIDEO_KEY=上記、ACCOUNT_SIDと同じ SK から始まる文字列
TWILIO_VIDEO_SECRET=上記、AUTH_TOKENと同じ、API SECRET
```

本来は、最初の `ACCOUNT_SID`と`AUTH_TOKEN`にそれぞれ正規のアカウント SID と AUTH TOKEN を入れたいのですけど、Twilio CLI の関係で API Key と SECRET を入れています。

## ローカル環境での実行

ここまでの状態で、ローカル環境での実行環境が整いましたので、`npm start` コマンドを使って早速起動してみましょう。

✋🏼 <font color='blue'>ヒント</font>
*`contents`フォルダに完成版の `video.html`、`video.js`、`video.css`が用意されていますので、ハンズオンをやらずに結果を確かめたい場合は、これらのファイルを`assets`フォルダにコピーしてから実行してください。*

```sh
$ npm start
> twilio-video-handson-webrtc-go@1.0.0 start
> twilio-run --env


│ WARNING Different Node.js Version Found
│ 
│ You are currently running Node.js 12.8.0 on this local machine. The production environment for Twilio Serverless currently supports versions 10.x.
│ 
│ When you deploy to Twilio Serverless, you may encounter differences between local development and production.
│ 
│ For a more accurate local development experience, please switch your Node.js version.
│ A tool like nvm (https://github.com/creationix/nvm) can help.

┌──────────────────────────────────────────────────────────┐
│                                                          │
│   Twilio functions available:                            │
│   └── /video-token | http://localhost:3000/video-token   │
│                                                          │
│   Twilio assets available:                               │
│   ├── /video.html | http://localhost:3000/video.html     │
│   └── /video.js | http://localhost:3000/video.js         │
│                                                          │
└──────────────────────────────────────────────────────────┘
```

無事に起動が確認できたら、早速ブラウザ上で以下のURLを起動しましょう。

http://localhost:3000/video.html

※初回は、カメラとマイクのアクセス許可が出るかもしれませんが、もし出た場合は許可してください。

![スクリーンショット 2020-11-26 8.28.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/38f48f80-4889-d0e0-d1c5-632c6ef40e19.png)

**入室**ボタンを押してルームに入ります。

ブラウザのタブを複製して、2枚めのタブでも入室してみましょう。

![スクリーンショット 2020-11-26 8.30.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/1e4c2ed3-899b-50c3-a8a2-68bf53ed5ae7.png)

ビデオ会議としてはこれで動作していますが、やはりデザインが気になりますよね・・・。
ということで、今回はちょっと見栄えを良くしていきたいと思います。

# STEP 1. 自身の映像にCSSを適用

まずはカメラの映像サイズを変更したいと思います。映像サイズを変更するためには、CSS を使うのがよさそうです。

## CSS ファイルを作成する

ではまずはじめに、以下のコマンドを使って assets フォルダに、 `video.css` を作成しましょう。

```sh
$ touch assets/video.css
```

作成した `video.css` をエディタで開いて、以下のコードを記載します。

```css:video.css
/* rootクラス */
:root {
    --video-width: 320px;   /* デフォルトの横幅 */
}

/* 映像スタイル */
.video-style {
    width: var(--video-width);
    height: var(--video-width) * ( 3 / 4 ); /* 4:3で表示 */
    object-fit: cover;
}
```
 
:root クラスを使って、CSS 内で変数を参照して値を更新できるようにしています。こうすることで、映像スタイルを複数作ったとしても、それぞれのスタイルごとにサイズを変更せずに済みます。
デフォルトの映像サイズを、:root クラス内の `--video-width` に指定してみましょう。

実際の映像に適用されるのが、 `.video-style` です。ここでは、縦横比を 4:3 にしました。
`object-fit: cover;` を指定することで、カメラの映像の縦横比が4:3以外だったとしても、自動で4:3に合わせて表示してくれます。

設定が完了したら忘れずに保存します。

## HTML ファイルから CSS を読み込む

では、今作成した CSS ファイルを HTML ファイルから参照できるようにしたいと思います。

- エディタで、`video.html` を開きます。
- 18行目と19行目の間に、以下のコードを記載します。

`  <link rel="stylesheet" href="video.css">` 

![スクリーンショット 2020-11-26 9.15.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/1544ef25-fba8-d898-ed6d-700870ed7a25.png)

## 自身のカメラ映像に、CSS を適用する

では最後に、自身のカメラ映像に今のスタイルを適用しましょう。

- エディタで、`video.js` を開きます。
- 16行目の // STEP 1. から // STEP 1. End の部分を以下のコードに置き換えます。

```javascript
        // STEP 1. 自身の映像にCSSを適用
        document.getElementById("myStream").classList.add("video-style");
        // STEP 1. End
```

![スクリーンショット 2020-11-26 9.21.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/cfe1c081-db08-35a4-4cf8-89cfa7fc47e0.png)

上記コードは、HTML 内に、`myStream` という id で指定しておいた \<video> タグにスタイルを適用するものです。

- 変更を保存して、再度ローカル環境でテストしてみましょう。
- ローカルサーバを停止してしまっている方は、再び `npm start` で起動します。

![スクリーンショット 2020-11-26 9.25.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/a25749a1-96f0-84d1-2a38-62a2381311eb.png)

指定したサイズになることを確認します。

# STEP 2. 相手の映像のサイズを変更する

現在の状態で複数タブを使った接続テストをすると、相手側の映像サイズが調整されないので、たとえば以下のようになります（環境にもよります）。

![スクリーンショット 2020-11-26 9.27.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/9c40d193-0a9c-39b8-275c-1f2ed9792a79.png)

ではさっそく、相手側の映像にも先程と同じスタイルを適用してみましょう。

- エディタで `video.js` を開きます。
- 122行目にある、// STEP 2. 〜 // STEP 2. End までの間を以下のコードで置き換えます。

```javascript
        // STEP 2. 映像トラックにCSSを設定
        if (track.kind === 'video') {
            child.classList.add("video-style");
        };
        // STEP 2. End
```

![スクリーンショット 2020-11-26 9.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/4fe6f88b-7242-ac6c-23e7-f27d52215bbb.png)

相手側の映像はトラックごとに処理しますので、映像トラックのときのみスタイルを適用するようにしています。

- 変更を保存します。
- ローカル環境でテストします。

![スクリーンショット 2020-11-26 9.37.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/6353983a-7be1-08d7-8928-d808fee0339d.png)

無事に相手側の映像も同じサイズになりましたね。

# STEP 3. ボタンの見栄えを良くする

せっかく画像がいい感じになってきたのに、入室と退室のボタンがいまいちです。
そこで、外部の CSS フレームワークを使って、ボタンの見栄えを良くしてみましょう。

今回利用するのは、シンプルなフラットデザインが好評のこちらのフレームワークです。
https://getuikit.com/

## HTML ファイルにフレームワークを読み込む

まずは、HTML ファイルに上記フレームワークを読み込みましょう。

- `video.html` をエディタで開きます。
- １９行目（先程のCSS）の上に、以下の行を追加します。

`  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.5.9/dist/css/uikit.min.css" />
`

![スクリーンショット 2020-11-26 9.45.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b54c46df-c1b8-5ba3-d78c-dd7f7cc0c81c.png)

## ボタンにスタイルを適用する

ではつぎに、ボタンにフラットデザインを適用してみましょう。

- `video.js` をエディタで開きます。
- 26行目の // STEP 3. から // STEP 3. End までを以下のコードで置き換えます。

```javascript
    // STEP 3. ボタンにCSSを適用する
    btnJoinRoom.classList.add("uk-button", "uk-button-primary");
    btnLeaveRoom.classList.add("uk-button", "uk-button-danger");
    // STEP 3. End
```

![スクリーンショット 2020-11-26 9.49.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/43ba1337-1b89-b4a2-61c4-4bf7c6f5f149.png)

uk- で始まるスタイルが、さきほど設定したフレームワークのデザインとなります。
ボタンに関するデザインは、[こちらのドキュメント](https://getuikit.com/docs/button)にサンプルとともに記載されています。

- 変更を保存します。
- ローカル環境でテストします。

![スクリーンショット 2020-11-26 9.52.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/c96e006b-436d-d1da-cfc2-8b3d46860feb.png)

ボタンの見栄えは良くなりましたが、カメラ映像に密着しちゃってますね。少しマージン（余白）を入れましょう。

- `video.css` をエディタで開きます。
- 以下の行を追加します。

```css
/* コントロールエリアのスタイル */
#room-controls {
    padding: 10px;
}
```

![スクリーンショット 2020-11-26 9.55.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/d170b905-f900-a33b-733b-3435a6d9abe0.png)

ボタンを表示しているエリアに、10px の予約をいれてみました。
- 変更を保存します。
- ローカル環境でテストします。

![スクリーンショット 2020-11-26 9.57.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/3392c2bd-3931-57ed-e981-5121bbd49799.png)

これでバッチリですね。

# STEP 4. 映像を横並びにして、参加者の数によってサイズを変える

ここまでのところで気になるのは、やはり映像の配置ですね。
縦配置ではなく、横配置にしたいところです。

## 横配置にする

この辺りもまったく Twilio とは関係のないところなのですが、やはり CSS に頼りましょう。

- `twilio.css` をエディタで開きます。
- 以下のコードを追加しましょう。

```css
/* 映像表示エリアを横並びにする */
#video-zone {
    display: flex;
    flex-wrap: wrap;
}
```

![スクリーンショット 2020-11-26 13.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/027dacab-c1e2-4bd9-a60a-081aaaf2e370.png)

カメラ画像を表示する HTML 内の親タグ（ id が video-zone の \<div> タグ ）に `display: flex` を指定して横並びにするとともに、`flex-wrap: wrap` を指定して、画面の横幅を超える場合は折り返すようにしておきます。

- 変更を保存します。
- ローカル環境でテストします。

![スクリーンショット 2020-11-26 13.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/6ef0f26f-627f-b89c-fcce-e58526dabde6.png)

いい感じですね！

では、この調子で最後のカスタマイズです。
Twilio Video では、最大50人までの会議ができますが、人数が多くなってきたときは一人ひとりの映像を小さくしたくなります。
そこで、人数に併せてカメラ映像サイズを変えてみましょう。

- `video.js` をエディタで開きます。
- 139行目の // STEP 4. から // STEP 4. End の間を次のコードで置き換えます。

```javascript
        // STEP 4. サイズの計算と適用
        const root = document.documentElement;
        if (!maxWidth && participantCount === 2) {
            // 最初の参加者が入ってきたときに、CSSの:rootに設定されている値を取得
            maxWidth = Number(getComputedStyle(root).getPropertyValue('--video-width').replace('px', ''));
            // 最小幅は、最大幅の半分とする
            minWidth = maxWidth / 2;
        }
        // 新しい幅を計算してみる
        const newWidth = maxWidth * 2 / participantCount;
        if (newWidth < minWidth) {
            // 最小幅より小さくなった場合は、最小幅を指定
            root.style.setProperty('--video-width', `${minWidth}px`);
        } else if (newWidth > maxWidth) {
            // 最大幅より大きくなった場合は、最大幅を指定
            root.style.setProperty('--video-width', `${maxWidth}px`);
        } else {
            // 計算した値を採用
            root.style.setProperty('--video-width', `${newWidth}px`);
        }
        // STEP 4. End
```

![スクリーンショット 2020-11-26 13.55.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/a3a961dd-77b7-1476-256b-fc8122aaaa6b.png)

ここはちょっと解説が必要ですね。

140行目で、`root` に設定したのは、CSS ファイルにある :root のパラメータにアクセスするためです。
141〜143行目では、最初に参加者が入ってきたときに、CSS ファイル内に指定してある現在の画像サイズを取得しています。
145行目で、映像サイズの最小値を最大値の半分に設定しています（ここは変えても大丈夫です）。

`resizeVideo()` は、参加者追加されたか、退室したときに呼ばれるようになっていて、現在の参加者は `participantCount` で管理しています。
横幅の計算は、映像サイズの最大値の２倍、すなわち、二人で会議している横並びのときの横幅を最大として、その値を参加者で割ることで、３名以上では少し画面を小さくする手法としています。
そして計算された画像サイズが最小値を超えなければ、計算値を画像サイズにしています。

- 変更を保存します。
- ローカル環境でテストします。

![スクリーンショット 2020-11-26 14.05.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/18af187c-42fe-2db5-0334-dc8d5ecff798.png)

参加人数が増えると３名からは映像サイズが小さくなっていくことがわかります。４名以上ではそれ以上は小さくならず、横幅を超えると折り返すことも確認できるかと思います。

以上で見栄えに関する作業は終了です。

# サーバーにデプロイ

ローカル環境でのテストが終わりましたので、いよいよサーバーにデプロイします。

## Twilio CLI の設定

※前回の記事ですでにCLIの設定が終わっている方は、[デプロイ](#デプロイ)まで飛ばしていただいて構いません。

まずは、Twilio CLI の Profile を設定します。
`twilio profiles:create` コマンドを使って新しく Profile を作成してください。

```sh
$ twilio profiles:create
You can find your Account SID and Auth Token at https://www.twilio.com/console
 » Your Auth Token will be used once to create an API Key for future CLI access to your Twilio Account or Subaccount, and then forgotten.
? The Account SID for your Twilio Account or Subaccount: <-- 控えておいたACから始まるアカウントSID を入力
? Your Twilio Auth Token for your Twilio Account or Subaccount: [hidden] <-- 控えておいたAuthTokenを入力
? Shorthand identifier for your profile: WebRTC Go CLI <--　プロファイル名として「WebRTC Go CLI」を入力
Created API Key SKxxxxxxxxxxxxxxxxxxxxxxxx and stored the secret in your keychain. See: https://www.twilio.com/console/runtime/api-keys/SKxxxxxxxxxxxxxxxxxxxxxxxx
twilio-cli configuration saved to "/Users/katsumi/.twilio-cli/config.json"
Saved WebRTC Go CLI.
```

このような感じで Profile が作成されますので、早速切り替えてみましょう。

```sh
$ twilio profiles:use 'WebRTC Go CLI'
set "WebRTC Go CLI" as active profile
twilio-cli configuration saved to "/Users/katsumi/.twilio-cli/config.json"
```

※プロファイル名にスペースを入れた場合、シングルコーテーションで囲う必要があります。

## デプロイ

ではいよいよサーバーへのデプロイです。
`twilio serverless:deploy` コマンドを使ってデプロイをしてみましょう。

```sh
$ twilio serverless:deploy --force

Deploying functions & assets to the Twilio Runtime

Account		SK****************************
Token		pQRS****************************
Service Name	twilio-video-handson-webrtc-go
Environment	dev
Root Directory	/Users/katsumi/Documents/workspace/webRTC/twilio-video-handson-webrtc-go
Dependencies
Env Variables	MAIN_ACCOUNT_SID, TWILIO_VIDEO_KEY, TWILIO_VIDEO_SECRET

✔ Serverless project successfully deployed

Deployment Details
Domain: twilio-video-handson-webrtc-go-XXXX-dev.twil.io
Service:
   twilio-video-handson-webrtc-go (ZS****************************)
Environment:
   dev (ZE****************************)
Build SID:
   ZB****************************
View Live Logs:
   Open the Twilio Console
Functions:
   https://twilio-video-handson-webrtc-go-XXXX-dev.twil.io/video-token
Assets:
   https://twilio-video-handson-webrtc-go-XXXX-dev.twil.io/video.html
   https://twilio-video-handson-webrtc-go-XXXX-dev.twil.io/video.js
```

上記のように、正常にデプロイが完了すると URL が払い出されます。
では、払い出された https://twilio-video-handson-webrtc-go-XXXX-dev.twil.io/video.html （XXXXはご自分の環境に合わせてください）にアクセスして、正常にビデオ会議ができることを確認します。

# まとめ

今回は、あまり Twilio に関連した話題ではなく、見栄えを調整する方法を說明しました。
今回の記事で作成した環境は、この後の記事でも使っていきたいと思っていますので、ぜひ消さずに残しておいてください。

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

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

自己紹介|　
:--|:--
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b51a8b88-abd5-ce5e-195a-de3564ba2ae6.png" height='200' width='150'/>|高橋克己（Katsumi Takahashi） 自称「<font color='red'>赤い芸人</font>」<br />グローバル・インターネット・ジャパン株式会社　代表取締役<br />株式会社KDDIウェブコミュニケーションズ　Twilio事業部エバンジェリスト<br /><br />2001年より大手通信事業者の法人サービスの教育に携わり、企業における電話のしくみや重要性を研究。2016年よりTwilio事業部にジョインし、Twilioを使ったスマートコミュニケーションの普及活動を精力的に行っている。<br />2019 Twilio Champions