agora.io WebSDK のDualStreamについて

本記事ではagora.io WebRTC SDKのDualStreamの機能、用途、実装方法、動作確認についてご説明します。

## DualStreamのサンプル
バージョン3は[こちら](https://github.com/fu-jimoto/AgoraIO-DualStream/tree/master/agoraDualStream_v3)をご利用ください。
バージョン4は[こちら](https://github.com/fu-jimoto/AgoraIO-DualStream/tree/master/agoraDualStream_v4)をご利用ください。

以降はバージョン4のサンプルを利用して説明していきます。

## DualStreamとは？
送信側からの高画質と低画質のビデオストリームを送信することができます。(DualStreamモードと呼びます)
DualStreamモードを利用すると、クライアント環境における問題(デバイス負荷やネットワークパフォーマンスが良くないため発生する映像の遅延や切断など)を改善することができます。

## DualStreamでできること
<dl>
  <dt>・高画質、低画質の切り替え</dt>
  <dd>受信側映像の解像度を高画質から低画質、又はその逆に切り替えることができます。</dd>
  <dt>・フォールバックによる自動切り替え</dt>
  <dd>フォールバックを設定することにより、受信側映像の高画質、低画質を自動的に切り替えます。</dd>
  <dd>・LOW_STREAMモード：ネットーワーク状況が良くない場合、自動的に低画質に切り替えます。</dd>
  <dd>・AUDIO_ONLYモード：低画質に切り替わった後、ネットーワーク状況がさらに良くない場合、最低限音声だけでも通話できるように音声モードに切り替えます。</dd>
</dl>

## DualStreamの用途
以下のようなケースで利用されることが多いです。

<dl>
<dt>・様々なデバイス(PC、スマホ、タブレット)で通話するケース</dt>
<dd>対策としては、クライアント環境に合わせて受信側映像の高画質、低画質を選択します。</dd>
<dt>・ネットワーク環境が厳しいクライアント環境のケース</dt>
<dd>対策としては、フォールバックを設定して、ネットワーク環境が厳しい場合は自動的に受信側映像を低画質に切替えます。</dd>
<dt>・デバイス負荷により映像や音声品質が良くない(映像遅延やノイズが出るなど)ケース</dt>
<dd>対策としては、負荷のあるクライアント環境に対し、受信側映像を低画質に設定します。</dd>
</dl>

## DualStreamの対応ブラウザ
デバイス毎のDualStreamのブラウザ対応表です。(2021/09時点)
（v4.7.0よりSafariがDualStreamに対応可能になりました。）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/a4092fa9-358e-ff1e-8121-60483ef87bbd.png" width="90%">

## DualStreamのAPI
| API名    | 説明 |
|:--------------|:------------|
| [enableDualStream](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#enableDualStream)       | DualStreamを有効にします。        |
| [setLowStreamParameter](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#setlowstreamparameter)     | 低画質を定義します。 <br>※デフォルト値はwidth: 160、height: 120、framerate: 15、bitrate: 50kbps     |
| [setRemoteVideoStreamtype](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#setremotevideostreamtype)       | 低画質、高画質を切り替えます。        | 
| [setStreamFallbackOption](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#setstreamfallbackoption)         | フォールバックを設定します。<br>※切替条件は非公開          | 
| [disableDualStream](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#disabledualstream)       | DualStreamを無効にします。       | 

※高画質はcreateCameraVideoTrackで設定します。詳細は[Set the Video Profile](https://docs.agora.io/en/Video/video_profile_web_ng?platform=Web)を参照してください。

[その他]
・[getRemoteVideoStats](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/iagorartcclient.html#getremotevideostats)
受信側の映像情報を取得します。
今回は高画質、低画質時の解像度を確認するために、receiveResolutionHeight、receiveResolutionWidthを利用します。

## DualStreamの実装

[DualStreamのサンプル](https://github.com/fu-jimoto/AgoraIO-DualStream)をダウンロードしてご参照ください。

### 作成するアプリ
・DualStreamを有効にする
・高画質,低画質をボタンで切り替える
・フォールバックを設定する
・受信側映像の受信状況を表示する

### 開発環境
Chrome 92.0.4515.159
AgoraVideoSDK for Web 4.7.0
※最新版SDKは[こちら](https://docs.agora.io/en/Video/downloads)からダウンロードできます。

### DualStream有効化
```javascript:basicVideoCall.js
async function join() {
  // Dual Streamの有効
  await client.enableDualStream().then(() => {
    console.log("enable dual stream success");
  }).catch(err => {
    console.log(err);
  });
}
```

### 低画質の定義

```javascript:basicVideoCall.js
async function join() {

  // 低画質の定義(120 × 90, 120 Kbps)
  await client.setLowStreamParameter({
    width: 120,
    height: 90,
    bitrate: 120,
  });
}
```


### 低画質、高画質への切り替え
```javascript:basicVideoCall.js
//高画質
async function hight(uid) {
  await client.setRemoteVideoStreamType(uid,0);
}
//低画質
async function low(uid) {
  await client.setRemoteVideoStreamType(uid,1);
}
```

### フォールバックの設定
```javascript:basicVideoCall.js
async function fallback(uid){
  var option = parseInt($(`#fb_option-${uid}`).val());
  await client.setStreamFallbackOption(uid, option);
}
```

### フォールバックのコールバック設定
```javascript:basicVideoCall.js
async function fallback(uid){
  client.on("stream-type-changed", handleStreamTypeChanged);
  client.on("stream-fallback", handleStreamFallback);
}
function handleStreamTypeChanged(uid, mediaType) {
  console.log("uid:" + "%s" + "medialType:" + "%s",uid, mediaType);
}
function handleStreamFallback(uid,isFallbackOrRecover) {
  console.log("uid:" + "%s" + "medialType:" + "%s", uid,isFallbackOrRecover);
}
```

### UIの追加
受信する映像に対し高画質、低画質、フォールバック切替ボタンを追加し、
低画質を設定しています。

```javascript:basicVideoCall.js
async function subscribe(user, mediaType) {
　//省略
  <button id="hight" onClick=hight(${uid})>Hight</button>
  <button id="low" onClick=low(${uid})>Low</button>
  <select name="fb_option" id="fb_option-${uid}" class="form-select" aria-label="">
  <option value=0>0</option>
  <option value=1 selected >1</option>
  <option value=2>2</option>
  </select>
  <button id="fallback" onClick=fallback(${uid})>FallBack</button>
　//省略
}
```

## 動作確認

以下2点を確認します。
１：高画質(640p)、低画質(120p)の切り替え
２：フォールバック設定による切り替え

### 1. 高画質(640p)、低画質(120p)の切り替え
[前提]
・Safari (iPhone)
・Chrome (PC)
・WebSDK v4.7.0

1.Safariユーザが入室します。
2.Chromeユーザが入室します。
どちらもデフォルトで高画質モードで表示されています。

#### 1-1.高画質(640p)の場合
3.「Hight」ボタンをクリックします。
　受信側映像が高画質に切り替わります。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/7081fe1b-c12b-bcd9-5c8d-5a3ba9bdc866.png)

#### 1-2.低画質(120p)の場合
4.「Low」ボタンをクリックします。
　受信側映像が低画質に切り替わります。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/fea313bd-d02b-46fa-f018-ea61b0070f9d.png)


### 2. フォールバック設定による切り替え
[前提]
・Chrome (PC)
・Firefox (PC)
・WebSDK v4.6.2

1.Chromeユーザが入室します。
2.Firefoxユーザが入室します。
どちらもデフォルトで高画質モードで表示されています。

(Chromeにて、受信側映像(Firefoxユーザ)に対し）
3.フォールバックを1(LOW_STREAM)で設定し、「Fallback」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/5563f9c3-af01-6a6d-fab6-fa87f9b746bc.png)

4.速度制限ツールを用いて、Chromeに対し送信および受信速度制限を設定します。
[注]速度制限ツールの性能により状況や結果も変わります。SDKと速度制限ツールには関連性はありません。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/191371f0-232d-aaeb-b9bc-dd53d43591f2.png" width="55%">
速度が制限されたことにより、映像の遅延や再入室などが発生します。

5.(一定時間経過後)低帯域に自動で切り替わります。
![11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/7e3b3315-7d26-1177-9faa-136320673831.png)

DualStreamによる受信側映像の高画質と低画質の切り替えができました。

## 補足
今回はWebSDKでの紹介でしたが、Native用のSDKでも同様の実装が可能です。

## FAQ
[DualStreamとは何ですか？](https://vcube-support.zendesk.com/hc/ja/articles/900001965946)
[simulcast機能はありますか？](https://vcube-support.zendesk.com/hc/ja/articles/360032879732)

# 最後に
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=5949127b865baa580756)
[<img width="912" alt="スクリーンショット 0001-08-15 13.41.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5d815376-9b89-08fa-9434-6fa7e8e67bcf.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=5949127b865baa580756)