AWS Kinesis Video StreamsでMMDをWebRTCで配信する

以前、MMDファイルをJavascripとThree.jsでブラウザから見れるようにしました。
（[「原神」がMMDモデルを配信してくれたので、JavascriptでMMDビューアを作った](https://qiita.com/poruruba/items/35085f3ab3db3fa17d2d)）

今回は、さらに進めて、MMDで踊っているさまをWebRTCで配信したいと思います。

WebRTCをするために、いろいろ準備が必要だったりするのですが、AWSのKinesis Video Streamsを使えば、必要な環境をそろえてくれているので、手軽に始めることができそうです。

ソースコードもろもろを以下に置きました。

poruruba/AWSKVS_WebRTC

https://github.com/poruruba/AWSKVS_WebRTC

今回の投稿では、まず使ってみていただけるように、構築方法から実際に配信してみるところを説明します。Webサイトを公開してありますので、まずは動きを確認してみてください。
次回は、具体的なソースコードの説明をする予定です。

今回、実際に触ってみていただくWebページのURLは以下です。

https://poruruba.github.io/AWSKVS_WebRTC/index.html

以降、順に説明していきますが、まずはその通りに設定してみてください！

ちなみに、配信するものとして以下の3種類を用意しました。
・PCに接続されたWebCamで撮影されたビデオと音声を配信する。
・PCのデスクトップ画面を配信する。
・MMDのモデル・ステージをモーションで踊っているさまを配信する。

※もちろん頑張ったのがMMDなので、ぜひ見て試してみてください。

# 構成

WebRTCのブラウザ向けクライアントライブラリは標準搭載を使いますが、配信側と受信側の接続ネゴシエーションは実装依存であり、今回はAWSが提供するライブラリを利用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/10af9aae-36e9-2610-7d09-494c827ecf76.png)

#準備が必要なもの

・MMDファイル
　　配信したいMMDファイルを用意します。以降では、有志の方が作成された3つのMMDファイルを利用させていただきます。
・AWSアカウント
　　AWS Kinesis Video StreamsとMMDファイル配信用に利用しますので、AWSアカウントが必要です。以降は、すでに取得されている前提です。

# 準備の流れ

以下の流れで進めていきます。以降、順に説明します。

①配信するMMDファイルの用意
②MMDファイルをS3に配備
③IAMユーザアカウントの作成
④シグナリングチャネルの作成

## ①配信するMMDファイルの用意

以下3つのMMDファイルを使わせていただきました。（どうもありがとうございました）
それぞれ手元にダウンロードしておきます。

Kizuna AI official website

https://kizunaai.com/download/

【MMD】Project mirai クローバー♣クラブ風ステージ

https://seiga.nicovideo.jp/seiga/im2701378

three.js：wavefile_v2.vmd

https://github.com/mrdoob/three.js/tree/dev/examples/models/mmd/vmds

## ②MMDファイルをS3に配備

S3のバケットを作成します。バケット名を適当に決めてください。ただし、バケット名は他の人と重複できないです。

このブロックのブロックパブリックアクセス設定は、とりあえずパブリックアクセスをすべてブロックのチェックをOffにします。（なので、公開したくないファイルは置かないようにします）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/59c7edfb-421d-d473-998d-1e5a9482253d.png)

MMDファイルをZIP解凍すると、フォルダの中にたくさんのファイルがあるので、そのままフォルダごとブラウザにドラッグアンドドロップしてアップロードします。
以下は、キズナアイさんのファイル群の様子です。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/1ae4f11d-884a-c6b7-99cd-4c2ad449aca3.png)

vmdファイルは、フォルダを作ってその中に入れておきましょうか。
フォルダ名をvmdsにしました。

こんな感じになりました。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/4751ead1-8037-37f6-b2a1-5e0a5ae8abb3.png)

次に、ブラウザからのHTTP Getで取得できるようにバケットポリシーを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/701474ad-4855-ec16-048e-371baa889fff.png)

以下のように入力します。バケット名は作成したS3バケット名に置き換えてください。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPermission",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::【バケット名】/*"
        }
    ]
}
```

実際にブラウザからGETできるかアクセスしてみましょう。
オブジェクトURLで示されたURLをブラウザから開くことができるはずです。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/48e9df91-960c-8441-994b-c09fd8e3cbbb.png)

最後に、CORS設定もしておきます。ブラウザから取得できても、Javascriptから取得するためには、CORS設定もしておく必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/9cddb361-b1b5-f34d-0abe-7ba71ef95a46.png)

以下を入力します。

```
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]
```

これで完了です。

## ③IAMユーザアカウントの作成

AWS Kinesis Video Streamsを利用しますので、2種類のユーザを作成します。

1つ目が、配信する側のユーザです。
アクセスの種類は、「プログラムによるアクセス」にチェックを入れます。
アクセス権限には、既存ポリシのAmazonKinesisVideoStreamsReadOnlyAccessとインラインポリシでkinesisvideo:ConnectAsMasterを加えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/d324d3d7-5df2-348c-a9e5-4caec8c9d6aa.png)

2つ目が、受信する側のユーザです。
アクセスの種類は、「プログラムによるアクセス」にチェックを入れます。
アクセス権限には、既存ポリシのAmazonKinesisVideoStreamsReadOnlyAccessとインラインポリシでkinesisvideo:ConnectAsViewerを加えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/11668f7b-8430-37df-0c11-0af544eca2ea.png)

これで、2つのユーザの「アクセスキーID」と「シークレットアクセスキー」が払い出されました。


## ④シグナリングチャネルの作成

それでは、今回の肝であるシグナリングチャネルを作成します。
これは、WebRTCを中継する大事なサーバ(STUN/TURNサーバ)の設定です。とはいっても、やることはシグナリングチャネル名を指定するだけです。

AWS管理コンソールから、サービスKinesis Video Streamsを選択し、左側のナビゲーションから、シグナリングチャネルを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/0a15811d-09cc-a699-18a7-b4964830a8d1.png)
  
「シグナリングチャネルを作成」ボタンを押下します。
シグナリングチャネル名に適当な名前を付けます。例えば、「signaling-test」とか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/c827ec64-1495-4b2c-bafd-06b3439bbebb.png)

最後に、「シグナリングチャネルを作成」ボタンを押下します。
これだけです。


# 配信してみる

準備が整いましたので、さっそく配信してみたいのですが、その前にS3にアップしたMMDファイルを逐一選択しなくてもよいように、Cookieに保存しておきます。
そのためのページを用意しました。この作業は、WebRTCやAWS Kinesis Video Streamsで必要な作業ではなく、用意したMMD配信ページでそのように作っているためです。

ブラウザから以下のURLを開きます。

https://poruruba.github.io/AWSKVS_WebRTC/index.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/d887cb05-e8d0-8a97-11b3-8c44de2cb5c8.png)

pmx_list、stage_list、vmd_listに、さきほどS3に挙げたMMDファイルのURLを登録しておきます。（バケット名によっては、URLのバケット名の位置が違うかもしれません）

pmx_list
　・title：キズナアイ
　・fname：https://【バケット名】.s3.ap-northeast-1.amazonaws.com/KizunaAI_ver1.01/kizunaai/kizunaai.pmx

stage_list
　・title：クローバー・クラブ風ステージ
　・fname：https:// 【バケット名】.s3.ap-northeast-1.amazonaws.com/%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%90%E3%83%BC%E3%83%BB%E3%82%AF%E3%83%A9%E3%83%96%E9%A2%A8%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B8/CloverClub.pmx

vmd_list
　・title：wavefile_v2
　・fname：https:// 【バケット名】.s3.ap-northeast-1.amazonaws.com/vmds/wavefile_v2.vmd

以下のようになったら準備オーケーです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/edddda32-ae18-692c-3e2a-63ada6ec62d9.png)

上記のページのMMDのリンクを開くか、以下のURLを開きます。

https://poruruba.github.io/AWSKVS_WebRTC/index_mmd.html
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/9570a045-9a4c-fbef-8163-38dde4e71977.png)

AWS_ACCESSKEY_IDとAWS_SECRET_ACCESSKEYのそれぞれに、先ほど払い出した配信する側ユーザのアクセスキーIDとシークレットアクセスキーを指定します。
SIGNALING_CHANNEL_NAMEには、シグナリングチャネル名を指定します。
最後に、「Start Master」ボタンを押下します。問題なければ、アコーディオンが閉じて、connectedのところがtrueになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/ae157ae1-45fa-52d4-a6d4-0ccd0259e55c.png)

次に、配信するMMDファイルを指定します。
stageやmodelの選択肢に、先ほど登録したものが現れているかと思いますので、選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/96d3aa0d-6e3c-c6c2-127b-811c71981dc8.png)

そして、vmdを選択することで、踊り始めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/730df8fe-8b93-e97c-df96-7bce73ede09b.png)

AWS管理コンソールの、Kinesis Video Streamsに戻って、シグナリングチャネルを選択し、メディア再生ビューワーをクリックします。すると、MMDのモデルが踊っているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/089bc6e4-4e22-c84e-c8a8-ef586b455535.png)

Kinesis Video Streamsには配信が届いているのは分かったので、今度はビューアとしてブラウザから受信してみます。

別のブラウザタブから以下を開きます。

https://poruruba.github.io/AWSKVS_WebRTC/index_viewer.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/dfe14fa7-0fb1-9201-1be4-f68a478768e4.png)
 
今度は、受信側のアカウントのアクセスキーID・シークレットアクセスキーを入力します。シグナリングチャネル名は同じです。
最後に、「StartViewer」ボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/dda91a46-24c3-5cd2-f89e-9be36d66ffac.png)

無事受信できました。
複数のブラウザや別のPCから開いてもちゃんと受信できるかと思います。（すごい。。）
ちなみに、配信側のMMDの再生は、再生しているブラウザを表示していないと踊りが一時停止してしまうので、ブラウザの一部でもよいので表示されている状態にしておく必要があります。（これは、three.jsの仕様です）

# 終わりに

WebRTCは難しいですし、簡単に使えるSTUN/TURNサーバがなかなかなかったのですが、AWS Kinesis Video Streamsのおかげで簡単に動かすことができました。

MMDだけでなく、PCに接続したWebCamの映像・画像を配信したり、デスクトップをそのまま配信するページも用意しておきました。

https://poruruba.github.io/AWSKVS_WebRTC/index_webcam.html

https://poruruba.github.io/AWSKVS_WebRTC/index_desktop.html

一方で、ブラウザでMMDを表示する方法は、それなりに面倒ですが、以下をご参照ください。

　[「原神」がMMDモデルを配信してくれたので、JavascriptでMMDビューアを作った](https://qiita.com/poruruba/items/35085f3ab3db3fa17d2d)


以上