メディア・コミュニケーション

WebRTCのメディア通信では何ができるのですか? #

WebRTCでは、オーディオやビデオのストリームを無制限に送受信できます。これらのストリームは、通話中にいつでも追加・削除できます。これらのストリームはすべて独立していることもあれば、まとめて送信することもできます。例えば、自分のデスクトップのビデオフィードを送信し、ウェブカムからのオーディオ/ビデオを含めることができます。

WebRTCプロトコルは、コーデックに依存しません。基礎となるトランスポートは、まだ存在しないものも含めて、すべてをサポートしています。ただし、通信相手であるWebRTCエージェントが、それを受け入れるために必要なツールを持っていない場合もあります。

また、WebRTCは、動的なネットワーク状況に対応できるように設計されています。通話中に帯域が増えたり減ったりすることがあります。また、突然パケットロスが多発することもあります。WebRTCはこのような状況にも対応できるように設計されています。WebRTCはネットワークの状態に対応し、利用可能なリソースで最高の体験を提供しようとします。

どのような仕組みになっているのですか? #

WebRTCは、RFC 3550で定義されている2つの既存のプロトコルRTPとRTCPを使用しています。

RTP(Real-time Transport Protocol)は、メディアを伝送するプロトコルです。動画をリアルタイムに配信することを目的に設計されています。遅延や信頼性に関するルールは規定されていませんが、それらを実装するためのツールが提供されています。RTPはストリームを提供し、1つの接続で複数のメディアフィードを実行できます。また、メディアパイプラインに供給するために必要な、タイミングや順序の情報も提供します。

RTCP(RTP Control Protocol)は、コールに関するメタデータを通信するためのプロトコルです。このフォーマットは非常に柔軟で、必要なメタデータを追加できます。通話に関する統計情報を通信するために使用されます。また、パケットロスの処理や輻輳制御の実装にも使用されます。これにより、変化するネットワークの状況に対応するために必要な双方向の通信が可能になります。

レイテンシー vs クオリティ #

リアルタイムメディアは、遅延と品質のトレードオフの関係にあります。遅延を許容すればするほど、高品質な映像が期待できます。

現実の制約 #

これらの制約は、すべて現実世界の制約に起因するもので、お客様が克服しなければならないネットワークの特性です。

ビデオは複雑 #

動画の転送は簡単ではありません。30分の非圧縮720 8bitビデオを保存するには、約110Gb必要です。この数字では、4人での電話会議は不可能です。もっと小さくする方法が必要ですが、その答えは映像の圧縮です。しかし、これにはデメリットもあります。

ビデオ101 #

ここでは、動画圧縮について詳しく説明しませんが、RTPがなぜこのように設計されているのかを理解するには十分です。動画圧縮とは、動画を新しいフォーマットにエンコードすることで、同じ動画をより少ないビット数で表現することです。

非可逆圧縮と可逆圧縮 #

動画のエンコードは、ロスレス(情報が失われない)とロッシー(情報が失われる可能性がある)の2種類があります。ロスレス圧縮の場合、相手に送るデータ量が多くなり、ストリームの遅延が大きくなったり、パケットの損失が多くなるため、RTPでは映像の品質が悪くなってもロッシー圧縮を行うのが一般的です。

イントラフレームとインターフレームの圧縮 #

動画の圧縮には2種類あります。1つ目はイントラフレームです。フレーム内圧縮では、1つのビデオフレームを記述するためのビットを削減します。静止画の圧縮にも同じ手法が使われており、JPEG圧縮法などがあります。

2つ目は、フレーム間圧縮です。動画は多くの画像で構成されているので、同じ情報を2度送らない方法を考えます。

フレーム間の種類 #

フレームには3つの種類があります。

  • I-Frame - 完全な画像で、何もなくてもデコードできます。
  • P-Frame - 部分的な画像で、前の画像を修正したもの。
  • B-Frame - 部分的な画像で、以前の画像と未来の画像を組み合わせたもの。

3つのフレームタイプを視覚化すると以下のようになります。

Frame types

動画はデリケート #

動画の圧縮は非常にステートフルであり、インターネットでの転送は困難です。I-Frameの一部が失われるとどうなるのか?P-Frameはどうやって修正すべき箇所を知るのでしょうか?映像圧縮がより複雑になるにつれ、この問題はさらに深刻になっています。幸いなことに、RTPとRTCPには解決策があります。

RTP #

パケットフォーマット #

すべてのRTPパケットは、以下のような構造になっています。

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       Sequence Number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Synchronization Source (SSRC) identifier            |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|            Contributing Source (CSRC) identifiers             |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            Payload                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

バージョン (V) #

バージョン は常に 2 です。

パディング (P) #

パディング はペイロードにパディングがあるかどうかを制御する bool です。

ペイロードの最後のバイトには、何バイトのパディングが追加されたかのカウントが入っています。

拡張 (X) #

セットされている場合、RTPヘッダーは拡張機能を持つことになります。これについては、以下で詳しく説明します。

CSRC 数 (CC) #

SSRCの後、ペイロードの前に続くCSRCの識別子の数です。

マーカー (M) #

マーカービットには事前に設定された意味はなく、ユーザーが好きなように使うことができます。

場合によっては、ユーザーが話しているときに設定されることもあります。また、キーフレームのマークとしてもよく使われます。

ペイロードタイプ (PT) #

ペイロードタイプ は、このパケットで伝送されるコーデックを示す一意の識別子です。

WebRTCでは、ペイロードタイプは動的なものです。ある通話での VP8 は、別の通話では異なる可能性があります。通話中の提供者は、Session Description の中でペイロードタイプとコーデックのマッピングを決定します。

シーケンス番号 #

シーケンス番号は、ストリームのパケットの順序付けに使用されます。パケットが送信されるたびに、シーケンス番号は1ずつ増加します。

RTPは、損失の多いネットワーク上で役立つように設計されています。これにより、受信者はパケットが失われたことを検出できます。

タイムスタンプ #

このパケットのサンプリングの瞬間です。これはグローバルクロックではなく、メディアストリームの中でどれだけの時間が経過したかを示すものです。

同期ソース (SSRC) #

SSRCは、このストリームの一意の識別子です。これにより、複数のメディアストリームを1つのストリーム上で実行できます。

コントリビューションソース(CSRC) #

どの SSRC がこのパケットに貢献したかを伝えるリストです。

これは一般的にトーキングインジケーターに使用されます。例えば、サーバー側で複数のオーディオフィードを1つのRTPストリームにまとめたとします。このフィールドを使用して、「入力ストリームAとCがこの瞬間に話していた」と言うことができます。

ペイロード #

実際のペイロードデータです。パディングフラグが設定されている場合は、何バイトのパディングが追加されたかが最後に表示されます。

拡張機能 #

RTCP #

Packet Format #

RTCPのパケットは、以下のような構造になっています。

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|    RC   |       PT      |             length            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            Payload                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

バージョン (V) #

バージョン は常に 2 です。

パディング (P) #

パディング は bool で、ペイロードにパディングがあるかどうかを制御します。

ペイロードの最後のバイトには、何バイトのパディングが追加されたかのカウントが含まれています。

受信レポート数 (RC) #

このパケットに含まれるレポートの数です。1つのRTCPパケットに複数のイベントを含めることができます。

パケットタイプ (PT) #

この RTCP パケットがどのタイプであるかを示す一意の識別子です。WebRTCエージェントは、これらのタイプをすべてサポートする必要はなく、エージェントによってサポートが異なる場合があります。しかし、一般的に目にするのはこれらのタイプです。

  • Full INTRA-frame Request (FIR) - 192
  • Negative ACKnowledgements (NACK) - 193
  • Sender Report - 200
  • Receiver Report - 201
  • Generic RTP Feedback - 205
  • Payload Specific Feedback - 206

これらのパケットタイプの意義については、以下で詳しく説明します。

Full INTRA-frame Request (FIR)とPicture Loss Indication (PLI) #

FIRとPLIの目的は似ています。これらのメッセージは、送信者にフルキーフレームを要求します。 PLIは、デコーダにパーシャルフレームが到着し、デコードできない場合に使用します。 これは、パケットロスが多い場合や、デコーダがクラッシュした場合などに起こります。

RFC5104によると、パケットやフレームが失われたときには FIR を使用してはならないとされており、それは PLI の仕事です。FIR はパケットロス以外の理由でキーフレームを要求します。例えば、ビデオ会議に新しいメンバーが入ってきたときなどです。FIRはビデオストリームのデコードを開始するために完全なキーフレームを必要とし、デコーダはキーフレームが到着するまでフレームを破棄します。

これにより、接続してからユーザーの画面に画像が表示されるまでの遅延を最小限に抑えることができます。

PLI パケットは、Payload Specific Feedback メッセージの一部です。

実際には、PLI パケットと FIR パケットの両方を扱うことができるソフトウェアは、どちらの場合も同じように動作します。 エンコーダーに信号を送り、新しいフルキーフレームを生成します。

Negative ACKnowledgements #

NACKは、送信者に1つのRTPパケットの再送を要求するものです。これは通常、RTP パケットが失われたときに発生しますが、遅延した場合にも発生します。

NACKは、フレーム全体の再送信を要求するよりも、はるかに帯域幅を効率的に利用できます。RTPはパケットを非常に小さなチャンクに分割するので、実際には1つの小さな欠落部分を要求しているに過ぎません。

送信者/受信者レポート #

これらのレポートは、エージェント間で統計情報を送信するために使用します。このレポートでは、実際に受信したパケット量やジッターを伝えます。

このレポートは、診断や輻輳制御に利用できます。

RTP/RTCPが共に問題を解決する方法 #

このように、RTPとRTCPが連携することで、ネットワークに起因するあらゆる問題を解決できます。これらの技術は今でも常に変化しています。

Negative Acknowledgment #

NACKとも呼ばれます。これは、RTPのパケットロスに対処する方法のひとつです。

NACKは、再送信を要求するために送信者に送り返されるRTCPメッセージです。受信者は、SSRCとシーケンス番号を含むRTCPメッセージを作ります。送信者は、再送信可能なこのRTPパケットを持っていない場合、そのメッセージを無視します。

前方誤り訂正 (Forward Error Correction) #

FECとも呼ばれます。パケットロスに対処するもう一つの方法です。FEC は、同じデータを要求されてもいないのに複数回送信することです。これは、RTP レベルで行われ、さらに下位のコーデックでも行われます。

通話中のパケットロスが安定している場合、FECはNACKよりもはるかに低遅延のソリューションです。NACKの場合は、パケットを要求してから再送信するまでの往復時間が大きくなります。

適応型ビットレートと帯域幅の推定 (Adaptive Bitrate and Bandwidth Estimation) #

リアルタイムネットワーキングで説明したように、ネットワークは予測不可能で信頼性がありません。帯域幅の利用可能性は、セッション中に何度も変化する可能性があります。 利用可能な帯域幅が1秒以内に劇的に(桁違いに)変化することも珍しくありません。

主なアイデアは、予測される、現在および将来の利用可能なネットワーク帯域幅に基づいて、エンコーディングのビットレートを調整することです。 これにより、可能な限り最高の品質の映像・音声信号を伝送し、ネットワークの輻輳によって接続が切断されることがないようにします。 ネットワークの挙動をモデル化し、それを予測するヒューリスティックな手法を「帯域推定」といいます。

これには様々なニュアンスがありますので、詳しくご紹介しましょう。

ネットワークの状態を伝える #

輻輳制御を実装する上での最初の障害は、UDPとRTPがネットワークの状態を通信しないことです。送信者としては、自分のパケットがいつ到着したのか、あるいは到着しているのかどうか、まったくわかりません。

RTP/RTCPには、この問題に対する3つの異なるソリューションがあります。それぞれに長所と短所があります。どのソリューションを使用するかは、どのようなクライアントを使用するかによります。トポロジーはどうなっているのか。あるいは、どれだけの開発時間を確保できるかによっても異なります。

受信者レポート (Receiver Reports) #

受信者レポートはRTCPメッセージであり、ネットワークステータスを伝達するための元の方法です。 それらはRFC3350で見つけることができます。 これらは各SSRCのスケジュールで送信され、次のフィールドが含まれています。

  • Fraction Lost – 前回のReceiver Report以降、何パーセントのパケットが失われたか。
  • Cumulative Number of Packets Lost – 通話全体で失われたパケット数。
  • Extended Highest Sequence Number Received – 最後に受信したシーケンス番号と、それが何回ロールオーバーしたかを示しています。
  • Interarrival Jitter – 通話全体のローリングジッターです。
  • Last Sender Report Timestamp – ラウンドトリップタイムの計算に使用される、送信者の最後の既知の時間。

送信者と受信者のレポート(SRとRR)は協力してラウンドトリップタイムを計算します。

送信者は自分のローカルタイムである sendertime1 をSRに含めます。 受信者は、SRパケットを受け取ると、RRを送り返します。 RRには、送信者から受け取ったばかりの sendertime1 などが含まれています。 SRを受信してからRRを送信するまでには遅延が発生します。そのため、RRには「前回の送信者レポートからの遅延時間」- DLSR も含まれています。 DLSR は後のプロセスでラウンドトリップタイムの推定値を調整するために使用されます。 送信者がRRを受信すると、現在時刻の sendertime2 から sendertime1DLSR を差し引きます。 この時間差をラウンドトリッププロパゲーションディレイまたはラウンドトリップタイムと呼びます。

rtt = sendertime2 - sendertime1 - DLSR

往復の時間をわかりやすく解説:

  • 私があなたにメッセージを送るとき、私の時計の現在の表示は「午後4時20分、42秒と420ミリ秒」です。
  • あなたはこの同じタイムスタンプを私に送り返します。
  • あなたはまた、私のメッセージを読んでからメッセージを送り返すまでの経過時間、例えば5ミリ秒を入れます。
  • このタイムスタンプを受け取った私は、再び時計を見ます。
  • 今、私の時計は午後4時20分、42秒690ミリ秒と表示されています。
  • つまり、あなたに届いてから私に戻ってくるまでに265ミリ秒(690 - 420 - 5)かかったことになります。
  • したがって、往復の時間は265ミリ秒です。

RTT

TMMBR, TMMBN, REMB #

次世代のネットワーク・ステータス・メッセージでは、すべての受信者がRTCPを介して送信者に明示的なビットレート要求をメッセージします。

  • Temporary Maximum Media Stream Bit Rate Request - 1つのSSRCに対する要求ビットレートの仮数/指数です。
  • Temporary Maximum Media Stream Bit Rate Notification - TMMBRを受信したことを通知するメッセージです。
  • Receiver Estimated Maximum Bitrate - セッション全体に対して要求されたビットレートの仮数/指数です。

TMMBRとTMMBNが先に登場し、RFC 5104で定義されています。REMBは後に登場し、draft-alvestrand-rmcat-rembでドラフトが提出されましたが、標準化されませんでした。

REMBを使用したセッションは以下のようになります。

REMB

ブラウザでは、受信帯域幅の推定に簡単な経験則を用いています。

  1. 現在のパケットロスが2%未満の場合、ビットレートを上げるようにエンコーダに指示する。
  2. パケットロスが10%以上の場合、現在のパケットロス率の半分だけビットレートを下げる。
if (packetLoss < 2%) video_bitrate *= 1.08
if (packetLoss > 10%) video_bitrate *= (1 - 0.5*lossRate)

この方法は、理論的にはとてもうまくいきます。送信側は受信側から推定値を受け取り、エンコーダのビットレートを受け取った値に設定します。なんということでしょう!これでネットワークの状況に合わせた調整ができました。

しかし実際には、REMB 方式には複数の欠点があります。

エンコーダの非効率性もその一つで、エンコーダにビットレートを設定しても、必ずしも要求した通りのビットレートで出力されるとは限りません。エンコーダーの設定やエンコードされるフレームによって、ビット数が少なくなったり多くなったりすることがあります。

たとえば、tune=zerolatency で x264 エンコーダーを使用すると、指定したターゲットビットレートから大きく外れることがあります。以下に考えられるシナリオを示します。

  • まず、ビットレートを 1000kbps に設定したとします。
  • エンコーダーは 700kbps しか出力しない。(別名 - 壁を見つめる)。
  • また、受信機がパケットロスゼロで 700kbps の映像を受信した場合、REMB ルール 1 を適用して受信ビットレートを8%増加させたとします。
  • 受信機は 756kbps の提案(700kbps * 1.08)をした REMB パケットを送信機に送ります。
  • 送信者は、エンコーダのビットレートを 756kbps に設定します。
  • エンコーダーはさらに低いビットレートを出力します。
  • これを繰り返して、ビットレートを極限まで下げていきます。

これでは、エンコーダのパラメータ調整が大変になってしまい、素晴らしい接続環境であっても、ユーザーが見られない映像になってしまうことがわかります。

トランスポートワイド輻輳制御 (Transport Wide Congestion Control) #

トランスポートワイド輻輳制御は、RTCPのネットワークステータス通信の最新の開発です。

TWCCは非常にシンプルな原理を使用しています。

TWCC

REMBとは異なり、TWCC受信機は自分の受信ビットレートを推定しようとはしません。TWCC受信機は、どのパケットがいつ受信されたかを送信者に知らせるだけです。送信者は、これらのレポートに基づいて、ネットワークで何が起こっているかを最新の状態で把握できます。

  • 送信者は、パケットシーケンス番号のリストを含む、特別なTWCCヘッダー拡張を持つRTPパケットを作成します。
  • 受信者は、各パケットがいつ受信されたかを送信者に知らせる特別なRTCPフィードバックメッセージで応答します。

送信者は、送信したパケット、そのシーケンス番号、サイズ、タイムスタンプを記録します。 送信者は、受信者からRTCPメッセージを受信すると、送信側のパケット間遅延と受信側の遅延を比較します。 受信遅延が増加した場合は、ネットワークの輻輳が発生していることを意味し、送信者はそれに対処する必要があります。

下の図では、インターパケット遅延の増加の中央値は+20ミリ秒で、ネットワークの輻輳が起きていることを明確に示しています。

TWCC with delay

TWCCは生のデータを提供し、ネットワークの状態をリアルタイムに把握できます:

  • パケットロスの統計情報をほぼ瞬時に確認でき、ロスの割合だけでなく、ロスした正確なパケットも確認できます。
  • 正確な送信ビットレート。
  • 正確な受信ビットレート
  • ジッターの推定値。
  • 送信パケットと受信パケットの遅延時間の違い。

送信側から受信側への受信ビットレートを推定するための些細な輻輳制御アルゴリズムは、受信したパケットサイズを合計し、それを経過したリモートタイムで割ることです。

帯域幅の推定値の生成 #

ネットワークの状態に関する情報が得られたので、利用可能な帯域幅を推定できます。2012年、IETFはRMCAT(RTP Media Congestion Avoidance Techniques)ワーキンググループを立ち上げました。 このワーキンググループには、輻輳制御アルゴリズムに関する複数の規格が提出されています。それ以前は、すべての輻輳制御アルゴリズムは独自のものでした。

最も導入されているのは、draft-alvestrand-rmcat-congestionで定義されている「A Google Congestion Control Algorithm for Real-Time Communication」です。 このアルゴリズムは、2つのパスで実行されます。まず、受信機レポートのみを使用する「損失ベース」のパス。TWCCが利用可能な場合は、その追加データも考慮されます。 また、カルマンフィルターを使用して、現在および将来のネットワーク帯域幅を予測します。

GCCに代わるものとしては、NADA: A Unified Congestion Control Scheme for Real-Time MediaSCReAM - Self-Clocked Rate Adaptation for Multimediaなどがあります。