WebRTCのRTCDataChannel APIを使って、複数人にデータを送信してみる

0 件のコメント
WebRTCで複数人接続してみるの続きです。

今回は「RTCDataChannel API」を使って、データの送受信を試してみたいと思います。

複数人接続の記事の後なので、複数人に対してデータの送受信までを試してみます。

RTCDataChannel APIとは?

Peerの接続を利用して、データを送受信できる仕組み。

・送受信できるデータ形式
Blob、ArrayBuffer、ArrayBufferViewのようなデータ形式をサポート。

・通信プロトコル
UDP、TCP、SCTPをサポート。

RTCDataChannel APIを使うには?

こんな感じで生成することができます。
// 端末A側のpeerを生成
var peer = new webkitRTCPeerConnection({
"iceServers": [{"url": "stun:stun.l.google.com:19302"}]
});
// 端末A側のdataChannelを生成(dataChannelOptionは省略可能
// オプションに関してはこちらの記事が詳しいです。
// http://www.html5rocks.com/ja/tutorials/webrtc/datachannels/
var dataChannelLabel = "test channel";
var dataChannelOption = {};
var dataChannel = peer.createDataChannel(dataChannelLabel, dataChannelOption);
dataChannel.onerror = function (error) {
// エラー時に動作
console.log(error);
};
dataChannel.onmessage = function (event) {
// Peer接続している端末から、send()された時に動作
console.log(event.currentTarget.label);
console.log("data channel message:", event.data);
};
dataChannel.onopen = function () {
// dataChannelの接続確立時に動作
console.log("data channel opened");
};
dataChannel.onclose = function () {
// dataChannelの切断時に動作
console.log("data channel closed");
};
DataChannelの接続リクエストをハンドリングする。
// ondatachannelで、
// 端末B側のdataChannel(event.channel)を取得できるので保持しておく
// createAnswerのコールバックのタイミングでもオッケイ。
var remoteDataChannel = null;
peer.ondatachannel = function(event) {
remoteDataChannel = event.channel;
};
これで送信する準備はオッケーです。
下記をconsoleから実行すると端末B側の「dataChannel.onmessage」が動作します。
remoteDataChannel.send("test test");

注意点ですが、Peerでの接続確立後に「peer.createDataChannel」をしても相手側の「peer.ondatachannel」は動作しませんでした。
オファー前に「peer.createDataChannel」をしとくと良いようです。
参考:http://blog.wnotes.net/blog/article/beginning-webrtc-datachannel

前回のソース(WebRTCで複数人接続してみる)を修正してみる

webrtc.jsを修正する
・initの処理を変更(this.dataChannelsとthis.remoteDataChannelsを初期化させる処理追加
/**
* 初期化
* @param {Object} option {
* videoElementId: "",
* iceCandidateCallback: function() {},
* dataChannels: [{
* label: 'test channel',
* option: {
* ordered: false, // 順序を保証しない
* maxRetransmitTime: 3000, // ミリ秒
* },
* onmessageCallback: function() {
* console.log("test channel received!!");
* }
* }]
* }
*/
init: function(option) {
this.option = option;
this.peer = null;
this.localStream = null;
this.isStartVideo = false;
this.dataChannels = {};
this.remoteDataChannels = {};
},
・connectの処理を変更(this.option.dataChannelsのif文を追加
/**
* コネクションをはる
* @return {Boolean} true: RTCPeerConnectionが生成済み, false: 生成できなかった
*/
connect: function() {
if (this.peer) {
return true;
}
if (!this.localStream) {
return false;
}
if (!this.option.videoElementId) {
return false;
}
this.peer = this.createPeer();
if (this.option.dataChannels && this.option.dataChannels.length > 0) {// Data Channelの設定があれば接続させる
for (var i = 0, l = this.option.dataChannels.length; i < l; i++) {
var dataChannelOption = this.option.dataChannels[i];
this.createDataChannel(dataChannelOption.label, dataChannelOption.option, dataChannelOption.onmessageCallback);
}
this.peer.ondatachannel = (function(event) {
this.remoteDataChannels[event.channel.label] = event.channel;
}.bind(this));
}
this.peer.addStream(this.localStream);
var iceCandidateCallback = this.option.iceCandidateCallback;
this.peer.onicecandidate = function(event) {
iceCandidateCallback && iceCandidateCallback(event.candidate);
};
var videoElementId = this.option.videoElementId;
this.peer.onaddstream = function(event) {
var video = document.getElementById(videoElementId);
video.src = window.webkitURL.createObjectURL(event.stream);
};
return true;
},
・createDataChannelを新規追加
/**
* Data Channelの生成
* @param {String} label
* @param {Object} option
* @param {Function} onmessageCallback
*/
createDataChannel: function(label, option, onmessageCallback) {
var dataChannel = this.peer.createDataChannel(label, option);
dataChannel.onerror = function (error) {
console.log(error);
};
dataChannel.onmessage = function (event) {
console.log(event.currentTarget.label);
console.log("data channel message:", event.data);
onmessageCallback && onmessageCallback();
};
dataChannel.onopen = function () {
console.log("data channel opened");
};
dataChannel.onclose = function () {
console.log("data channel closed");
};
this.dataChannels[label] = dataChannel;
},
index.htmlを修正する
・createWebrtcInstanceの処理を変更(new するところに、dataChannelsを追加しただけ
// WebRTCのインスタンスを生成する
// @param {String} id
// @return {Object} WebRTCインスタンス
createWebrtcInstance: function(id) {
var videoElementId = this.getVideoElementId(id);
var video = document.createElement('video');
video.id = videoElementId;
video.autoplay = true;
document.getElementsByTagName('body')[0].appendChild(video);
return new Webrtc({
videoElementId: videoElementId,
iceCandidateCallback: (function(candidate) {
this.sendMessage(this.messageTypes.candidate, {sendto: id, fromUserId: this.userId, candidate: candidate});
}.bind(this)),
dataChannels: [{
label: 'test channel',
option: {
ordered: false, // 順序を保証しない
maxRetransmitTime: 3000, // ミリ秒
},
onmessageCallback: function() {
console.log("test channel received!!");
}
}]
});
},
追加してるコードは50行ぐらいです。

データ送受信の実行手順

1. WebRTCで複数人接続してみるの「作ってみた」の手順通り実施し、複数人接続をさせておく

2. 全てのブラウザでDeveloper Toolsを開く

3. どれか1つでconsoleから下記を実行する
for (var i in webrtcTest.webRtcInstances) {
  if (i !== webrtcTest.localInstanceKey) {
    webrtcTest.webRtcInstances[i].remoteDataChannels['test channel'].send("test dayo");
  }
}
4. 実行したタブ以外で、下記のようなメッセージがconsole上に流れていることを確認できる
data channel message:test dayo
できた!!

(個別に送信したい場合は、下記を実行する
webrtcTest.webRtcInstances[id].remoteDataChannels['test channel'].send("test dayo");
※ idは送信したい端末のid

終わりに

ここまでやったらWebRTCはお腹いっぱい気味。
つぎは、ファイルの送受信をできるようにするかなあ。。
(チャンクさせるようにするなんて面倒だ。。

まあ、そこまでやるならサービスレベルのものを作るときかなー。

あとは、peer.jsとかライブラリを使ってみるとか。
気が向いたらやります。

参考

・WebRTC data channels
http://www.html5rocks.com/ja/tutorials/webrtc/datachannels/
・WebRTC-DataChannel使ってみたよ
http://blog.wnotes.net/blog/article/beginning-webrtc-datachannel

以上!

0 件のコメント :

コメントを投稿