前回までのおさらい
SKYMENUCloud Devicecontrol Editionで利用しているWebRTCの技術について、 基本的なところから開発中に苦労した点までを計3回に分けてわかりやすく紹介しています。
前回の記事では 基礎的な部分の解説をおこないました。
- WebRTCの基礎を理解する~ブラウザ同士がつながる仕組み~
- WebRTCの帯域制御とQuality設定 ~サンプルコードを用いて紹介~(本記事)
- WebRTCのパフォーマンス品質の測定と監視について
今回はその次のステップとして、運用目的にあった調整が必要である点について、具体的なサンプルコードを用いて紹介していきます。
帯域制御とQuality設定とは?
WebRTCは、ブラウザ同士が直接メディア(映像・音声)をやり取りするリアルタイム通信技術です。
そのため、ネットワーク品質の影響を強く受けます。
回線が混雑していたり、動画配信に必要な帯域を確保できない状況では、映像の遅延やフリーズ、音声の途切れといった問題が発生します。
このような状況を避けるために重要になるのが 帯域制御(Bandwidth Control) と Quality設定 です。
-
帯域制御:
ネットワークが処理できる量に合わせて、送信するデータ量を適切に調整すること -
Quality設定:
映像の解像度やフレームレートなどを適切に選択し、通信の安定性と画質のバランスを取ること
WebRTCにはブラウザ自身による「自動帯域制御(GCC: Google Congestion Control)」が存在しますが、 送信側が適切な設定を行うことで、目的に応じてより安定した通信を実現できます。
WebRTCの品質調整に使う主な設定
WebRTCの品質調整に使う代表的な3つの設定を紹介します。
| 設定項目 | 説明 | 設定対象のインスタンス |
|---|---|---|
| maxBitrate | 1秒あたりのデータ量[bps] | RTCRtpSender |
| framerate | フレームレートの上限 fpsが高いほど動きの滑らかさが増しますが、 その分、帯域も利用します |
getDisplayMediaの constraints |
| contentHint | 映像がどんな種類のコンテンツか、ブラウザにヒントとして伝えるための設定です ブラウザはこのヒントを使って、適切なエンコード方式を選択します |
MediaStreamTrack |
実装してみよう — bitrate / fps / contentHint を設定した画面共有
今回はWebRTCのデモサイトでコードがいくつか公開されているので、そのコードを編集して動かしてみたいと思います。
1. 準備(サンプルプロジェクトのダウンロード)
WebRTCサンプルコード(GitHub)をダウンロードしておきます。
今回はこのサンプルコードのうち、webrtc/samples/tree/gh-pages/src/content/peerconnection/bandwidthのコードに編集を加えていきます。
このbandwidthのプロジェクトでは同一ブラウザ内でのP2P接続を確立する為、Signalingサーバー等を立てる手間なく試す事ができます。
編集対象ファイルは全てwebrtc/samples/blob/gh-pages/src/content/peerconnection/bandwidth/js/main.jsです。
2. Qualityを指定して、画面共有するように書き換える
94行目付近
+// --> 1. この定義を追加
+// 送信対象となるvideoの画質やフレームレートを指定します
++const displayMediaOptions = {
++ video: {
+ cursor: 'always',
+ width: {ideal: 1280},
+ height: {ideal: 720},
+ bitrate: {ideal: 600000},
+ // ここでは仮にスライドや資料の共有を想定して低めに設定してみます
+ frameRate: {ideal: 5}
+ },
+ audio: false
+};
// <-- ここまで追加分
function call() {
callButton.disabled = true; bandwidthSelector.disabled = false; console.log('Starting call'); const servers = null; pc1 = new RTCPeerConnection(servers); console.log('Created local peer connection object pc1'); pc1.onicecandidate = onIceCandidate.bind(pc1); pc2 = new RTCPeerConnection(servers); console.log('Created remote peer connection object pc2'); pc2.onicecandidate = onIceCandidate.bind(pc2); pc2.ontrack = gotRemoteStream; if (synthetic.checked) { console.log('Requesting synthetic local stream'); gotStream(syntheticVideoStream()); } else { console.log('Requesting live local stream'); // 2.画面共有ストリームを取得に書き換えます
- // --> 変更前(カメラの映像を送信対象に指定している)
- navigator.mediaDevices.getUserMedia({video: true})
- .then(gotStream)
- .catch(e => alert('getUserMedia() error: ' + e.name));
+ // --> 変更後
+ navigator.mediaDevices.getDisplayMedia(displayMediaOptions)// ★ここを変更
+ .then(gotStream)
+ .catch(e => console.log('getUserMedia() error: ', e));
}
}
上記コードの修正により[call]ボタンを押下時に以下のような画面が現れ、 選択した画面を送信するストリームとして指定できるようになります。

3. 画質優先になるようcontentHintを指定する
63行目付近
function gotStream(stream) {
hangupButton.disabled = false; console.log('Received local stream'); localStream = stream; localVideo.srcObject = stream; localStream.getTracks().forEach(track => {
+ // ここでは仮にスライドや資料の共有を想定してdetailを指定しておきます
+ // 代表的な他候補: "text" | "motion"
+ // https://developer.mozilla.org/ja/docs/Web/API/MediaStreamTrack/contentHint
+ track.contentHint = "detail";// ★ここを追加
pc1.addTrack(track, localStream); }); console.log('Adding Local Stream to peer connection'); // ...略
}
4. maxBitrateの指定により使用帯域を制限する
※ 解説のみです。コードの変更はありません。
209行目付近
function setBandwidth(bandwidthInKbps) {
// In modern browsers, use RTCRtpSender.setParameters to change bandwidth without // (local) renegotiation. Note that this will be within the envelope of // the initial maximum bandwidth negotiated via SDP. if ((adapter.browserDetails.browser === 'chrome' || adapter.browserDetails.browser === 'safari' || (adapter.browserDetails.browser === 'firefox' && adapter.browserDetails.version >= 64)) && 'RTCRtpSender' in window && 'setParameters' in window.RTCRtpSender.prototype) { const sender = pc1.getSenders()\[0\]; const parameters = sender.getParameters(); if (!parameters.encodings) { parameters.encodings = \[{}\]; } if (bandwidthInKbps === 'unlimited') { delete parameters.encodings\[0\].maxBitrate; } else { // ここで最大使用帯域を指定します parameters.encodings\[0\].maxBitrate = bandwidthInKbps \* 1000; } return sender.setParameters(parameters); } // ...略
}
5. 動かしてみよう
画面共有対象に「動画を指定した場合」と「静的コンテンツ(webページ)を指定した場合」の見え方を比較してみます。
帯域(bandwidth)をUnlimited(無限)から75Kbitに落として、送信データ量のグラフと受信側の映像が送信元と比べてどう見えるかを確認してみます。
動画を指定した場合

① 帯域指定前(bandwidth: Unlimited)

② 帯域指定後(bandwidth: 75kbps)

帯域指定をした瞬間を境に画質が目に見えて劣化しているのが分かります。
また、再生していてもフレームの顕著なカクツキがみられました。
動画を共有したい場合は、低すぎるmaxBitrate指定では実用に耐えられない事が分かります。
静的コンテンツ(webページ)を指定した場合

① 帯域指定前(bandwidth:

② 帯域指定後(bandwidth: 75kbps)

Webページを画面共有したい場合は、動きが動画より少ない為キーフレームを賢く圧縮しやすく
frameRateやmaxBitrateを低く設定しても、ある程度の実用に耐えられる事が分かります。
帯域制御しないとどうなるか?
-
ネットワークが詰まる → パケットロスの発生につながる
-
映像のブロック化 / ぼやけ → 映像品質ダウン
-
音声も巻き込まれた場合 → コミュニケーション断絶
さらに、視聴者人数が増えるほど遅延影響が蓄積するため、1対多の場合はより帯域抑制が重要になります。
まとめ
-
帯域制御がなぜ必要?:
あらかじめ使用帯域を指定しておく事で、遅延やパケットロスを防ぐ、安定した通信に繋がる -
品質調整がなぜ必要?:
用途によって「優先すべき品質」が違うので、適切な設定を選ぶ事が大切 -
何を制御?:
bitrate / fps / contentHint
次記事では、WebRTCのパフォーマンス・通信品質の測定をどのようにするのかについて解説していきます。

