# サイマルキャスト機能

## 概要

サイマルキャスト (Simulcast) は、配信時に 1 つの RTCPeerConnection から複数種類のエンコードした映像を配信する技術です。

映像を配信する際、 Sora に対して、 1 つの RTCPeerConnection で複数種類のエンコードした映像を送信することにより、
受信者がどの映像を受信するかを選択できるようになります。

## 注意

### 現時点でのサイマルキャストの仕様

2022 年 12 月 時点でサイマルキャストで出力されるストリームの本数は解像度とビットレートに依存しています。

**解像度とビットレートとストリーム数の関係**

* - 解像度
  - ビットレート
  - ストリーム数
* - 1920x1080
  - 5000 kbps
  - 3
* - 1280x720
  - 2500 kbps
  - 3
* - 960x540
  - 1200 kbps
  - 3
* - 640x360
  - 700 kbps
  - 2
* - 480x270
  - 450 kbps
  - 2
* - 320x180
  - 200 kbps
  - 1

この値は libwebrtc にハードコードされています。

```cpp
// These tables describe from which resolution we can use how many
// simulcast layers at what bitrates (maximum, target, and minimum).
// Important!! Keep this table from high resolution to low resolution.
constexpr const SimulcastFormat kSimulcastFormats[] = {
    {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(5000),
    webrtc::DataRate::KilobitsPerSec(4000),
    webrtc::DataRate::KilobitsPerSec(800)},
    {1280, 720, 3, webrtc::DataRate::KilobitsPerSec(2500),
    webrtc::DataRate::KilobitsPerSec(2500),
    webrtc::DataRate::KilobitsPerSec(600)},
    {960, 540, 3, webrtc::DataRate::KilobitsPerSec(1200),
    webrtc::DataRate::KilobitsPerSec(1200),
    webrtc::DataRate::KilobitsPerSec(350)},
    {640, 360, 2, webrtc::DataRate::KilobitsPerSec(700),
    webrtc::DataRate::KilobitsPerSec(500),
    webrtc::DataRate::KilobitsPerSec(150)},
    {480, 270, 2, webrtc::DataRate::KilobitsPerSec(450),
    webrtc::DataRate::KilobitsPerSec(350),
    webrtc::DataRate::KilobitsPerSec(150)},
    {320, 180, 1, webrtc::DataRate::KilobitsPerSec(200),
    webrtc::DataRate::KilobitsPerSec(150),
    webrtc::DataRate::KilobitsPerSec(30)},
    // As the resolution goes down, interpolate the target and max bitrates down
    // towards zero. The min bitrate is still limited at 30 kbps and the target
    // and the max will be capped from below accordingly.
    {0, 0, 1, webrtc::DataRate::KilobitsPerSec(0),
    webrtc::DataRate::KilobitsPerSec(0),
    webrtc::DataRate::KilobitsPerSec(30)}};
```



### SDK 対応状況

最新版の JavaScript SDK, iOS SDK, Android SDK, Unity SDK, C++ SDK では、
配信と視聴ともに VP8 と H.264 に対応済みです。

### 配信ブラウザの対応状況

**Firefox は配信に対応していません**

配信側は Chrome と Edge と Safari の最新バージョンに対応しています。

### 視聴ブラウザの対応状況

視聴側は Chrome と Safari と Firefox と Edge の最新バージョンに対応しています。

### 映像コーデック

配信時に利用できる映像コーデックは VP8 と H.264 です。

> **注釈**
>
> VP8 と H.264 両方のコーデックが利用できる場合、VP8 が比較的安定しています。

### 非対応機能

**以下はすべて今後対応予定です**

- ULPFEC 機能には対応していません


## 映像の優先度

サイマルキャストでは 1 つのクライアントからの同じ映像を複数のエンコードで配信することが可能です。

Sora では 1 つのクライアントから最大 3 種類のエンコードで映像を受信する仕組みが入っています。
この 3 種類の映像のそれぞれに r0 / r1 / r2 の 3 つの値を定義しています。
この値は rid と呼ばれています。

配信継続の優先度は r0 > r1 > r2 です。

例えば、回線が不安定だったりマシンの負荷が高かった場合、rid が r2 の映像の配信が最初に停止します。
さらに配信状況が悪化した場合は rid が r1 の映像の配信が停止します。 r0 の映像は必ず配信されます。

## 映像の種類のデフォルト

Sora ではサイマルキャストで配信する映像の種類にデフォルト値を設定しています。

```json
[
    {"rid": "r0", "active": true, "scaleResolutionDownBy": 4.0},
    {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0},
    {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0}
]
```

### r0

rid が r0 の場合は通常の解像度から解像度 (一辺) が 1/4 の映像になるように設定されています。

### r1

rid が r1 の場合は通常の解像度から解像度 (一辺) が 1/2 の映像になるように設定されています。

### r2

rid が r2 の場合は通常の解像度のままの映像に設定されています。


## 映像のエンコーディングパラメータのカスタマイズ

Sora ではサイマルキャストでの映像のエンコーディングパラメータを自由に設定することができます。

- sora.conf のファイルで指定することで全体のサイマルキャストのエンコーディングパラメータが指定できます
- 認証成功時に simulcast_encodings で払い出すことで個別にサイマルキャストのエンコーディングパラメータが指定できます

### sora.conf でファイル指定

sora.conf にて `simulcast_encodings_file` で JSON を指定してください。

```ini
simulcast_encodings_file = etc/simulcast_encodings.json
```

### sora.conf で指定する JSON ファイルの記述方法

```json
[
    {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 5.0},
    {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 20.0},
    {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0}
]
```

### 認証成功時に simulcast_encodings で払い出す記述方法

```json
{
    "allowed": true,
    "simulcast_encodings": [
        {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 5.0},
        {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 20.0},
        {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0}
    ]
}
```

### カスタマイズの設定

- rid- 必須
  - string (r0 / r1 / r2)
- active- このエンコーディングパラメータを有効にします
  - オプション
  - boolean
- scaleResolutionDownBy- オプション
  - 1 以上の number (float または integer)
- maxBitrate- オプション
  - 最大ビットレートを指定する
  - 0 以上の integer
- maxFramerate- オプション
  - 最大フレームレートを指定する
  - 0 以上の number (float または integer)
- adaptivePtime- **この設定は Chrome でしか利用できません**
  - オプション
  - boolean

### active: false の挙動

r1 の active を false にカスタマイズしている配信で r1 を受信をリクエストした場合、r0 が配信されます。

```json
[
    {"rid": "r0", "active": true},
    {"rid": "r1", "active": false},
    {"rid": "r2", "active": true}
]
```

r0 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r1 が配信されます。

```json
[
    {"rid": "r0", "active": false},
    {"rid": "r1", "active": true},
    {"rid": "r2", "active": true}
]
```

r0 と r1 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r2 が配信されます。

```json
[
    {"rid": "r0", "active": false},
    {"rid": "r1", "active": false},
    {"rid": "r2", "active": true}
]
```

## 配信側の利用方法

シグナリング開始時に指定できます。

### シグナリング開始時

シグナリングの `"type": "connect"` 時に `"simulcast": true` を指定することで、有効になります。
映像コーデックは `VP8` または `H264` を選択してください。

```json
{
    "type": "connect":,
    "role": "sendonly",
    "channel_id": "sora",
    "video": {"codec_type": "VP8"},
    "multistream": false,
    "simulcast": true
}
```

マルチストリーム利用時にも利用可能です。

```json
{
    "type": "connect":,
    "role": "sendonly",
    "channel_id": "sora",
    "video": {"codec_type": "VP8"},
    "multistream": true,
    "simulcast": true
}
```

## 視聴側の利用方法

シグナリング開始時に指定できます。

### シグナリング開始時

- シグナリング `"type": "connect"` 時に `"simulcast": true` を指定することで、有効になります
- `simulcast_rid` には `r0` / `r1` / `r2` が指定可能です- `simulcast_rid` を指定しない場合は `r0` が指定されます
  - この値は **サイマルキャストで配信されている映像を受信する際のデフォルト値** です
  - この値は `sora.conf` の `default_simulcast_rid` で変更可能です
- 映像コーデックは `VP8` または `H264` を選択してください

```json
{
    "type": "connect":,
    "role": "recvonly",
    "channel_id": "sora",
    "video": {"codec_type": "VP8"},
    "multistream": false,
    "simulcast": true,
    "simulcast_rid": "r2"
}
```

マルチストリーム利用時にも指定できます。

```json
{
    "type": "connect":,
    "role": "recvonly",
    "channel_id": "sora",
    "video": {"codec_type": "VP8"},
    "multistream": true,
    "simulcast": true,
    "simulcast_rid": "r2"
}
```

## 視聴側のストリームの変更 API

詳細は [サイマルキャスト API](API.html#adcbc8) をご確認ください

## シーケンス図

seqdiag {
    default_fontsize = 15;
    edge_length = 250;

    activation = none;

    クライアント1 ->> Sora [label = '{"type": "connect",\n"role": "sendonly",\n"simulcast": true}'];

    === クライアント1 WebRTC 確立 ===

        Sora <<- クライアント2 [label = '{"type": "connect",\n"role": "recvonly",\n"simulcast": true\n"simulcast_rid": "r1"}'];

    === クライアント2 WebRTC 確立 ===

    クライアント1 ->> Sora [label = '映像\nrid: r0', noactivate];
    クライアント1 ->> Sora [label = '映像\nrid: r1', noactivate];
        Sora ->> クライアント2 [label = '映像\nrid: r1', noactivate];
    クライアント1 ->> Sora [label = '映像\nrid: r2', noactivate];



}
