Agoraを使って画面共有ツールを作る

# 1. はじめに
こんにちは、普段はしょうもないウェブツールなどを作ったりIT関係のブログを書いたりしている[なりかくん](https://narikakun.net/)です。

今回は、Agoraというサービスを使って画面共有ツールを作りたいと思います。
この記事は、[V-CUBE Advent Calendar 2022](https://qiita.com/advent-calendar/2022/agora)の12日目の記事です。

# 2. Agoraってなに？
まず最初に「Agoraってなんだよ。」と思った方向けに簡単に説明させていただきます。
Agoraというのは、スマホアプリやWebサイトに、ビデオや音声通話・ライブ配信を簡単に実装できるSDKツールです。
例えば、Discordのような音声通話やビデオ通話・画面共有の機能を簡単に搭載することが出来ます。

https://jp.vcube.com/sdk

# 3. サンプルプログラムが豊富
Agoraでは、サンプルプログラムが非常に豊富に用意されています。細かくは紹介しませんが一部紹介しておきます。
## 3-1. Web系のサンプルプログラム
| 機能 | サンプルプログラム |
|:-:|:-:|
|  ライブ配信をする | https://github.com/AgoraIO/API-Examples-Web/blob/main/Demo/basicLive  |
|  ビデオ通話をする | https://github.com/AgoraIO/API-Examples-Web/blob/main/Demo/basicVideoCall  |
|  画面共有をする |  https://github.com/AgoraIO/API-Examples-Web/blob/main/Demo/shareTheScreen |

## 3-2. 各OSの例
| プラットフォーム | 言語 | サンプルプログラム |
|:-:|:-:|:-:|
| Android  | Java |  https://github.com/AgoraIO/API-Examples/blob/main/Android/APIExample |
|  iOS | Swift  | https://github.com/AgoraIO/API-Examples/blob/main/iOS/APIExample  |
| macOS  | Swift  | https://github.com/AgoraIO/API-Examples/blob/main/macOS  |
| Windows  |  C++ | https://github.com/AgoraIO/API-Examples/blob/main/windows  |

# 4. 早速作る
では、さっそく画面共有ツールを作ってみます。今回は、先ほど紹介した画面共有のサンプルプログラムを少しいじってシンプルにしました。
```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Share The Screen Agora</title>
    <style>
        .player {
            width: 480px;
            height: 320px;
        }
        .player-name {
            margin: 8px 0;
        }
        @media (max-width: 640px) {
            .player {
                width: 320px;
                height: 240px;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row video-group">
        <div class="col">
            <p id="local-player-name" class="player-name"></p>
            <div id="local-player" class="player"></div>
        </div>
        <div class="w-100"></div>
        <div class="col">
            <div id="remote-playerlist"></div>
        </div>
    </div>
</div>

<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>
<script src="./videoShare.js"></script>
</body>
</html>
```
```js:videoShare.js
let client = AgoraRTC.createClient({
    mode: "rtc",
    codec: "vp8"
});
AgoraRTC.enableLogUpload();
let localTracks = {
    screenVideoTrack: null,
    audioTrack: null,
    screenAudioTrack: null
};
let options = {
    appid: "AppID",
    channel: "room1",
    uid: null,
    token: null
};

join();

async function join() {
    client.on("user-published", handleUserPublished);
    client.on("user-unpublished", handleUserUnpublished);
    let screenTrack;
    [options.uid, localTracks.audioTrack, screenTrack] = await Promise.all([
        client.join(options.appid, options.channel, options.token || null, options.uid || null),
        AgoraRTC.createMicrophoneAudioTrack(), AgoraRTC.createScreenVideoTrack({
            encoderConfig: "720p"
        }, "auto")]);
    if (screenTrack instanceof Array) {
        localTracks.screenVideoTrack = screenTrack[0];
        localTracks.screenAudioTrack = screenTrack[1];
    } else {
        localTracks.screenVideoTrack = screenTrack;
    }
    localTracks.screenVideoTrack.play("local-player");
    $("#local-player-name").text(`localVideo(${options.uid})`);
    localTracks.screenVideoTrack.on("track-ended", () => {
        localTracks.screenVideoTrack && localTracks.screenVideoTrack.close();
        localTracks.screenAudioTrack && localTracks.screenAudioTrack.close();
        localTracks.audioTrack && localTracks.audioTrack.close();
    });
    if (localTracks.screenAudioTrack == null) {
        await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack]);
    } else {
        await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack, localTracks.screenAudioTrack]);
    }
}
async function subscribe(user, mediaType) {
    const uid = user.uid;
    await client.subscribe(user, mediaType);
    if (mediaType === 'video') {
        const player = $(`
      <div id="player-wrapper-${uid}">
        <p class="player-name">remoteUser(${uid})</p>
        <div id="player-${uid}" class="player"></div>
      </div>
    `);
        $("#remote-playerlist").append(player);
        user.videoTrack.play(`player-${uid}`);
    }
    if (mediaType === 'audio') {
        user.audioTrack.play();
    }
}
function handleUserPublished(user, mediaType) {
    subscribe(user, mediaType);
}
function handleUserUnpublished(user, mediaType) {
    if (mediaType === 'video') {
        const id = user.uid;
        $(`#player-wrapper-${id}`).remove();
    }
}
```

実際に動かしてみると、ブラウザを開いたら共有する画面を選択する画面が表示されます。そして、画面を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/314eb8d9-6699-3ad6-a853-339948d417fb.png)
すると、共有している画面が表示されます。もちろん音声も共有できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/952b305e-cd20-80f1-3e7d-7e66a88f52dd.png)
別のブラウザから同じページを開いてみると、共有されている画面を表示することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/278fcb40-843f-51de-b5a8-1fafb7f025b6.png)
また、複数人の同時共有も可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/83cc0a88-a854-424e-6cda-01f4dce63032.png)
また、iOSからこのページを開くと、しっかり共有された画面を表示することが出来ました。
こんな簡単に画面共有ツールを作れるのは最強ですね！

# 5. さいごに
今回は、サンプルプログラムを利用させていただき画面共有ツールを作ってみました。いかがでしたでしょうか。
作ったゲームなどのボイスチャットなどにも使えるみたいです。ぜひ使ってみてください！

https://jp.vcube.com/sdk