WebRTC スタートガイド

WebRTC は、オープンで制約のないウェブを求める長い戦いの新たな戦線です。

JavaScript の発明者、Brendan Eich

プラグインなしのリアルタイム コミュニケーション

スマートフォン、テレビ、パソコンが共通のプラットフォームで通信できる世界を想像してみてください。ウェブアプリにビデオチャットやピアツーピアのデータ共有を簡単に追加できることを想像してみてください。これが WebRTC のビジョンです。

お試しになる場合は、WebRTC は、Google Chrome、Safari、Firefox、Opera のパソコン版とモバイル版で利用できます。まず、appr.tc のシンプルなビデオチャット アプリから始めることをおすすめします。

  1. ブラウザで appr.tc を開きます。
  2. [参加] をクリックしてチャットルームに参加し、アプリにウェブカメラの使用を許可します。
  3. ページの最後に表示された URL を新しいタブで開くか、別のパソコンで開くことをおすすめします。

クイック スタート

この記事を読む時間がない場合や、コードだけが必要な場合は、

または、WebRTC コードラボに直接進んでください。このコードラボでは、シンプルなシグナリング サーバーを含む、完全なビデオチャット アプリを構築する方法を段階的に説明しています。

WebRTC の簡単な歴史

ウェブの最後の大きな課題の 1 つは、音声と動画による人間同士のコミュニケーション、つまりリアルタイム通信(RTC)を可能にすることです。RTC は、ウェブアプリでテキスト入力にテキストを入力するのと同じくらい自然なものにする必要があります。それがないと、イノベーションを起こしたり、ユーザーが交流するための新しい方法を開発したりする能力が制限されます。

これまで、RTC は企業向けで複雑なものであり、高価な音声技術や動画技術をライセンス取得するか、自社で開発する必要がありました。RTC テクノロジーを既存のコンテンツ、データ、サービスと統合することは、特にウェブ上で困難で時間がかかりました。

Gmail のビデオチャットは 2008 年に人気を博し、2011 年には Google が Hangouts を導入しました。Hangouts は Gmail と同様に Talk を使用していました。Google は、コーデックやエコー キャンセルの手法など、RTC に必要な多くのコンポーネントを開発した GIPS という会社を買収しました。Google は、GIPS で開発された技術をオープンソース化し、インターネット技術特別調査委員会(IETF)とワールドワイド ウェブ コンソーシアム(W3C)の関連する標準化団体と連携して、業界のコンセンサスを確保しました。2011 年 5 月、Ericsson が WebRTC の最初の実装を構築しました。

WebRTC は、リアルタイムのプラグイン不要の動画、音声、データ通信のためのオープン標準を実装しました。ニーズは現実のものでした。

  • 多くのウェブサービスで RTC が使用されていましたが、ダウンロード、ネイティブ アプリ、プラグインが必要でした。Skype、Facebook、ハングアウトなどが含まれます。
  • プラグインのダウンロード、インストール、更新は複雑で、エラーが発生しやすく、面倒です。
  • プラグインは、デプロイ、デバッグ、トラブルシューティング、テスト、メンテナンスが難しく、ライセンスが必要になったり、複雑で高価なテクノロジーとの統合が必要になったりする場合があります。そもそも、プラグインをインストールしてもらうこと自体が難しい場合も多いでしょう。

WebRTC プロジェクトの基本原則は、API がオープンソースで無料であり、標準化され、ウェブブラウザに組み込まれ、既存のテクノロジーよりも効率的であることです。

現在の状況

WebRTC は Google Meet などのさまざまなアプリで使用されています。WebRTC は WebKitGTK+ および Qt ネイティブ アプリにも統合されています。

WebRTC は次の 3 つの API を実装しています。 - MediaStreamgetUserMedia とも呼ばれます) - RTCPeerConnection - RTCDataChannel

API は次の 2 つの仕様で定義されています。

3 つの API はすべて、モバイルとデスクトップで Chrome、Safari、Firefox、Edge、Opera によってサポートされています。

getUserMedia: デモとコードについては、WebRTC のサンプルをご覧ください。また、Chris Wilson 氏の素晴らしい例では、getUserMedia をウェブ オーディオの入力として使用しています。

RTCPeerConnection: シンプルなデモと完全な機能のビデオチャット アプリについては、それぞれ WebRTC サンプル ピア接続appr.tc をご覧ください。このアプリは、WebRTC コミュニティの協力を得て Google が管理している JavaScript シムである adapter.js を使用して、ブラウザの違いと仕様の変更を抽象化します。

RTCDataChannel: 実際の動作については、WebRTC サンプルでデータチャンネルのデモをご覧ください。

WebRTC Codelab では、3 つの API をすべて使用して、ビデオチャットとファイル共有用のシンプルなアプリを構築する方法を示しています。

初めての WebRTC

WebRTC アプリでは、次の処理を行う必要があります。

  • ストリーミング音声、動画、その他のデータを取得します。
  • IP アドレスやポートなどのネットワーク情報を取得し、他の WebRTC クライアント(ピア)と交換して、NAT やファイアウォール経由でも接続を可能にします。
  • シグナリング通信を調整して、エラーを報告し、セッションを開始または終了します。
  • 解像度やコーデックなどのメディアとクライアントの機能に関する情報を交換します。
  • ストリーミング音声、動画、データを通信します。

ストリーミング データを取得して通信するために、WebRTC は次の API を実装します。

  • MediaStream は、ユーザーのカメラやマイクなどからのデータ ストリームにアクセスします。
  • RTCPeerConnection は、暗号化と帯域幅管理の機能を使用して音声通話またはビデオ通話を有効にします。
  • RTCDataChannel は、汎用データのピアツーピア通信を可能にします。

(WebRTC のネットワークとシグナリングの側面については、後ほど詳しく説明します)。

MediaStream API(getUserMedia API とも呼ばれます)

MediaStream API は、同期されたメディア ストリームを表します。たとえば、カメラとマイクの入力から取得したストリームには、同期された動画トラックと音声トラックがあります。(MediaStreamTrack<track> 要素を混同しないでください。<track> 要素はまったく異なるものです)。

MediaStream API を理解する最も簡単な方法は、実際の使用例を確認することです。

  1. ブラウザで WebRTC サンプル getUserMediaに移動します。
  2. Console を開きます。
  3. グローバル スコープにある stream 変数を検査します。

MediaStream には入力(getUserMedia() によって生成された MediaStream の場合もある)と出力(動画要素または RTCPeerConnection に渡される場合もある)があります。

getUserMedia() メソッドは MediaStreamConstraints オブジェクト パラメータを受け取り、MediaStream オブジェクトに解決される Promise を返します。

MediaStream には、'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ' などの label があります。MediaStreamTrack の配列は、getAudioTracks() メソッドと getVideoTracks() メソッドによって返されます。

getUserMedia の例では、stream.getAudioTracks() は空の配列を返し(音声がないため)、動作中のウェブカメラが接続されていると仮定すると、stream.getVideoTracks() はウェブカメラからのストリームを表す 1 つの MediaStreamTrack の配列を返します。各 MediaStreamTrack には種類('video' または 'audio')、label'FaceTime HD Camera (Built-in)' など)があり、音声または動画の 1 つ以上のチャンネルを表します。この場合、動画トラックは 1 つだけで音声はありませんが、フロント カメラ、リアカメラ、マイクからストリームを取得するチャットアプリや、画面を共有するアプリなど、複数のトラックがあるユースケースを簡単に想像できます。

srcObject 属性を設定すると、MediaStream を動画要素にアタッチできます。以前は、src 属性を URL.createObjectURL() で作成されたオブジェクト URL に設定することで行われていましたが、これは非推奨になりました

getUserMedia は、Web Audio API の入力ノードとしても使用できます。

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

Chromium ベースのアプリや拡張機能にも getUserMedia を組み込むことができます。マニフェストに audioCapture 権限または videoCapture 権限(あるいはその両方)を追加すると、インストール時に 1 回だけ権限をリクエストして付与できるようになります。その後、カメラやマイクへのアクセス許可をユーザーに求めることはありません。

getUserMedia() の権限は 1 回付与するだけで済みます。初回は、ブラウザの情報バーに [許可] ボタンが表示されます。getUserMedia() の HTTP アクセスは、強力な機能に分類されたため、2015 年末に Chrome によって非推奨になりました。

この意図は、カメラやマイクだけでなく、あらゆるストリーミング データソースで MediaStream を有効にすることです。これにより、保存されたデータや、センサーなどの任意のデータソースからのストリーミングが可能になります。

getUserMedia() は、他の JavaScript API やライブラリと組み合わせることで真価を発揮します。

  • Webcam Toy は、WebGL を使用して、共有またはローカルに保存できる写真に奇妙で素晴らしい効果を追加するフォトブース アプリです。
  • FaceKat は、headtrackr.js で構築された顔追跡ゲームです。
  • ASCII Camera は、Canvas API を使用して ASCII 画像を生成します。
idevelop.ro/ascii-camera で生成された ASCII 画像
gUM ASCII アート!

制約

制約を使用して、getUserMedia() の動画解像度の値を設定できます。また、アスペクト比、向きモード(前面カメラまたは背面カメラ)、フレームレート、高さ、幅、applyConstraints() メソッドなどの他の制約のサポートも可能になります。

例については、WebRTC サンプル getUserMedia: 解像度を選択をご覧ください。

許可されていない制約値を設定すると、たとえば、リクエストされた解像度が使用できない場合、DOMException または OverconstrainedError が返されます。実際の動作については、WebRTC サンプル getUserMedia: 解像度を選択のデモをご覧ください。

画面とタブのキャプチャ

Chrome アプリでは、chrome.tabCapture API と chrome.desktopCapture API を使用して、単一のブラウザタブやデスクトップ全体のライブ動画を共有することもできます。(デモと詳細については、WebRTC を使用した画面共有をご覧ください。この記事は数年前のものですが、今でも興味深い内容です)。

試験運用版の chromeMediaSource 制約を使用すると、Chrome で画面キャプチャを MediaStream ソースとして使用することもできます。スクリーン キャプチャには HTTPS が必要です。また、この投稿で説明されているように、コマンドライン フラグで有効にするため、開発でのみ使用してください。

シグナリング: セッション制御、ネットワーク、メディア情報

WebRTC は RTCPeerConnection を使用してブラウザ(ピアとも呼ばれます)間でストリーミング データを通信しますが、通信を調整して制御メッセージを送信するメカニズム(シグナリングと呼ばれるプロセス)も必要です。シグナリング方法とプロトコルは WebRTC で指定されていません。シグナリングは RTCPeerConnection API の一部ではありません。

代わりに、WebRTC アプリ デベロッパーは、SIP や XMPP など、任意のメッセージング プロトコルと、適切な全二重(双方向)通信チャネルを選択できます。appr.tc の例では、シグナリング メカニズムとして XHR と Channel API を使用しています。この codelab では、Node サーバーで実行されている Socket.io を使用します。

シグナリングは、次の 3 種類の情報を交換するために使用されます。

  • セッション制御メッセージ: 通信の開始または終了、エラーの報告。
  • ネットワーク構成: 外部に提示されるパソコンの IP アドレスとポートは何ですか?
  • メディア機能: ブラウザと、通信を希望するブラウザで処理できるコーデックと解像度。

ピアツーピア ストリーミングを開始するには、シグナリングによる情報の交換が正常に完了している必要があります。

たとえば、アリスがボブと通信したいとします。W3C WebRTC 仕様から抜粋した、シグナリング プロセスを示すコードサンプルを次に示します。このコードは、createSignalingChannel() メソッドで作成されたシグナリング メカニズムが存在することを前提としています。また、Chrome と Opera では、現時点では RTCPeerConnection に接頭辞が付いていることに注意してください。

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

まず、アリスとボブがネットワーク情報を交換します。(「候補を見つける」という表現は、ICE フレームワークを使用してネットワーク インターフェースとポートを見つけるプロセスを指します)。

  1. Alice は、ネットワーク候補が利用可能になったときに実行される onicecandidate ハンドラを使用して RTCPeerConnection オブジェクトを作成します。
  2. Alice は、WebSocket などのシグナリング チャネルを使用して、シリアル化された候補データを Bob に送信します。
  3. Bob が Alice から候補メッセージを受け取ると、addIceCandidate を呼び出して候補をリモート ピアの説明に追加します。

WebRTC クライアント(ピアとも呼ばれます。この例では Alice と Bob)は、解像度やコーデック機能などのローカルとリモートの音声と動画のメディア情報を確認して交換する必要もあります。メディア構成情報を交換するためのシグナリングは、セッション記述プロトコル(SDP)を使用してオファーアンサーを交換することで行われます。

  1. Alice が RTCPeerConnection createOffer() メソッドを実行します。この戻り値は RTCSessionDescription(Alice のローカル セッションの説明)に渡されます。
  2. コールバックで、アリスは setLocalDescription() を使用してローカルの説明を設定し、シグナリング チャネルを介してこのセッションの説明をボブに送信します。RTCPeerConnection は、setLocalDescription() が呼び出されるまで候補の収集を開始しません。これは JSEP IETF ドラフトで明文化されています。
  3. Bob は、setRemoteDescription() を使用して、Alice から送信された説明をリモートの説明として設定します。
  4. Bob は RTCPeerConnection createAnswer() メソッドを実行し、Alice から取得したリモートの説明を渡して、Alice の説明と互換性のあるローカル セッションを生成できるようにします。createAnswer() コールバックには RTCSessionDescription が渡されます。Bob はそれをローカルの説明として設定し、Alice に送信します。
  5. Alice は Bob のセッションの説明を取得すると、setRemoteDescription を使用してそれをリモートの説明として設定します。
  6. Ping!

RTCSessionDescription オブジェクトは、セッション記述プロトコル(SDP)に準拠する BLOB です。シリアル化された SDP オブジェクトは次のようになります。

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

ネットワーク情報とメディア情報の取得と交換は同時に行うことができますが、ピア間の音声と動画のストリーミングを開始するには、両方のプロセスが完了している必要があります。

前述のオファー/アンサー アーキテクチャは、JavaScript セッション確立プロトコル(JSEP)と呼ばれます(最初の WebRTC 実装に関する Ericsson のデモ動画で、シグナリングとストリーミングのプロセスを説明する優れたアニメーションが紹介されています)。

JSEP アーキテクチャ図
JSEP アーキテクチャ

シグナリング プロセスが正常に完了すると、発信者と着信者の間でピアツーピアで直接データをストリーミングできます。失敗した場合は、仲介リレーサーバーを介してストリーミングできます(詳しくは後述)。ストリーミングは RTCPeerConnection のジョブです。

RTCPeerConnection

RTCPeerConnection は、ピア間のストリーミング データの安定した効率的な通信を処理する WebRTC コンポーネントです。

次の図は、RTCPeerConnection の役割を示す WebRTC アーキテクチャ図です。ご覧のとおり、緑色の部分は複雑です。

WebRTC アーキテクチャ図
WebRTC アーキテクチャ(webrtc.org より)

JavaScript の観点からこの図で理解すべき主な点は、RTCPeerConnection がウェブ デベロッパーを、その下に潜む無数の複雑さから守っているということです。WebRTC で使用されるコーデックとプロトコルは、信頼性の低いネットワークでもリアルタイム通信を可能にするために、膨大な量の処理を行っています。

  • パケットロス隠蔽
  • エコー キャンセリング
  • 帯域幅の適応性
  • 動的ジッター バッファリング
  • AGC
  • ノイズ リダクションとノイズ サプレッション
  • イメージのクリーニング

上記の W3C コードは、シグナリングの観点から見た WebRTC の簡略化された例を示しています。以下では、2 つの動作する WebRTC アプリのチュートリアルを紹介します。1 つ目は RTCPeerConnection を示す簡単な例で、2 つ目は完全に動作するビデオチャット クライアントです。

サーバーなしの RTCPeerConnection

次のコードは、1 つのウェブページにローカルとリモートの RTCPeerConnection(ローカルとリモートの動画)がある WebRTC サンプル ピア接続から取得したものです。これはあまり役に立ちませんが(呼び出し元と呼び出し先が同じページにあるため)、ページ上の RTCPeerConnection オブジェクトが仲介シグナリング メカニズムを使用せずに直接データとメッセージを交換できるため、RTCPeerConnection API の動作が少し明確になります。

この例では、pc1 はローカル ピア(発信者)を表し、pc2 はリモート ピア(着信者)を表します。

発信者

  1. 新しい RTCPeerConnection を作成し、getUserMedia() からストリームを追加します。 ```js // Servers はオプションの構成ファイルです。(TURN と STUN については後で説明します)。 pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. オファーを作成し、pc1 のローカル説明として、pc2 のリモート説明として設定します。呼び出し側と呼び出し先が同じページにあるため、シグナリングを使用せずにコード内で直接行うことができます。 js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Callee

  1. pc2 を作成し、pc1 からのストリームが追加されたら、動画要素に表示します。 js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API プラス サーバー

実際の環境では、WebRTC にはサーバーが必要です。そのため、次のようなことが起こります。

  • ユーザー同士が互いを見つけ、名前などの現実世界の情報を交換します。
  • WebRTC クライアント アプリ(ピア)がネットワーク情報を交換します。
  • ピアは、動画の形式や解像度などのメディアに関するデータを交換します。
  • WebRTC クライアント アプリは NAT ゲートウェイとファイアウォールを通過します。

つまり、WebRTC には次の 4 種類のサーバーサイド機能が必要です。

  • ユーザーの検出とコミュニケーション
  • シグナリング
  • NAT/ファイアウォール トラバーサル
  • ピアツーピア通信が失敗した場合のリレー サーバー

NAT トラバーサル、ピアツーピア ネットワーキング、ユーザー検出とシグナリング用のサーバーアプリを構築するための要件については、この記事では説明しません。STUN プロトコルとその拡張機能である TURN は、ICE フレームワークによって使用され、RTCPeerConnection が NAT 走査やその他のネットワークの変動に対応できるようになります。

ICE は、2 つのビデオチャット クライアントなどのピアを接続するためのフレームワークです。最初に、ICE は UDP を介して可能な限り低いレイテンシでピアを直接接続しようとします。このプロセスでは、STUN サーバーのタスクは 1 つだけです。NAT の背後にあるピアがパブリック アドレスとポートを検出できるようにすることです。(STUN と TURN の詳細については、WebRTC アプリに必要なバックエンド サービスを構築するをご覧ください)。

接続候補の検索
接続候補を検索しています

UDP が失敗すると、ICE は TCP を試します。直接接続が失敗した場合(特にエンタープライズ NAT 走査とファイアウォールが原因の場合)、ICE は仲介(リレー)TURN サーバーを使用します。つまり、ICE は最初に UDP で STUN を使用してピアを直接接続し、失敗した場合は TURN リレーサーバーにフォールバックします。「候補の検索」とは、ネットワーク インターフェースとポートを見つけるプロセスを指します。

WebRTC データ経路
WebRTC データ経路

WebRTC エンジニアの Justin Uberti が、2013 年の Google I/O WebRTC プレゼンテーションで ICE、STUN、TURN について詳しく説明しています。(プレゼンテーションのスライドで、TURN サーバーと STUN サーバーの実装例を確認できます)。

シンプルなビデオチャット クライアント

WebRTC を試すのに最適な場所は、appr.tc のビデオチャット デモです。ここでは、STUN サーバーを使用したシグナリングと NAT/ファイアウォール走査が完了しています。このアプリは、仕様の変更や接頭辞の違いからアプリを分離するためのシムである adapter.js を使用します。

このコードは、ログ記録を意図的に詳細にしています。コンソールでイベントの順序を確認します。以下に、コードの詳細なチュートリアルを示します。

ネットワーク トポロジ

現在実装されている WebRTC は一対一の通信のみをサポートしていますが、複数のピアが互いに直接通信したり、マルチポイント制御ユニット(MCU)を介して通信したりするような、より複雑なネットワーク シナリオで使用できます。MCU は、多数の参加者を処理し、ストリームの選択的転送、音声と動画のミキシングや録画を行うことができるサーバーです。

マルチポイント コントロール ユニットのトポロジ図
マルチポイント制御ユニットのトポロジの例

既存の WebRTC アプリの多くはウェブブラウザ間の通信のみをデモしていますが、ゲートウェイ サーバーを使用すると、ブラウザで実行されている WebRTC アプリが 電話PSTN とも呼ばれます)や VOIP システムなどのデバイスとやり取りできるようになります。2012 年 5 月、Doubango Telecom は WebRTC と WebSocket で構築された sipml5 SIP クライアントをオープンソース化しました。これにより、iOS と Android で実行されているブラウザとアプリ間でビデオ通話が可能になりました(他の用途にも使用できます)。Google I/O で、Tethr と Tropo は、OpenBTS セルを使用して、フィーチャー フォンとコンピュータ間の通信を WebRTC で実現する災害通信用のフレームワークブリーフケースに収めてデモを行いました。携帯通信会社を利用しない電話通信!

Google I/O 2012 での Tethr/Tropo のデモ
Tethr/Tropo: ブリーフケースに入った災害通信

" id="rtcdatachannel_api" tabindex="-1">RTCDataChannel API<

WebRTC は、音声と動画だけでなく、他の種類のデータのリアルタイム通信もサポートしています。

RTCDataChannel API を使用すると、低レイテンシと高スループットで任意のデータをピアツーピアで交換できます。シングル ページ デモと、シンプルなファイル転送アプリの作成方法については、それぞれ WebRTC サンプルWebRTC Codelab をご覧ください。

この API には、次のような多くのユースケースが考えられます。

  • ゲーム
  • リモート デスクトップ アプリ
  • リアルタイム テキスト チャット
  • ファイル転送
  • 分散型ネットワーク

この API には、RTCPeerConnection を最大限に活用し、強力で柔軟なピアツーピア通信を可能にするための機能がいくつかあります。

  • RTCPeerConnection セッション設定の活用
  • 優先度付きの複数の同時チャンネル
  • 信頼できる配信セマンティクスと信頼できない配信セマンティクス
  • 組み込みのセキュリティ(DTLS)と輻輳制御
  • 音声や動画の有無にかかわらず使用できる

構文は、send() メソッドと message イベントを含む WebSocket と意図的に似ています。

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

通信はブラウザ間で直接行われるため、ファイアウォールと NAT に対応するためのホールパンチングが失敗した場合にリレー(TURN)サーバーが必要になったとしても、RTCDataChannel は WebSocket よりもはるかに高速になる可能性があります。

RTCDataChannel は、Chrome、Safari、Firefox、Opera、Samsung Internet で利用できます。Cube Slam ゲームは、API を使用してゲームの状態を通信します。友だちと遊ぶか、クマと遊ぶかを選択します。革新的なプラットフォーム SharefestRTCDataChannel を介したファイル共有を可能にし、peerCDN は WebRTC がピアツーピアのコンテンツ配信をどのように実現できるかを示しました。

RTCDataChannel の詳細については、IETF のプロトコル仕様のドラフトをご覧ください。

セキュリティ

リアルタイム通信アプリやプラグインがセキュリティを侵害する可能性はいくつかあります。次に例を示します。

  • 暗号化されていないメディアやデータは、ブラウザ間、またはブラウザとサーバー間で傍受される可能性があります。
  • アプリがユーザーに知られることなく動画や音声を録画して配布する可能性があります。
  • マルウェアやウイルスは、無害に見えるプラグインやアプリと一緒にインストールされることがあります。

WebRTC には、これらの問題を回避するための機能がいくつかあります。

  • WebRTC の実装では、DTLSSRTP などの安全なプロトコルが使用されます。
  • 暗号化は、シグナリング メカニズムを含むすべての WebRTC コンポーネントで必須です。
  • WebRTC はプラグインではありません。コンポーネントは、別のプロセスではなく、ブラウザのサンドボックスで実行されます。コンポーネントは個別にインストールする必要はなく、ブラウザが更新されるたびに更新されます。
  • カメラとマイクへのアクセスは明示的に許可する必要があり、カメラまたはマイクが動作しているときは、ユーザー インターフェースで明確に示されます。

ストリーミング メディアのセキュリティに関する詳細な説明は、この記事の対象外です。詳しくは、IETF が提案した Proposed WebRTC Security Architecture をご覧ください。

まとめ

WebRTC の API と標準は、電話、ゲーム、動画制作、音楽制作、ニュース収集など、コンテンツ作成とコミュニケーションのためのツールを民主化し、分散化することができます。

これほど破壊的なテクノロジーは他にありません。

ブロガーの Phil Edholm 氏が述べているように、「WebRTC と HTML5 は、情報に対してブラウザが実現したのと同じ変革をリアルタイム コミュニケーションにもたらす可能性があります。」

デベロッパー ツール

その他の情報

標準とプロトコル

WebRTC サポートの概要

MediaStream API と getUserMedia API

  • Chrome デスクトップ 18.0.1008 以降、Chrome for Android 29 以降
  • Opera 18 以降、Opera for Android 20 以降
  • Opera 12、Opera Mobile 12(Presto エンジンに基づく)
  • Firefox 17 以降
  • Microsoft Edge 16 以降
  • iOS の Safari 11.2 以降、macOS の Safari 11.1 以降
  • Android の UC 11.8 以降
  • Samsung Internet 4 以降

RTCPeerConnection API

  • Chrome デスクトップ 20 以降、Android 版 Chrome 29 以降(フラグなし)
  • Opera 18 以降(デフォルトでオン)、Opera for Android 20 以降(デフォルトでオン)
  • Firefox 22 以降(デフォルトでオン)
  • Microsoft Edge 16 以降
  • iOS の Safari 11.2 以降、macOS の Safari 11.1 以降
  • Samsung Internet 4 以降

RTCDataChannel API

  • Chrome 25 で試験運用版がリリースされましたが、Chrome 26 以降(Android 版 Chrome 29 以降)ではより安定したバージョンがリリースされています(Firefox との相互運用性も備わっています)。
  • Opera 18 以降、Opera for Android 20 以降で安定版(Firefox との相互運用性あり)
  • Firefox 22 以降(デフォルトでオン)

getUserMediaRTCPeerConnection などの API のクロスプラットフォーム サポートについて詳しくは、caniuse.comChrome プラットフォームのステータスをご覧ください。

RTCPeerConnection のネイティブ API は、webrtc.org のドキュメントでも入手できます。