データチャネルを利用したデータの送受信

この章では、データチャネル API (RTCDataChannel) を利用したデータの送受信について説明します。

概要

データチャネルは、ピア接続間で任意のデータを送受信するための機能です。 RTCPeerConnection 自身でやりとりするデータ形式以外(テキスト、バイナリ等)を扱うことができます。

データチャネルは RTCPeerConnection に紐付ける形で作成・管理を行います。

1つのピア接続に対して複数のデータチャネルを紐付けることが可能です。

データチャネルを作成する

RTCPeerConnection の以下のメソッドでデータチャネルを新規に生成できます。

  • createDataChannel(label [,options])

第1引数にはデータチャネルの識別子となるラベルを文字列で指定します。 データチャネルが所属するピア接続において、複数の異なるデータチャネルに対して同一のラベルは使えません。

例: データチャネルを生成する

var pc = new RTCPeerConnection();
pc.createDataChannel("spam");

第2引数ではオプションを指定します。(省略可) 指定できるオプションは以下の通りです。 maxPacketLifeTimemaxRetransmits を同時に指定することはできません。

  • id: データチャネルの固有 ID を表します。

  • ordered: メッセージの送信順序を保証するかどうかのフラグを表します。

  • maxPacketLifeTime: メッセージの送信に成功するまで再送を繰り返す時間(ミリ秒)を表します。この時間を過ぎても送信に失敗する場合、再送が止められます。

  • maxRetransmits: メッセージの最大再送信回数を示す数値を表します。

  • protocol: 利用する sub protocol を表します。

  • negotiated: 利用側のアプリケーションがこのデータチャネルをネゴシエーションしたかどうかのフラグを表します。

例: データチャネルをオプションを指定して生成する

var pc = new RTCPeerConnection();
pc.createDataChannel("spam", { ordered: true, maxRetransmits: 10000});

データチャネルが作成された通知を受け取る

ピアでの接続を行っていて、リモートでデータチャネルが新規に作成された際、 RTCPeerConnectionondatachannel イベントが発火します。

例: リモートでデータチャネルが生成されたときのコールバックを登録する

const pc = new RTCPeerConnection();
pc.ondatachannel = (event) => {
  console.log("# ondatachannel, label=>", event.channel.label);
};

データチャネルの接続状態

RTCDataChannel の接続状態は、 readyState プロパティに格納されています。

readyState の値は以下のいずれかとなります。初期状態は opening です。

  • opening

  • open

  • closing

  • closed

接続状態(readyState)が変更された際は以下のイベントが発火します。 各イベントの詳細については API リファレンス を参照してください。

  • onopen: readyStateopen になったときに発火します。

  • onclosing: readyStateclosing になったときに発火します。

  • onclose : readyStateclosed になったときに発火します。

例: データチャネルの接続状態が変更されたときのコールバックを登録する

const pc = new RTCPeerConnection();
const dataChannel = await pc.createDataChannel("spam", {ordered: true});
dataChannel.onopen = (event) => {
  console.log("# datachannel onopen");
};
dataChannel.onclosing = (event) => {
  console.log("# datachannel onclosing");
};
dataChannel.onclose = (event) => {
  console.log("# datachannel onclose");
};

データを送信する

RTCDataChannel の以下のメソッドでデータを送信できます。

  • send(data)

送信できる data の型は string, ArrayBuffer, ArrayBufferView のいずれかです。

例: データチャネルで文字列データを送信する

const pc = new RTCPeerConnection();
const dataChannel = await pc.createDataChannel("myLabel", {ordered: true});
dataChannel.onopen = (event) => {
   await dataChannel.send("egg");
};

データを受信する

リモートからデータを受信した際、 RTCDataChannelonmessage イベントが発火します。

onmessage イベントの詳細については API リファレンス を参照してください。

例: データチャネルでメッセージを受け取ったときのコールバックを登録する

const pc = new RTCPeerConnection();
...
const dataChannel = await pc.createDataChannel("myLabel", {ordered: true});
dataChannel.onmessage = (event) => {
  console.log("# datachannel onmessage, is binary data=>", event.binary);
  console.log("# datachannel onmessage, data =>", event.data);
}

データチャネルを閉じる

データチャネルの接続を閉じるには、 RTCDataChannel の以下のメソッドを呼び出します。

  • close()

複数のデータチャネルを管理する

RTCDataChannellabel プロパティの値を識別子として用いることで、 一つのピア接続に対して複数のデータチャネルを発行・管理することができます。

例: 複数のデータチャネルを発行する

const pc = new RTCPeerConnection();
const labelChannel1 = "spam";
const labelChannel2 = "egg";
(async function() {
  // 1 本目の dataChannel と event handler を登録
  const channel1 = await pc.createDataChannel(labelChannel1, {ordered: true});
  channel1.onopen = (event) => {
    console.log("channel1 onopen");
  }
  channel1.onclose = (event) => {
    console.log("channel1 onclose");
  }
  channel1.onmessage = (event) => {
    console.log("channel1 onmessage =>", event.data);
  }

  // 2 本目の dataChannel と event handler を登録
  const channel2 = await pc.createDataChannel(labelChannel2, {ordered: false});
  channel2.onopen = (event) => {
    console.log("channel2 onopen");
  }
  channel2.onclose = (event) => {
    console.log("channel2 onclose");
  }
  channel2.onmessage = (event) => {
    console.log("channel2 onmessage =>", event.data);
  }
})();

例: リモートで発行された複数のデータチャネルを管理する

const pc = new RTCPeerConnection();
const labelChannel1 = "spam";
const labelChannel2 = "egg";
pc.ondatachannel = (event) => {
   console.log("ondatachannel label=>", event.channel.label);
   if (event.channel.label === labelChannel1) {
     // 1 本目
     // event handler を登録
     event.channel.onopen = (event) => {
       console.log("channel1 onopen");
     }
     event.channel.onclose = (event) => {
       console.log("channel1 onclose");
     }
     event.channel.onmessage = (messageEvent) => {
       console.log("channel1 onmessage =>", messageEvent.data);
     }
    return;
   }
   if (event.channel.label === labelChannel2) {
     // 2 本目
     // event handler を登録
     event.channel.onopen = (event) => {
       console.log("channel2 onopen");
     }
     event.channel.onclose = (event) => {
       console.log("channel2 onclose");
     }
     event.channel.onmessage = (messageEvent) => {
       console.log("channel2 onmessage =>", messageEvent.data);
     }
    return;
   }
   console.log("unknown datachannel");
}

onbufferedamountlow イベントと bufferedAmountLowThreshold プロパティについて

RTCDataChannel オブジェクトの未送信データのバイトサイズは bufferedAmount プロパティに格納されています。 この未送信データのバイトサイズのしきい値として bufferedAmountLowThreshold プロパティを利用します。

bufferedAmountbufferedAmountLowThreshold の値以下になったとき、 onbufferedamountlow イベントが発火します。 bufferedAmountLowThreshold プロパティの初期値は 0 です。

onbufferedamountlow イベントの詳細については API リファレンス を参照してください。

例: 未送信データのバイトサイズが 2048 以下になったときのコールバックを登録する

const pc = new RTCPeerConnection();
const dataChannel = await pc.createDataChannel("spam", {ordered: true});
dataChannel.bufferedAmountLowThreshold = 2048;
dataChannel.onbufferedamountlow = (event) => {
  console.log("# datachannel onbufferedamountlow, bufferedAmount=>", dataChannel.bufferedAmount);
};

データ形式(binaryType)について

Web API では RTCDataChannel オブジェクトの binaryType プロパティに blob または arraybuffer を指定することで 送受信するデータの形式を指定できますが、本ライブラリでは arraybuffer のみサポートしています。 blob を指定することは出来ないので、注意してください。

Android で利用する際の注意点

Android の場合、 RTCDataChannel オブジェクトから以下のプロパティの取得を行えないので、注意してください。

  • ordered

  • maxPacketLifeTime

  • maxRetransmits

  • protocol

  • negotiated