【Vonage】Video API スタートアップガイド「ビデオ通話が簡単に出来ちゃうAPIがあるんですか！？」


<!--
？「おやおや？あんた、見ない顔だねぇ」
？「インターネットの旅人さんかい？」
？「こんなところに人が来るなんて珍しいなぁ...」
？「ま、面白いもんはなにもありゃしないがね」
 _       __       __                                 __            ____                __                            __   __
| |     / /___   / /_____ ____   ____ ___   ___     / /_ ____     / __ ) ____ _ _____ / /__ __  __ ____ _ _____ ____/ /  / /
| | /| / // _ \ / // ___// __ \ / __ `__ \ / _ \   / __// __ \   / __  |/ __ `// ___// //_// / / // __ `// ___// __  /  / / 
| |/ |/ //  __// // /__ / /_/ // / / / / //  __/  / /_ / /_/ /  / /_/ // /_/ // /__ / ,<  / /_/ // /_/ // /   / /_/ /  /_/  
|__/|__/ \___//_/ \___/ \____//_/ /_/ /_/ \___/   \__/ \____/  /_____/ \__,_/ \___//_/|_| \__, / \__,_//_/    \__,_/  (_)   
                                                                                         /____/                             
-->

皆さんこんにちは！
筆が遅すぎて、アドベントカレンダーに**代わりに投稿**されてしまった**POTI**です ^__^

今年は、[Vonage Advent Calendar 2023](https://qiita.com/advent-calendar/2023/vonage) に参加してみました！
ということで今回は、

<!-- > ・参考文献等が豊富でこれからも読み続けられそうな記事
> ・これから開発を進めるにあたって参考になり得る記事

参考になる記事、、、
うーん・・・ -->

**Vonage様** から提供されている 沢山のコミュニケーションAPI の中から個人開発者の方にも比較的需要がありそうな、**「簡単にビデオ通話が実装できちゃうAPI」** こと **Vonage - Video API**（以下 Video API）について解説していくことにします！

# はじめに

本記事では、

* 「**Video API** のことはよく知らないけど、**簡単にビデオ通話が実装できる**って聞いたの、、、」
* 「公式ガイドとかチュートリアルとか見てきたけど、**いまいちよく分からなくて**、、、」
* 「軽くデモを試してみたんだけど、もっとこんな機能を **実装** してみたいな、、、」

といった Video API をこれから使い始める方々に、Video API について **噛み砕いて** 解説していきます。

* 「[Video APIの仕組み](https://qiita.com/potistudio2022/items/b386e5a6f1de614c6a0c#video-api-%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF)」では、ビデオ通話の最中、内部でナニが行われているのか、公式ガイドを元に分かりやすく解説しています。
* 「[実践してみよう](https://qiita.com/potistudio2022/items/b386e5a6f1de614c6a0c#%E5%AE%9F%E8%B7%B5%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)」では、実際に **Webで動く簡易的なデモ** を詳しい手順とともに作成していきます。
* 「[さらにカスタマイズ](https://qiita.com/potistudio2022/items/b386e5a6f1de614c6a0c#%E3%81%95%E3%82%89%E3%81%AB%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)」では、Video API で簡単に実装できる、**より高度なカスタマイズオプション** をサクッと紹介しています。
* 「[参考にしたい記事の紹介](https://qiita.com/potistudio/items/b386e5a6f1de614c6a0c#%E3%81%8A%E3%81%BE%E3%81%91%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%81%84%E8%A8%98%E4%BA%8B%E3%81%AE%E7%B4%B9%E4%BB%8B)」では、Video API を活用した **さらに高度な実装** を解説されている記事を **厳選して** 紹介しています。

Video API 初学者から中級者を主な対象に、「参考になるかな？」と精一杯書いてみました。

## 対象読者

* **Vonage Video API についてもっとよく知りたいと思っている方**
* **Video API で理想のビデオ通話を作ってみたいと思っている方**

:::note warn
実践編では、別途これらが必要です。

* JavaScript の基本的な知識
* Webページの仕組み（フロントエンド・バックエンド）について大体理解している
:::
<!-- TODO: -->
# Vonage Video API とは

**Vonage - Video API（旧 TokBox OpenTok）**

アメリカの *Vonage社* が提供する *Video API* は、高品質なビデオ・音声・メッセージング・画面共有を **Webページやモバイルアプリに簡単に実装することができる API** です。
Video API では、たくさんのプラットフォーム・言語に向けてSDKが提供されており、ネイティブコードから直接使用することが出来ます。

Vonage Video API では、これらのプラットフォーム・言語に提供されています。

プラットフォーム：Web / Android / Windows / macOS / iOS / Linux / React Native
言語：.NET / Java / Node / PHP / Python / Ruby

![Vonage Video API 公式サイトのトップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/d8a858af-5ad3-73d2-ed90-da2980549e1c.png "Vonage Video API 公式サイトのトップ")

<!-- TODO: Video Chat Embed との違い -->
# Video API の仕組み

解説を始める前に、出てくる単語について定義をしておきます。

|単語|意味|
|:---:|:---:|
|Vonageサーバー|Vonage側のサーバー|
|アプリサーバー|ページのバックエンド|
|クライアント|ページのフロントエンド|

↓ ここで解説する内容は公式ガイドにも詳しく載っています（ただし英語のみ）↓

https://tokbox.com/developer/guides/basics/

それでは、Video API がどのように通話を実現しているのか、解説していきます。

## 1. セッションの作成

通話を行うには、参加者全員を格納しておくための、個別の、いわゆる **部屋** が必要ですね。
部屋を作成するためには、Vonageへ、リクエストを行います。

:::note info
Vonage のダッシュボードから手動で作成することも出来ますが、
毎回手動でやるわけにもいかないじゃないですか、、、
なのでここでは、クライアントから自動で作成できるようにします。
（そっちの方が実用的ですしね）
:::

まず、アプリケーションサーバーが起動すると、Vonageへセッションの作成をリクエストします。
Vonageがセッションの作成に成功した場合、**リクエストの返答として、セッションのIDを返します**。
（失敗した場合は**エラーの詳細**が返されます）

:::note info
このセッションIDは、後でVonage側のセッションに**接続する際に使用**するため、サーバー側で保存しておきます。
:::

```plantuml
Server -> Vonage: セッションの作成をリクエスト
Vonage -> Vonage: セッションを作成
alt 作成に成功
  Vonage --> Server: セッションIDを返す
else 作成に失敗
  Vonage --> Server: 失敗エラーの詳細
end
```

### セッションについて詳しく

> セッションは、一意のセッション ID に関連付けられ、クライアントがリアルタイムで相互に対話できる「ルーム」と考えることができます。

つまり、
Zoomでいう一つの会議、YouTubeでいう一つの配信、Discordでいう一つのボイスチャンネル・・・
といった具合の、いわゆる **互いにビデオ通話を行うための部屋** を表したものです。

一つのセッションには、それを表す一意のIDが紐付けられます。
また、セッションには有効期限がなく、明示的に破棄することも出来ません。
（代わりにトークンで管理）
あくまで、**一つの部屋を表したもの** であることに注意です。

## 2. トークンの取得

さて、セッションに接続するためには、セッションIDともうひとつ、**認証情報を表す一意のトークンが必要**です。
このトークンの生成は、Vonageへのリクエストはせず、アプリケーションサーバーがSDKを通して**セッションIDから生成**します。

```plantuml
Client -> Server: トークンとセッションIDをリクエスト
Server -> Server: セッションIDから一意のトークンを生成
Server --> Client: セッションIDと生成されたトークンを返す
```

### ※ トークンについて詳しく

> 【公式ガイドの訳】
> 
> トークンは、クライアントがセッションに参加できるようにする一意の認証「キー」です。
> クライアントがセッションに参加しようとすると、アプリサーバーは一意のトークンを生成し、それをセッション ID とともにクライアントに送信します。
> トークンには、パブリッシャー、サブスクライバー、モデレーターなどの役割を割り当てることもできます。
> これにより、セッション内のストリームの公開やストリームのサブスクライブなど、クライアントの権限が決まります。

トークンには有効期限が設定でき、最大で３０日、デフォルトでは２４時間となっています。
また、トークンには有効期限がありますが、セッションには有効期限がないことに注意です。

トークンの生成時には、VonageサーバーへのAPI呼び出しはなく、ハッシュ関数とシークレットキーさえあれば自由に生成できます。
また、公式では、トークンを使用する際のある程度のベストプラクティスが紹介されています。

* クライアントが接続しようとしたときに、クライアント毎の新しいトークンを生成する
* トークンには有効期限を設定する（デフォルトでは24時間）
* トークンを保存したり、再利用したりしない
* トークンに含まれた接続データを使用してユーザーを識別する

## 3. セッションへ接続

やっとこさ、用意されたセッションへ接続することが出来ます。
Vonageに向けて先程用意した、**"セッションID"** と **"認証トークン"** を送信し、

Video API の接続は ***WebSocket*** で行われています。

```plantuml
Client -> Vonage: セッションID & 認証トークンで接続をリクエスト
Vonage --> Client: 「入れたよ」
```

<details><summary>WebSocketってなぁに？</summary>

調べてみたら、意外と高度な技術なんですね。
↓ こちらは５年前の記事ですが細かい部分までしっかり解説されています。興味のある方はぜひ ↓

[WebSocketについて調べてみた。- Qiita](https://qiita.com/south37/items/6f92d4268fe676347160)

</details>

## 4. 二人目登場

さて、このままボッチでビデオを配信し続けていてもいいのですが、第２者が居ないとビデオ通話は成立しません！
ということで、お友達を連れてみましょう。
※ お友達が居ない方はスルーしてください（）

２人目以降の参加にも、セッションIDと認証トークンが必要です。
これらの情報はアプリケーションサーバーに保存してあるんでしたね。

２人目がアクセスすると、サーバーは以前に生成したセッションIDとトークンを使用して、セッションに参加させます。

セッションに居るクライアントが、それぞれ自身の映像をVonageに **送信（パブリッシュ）** し、他の参加者の映像を **受信（サブスクライブ）** することで、ビデオ通話が実現します。

映像の通信にも ***WebSocket*** が使われています。

```plantuml
' participant Vonage as Vonage
' participant クライアント２ as Client2
' participant クライアント１ as Client1

Client1 -> Vonage: パブリッシュ
Client2 -> Vonage: パブリッシュ
|||
Vonage -> Client2: サブスクライブ
Vonage -> Client1: サブスクライブ
```

# 実践してみよう

さて、Video API について大方理解できましたか？
ここからは、いよいよ本番です！
先程の流れをもとに、実際に動作する簡易的なデモを作ってみましょう！

## 実装する機能

* サーバーサイドでの動的トークン発行
* ビデオ・音声通話（ホスト）
* ビデオ・音声通話（クライアント）

## 使用する技術

* Webフレームワークに[SvelteKit](https://kit.svelte.dev) & [Svelte](https://svelte.dev)
* ビデオ通話に[Vonage Voice API](https://www.vonage.com/communications-apis/video/features/video-chat-embeds)
<!-- * データベースの管理に[Supabase] -->

## 実際の動作の流れ

<!-- 1. ユーザーは指定されたページを開いて待機 -->
<!-- 2. 開始時刻になったら主催側がホストを開始 -->
<!-- 3. 面接中は主催側で録画 & 録音 -->
<!-- 4. 主催側がホストを終了し、クライアント側もそれに応じて自動で終了する -->

```plantuml
title ビデオ通話の全体の流れ

actor クライアント2 as Client2
actor クライアント1 as Client1
participant アプリサーバー as Server
participant Vonageサーバー as Vonage

|||
Client1 --> Server: 最初のアクセス

== 準備 ==

Server -> Vonage: セッションを作成
Vonage --> Server: セッションID ＼(ﾟｰﾟ＼)
Server -> Server: トークンを生成
Server -> Vonage: セッションに参加

== 通話 ==

Client1 -> Vonage: 映像・音声をパブリッシュ
Vonage -> Client1: 映像・音声をサブスクライブ
...

== ==
Client2 -> Server: ２人目以降がアクセス
|||
group 人数分増える
  Client1 -> Vonage: 映像・音声をパブリッシュ
  Client2 -> Vonage: 映像・音声をパブリッシュ
  |||
  Vonage -> Client1: 映像・音声をサブスクライブ
  Vonage -> Client2: 映像・音声をサブスクライブ
end
...
```

図が大きくて一見複雑そうに見えますが、準備さえすればあとはVideo APIさんが自動で継続的に通信してくださります。

## 新規プロジェクト作成

まずはVideo APIのダッシュボードにアクセスして、新しいプロジェクトを作成します。
（ログインしていない場合はログインしましょう）
↓↓
[Vonage Video API Account](https://tokbox.com/account/)

ログイン出来たら、サイドバー（左側）にある **Create Project** からプロジェクトの作成を行います。

![vivaldi_JAfno8EOcg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/724a5c01-4477-5ec9-8e56-52acee9e2e98.png)

***

すると、プロジェクトの種類を訊かれるポップアップが表示されます。

![vivaldi_hyTOZ4jAJa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/d81bd73a-38e8-33cd-dad4-b9e35cc20d42.png)

今回は、右側の **Vonage Video API** の下にある **Create Custom Project** を押して、作成を始めます。

***

![vivaldi_mZJ3PlcW7s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/f57ea3c0-a418-171c-932c-e9f389d7b34c.png)

プロジェクト名（上）は自由に決められます。センスが問われますね。
コーデック（下）には、安定の **VP8** を使用します。

:::note warn
もうひとつ、**H.264** の選択も出来ますが、**VP8** の方が推奨されるようです。
選択しようとすると、このような注意書きが出ます。

> H.264 は大規模なセッションには推奨されず、古い Android デバイスではサポートされない可能性があります。スケーラブルビデオはサポートされていません。
:::

***

![vivaldi_GldsbJDUVY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/8e3f0ab5-5f5e-ae25-cc7b-9033e40ab706.png)

**Congulation!!!**

無事、プロジェクト作成が完了し、専用の ```API Key``` と ```SECRET Key``` が発行されました！
これらは、実際に Video API を使う際に必要となります。
（※ 画像のキーはフェイクです）

このデモは一つのページ上に作成することが出来ます。（ルーティングはお好みで）

* ビデオ通話（クライアント） ```/vonage/lobby```

:::note info
フレームワークに ```SvelteKit``` を使用すると、フロントエンドとバックエンドを手軽に連携できます。（唐突な布教）
:::

## ダッシュボードから必要な情報を確認する

こちらは、Video APIダッシュボードで確認できる、プロジェクト設定画面のトップです。
（画像のキーは参考のためのフェイクです）

![Video APIダッシュボードのトップ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740248/72fa32f3-85b9-5d62-37b6-e7a2fba76d00.png)

下の欄にある、**PROJECT API KEY** と **PROJECT SECRET** がセッションの作成に必要な項目です。

:::note warn
特に、**PROJECT SECRET は絶対に外部に公開しないで** ください。
悪用される危険性があります。
（２度いいますが、この参考画像はフェイクです）
:::

## ビデオ通話の準備をする

ビデオ通話を開始するためには、トークンを発行して、ホストとクライアントの双方に適用しなければなりません。
これらを、サーバーサイド（Node.js）で専用のSDKを通して行っていきます。
Vonageとの通信には **TokBox SDK** というのを使います。

まずは、npmからOpenToK SDKをインストールしましょう。

```shell
$ npm install opentok || yarn add opentok || pnpm add opentok
```

続いて、SDKをプロジェクトにインポートし、SDKのインスタンスを作成します。

:::note warn
インスタンスの作成では、引数にAPI KeyとProject Secretが必要になります。
これらはVonageのプロジェクトダッシュボードからコピーし、プロジェクトに合わせて、環境変数などからインポートしてください。
:::

```javascript
import OpenTok from "opentok";

// SDKのインスタンスを作成
const openToK = new OpenTok (API_KEY, PROJECT_SECRET);
```

これで、SDKを使用する順位が整いました！

### セッションIDの生成

トークンを発行するにはまず、セッションを作成する必要があります。
これには、```OpenToK.createSession()``` 引数のコールバック内でごにゃごにゃします。

```diff_javascript:app.ts
+ openToK.createSession ((error, session) => {
+     if (error) throw error;

+     const sessionID = session?.sessionId; // セッションからIDを取得
+     console.log (`ID: ${sessionID}`);
+ });
```

<details><summary>"session"の後にある"?"ってなぁに？</summary>

```?``` はTypeScriptで使える記号です。
いわゆる *"nullチェック"* をインラインで記述できます。

sessionはエラーが起きた場合、中身が渡されないので、
その時にnullエラーが出ないよう、これでチェックを行っています。

[TypeScriptでよく見る「？」「！」と仲良くしたい - オプショナルチェイニング(?.) - Zenn](https://zenn.dev/oreo2990/articles/3d780560c5e552#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%81%E3%82%A7%E3%82%A4%E3%83%8B%E3%83%B3%E3%82%B0(%3F.))

</details>

はい、これだけです！
実行すると、生成されたセッションIDがコンソールに表示されます。

```shell:console
ID: 1_MX40NzgzNzMyMX5-MTcwMzMyNDMyNjcyM354anBaTUVkQ2NGN0NmMnpoRC95MUR3amN-UH5-
```

### 異なるクライアント間で同じセッションIDを使用する

最初にアクセスしたクライアントがVonageサーバーからセッションIDを受け取った後、
別のクライアントが同じ部屋に入室するためには、同じセッションIDを使用していなければなりません。
そのため、後にアクセスしたユーザーが **既に生成されたセッションID** を使えるように、**外部のデータベースに保存して**、別のクライアントから読み出せるようにします。

データベースと聞いて拒否反応が出てしまった方、安心してください。
私もデータベースアレルギーです。
ですが、使用するのは値の格納・取り出しだけですのでほんのちょびっとです。

とはいいましたが、この記事はあくまで Video API の実装例の解説ですので、データベースを使用した詳しい実装は他の記事に譲ります。
値の格納・取り出しが出来ればOKです。
機能としては、

1. 最初のクライアントがセッションIDを取得と同時にデータベースへ格納
2. 別のクライアントがアクセスした際、データベースにセッションIDが既に存在したらそれを使用。
3. 各々トークンを生成して入室

という感じのものを実装してください。
これで、**「同じセッションID、異なるトークン」** で同じ部屋にそれぞれ入室できたら完了です。

今回、私はデータベースに ***Supabase*** というSaaSを使用しましたが、ここは、ご自身の使い慣れたものを使用してください。

:::note info
追加で応用的な実装をいくつか

* セッションIDと一緒に有効期限を設定して保存する
* クライアントが全員退出したらセッションIDを破棄する（＝ セッションの破棄）
:::

### セッションIDからトークンを発行

続いて、このIDを使用してトークンの発行を行います。
発行には ```Session.generateToken``` を使用します。
```Session``` は、先程作成したセッションのオブジェクトです。
コールバック関数で引数にとったやつですね。

```diff_javascript:app.ts
openToK.createSession ((error, session) => {
    if (error) throw error;

    const sessionID = session?.sessionId;
-   console.log (`"ID": ${sessionID}`);
+   const token = session?.generateToken(); // トークンを生成する関数
+   console.log (`Token: ${token}`);
});
```

**たった１行！**
いやぁ、ホントにコストが少なくて便利ですねぇ（感激）

てことで、生成されたトークンはこんな感じです。

```shell:console
Token: T1==cGFydG5lcl9pZD00NzgzNzMyMSZzaWc9YzcwMDA4YzllMTBmODZmNGEwYzk3ZTZhNzJiMDZmNDE0ZTljNTllODpzZXNzaW9uX2lkPTJfTVg0ME56Z3pOek15TVg1LU1UY3dNek15TXpNM01qY3hNWDVDYUhGMmVWWlVNbVpoUzJaMFpGSnNSVzFuUWxnMWJHZC1VSDUtJmNyZWF0ZV90aW1lPTE3MDMzMjMzNzImbm9uY2U9MC4xNDczMjAxNjg5MDMyMTA0MiZyb2xlPXB1Ymxpc2hlciZleHBpcmVfdGltZT0xNzAzNDA5NzcyJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9
```

## クライアントに映像を表示させる

HTMLに ```<script>``` タグを使用して、**Video API のクライアントSDK** を読み込みます。

```diff_html:index.html
<head>
    <!-- titleとかmetaとか -->
+   <script async src="https://static.opentok.com/v2/js/opentok.min.js"></script>
</head>
```

これで、ページ内でSDKが使えるようになりました。
SDKからは、```OT```（**O**pen**T**okの略）というオブジェクトが提供されており、ここから関数を呼び出して操作を行います。

### セッションの作成

まずは、セッションを作成します。
```OT.initSession()``` は、アプリケーションIDとセッションIDを使用してセッションを作成します。
返り値として、セッションを表すオブジェクトが返されるので、変数にしまっておきましょう。

```javascript
const session = OT.initSession (APP_ID, SESSION_ID); // セッションを作成
```

セッションを作成するときには、オプションで次の項目が設定できます。

* メディアモード
  クライアントが映像を送信する方法を指定します。
  ```Relayed``` と ```Routed``` の２つが指定できます。
* 自動アーカイブ
  ビデオ通話が開始された時に、自動的に記録を開始するかを指定します。
  デフォルトでは、自動的には行われません。
* ロケーション
  接続するサーバーの地域に影響します。（東京サーバーやシンガポールサーバー等）
  基本的には、クライアントに基づいて自動で決定されるため、指定せずに大丈夫です。

### パブリッシャーの作成

次に、パブリッシャーを作成します。
このオブジェクトが映像をVonageサーバーに送信します。
返り値として、パブリッシャーを表すオブジェクトが返されるので、同じように変数にしまっておきましょう。

```javascript
const publisher = OT.initPublisher(); // パブリッシャーを作成
```

### パブリッシャーを接続

パブリッシャーをVonageサーバーと接続します。
```Session.connect()``` を使用し、第一引数に生成したトークン、第二引数にコールバック関数を渡します。
そして、コールバック関数内で ```Session.publish()``` を使用して、映像をパブリッシュします。
引数には、先ほど作成したパブリッシャーのオブジェクトを渡します。

```javascript
session.connect (TOKEN, error => {
    if (error) throw error; // エラーハンドリング

    session.publish (publisher); // パブリッシュ
});
```

### サブスクライバーの作成

サブスクライバーの作成は、パブリッシャーとはちょっと異なり、このようになります。
というかどちらかというと、「登録」といったほうが良いですかね。

```javascript
session.on ("streamCreated", event => {
    session.subscribe (event.stream); // サブスクライバーを作成
});
```

```Session.on (event, callback)``` はイベントハンドラーです。
第一引数で指定したイベントが発行された時に、第二引数のコールバック関数を呼び出します。

今回では、```"streamCreated"``` というイベントが発行されたときを刺します。

***

ということで、完成したクライアント側の全体像がこちらです。

```javascript:index.ts
const session = OT.initSession (APP_ID, SESSION_ID); // セッションに接続
const publisher = OT.initPublisher(); // パブリッシャーを作成

session.connect (token, error => {
    if (error) throw error; // エラーハンドリング

    session.publish(publisher); // パブリッシュ
});

session.on ('streamCreated', event => {
    session.subscribe (event.stream); // サブスクライバーを作成
});
```

**Congratulations!!!**

これだけで、映像・音声のパブリッシュとサブスクライブが完了します。
後は、カメラやマイクで遊んでみてください。

インターネットに公開してURLを共有すれば、お友達を連れ込むことを出来るでしょう。

↓ より詳しいチュートリアルは公式ガイドをお読みください ↓

https://tokbox.com/developer/tutorials/web/basic-video-chat/

↓ また、実際にコードを書いてリアルタイムで体験する場も用意されています ↓

[Set up a simple browser-based audio-video chat with Vonage Video API in a few minutes](https://dashboard.nexmo.com/getting-started/video)

<!-- ## ビデオ通話を終了する

通話が終わったら、クライアントを切断しなければなりません。
ここでは、クライアントの操作をできる限り削減するため、ホスト（サーバー）から一方的に切断します。
切断には ```OpenToK.forceDisconnect()``` を使用し、引数には初めに生成したセッションIDとコネクションID、オプションでエラーハンドリングのためのコールバック関数を指定します。

```javascript:app.ts
openToK.forceDisconnect (sessionId, connectionId, error => {
    if (error) throw error;
});
``` -->

# さらにカスタマイズ

Video API で出来るのはただのビデオ通話だけではありません！
知る人ぞ知るあんなサービスやこんなサービスにも利用されている、一見複雑そうな便利機能・・・
そいつらも、パパッと簡単に組み込むことが出来ちゃう。そう、**Vonageならね**。

<!-- ## ライブキャプチャー -->

<!-- ## 拡張機能なしで画面配信をする

Video API ならブラウザに拡張機能をインストールせずに画面配信[^3]を行うことが出来ます。

:::note warn
モバイルブラウザでは画面配信はサポートされていません。
また、画面配信を利用するには、ページをHTTPS経由で通信する必要があります。
:::

[^3]: カメラの映像ではなく、デスクトップに表示されている画面を使用する -->

<!-- ## セッションにモデレーターを追加する

モデレーター・・・
つまり管理者の次に偉い、第２の管理者ですね（常に監視し、即座に対処する、警察みたい）
YouTubeやTwitchなんかのライブ配信プラットフォーム等ではよく聞くのではないでしょうか。

Video API ではビデオ通話の中にこれを追加することも可能です（もちろん専属の人手が必要ですがね） -->

## ビデオ通話をアーカイブ（記録）する

Video API では、ビデオ通話の録音・録画がサポートされています。

**１つの記録ごとに最大４時間**の録画が可能で、ビデオ通話がそれ以上行われる場合は、**自動で４時間毎に区切られながら記録される**ことになります。
つまり、９時間のビデオ通話を録画する場合、４時間の記録が２つと１時間の記録が１つできるわけです。

Video API のサーバーサイドSDKには、アーカイブのための関数が揃っています。

<!--TODO: APIについてもっと掘り下げる-->
* アーカイブの開始 ```OpenTok.startArchive (sessionId, options, callback)```
* アーカイブの停止 ```OpenTok.stopArchive (archiveId, callback)```
* アーカイブのリストアップ ```OpenTok.listArchives (options, callback)```
* アーカイブのメタ情報を取得 ```OpenTok.getArchive (archiveId, callback)```
* アーカイブの削除 ```OpenTok.deleteArchive (archiveId, callback)```

また、あらかじめアーカイブを自動で行うようにすることも可能です。
自動的に記録を行いたい場合は、セッションを作成する際、引数にオプションとして指定する必要があります。

:::note warn
アーカイブを行えるのは、メディアモードが```routed```に指定されているセッションだけです。
そのため、オプションで同時にメディアモードも指定してあげる必要があります。
:::

```diff_javascript
- openToK.createSession ((error, session) => {
+ openToK.createSession ({ mediaMode: "routed", archiveMode: "always" }, (error, session) => {
    if (error) throw error;

    /* ... */

  });
```

この、```{ mediaMode: "routed", archiveMode: "always" }``` オプションを ```OpenToK.createSession()``` の第１引数に渡すことで、ルーティングモードと自動アーカイブの設定を行っています。

**Congratulations!!!**

ビデオ通話を開始すると自動でアーカイブが始まり、ビデオ通話を終了した段階で、一連の記録がVonageに保存されます。

<!--TODO: アーカイブの確認方法の解説 -->

## 接続にIP制限をかける

:::note warn
IP制限の機能はエンタープライズ版のみの機能となります。
:::

プライベートな会話をしてる最中、見ず知らずの人がいきなり割り込んできたら、、、
大半の人は、嫌でしょう。
特に、大事な会議なんかに入ってこられたら、、、ゾワッとしますね。

そこで便利なのが、IPアドレスによるアクセスの制限です。
これを組み込むと、ビデオ通話に参加できる端末を限定することが出来ます。
<!--IPアドレスをちょろっと紹介
<details><summary>IPアドレスってなぁに？？？</summary>

IPはIP

</details>
-->

インターネットは広いですから、そのままでは誰でもセッションにアクセスし放題です。
会議なんかを想像していただけるとわかりやすいと思います。
Zoomなんかの会議中、見知らぬ人がいきなり入ってきて、、、

> ？「（ピコンッ）」
> 部長「誰だ貴様！」
> ？「地獄からの使者、スパイダーマ(ry」
> 部長「警備員！！！」

なんてことが起こりかねません。なんと恐ろしい。

こうならないようにも、プライベートな場には事前にセッションにIP制限をかけて、参加者を限定しておくことができます。
近代的ですね。

私は個人アカウントなので、設定方法の詳しい解説は出来ませんが（そもそもアクセス権がないため）
試してみたい方は ↓公式ガイド↓ をお読みください（ただし英語）

https://tokbox.com/developer/guides/ip-addresses/

# まとめ

* Vonage Video API を使えば、簡単にビデオ通話が実装できる！
* なんといっても多機能！

以上、私の知識を絞り出して書かせていただきました！
（ごちゃごちゃ詰め込みすぎて読みにくくなっちゃったかな？と少し心配ですが、、、）
参考になりましたら幸いです 🙏🙏🙏

また、不明な点、間違った点がございましたら、コメント等で気軽にご指摘ください。
随時更新して参ります！💪

# 【おまけ】参考にしたい記事の紹介

今回紹介したものの他にも、いろんな方々がいろんな活用例を解説してくださっています。
ぜひ参考にして、いっぱいインスピレーションを浴びてみてください。🚿

## Vonage 公式ガイド

* たくさんのチュートリアルが紹介されています。
  公式なので安心感も 👍

https://developer.vonage.com/en/video/tutorials

## 2023年の参考記事

* ブラウザの ```Canvas API``` を利用して、AI画像認識を実装するというなんともツヨツヨ！
高度なことをしていらっしゃるので、腕に自身のある方は挑戦してみては・・・

https://qiita.com/youtoy/items/be460a8943313bf733e7

* こちらでは、iOSのネイティブアプリ（Swift）内でARの実装をされています

https://qiita.com/tabu_ch/items/807b10a0f723918bc428

## 2022年の参考記事

* こちら、かなり実践的な内容となっています。
  Video API の活用例として非常に参考になります。

https://qiita.com/ikea_shark_jk/items/9e46776c0b690b882f83

# おわりに

執筆時点でアドベントカレンダーもいよいよ終盤・・・
隙間がどんどん埋まっていくのを視界の端に「早く仕上げなきゃ」と、
焦燥感がダバダバ溢れ、せっせとやる気に変換している今日この頃、、、
**私は家で独りです** ¬_¬

さて、ケ◯タッキーでも食べますか