【SkyWay】PC⇄スマホでビデオ通話を作成してみた（初心者向け）

# はじめに

Qiitaが[面白そうなイベント](https://qiita.com/official-events/93564ad363199fa7999c)やってたので、参加してみました🙋‍♂️

# 概要

PCとスマホでビデオ通話を作成しました！
SkyWayというものを使えば、簡単に実装できるみたい。
>SkyWay はアプリケーションに音声・ビデオ通話をはじめとしたリアルタイム・コミュニーケーション機能を容易に組み込むことを可能とするプラットフォームです。

詳しくは[こちら](https://skyway.ntt.com/ja/docs/user-guide/introduction/)。

https://skyway.ntt.com/ja/docs/user-guide/introduction/

開発ドキュメントも充実しているので、比較的簡単に実装できました。ただ、サーバ構築部分だったり、スマホの接続方法だったりが少し手間取ったので、そこら辺を補足しながら説明していければと思います。

# 出来上がったもの

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/bedcdc8c-66a2-f616-8f50-90ca48fe9c6d.gif" width="50%">

スマホの画面はこんな感じです。左側が自分の映像、右側が相手の映像。

# 構成
![無題のプレゼンテーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/a8d58883-c9fb-62bc-e542-175aae94320c.png)
ざっくりこんな感じ。やることとしては、

**1. SkyWayサイトからIDとキーを取得**
**2. コード作成**
**3. サーバ立ち上げ**
**4. Port Forwarding接続**

となってます。

# SkyWayサイトからIDとキーを取得
[ここ](https://console.skyway.ntt.com/signup/)からSkyWayアカウントを作成。

https://console.skyway.ntt.com/signup/

![sign_up](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/c545674c-2012-05ce-4725-fe489201d4cc.png)

トップ画面で`プロジェクトを作成`をクリック、`アプリケーションを作成`をクリックする。

![top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/82b58090-1389-689c-9cca-eafa7481fc3e.png)

ここで出てくる`アプリケーションID`と`シークレットキー`をメモしておく。

# コード作成
ここら辺は、[SkyWayの開発者ドキュメント](https://skyway.ntt.com/ja/docs/user-guide/javascript-sdk/quickstart/)通りでOK。以下の`index.html`と`main.js`を同一フォルダ内に保存。

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>SkyWay Tutorial</title>
  </head>
  <body>
    <p>ID: <span id="my-id"></span></p>
    <div>
      room name: <input id="room-name" type="text" />
      <button id="join">join</button>
    </div>
    <video id="local-video" width="400px" muted playsinline></video>
    <div id="button-area"></div>
    <div id="remote-media-area"></div>
    <script type="module" src="main.js"></script>
  </body>
</html>
```

`main.js`内に、先ほどメモした`アプリケーションID`と`シークレットキー`を貼り付ける。

```main.js
const token = new SkyWayAuthToken({
  jti: uuidV4(),
  iat: nowInSec(),
  exp: nowInSec() + 60 * 60 * 24,
  scope: {
    app: {
      id: 'ここにアプリケーションIDをペーストしてください',
      turn: true,
      actions: ['read'],
      channels: [
        {
          id: '*',
          name: '*',
          actions: ['write'],
          members: [
            {
              id: '*',
              name: '*',
              actions: ['write'],
              publication: {
                actions: ['write'],
              },
              subscription: {
                actions: ['write'],
              },
            },
          ],
          sfuBots: [
            {
              actions: ['write'],
              forwardings: [
                {
                  actions: ['write'],
                },
              ],
            },
          ],
        },
      ],
    },
  },
}).encode('ここにシークレットキーをペーストしてください');

(async () => {
  const localVideo = document.getElementById('local-video');
  const buttonArea = document.getElementById('button-area');
  const remoteMediaArea = document.getElementById('remote-media-area');
  const roomNameInput = document.getElementById('room-name');

  const myId = document.getElementById('my-id');
  const joinButton = document.getElementById('join');

  const { audio, video } =
    await SkyWayStreamFactory.createMicrophoneAudioAndCameraStream();
  video.attach(localVideo);
  await localVideo.play();

  joinButton.onclick = async () => {
    if (roomNameInput.value === '') return;

    const context = await SkyWayContext.Create(token);
    const room = await SkyWayRoom.FindOrCreate(context, {
      type: 'p2p',
      name: roomNameInput.value,
    });
    const me = await room.join();

    myId.textContent = me.id;

    await me.publish(audio);
    await me.publish(video);

    const subscribeAndAttach = (publication) => {
      if (publication.publisher.id === me.id) return;

      const subscribeButton = document.createElement('button');
      subscribeButton.textContent = `${publication.publisher.id}: ${publication.contentType}`;
      buttonArea.appendChild(subscribeButton);

      subscribeButton.onclick = async () => {
        const { stream } = await me.subscribe(publication.id);

        let newMedia;
        switch (stream.track.kind) {
          case 'video':
            newMedia = document.createElement('video');
            newMedia.playsInline = true;
            newMedia.autoplay = true;
            break;
          case 'audio':
            newMedia = document.createElement('audio');
            newMedia.controls = true;
            newMedia.autoplay = true;
            break;
          default:
            return;
        }
        stream.attach(newMedia);
        remoteMediaArea.appendChild(newMedia);
      };
    };

    room.publications.forEach(subscribeAndAttach);
    room.onStreamPublished.add((e) => subscribeAndAttach(e.publication));
  };
})();
```

# サーバ立ち上げ
Visual Studio Codeをインストール。

https://code.visualstudio.com/download

先ほど作成したコードが保存されているフォルダをVisual Studio Codeで立ち上げる。拡張機能からLive Serverを検索し、インストール。

![visual_studio_code 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/cfa643f7-2f7a-6821-72c5-1a48ffbdb3d4.png)

右下の`Go Live`をクリック。自動でブラウザが立ち上がる。

![go_live.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/74dc99f9-d221-155c-970a-f25c1612d863.png)


# Port Forwarding接続
PCとAndroidスマホをコードで繋ぐ。Android側のUSBデバッグを有効にする。詳しくは[こちら](https://developer.android.com/studio/debug/dev-options?hl=ja)。

https://developer.android.com/studio/debug/dev-options?hl=ja

PCのChromeで`Chrome://inspect`を入力し、DevTools画面を立ち上げる。

![chrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/1abc994a-a273-8377-e137-b5e62d2ababb.png)

先ほど自動で立ち上がったブラウザのポート番号を入力。
Androidスマホ側のChromeで、先ほど自動で立ち上がったブラウザのURLを入力することで、ビデオ通話が可能となる。

# さいごに
初心者なので間違いがあったら申し訳ありません。
少し手間取ったところもありましたが、上手く実装できた時は感動しました😂
チュートリアルに従って基本的な動作の実装を行いましたが、UIとか機能とかの面で色々応用ができそう！
いいね宜しくお願いします🙇‍♂️