SkyWay Media Pipeline Factoryを試してみた

アドベントカレンダー初挑戦です!

SkyWay Media Pipeline Factoryが凄そうだったので試してみました。
チュートリアルを終えたら速攻で詰まったので、単なる紹介記事です! (開き直り)

## 基本用語
WebRTC: ブラウザ上でリアルタイム通信する技術 (ex. ビデオ通話)
SkyWay: WebRTCを簡単に使うためのプラットフォーム
(いらないのでは? と思いつつも分野外の人に向けて)

## SkyWay Media Pipeline Factoryって何?
[SkyWay Media Pipeline Factory](https://webrtc.ecl.ntt.com/m-pipe/)とは、NTTが2019年1月に試験提供した、SkyWayの実験的機能です。
SkyWayでやりとりするデータをクラウドに流して、あれこれ加工できるようになります。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162371/07c52a74-7cca-1c4c-2cc3-8feaf404b7ee.png)

音声をクラウドに流す→録音→AIで解析→ログやメトリクスを保存、なんて感じでWebRTCのデータをパイプライン的に加工。しかも、その設定やデプロイをGUIでできる!
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162371/c9b3626a-6473-1977-4c7a-71c390c2b1b9.png)

...とめっちゃ夢が広がる機能なんですが、まだ試験段階(α版)ということもあり、何でも揃っているわけではありません。

以下、試した内容や感想などを書きます。

## 試した動機
* WebRTCを使ったビデオ通話の録音・録画をしたかった
* 会社の人に「こんなんあるよ」と教えてもらって、調べたら面白そうだった

## 試した内容
アカウント作成
→パイプライン(=クラウド上で動く一連の処理)の作成
→デプロイ
→ビデオ通話のサンプルコード([前に作ったやつ](https://qiita.com/arene-calix/items/129dddd0d9db8f3f516f))を修正して、パイプラインにデータを送るようにする
→サンプルコードを動かして、パイプラインにデータが飛んでくることを確認
(→自前で音声合成する必要があり、ここで挫折)

#### パイプラインの作成～デプロイ

[公式のGetting Started](https://manual.m-pipe.net/tutorials/getting-started)に従いました。
ドキュメントに従ってぽちぽちGUIを触るだけで、簡単にデプロイができました。
(ホスティングには[netlify](https://qiita.com/TakahiRoyte/items/b7c4d1581df1a17a93fb)が使われているようです)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162371/0d887559-b6a6-9d54-4e8e-18a701b4a18e.png)

#### 既存コードの修正

[公式のコーディングガイド](https://manual.m-pipe.net/tutorials/coding-guide)に従いました。

変更はごく少量。
具体的にはpeer.on("open")イベントの中にパイプラインと接続する処理を足すだけ。
単にデータを送るだけなら、簡単に既存アプリへ組み込めます。

以下は、ブラウザを2窓立ち上げて、両者間でビデオ通話するコード(の大枠)です。

```js
/*
 * callする方、される方の共通処理
 */
// 自デバイスの音声、映像を取得
const localStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true
});

// Peer(接続管理用オブジェクト)の作成
const peer = (window.peer = new Peer({
  key: "自分のSkyWayアプリのAPIキー"
});

// peerができたらパイプラインと接続する(唯一の変更箇所)
- peer.on("open", (id) => {localPeerId = id});
+ peer.on("open", async (id) => {
+   localPeerId = id;
+   
+   // デプロイしたパイプラインのAPIを叩いてpeerId(≒パイプラインへ繋ぐ電話番号)とtokenをもらう
+   const entrypoint = "https://userfront.m-pipe.net/↑のデプロイ画面に表示されるエントリポイントのURL/";
+   const body = JSON.stringify({eventParams: {clientId: id}});
+   const res = await fetch(`${entrypoint}/session`, {
+     method: "POST",
+     headers: {
+       "Accept":       "application/json",
+       "Content-Type": "application/json"
+     },
+     body
+   });
+   const {token, peerid} = await res.json();
+ 
+   // パイプラインへ音声・映像を送信
+   peer.call(peerid, localStream, {metadata: {token}});
+ });

/*
 * callする方の処理 (変更の必要なし)
 */
// callボタンを押したら、相手へ自分の音声・映像を送信
callButton.addEventListener("click", () => {
  if (!peer.open) {
    return;
  }
  // remotePeerIdには、相手のlocalPeerIdを指定
  // (パイプラインから帰ってきたpeerIdではない)
  const mediaConnection = peer.call(remotePeerId, localStream);
  mediaConnection.on("stream", async stream => {
    remoteVideoElement.srcObject = stream;
    await remoteVideoElement.play().catch(console.error);
  });
});

/*
 * callされる方の処理 (変更の必要なし)
 */
// callされたら、answerし、相手へ自分の音声・映像を送信
peer.on("call", mediaConnection => {
  mediaConnection.answer(localStream);
  mediaConnection.on("stream", async stream => {
    remoteVideoElement.srcObject = stream;
    await remoteVideoElement.play().catch(console.error);
  });
});
```

ポイントは、既存のWebRTC通信とは**別に**パイプラインへデータを送る用のコネクションを張ることです。　
　自分相手がそれぞれPeerを作成(localPeerIdを取得)
　→パイプラインと接続(パイプラインからpeerIdが返ってくる)
　→peerIdではなく、localPeerIdを指定してcall/answerする

p2pに組み込む方法は公式に明確な記述がなく、けっこう躓きました。
[ビデオ通話に組み込まれた方の資料](https://slides.com/kazukitahara-1/skyway-media#/9)を見てようやく"別なんだ!"ということが分かった。
(改めて公式トップページの画像(本記事の最初に張った画像)を見ると、ちゃんと別コネクションになっている。。。)


#### パイプラインにデータが飛んでくることを確認
GUI操作でログを確認できます。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162371/30d5a9ea-8332-1d39-3947-ca6e4bb318e7.png)

## 試してみた感想
* さくっとデプロイできてログとかとれるの凄い
* 既存アプリへ組み入れる際の影響も少なそう
* 現状だとドキュメントやネット上の情報が少なく、チュートリアル以上のことをやろうとすると速攻で詰まる(かなりの腕力を要求される)
* クラウドを使うのでAWS等の知識も必要(この辺弱いのも挫折した一因)
* 作成中の機能とかもあって、まさにα-trial
* 公式トップでは音声の合成やAI解析などのユースケースを挙げているが、現状その辺は自力で解決する必要がある(例えば音声の合成は自前で組む必要がある)
* 実サービスへ組み込むには、公式とがっぷり四つに組む必要がありそう
* [ビデオ通話に組み込んだ事例](https://slides.com/kazukitahara-1/skyway-media)、マジですごい

## 最後に
このまま発展して、β-trial、そして正式リリースへと至りますよう!
そして、音声合成とかAI解析とかをサクッと使えるようになりますよう。。。