# 帯域推定機能

## 概要

Sora ではクライアントの間で利用できるネットワーク帯域を推定する帯域推定機能を搭載しています。

WebRTC では、ネットワークの帯域に合わせて映像や音声のビットレートを動的に変更します。
帯域推定機能では、映像や音声のパケット単位で受信状況をフィードバックすることで、従来よりも精度よく帯域を推定します。
これにより、帯域が不足した場合の追従と、帯域が回復した場合の復帰が改善します。

帯域推定は、次の 2 つの方向で動作します。

- 配信側 (クライアントから Sora への方向)- Sora が、受信したパケットの受信状況をクライアントにフィードバックします
  - クライアントの libwebrtc が、フィードバックをもとに帯域を推定し、映像エンコーダーのビットレートを制御します
- 視聴側 (Sora からクライアントへの方向)- クライアントが、Sora から送信されたパケットの受信状況を Sora にフィードバックします
  - Sora が、フィードバックをもとに帯域を推定します

> **重要**
>
> Sora は、クライアントの映像エンコーダーを直接制御しません。配信側のビットレートは、Sora からのフィードバックを受け取ったクライアントの libwebrtc が決定します。

> **注釈**
>
> libwebrtc は WebRTC の実装の一つです。Google Chrome、Safari、Firefox といった主要ブラウザーのほか、弊社が提供している Sora のクライアント SDK、 [WebRTC Native Client Momo](https://github.com/shiguredo/momo) 、 [WebRTC 負荷試験ツール Zakuro](https://github.com/shiguredo/zakuro) なども libwebrtc を利用しています。

## 仕組み

[Transport-Wide Congestion Control](https://datatracker.ietf.org/doc/html/draft-holmer-rmcat-transport-wide-cc-extensions-01) (TWCC) という仕組みを利用して、帯域を推定します。

TWCC は、パケット単位で受信状況をフィードバックする仕組みです。
送信側は、すべてのパケットに通し番号を付与します。
受信側は、どのパケットをいつ受信したか、どのパケットが失われたかを一定間隔でまとめて送信側に通知します。
送信側は、パケットの到着間隔の変化からネットワークの混雑状況を判断し、利用できる帯域を推定します。

### 配信側 (クライアントから Sora への方向)

- クライアントは、通し番号を付けたパケットを Sora に送信します
- Sora は、受信したパケットの受信状況を TWCC でクライアントにフィードバックします
- クライアントの libwebrtc は、TWCC のフィードバックをもとに送信側の帯域推定を行い、映像エンコーダーのビットレートを制御します
- 映像の TWCC は Sora 2025.1.0 以降で、音声の TWCC は Sora 2025.2.0 以降で有効です

```mermaid
sequenceDiagram
    participant P as 配信側クライアント
    participant S as Sora
    P ->> S: パケット (通し番号付き)
    S -->> P: TWCC フィードバック
    note over P: クライアントの libwebrtc が帯域を推定し<br>エンコーダーのビットレートを制御
```

### 視聴側 (Sora からクライアントへの方向)

- クライアントは、Sora から送信されたパケットの受信状況を TWCC で Sora にフィードバックします
- Sora は、パケットの到着間隔から求める遅延ベースの推定と、パケットロスから求めるロスベースの推定を組み合わせて帯域を推定します
- 推定した帯域は、次の用途で利用します- シグナリング通知 `network.status` の `estimated_bandwidth`
  - サイマルキャスト受信時の [RID 自動切り替え](SIMULCAST.html#0eb8c3)

```mermaid
sequenceDiagram
    participant S as Sora
    participant V as 視聴側クライアント
    S ->> V: パケット (通し番号付き)
    V -->> S: TWCC フィードバック
    note over S, V: Sora が帯域を推定し<br>通知や RID 自動切り替えに利用
```

## バージョンごとの変更

### 2026.1.0

- ネットワークの状態をシグナリングで通知する機能が正式版になりました (推定結果の通知も含みます)

### 2025.2.0

- 音声の TWCC を有効にしました
- 実験的機能として、サイマルキャスト受信時の RID 自動切り替えを追加しました
- 再送要求の頻度を利用した不安定レベルの通知機能を廃止しました

### 2025.1.0

- 帯域推定機能を追加しました
- 映像の TWCC を既定で有効にしました
- Sora 自身の帯域推定を既定で有効にしました
- 実験的機能として、シグナリング通知 `network.status` に `estimated_bandwidth` を追加しました

## 設定ビットレートと実ビットレートの関係

> **重要**
>
> TWCC を利用する場合、実際の映像ビットレートは、設定した映像ビットレートを下回ります。これは libwebrtc の意図的な挙動です。

Sora に指定した映像のビットレートと、実際に配信される映像のビットレートは一致しません。
原因は、TWCC を利用する場合の libwebrtc のビットレート計算にあります。

### ビットレートの指定方法

音声と映像のビットレートは、次のいずれかの方法で指定します。

- クライアントがシグナリングの `"type": "connect"` で `audio` の `bit_rate` と `video` の `bit_rate` を指定する
- 認証ウェブフックのレスポンスで `audio_bit_rate` と `video_bit_rate` を指定する
- `sora.conf` の [default_audio_bit_rate](SORA_CONF.html#07627a) と [default_video_bit_rate](SORA_CONF.html#620132) を指定する

指定した値は kbps 単位で扱われ、次のようにクライアントに通知されます。

- 映像: `video` の `bit_rate` で指定した値を、SDP の `b=TIAS` で通知
- 音声: SDP の `maxaveragebitrate` (Opus のパラメーター)

`b=TIAS` は、映像のビットレートの上限を伝えるための SDP の項目で、[RFC 3890](https://datatracker.ietf.org/doc/html/rfc3890) で定義されています。
`video` の `bit_rate` はこの上限を指定する値であり、指定したビットレートでの送信を保証するものではありません。

> **注釈**
>
> `x-google-start-bitrate` は、libwebrtc の映像エンコーダーが最初に利用するビットレートを指定する SDP パラメーターです。
> Google 固有のパラメーターで、RFC では定義されておらず、libwebrtc を利用しないクライアントでは解釈されません。
>
> Sora は、配信する映像のビットレートをクライアントに通知する際に、 `b=TIAS` に加えて `x-google-start-bitrate` も通知します。
> WHIP と WHEP では、 `x-google-start-bitrate` に対応していません。

### libwebrtc のビットレート計算

- TWCC を利用しない場合、libwebrtc は受信側が通知してくる利用可能な帯域をもとに、目標ビットレートを決定します
- TWCC を利用する場合、libwebrtc はパケット単位のフィードバックから送信側で帯域を推定します- 目標ビットレートには、映像や音声のデータ本体だけではなく、パケットに付加される情報 (ヘッダー) や暗号化、UDP/IP などの通信に必要なオーバーヘッドも含まれます
  - エンコーダーには、目標ビットレートからオーバーヘッドと、データの欠落に備える保護分を差し引いたビットレートを指示します
- この挙動は libwebrtc の [Only include overhead if using send side bandwidth estimation](https://webrtc.googlesource.com/src.git/+/c3eb9fd49f7343ab7ea2ea49ae1fa576aae5231d) で M81 (2020 年) 以降に意図的に導入されています

### 実際の挙動

- ネットワークに余裕がある場合でも、映像の実ビットレートは `video` の `bit_rate` で指定した値より低くなります- 差の目安は 1 割弱です
  - 音声と映像を送信する場合、映像には音声の配分を差し引いたビットレートが割り当てられます
  - 実際の差はパケットサイズ、フレームレート、コーデック、再送 (RTX) やデータ保護 (FEC) の利用状況により変わります
  - パケットサイズが小さいほど、オーバーヘッドの割合は大きくなります
- この差は、libwebrtc がパケットのオーバーヘッドを目標ビットレートから差し引くために発生します。不具合ではありません
- Sora 2024.2.x では TWCC が既定で無効だったため、同じビットレートを指定しても Sora 2025.1.0 以降の方が実ビットレートは低くなります
- Sora 2025.2.0 以降は音声も TWCC の対象になるため、音声を含めた帯域の推定が行われます

### オーバーヘッドの内訳と差し引き

ここでは、音声と映像を送信する想定で、ネットワークに余裕があり、映像のビットレートを指定した場合の例を説明します。

libwebrtc は、指定された映像のビットレートをそのままエンコーダーには指示しません。
libwebrtc は、パケットの送信に必要な次の情報を「オーバーヘッド」としてビットレートから差し引きます。

- RTP (音声や映像のパケットを送信するコンテナ) のヘッダー: 12 バイト
- RTP のヘッダー拡張 (TWCC の通し番号などの追加情報): 約 8 バイト
- 再送用のヘッダー (RTX): 2 バイト
- 暗号化: 10 バイト
- UDP/IP (ネットワークでパケットを送るための基本的な仕組み) のヘッダー: 28 バイト
- 合計: 約 60 バイト

libwebrtc は、最大パケットサイズ 1200 バイトにトランスポートのオーバーヘッド 38 バイト (暗号化と UDP/IP) を加えた 1238 バイトを 1 パケットとして、1 秒あたりのパケット数を計算します。
このパケット数に 1 パケットあたりのオーバーヘッド (約 60 バイト) を掛けた分が、映像のビットレートから差し引かれます。

また、指定した映像のビットレートは、音声と映像の合計の上限として扱われます。
音声 (Opus) の分が先に確保され、残りが映像に配分されます。
そのため、映像に配分されるビットレートは、指定した映像のビットレートから音声のビットレートを引いたものになります。
音声のビットレートを大きくするほど、映像のビットレートから差し引かれる分も大きくなります。

この条件での計算例は、次のとおりです。

| 指定した映像のビットレート | 音声 | 映像の配分 | オーバーヘッド | 映像エンコーダーへの指示 |
| --- | --- | --- | --- | --- |
| 500 kbps | 32 kbps | 468 kbps | 約 23 kbps | 約 445 kbps |
| 500 kbps | 64 kbps | 436 kbps | 約 22 kbps | 約 414 kbps |
| 2.5 Mbps | 32 kbps | 2.47 Mbps | 約 120 kbps | 約 2.35 Mbps |
| 2.5 Mbps | 64 kbps | 2.44 Mbps | 約 118 kbps | 約 2.32 Mbps |
| 5 Mbps | 32 kbps | 4.97 Mbps | 約 241 kbps | 約 4.73 Mbps |
| 5 Mbps | 64 kbps | 4.94 Mbps | 約 240 kbps | 約 4.70 Mbps |

このように、映像のビットレートは音声の分だけ低くなります。
指定した映像のビットレートが小さいほど影響は大きく、500 kbps では差が 1 割を超えることもあります。

音声のビットレートを指定しない場合、libwebrtc のデフォルト値 (モノラルで 32 kbps、ステレオで 64 kbps) が使われます。
また、 Sora のデフォルトではステレオが有効です。

### 実測値

Sora 2026.1.2 と Sora Python SDK (libwebrtc M150.7871) を利用して計測した値です。
映像は VP8、IPv4、UDP を利用し、音声のビットレートは Opus 64 kbps を指定しています。
値はクライアントの `getStats()` の `targetBitrate` から取得しています。

| 指定した映像のビットレート | 計算上の値 | 実測値 | 誤差 |
| --- | --- | --- | --- |
| 500 kbps | 約 414 kbps | 約 382 kbps | 約 32 kbps 低い (約 8%) |
| 2.5 Mbps | 約 2.32 Mbps | 約 2.31 Mbps | 約 10 kbps 低い (1% 未満) |
| 5 Mbps | 約 4.70 Mbps | 約 4.71 Mbps | ほぼ同じ |

音声は、いずれの場合も 64 kbps が指示され、実際には約 55 kbps で送信されています。
指定した映像のビットレートが小さい場合、計算上の値よりも低くなることがあります。
音声は、音声のビットレートに加えて、音声のパケットのオーバーヘッドも指定したビットレートから確保されます。
映像も、1 フレームあたりに必要なパケット数をもとにオーバーヘッドが差し引かれます。
ビットレートが低いほど、これらのオーバーヘッドが相対的に大きな割合を占めます。

## 帯域が不安定だと判断したときの挙動

Sora とクライアントは、パケットの到着間隔とパケットロスから、帯域が不安定だと判断します。

- パケットの到着間隔が送信間隔より長くなると、ネットワークのキューが詰まり始めていると判断します
- パケットロスが増えると、帯域が不足していると判断します
- 帯域が不安定だと判断した場合、目標ビットレートや推定帯域を大きく下げます- 遅延の増加を検出した場合は、実際に送受信できたビットレート (スループット) の 85% 程度まで下げます
  - パケットロスが 10% 以上の場合も下げます

### 配信側のビットレート制御

- クライアントの libwebrtc が、映像エンコーダーに指示するビットレートを下げます

```mermaid
sequenceDiagram
    participant P as 配信側クライアント
    participant S as Sora
    P ->> S: パケット
    S -->> P: TWCC フィードバック
    note over P: 到着間隔の広がりやパケットロスから<br>帯域が不足していると判断し<br>エンコーダーのビットレートを下げる
```

### 視聴側の RID 自動切り替え

- サイマルキャスト機能の利用時に、現在実験的機能として提供している [RID 自動切り替え](SIMULCAST.html#0eb8c3) を有効にしている場合、Sora はビットレートが低い映像に切り替えます
- 現時点の RID 自動切り替えは、ビットレートを下げる方向にのみ対応しています。帯域が回復しても、自動では高画質の映像に戻りません
- Sora は、RID 自動切り替え以外に、転送する映像のビットレートを直接制限しません

```mermaid
sequenceDiagram
    participant S as Sora
    participant V as 視聴側クライアント
    S ->> V: パケット
    V -->> S: TWCC フィードバック
    note over S: 到着間隔の広がりやパケットロスから<br>帯域が不足していると判断し<br>RID を低画質に切り替える
```

## 帯域が回復したときの挙動

- パケットロスが 2% 以下の状態になると、目標ビットレートを少しずつ上げます
- 帯域が回復した場合も、一度に大きく戻さずに段階的にビットレートを上げます
- 利用できる帯域を調べるために、一時的に多めのデータを送信することがあります
- 推定した帯域は、実際に利用できる帯域を保証するものではありません

## 確認方法

- 視聴側では、シグナリング通知 `network.status` の `estimated_bandwidth` で Sora が推定した帯域を確認できます。詳細は [ネットワークのシグナリング通知](SIGNALING_NOTIFY.html#58a82d) をご確認ください
- サーバー側の [統計 API](API_STATS.html) では、次の項目で TWCC が動作しているかを確認できます- `total_received_rtp_hdrext_transport_wide_cc`- 配信側から受信した、TWCC の通し番号が付いたパケットの数
  - `total_sent_rtcp_rtpfb_transport_wide`- 配信側に送信した TWCC のフィードバックの数
  - `total_sent_rtp_hdrext_transport_wide_cc`- 視聴側に送信した、TWCC の通し番号が付いたパケットの数
  - `total_received_rtcp_rtpfb_transport_wide`- 視聴側から受信した TWCC のフィードバックの数
- 配信側では、クライアントの `getStats()` で取得できる送信映像の `targetBitrate` (目標ビットレート) と `bytesSent` (送信済みバイト数) を比較することで、目標ビットレートと実ビットレートの差を確認できます

## よくある質問

### 設定したビットレートまで映像の実ビットレートが上がらないことはありますか？

はい。TWCC を利用する場合、libwebrtc はオーバーヘッドを目標ビットレートに含めて計算し、エンコーダーにはオーバーヘッド分を差し引いたビットレートを指示します。そのため、ネットワークに余裕があっても実ビットレートは設定値を下回ります。目安は 1 割弱です。

### Sora のバージョンアップで実ビットレートが低くなることはありますか？

はい。Sora 2025.1.0 で映像の TWCC を有効にし、Sora 2025.2.0 では音声も TWCC の対象にしました。Sora 2024.2.x 以前と比べて、同じビットレートを指定した場合の実ビットレートが低くなることがあります。

### TWCC を無効にすることはできますか？

いいえ。Sora には、TWCC を無効にする公開設定はありません。

TWCC のフィードバックを利用した帯域推定により、クライアントの libwebrtc は帯域の変化に合わせて送信ビットレートを調整します。
これにより、ネットワークの混雑によるパケットの遅延やロスを抑えられます。
