WebRTCで音声コーデックを変更した時の影響について色々調べてみた

# はじめに

WebRTCでは一般的にOpusという音声コーデックが利用されますが、他の音声コーデックも利用可能です。この記事では、WebRTCで利用可能な音声コーデックの特徴などをまとめていきます。取り留めの無い内容になっていますがご容赦ください…。

## 2019.11現在 libwebrtc で利用可能な音声コーデック

Chrome M78のSDPの情報から以下のコーデックが利用可能というのがわかります。

```
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
```

この記事ではこれらのコーデックの中から、以下のコーデックについて取り上げていきたいと思います。

- OPUS
- ISAC/16000
- G722
- PCMU(G.711 u-law)

`ISAC/32000` については、現在のSkyWayのSDKでは明示的に指定出来ないため、今回は取り上げません。
また、SkyWayのAndroid SDKとiOS SDKでは `a=rtpmap:102 ILBC/8000` が候補として出てきますが、Chrome M78では[無効化](https://chromium.googlesource.com/chromium/src/+/refs/tags/78.0.3904.113/.gn#62)されているため、今回は取り上げません。

# コーデックの特徴を確認

まずは、これらのコーデックの特徴を確認するために、消費するリソースの比較と聴き比べをしてみました。

## 確認方法

確認方法は以下の図の通りです。
音源にはライセンスフリー音楽素材の[フタツココロ](https://www.youtube.com/watch?v=LSgibVLEwS0)を利用させていただきました。有難うございました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/13eb1791-a43e-a99a-a1c4-ed4b5614da95.png)

スマホとPCのアプリケーションの環境は以下の通りで、両者は同じLANにつながっており、LAN内でP2P通信を行います。

- スマホ側
    - Galaxy SC-09+
    - Android 9
    - SkyWay Android SDK v1.1.3
    - サンプルアプリ（p2p-call)を改造して利用
      - 音声のみで映像は利用しない

- PC側
    - Chrome M78 on macOS
    - SkyWay JS SDK v2.0.3
    - アンプルアプリ(p2p-media)を改造して利用
      - 音声のみで映像は利用しない


## 確認結果

上図の6で出来上がった音声ファイルをダウンロードできるようにしています。楽曲の前奏からAメロ部分が収録されています。毎回手動でやっているので、変な音が入っていたり、長さが違ったりします。参考程度でお聞きください。また、音量が小さいのでイヤホンの利用を推奨します。

### OPUS

- 音質: [録音ファイルダウンロード](https://drive.google.com/file/d/1Ptb0CQ2gOrM6qCwF0pVhhdxm5GCqJftW/view?usp=sharing)
  - 感想: リファレンスとなる音質なので特に感想はありません
- PCの受信ネットワーク帯域: **4.5KB/s前後**
<details><summary>グラフを表示</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/9cdfb6bb-158b-6df6-3d6e-434752cb912b.png)
</div></details>
- Android端末のCPU使用率: **２%〜5%**
<details><summary>グラフを表示</summary><div>
![opus_android_cpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/1305be62-2347-d707-efb9-f6ff496e0c79.png)
</div></details>
- Android端末の送信ネットワーク帯域: **3.9KB/s〜8.1KB/s**
<details><summary>グラフを表示</summary><div>
![opus_android_nw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/892dcac7-9df9-25f8-bcdf-6fe0efbe3147.png)
</div></details>


### ISAC/16000

- 音質: [録音ファイルダウンロード](https://drive.google.com/file/d/1vYJlMKOjSA3O0IF2SMIa7O-aqF4NPHo9/view?usp=sharing)
  - 感想: 音質はOpusと比べると落ちるが、会話で利用する分には十分な音質
- PCの受信ネットワーク帯域: **4KB/s前後**
<details><summary>グラフを表示</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/ad2a2e62-c9d8-1723-64d6-af75307a7469.png)
</div></details>
- Android端末のCPU使用率: **1%〜3%**
<details><summary>グラフを表示</summary><div>
![isac_android_cpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/90af9ed7-5299-480f-3878-9cb044f7a982.png)
</div></details>
- Android端末の送信ネットワーク帯域: **0.6KB/s〜9KB/s**
<details><summary>グラフを表示</summary><div>
![isac_android_nw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/75cdcb8c-1315-9e84-0399-694cf9aa1c60.png)
</div></details>

### G722

- 音質: [録音ファイルダウンロード](https://drive.google.com/file/d/1wE7GElXZD34uzjSqLBK5v0cjCoZ8G67z/view?usp=sharing)
  - 感想: Opusよりも音質がよく感じる
- PCの受信ネットワーク帯域: **8.5KB/s前後**
<details><summary>グラフを表示</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/f25a0879-e79f-e55d-2068-36d6e0d50fdc.png)
</div></details>
- Android端末のCPU使用率: **1.1%〜3%**
<details><summary>グラフを表示</summary><div>
![g722_android_cpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/47e40e11-e6b7-6901-7080-650a018d0edc.png)
</div></details>
- Android端末の送信ネットワーク帯域: **1.8KB/s〜19.1KB/s**
<details><summary>グラフを表示</summary><div>
![g722_android_nw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/64997086-1bab-0c13-0ded-2f65b5eaeb12.png)
</div></details>

### PCMU(G.711 u-law)

- 音質: [録音ファイルダウンロード](https://drive.google.com/file/d/19CUCqRr-ugUonCpYV2qfPGI4xMGkG7KO/view?usp=sharing)
  - 感想: ノイズが酷くこもって聞こえる、音質は今回比較した中では最低
- PCの受信ネットワーク帯域: **9KB/s前後**
<details><summary>グラフを表示</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/ede29986-45c9-b68d-7f24-c53f792076ff.png)
</div></details>
- Android端末のCPU使用率: **1%〜3%**
<details><summary>グラフを表示</summary><div>
![pcmu_android_cpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/c50a342f-df90-68f3-a553-914c04770337.png)
</div></details>
- Android端末の送信ネットワーク帯域: **0.6KB/s〜21.1KB/s**
<details><summary>グラフを表示</summary><div>
![pcmu_android_nw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/68414128-c5c2-d8ab-b5c8-79aa0e845ba1.png)
</div></details>


### まとめ

まとめると以下のようになります。グラフの読みは目視でやっているところもあり、数値の正確さは保証しませんが、普段使っているOpusと傾向を比較してもらえればと思います。太字になっている部分はそのコーデックの特徴的な部分です。

|コーデックの種類|音質（主観）|PCの受信ネットワーク帯域|Android端末のCPU使用率|Android端末の送信ネットワーク帯域|
|:--|:--|:--|:--|:--|
|Opus|-|4.5KB/s前後|2%〜5%|3.9KB/s〜8.1KB/s|
|ISAC/16000|Opusより劣る|**4KB/s前後**|**1%〜3%**|**0.6KB/s〜9KB/s**|
|G722|**Opusより良い**|8.5KB/s前後|**1.1%〜3%**|1.8KB/s〜19.1KB/s|
|PCMU|この中では一番悪い|9KB/s前後|**1%〜3%**|0.6KB/s〜21.1KB/s|

この結果から、Opus以外に現実的に取りうる選択肢は、以下の2つだと考えます。

- ネットワーク帯域の節約やマシン負荷を低減させたい場合は **ISAC/16000**
- 音質重視なら **G722**


### 参考: iSACとG.722について

参考までに、iSACとG.722がどういうコーデックなのかを外部のドキュメントを引用して解説します。以後、コーデック名の表記方法は一般的な表記に統一します。

#### iSAC

iSACはGlobal IP Solutionsが開発していた広帯域音声コーデックで、2011年にGoogleに買収され、WebRTC向けのコーデックとして、WebRTCコードベースで利用する場合はロイヤリティフリーで利用できるようになっています。
ワイドバンドとスーパーワイドバンドが利用できて、それぞれ以下のサンプリングレート、ビットレートとなります。

- サンプリングレート: 16kHz / 32kHz
- ABR対応(10kbps ~ 32kbps / 10kbps ~ 52kbps)

WebRTC（libwebrtc）では、`ISAC/16000` と `ISAC/32000` が利用できます。[ソースコード](https://chromium.googlesource.com/external/webrtc/+/HEAD/api/audio_codecs/isac/audio_encoder_isac_float.cc#55)から、サンプリングレートが16kHzの場合はビットレートが32kbps、サンプリングレートが32kHzの場合はビットレートが52kbpsとなるようです。

出典: [wikipedia](https://en.wikipedia.org/wiki/Internet_Speech_Audio_Codec)


#### G.722

G.722は、ITU-Tにより勧告されたロイヤリティフリーの広帯域音声コーデックです。
PCMU(G711)等の狭帯域コーデックと比較して音質が向上していますが、その複雑さは変わらないという利点があります。

RTPによりカプセル化される場合、サンプリングレートは16kHzですが、SDP上は歴史的経緯から互換性を維持するために8kHzとなっているようです。また、ビットレートは64kbit/s、56kbit/s、48kbit/sの３種類が規定されていますが、64kbit/sでエンコードされるようです。

WebRTC(libwebrtc)も[ソースコード](https://chromium.googlesource.com/external/webrtc/+/HEAD/api/audio_codecs/g722/audio_encoder_g722.cc#55)からは、上記設定のよう見えます（ここは自身がなく…間違っているかも）。

出典: [wikipedia](https://ja.wikipedia.org/wiki/G.722#cite_note-2)
出典: [RFC7875 -  Additional WebRTC Audio Codecs for Interoperability](https://tools.ietf.org/html/rfc7875#section-4.3)

# 通信品質が悪くなった時に影響が少ないコーデックはどれか

WebRTCを使っていると、通信品質が良くない時にどのような影響が出るのか、非常に気になると思います。今回は一例として、意図的に帯域制限をかけて、コーデック毎にどのような影響が出るかを調べてみました。

## 帯域制限のかけ方

macOSに標準インストールされている以下のツールを使います。

- dnctl -- Traffic shaper control program
- pfctl — control the packet filter (PF) device

### 設定例

dummynet(トラフィックシェーパー)のpipeに再現させたい状況を設定

```
$ sudo dnctl pipe 1 config bw 100kbit/s // 帯域制限
```

全てのUDP通信(IN/OUT)のトラフィックにpipeに設定した状況を適用

```
$ sudo vi /etc/pf.conf

dummynet in proto udp all pipe 1
dummynet out proto udp all pipe 1

$ sudo pfctl -f /etc/pf.conf
$ sudo pfctl -e
```

## 検証方法と結果

上記ツールを用いて帯域を10kbpsずつ絞っていくと、次第に音飛びが発生するようになり、最後にはほとんど音が聞こえなくなります。
音飛びはパケットロスが原因で発生していると思われますが、今回の環境では、音飛びの程度が許容範囲でこれなら使えるなと思える帯域の下限値は以下の通りでした。

G.722 : **100kbps**
Opus : **70kbps**
iSAC : **50kbps**

こういうシチュエーションだと、使用する帯域が一番小さいiSACが優位という形になります。

# コーデックのブラウザごとの対応状況

今回取り上げた音声コーデックを含め、現在利用可能なコーデックのブラウザごとの対応状況は以下の通りです。SDPの情報から判断しています。

|ブラウザ|Opus|iSAC/16000|iSAC/32000|G.722|iLBC|PCMU(G.711 u-law)|PCMA(G.711 a-law)|
|:--|:--|:--|:--|:--|:--|:--|:--|
|Chrome M78|○|○|○|○|x|○|○|
|Safari v13.0.3|○|○|x|○|○|○|○|
|Firefox 70.0.1|○|x|x|○|x|○|○|
|Edge Beta v79.0.309.25|○|○|○|○|x|○|○|

すべてのブラウザで対応しようと考えるとOpusとG.722が有力候補です。それ以外のコーデックを使いたければ、ブラウザごとにコーデックを使い分ける必要があります。

また、出典として以下のサイトをご紹介しようと思いましたが、対応表の情報は古そうです。ご注意を。

[MDM - Codecs used by WebRTC
](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#Supported_audio_codecs)


# Skypeとの音質比較

仕事柄、Skypeとの比較についてはよく質問を受けます。
今回Skypeと聴き比べはしていませんが、コーデックの違いという観点で言えば、Skypeは以下のコーデックを利用可能で、WebRTCとは利用可能コーデックのラインナップが異なります。

<img width="910" alt="skype_audio_codec.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/b8777ecc-bf02-8f46-dec6-3e910aa0c5ca.png">
引用元: [Plan network requirements for Skype for Business](https://docs.microsoft.com/ja-jp/skypeforbusiness/plan-your-deployment/network-requirements/network-requirements)

同ページの注意書きには、以下の通り、通常はGのコーデックが利用されると書かれているので、`G.722`または`G.711`が通常は利用されているものと推測されます。 `G.722 ステレオ` については、特殊な環境でしか使わないようなので無視して構わないと思います。

<img width="608" alt="skype_audio_codec_attention.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6651/e2de9619-352d-816f-480c-60223e4b0091.png">
引用元: [Plan network requirements for Skype for Business](https://docs.microsoft.com/ja-jp/skypeforbusiness/plan-your-deployment/network-requirements/network-requirements)

`G.722`を使っているSkypeとWebRTC標準の`Opus`を比較すると、Skypeの方が音質が良いことが予想されるので、音質面でこだわりたい場合は、`Opus`から`G.722`に変更するのが良いかもしれません。

# 最後に

この記事では、WebRTCで選択できる音声コーデックについて、

- コーデックの特徴を確認
- 通信品質が悪くなった時に影響が少ないコーデックはどれか
- コーデックのブラウザごとの対応状況
- Skypeとの音質比較

をまとめました。

音声コーデックは大半の方がOpusをそのまま利用していると思いますが、利用シーンや要求条件によっては、別のコーデックを利用するという選択肢も有ります。
ブラウザ毎に実装違うというWebRTCあるあるな課題をクリアしていく必要は出てきますが…WebRTCの音声に課題をお持ちの方は、一度ご検討頂ければと思います。