Twilio Video ことはじめ

# Twilio Video
本内容は、Twilio-UG 東京 で開催される Twilio Video で用いられるハンズオン内容です。
https://twiliojp-ug.doorkeeper.jp/events/41782

発表資料
https://speakerdeck.com/honkimi/twilio-video-hanzuonzi-liao

# 用意するもの
以下の 4つの文字列を適当な場所にコピーしておいてください。

- Account SID
- Auth Token

Twilio 管理画面 右上 の"アカウント"から取得。

- API Key
Twilio 管理画面 左上 の "製品一覧" より "プログラマブルビデオ" を選択。
上タブの "ツール" -> "APIキー" から "APIキーを作成する"
"videokey"と入れて生成。

- Configuration SID
上タブの "プログラマブルビデオ" -> "コンフィギュレーションプロファイル"を選択。
"コンフィグレーションプロファイルを作成する"ボタンをクリック
フレンドリーネームに "hellovideo" を入力し、一番下の保存ボタンをクリック

# Quick Start のダウンロード
以下より、お好みの言語の Quick Start アプリをダウンロードしてください。

- [PHP](https://github.com/TwilioDevEd/video-quickstart-php/archive/master.zip) の場合、php コマンドが実行できれば OK です。
- [Ruby](https://github.com/TwilioDevEd/video-quickstart-ruby/archive/master.zip) の場合、 gem から `bundler` をインストールしてある必要があります。
- [Node.js](https://github.com/TwilioDevEd/video-quickstart-node/archive/master.zip) の場合、 node, npm コマンドが実行できる必要があります。

## PHP の場合
`config.example.php` をコピーし、 `config.php` を作ります。
`config.php` を編集し、先ほどメモした値に入れ替えてください。

ターミナル(コマンドプロンプト)を開き、以下のコマンドを実行します。

```
cd 展開したPHPプログラムのフォルダ(ディレクトリ)
php -S localhost:8000
```

`localhost:8000` を Chrome, Firefox でそれぞれ開いて Video の画面が出て、`Connected to Twilio. Listening for incoming Invites as ~`と表示されればOKです。

## Ruby の場合
`.env.example` をコピーし、 `.env` を作ります。
`.env` を編集し、先ほどメモした値に入れ替えてください。

以下のコマンドを実行します。

```
cd 展開した Ruby プログラムのフォルダ(ディレクトリ)
bundle install
bundle exec ruby app.rb
```

`http://localhost:4567` を Chrome, Firefox でそれぞれ開いて Video の画面が出て、`Connected to Twilio. Listening for incoming Invites as ~`と表示されればOKです。

## Node.js の場合

`.env.example` をコピーし、 `.env` を作ります。
`.env` を編集し、先ほどメモした値に入れ替えてください。

以下のコマンドを実行します。

```
npm install
node .
```

`http://localhost:3000` を Chrome, Firefox でそれぞれ開いて Video の画面が出て、`Connected to Twilio. Listening for incoming Invites as ~`と表示されればOKです。

## 上記セットアップがうまくいかなかった場合
[Twilio Video のテスティングツール](https://jp.twilio.com/user/account/video/dev-tools/testing-tools) で適当な identity を入力し、トークンを生成します。

Dropbox などの public 領域に サンプルの HTML, CSS, JavaScript を置き、JavaScript を以下のように修正します。`$.getJSON`の{}で括られた範囲

```
identity = "入力した identity";
var accessManager = new Twilio.AccessManager("生成されたトークン");
conversationsClient = new Twilio.Conversations.Client(accessManager);
conversationsClient.listen().then(clientConnected, function (error) {
    log('Could not connect to Twilio: ' + error.message);
});

```

# 実行確認
Firefox, Chrome でそれぞれ開き、 どちらかのブラウザに相手の識別子 `Invites as ~ の ~` を入力してビデオ通話を開始させましょう！


# index.html の確認
メモ帳を開き、ダウンロードしたフォルダの中に `index.html` がありますので、それを開きます。

```
  <script type="text/javascript" src="//code.jquery.com/jquery-1.7.1.min.js"></script>
  <script src="//media.twiliocdn.com/sdk/js/common/v0.1/twilio-common.min.js"></script>
  <script src="//media.twiliocdn.com/sdk/js/conversations/v0.13/twilio-conversations.min.js"></script>
  <script src="index.js"></script>
```

# index.js の確認
続いて `index.js` を開きます(Node.jsの場合`quickstart.js`)。ここが今回一番重要な部分です。

```
var conversationsClient;
var activeConversation;
var previewMedia;
var identity;

// WebRTC が使えるかの確認
if (!navigator.webkitGetUserMedia && !navigator.mozGetUserMedia) {
    alert('WebRTC is not available in your browser.');
}

// token を Ajax で取得
$.getJSON('/token', function(data) {
    // data には identity と token のオブジェクトが入っている。
    identity = data.identity;
    var accessManager = new Twilio.AccessManager(data.token);

　　　　　　　　// ブラウザのConsoleを開き、identity を確認しましょう。
    // identity を友達に教えて、それを入力してもらうことでビデオ通話が開始します。
    console.log(identity);

    // 会話用のクライアントを作成し、 Twilio へ接続
    conversationsClient = new Twilio.Conversations.Client(accessManager);
    conversationsClient.listen().then(clientConnected, function (error) {
        log('Could not connect to Twilio: ' + error.message);
    });
});

// 接続に成功した場合に呼ばれるコールバック
function clientConnected() {
    document.getElementById('invite-controls').style.display = 'block';
    log("Connected to Twilio. Listening for incoming Invites as '" + conversationsClient.identity + "'");

    conversationsClient.on('invite', function (invite) {
        log('Incoming invite from: ' + invite.from);
        invite.accept().then(conversationStarted);
    });

    // 会話を生成するためにボタンクリックのイベントを定義
    document.getElementById('button-invite').onclick = function () {
        var inviteTo = document.getElementById('invite-to').value;
        if (activeConversation) {
            // 参加者を追加
            activeConversation.invite(inviteTo);
            } else {
            // 会話を生成
            var options = {};
            if (previewMedia) {
                options.localMedia = previewMedia;
            }
            conversationsClient.inviteToConversation(inviteTo, options).then(conversationStarted, function (error) {
                log('Unable to create conversation');
                console.error('Unable to create conversation', error);
            });
        }
    };
}

// 会話がアクティブな状態で呼ばれる
function conversationStarted(conversation) {
    log('In an active Conversation');
    activeConversation = conversation;
    // ビデオのプレビューがまだの場合、ローカルビデオを描画
    if (!previewMedia) {
        conversation.localMedia.attach('#local-media');
    }

    // 参加者が加わった時に、スクリーンにビデオを描画
    conversation.on('participantConnected', function (participant) {
        log("Participant '" + participant.identity + "' connected");
        participant.media.attach('#remote-media');
    });

    // 参加者が切断した時に、ログに出力
    conversation.on('participantDisconnected', function (participant) {
        log("Participant '" + participant.identity + "' disconnected");
    });

    // 会話が終わった時に、ローカルビデオの表示を停止
    conversation.on('disconnected', function (conversation) {
        log("Connected to Twilio. Listening for incoming Invites as '" + conversationsClient.identity + "'");
        conversation.localMedia.stop();
        conversation.disconnect();
        activeConversation = null;
    });
}

// ローカルビデオのプレビュー
document.getElementById('button-preview').onclick = function () {
    if (!previewMedia) {
        previewMedia = new Twilio.Conversations.LocalMedia();
        Twilio.Conversations.getUserMedia().then(
        function (mediaStream) {
            previewMedia.addStream(mediaStream);
            previewMedia.attach('#local-media');
        },
        function (error) {
            console.error('Unable to access local media', error);
            log('Unable to access Camera and Microphone');
        });
    };
};

// ログ出力
function log(message) {
    document.getElementById('log-content').innerHTML = message;
}
```

## Try!

- ビデオ通話は何人までできるか、グループで試してみましょう！
- 現在は相手に着信が来たらそのまま開始されますが、"開始","拒否"ボタンのように選択できるようにするにはどうすればいいでしょうか。ヒント: `invite.accept().then(conversationStarted);` でいきなり`accept`しちゃってますね。
- 音声のミュート、ビデオのポーズなどの実装方法を調べてみましょう。[Videoのドキュメント](https://media.twiliocdn.com/sdk/js/conversations/releases/0.13.5/docs/index.html)にあります。
- 余裕があれば [iOS](https://jp.twilio.com/docs/api/video/guide/quickstart-ios) や [Android](https://jp.twilio.com/docs/api/video/guide/quickstart-android) のクイックスタートを読んでみましょう！