HTML5 WebRTCを使ったライブチャットを作ってみよう
WebRTCとは
WebRTCは、Web Real-Time Communicationの略で、WebブラウザだけでJavaScript APIを介してリアルタイムコミュニケーション機能を実現するためのAPIです。WebRTCでは、P2Pのコネクション確立からデータ通信を行うための仕様が定義されています。
よって、WebRTCを使うとプラグイン無しで、双方向のリアルタイムコミュニケーション機能を必要とするコンテンツが容易に開発できます。
現状は、W3Cでドラフトが公開されています。http://www.w3.org/TR/webrtc/
WebRTCはいくつかの関連するAPIがあります。その中には、前回紹介したMedia Stream APIも含まれます。
まだドラフトなのでWebRTCに対応ブラウザは、下記のようになっています。
PC
- Google Chrome 23
- Mozilla Firefox 22
- Opera 12
Android
- Google Chrome 28 (29 から標準で有効)
- Mozilla Firefox 24
- Opera Mobile 12
WebRTCの使い方
まずはWebRTCを接続手順を説明します。
最初にベンダープレフィクスのついているクラスがいくつかあるので、使えるかどうか確認します。
window.RTCPeerConnection = ( window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection); window.RTCSessionDescription = ( window.mozRTCSessionDescription || window.RTCSessionDescription); window.RTCIceCandidate = ( window.mozRTCIceCandidate || window.RTCIceCandidate);
次に接続用のwindow.RTCPeerConnectionを生成します。 今回ローカル接続なので、引数は無しです。
var pc1 = new RTCPeerConnection(); //送信側 var pc2 = new RTCPeerConnection(); //受信側
ICEの候補が取得できるイベントをハンドリングしておきます。 ICEの候補が見つかったら受信側に設定します。
pc1.onicecandidate = onIceCandidate1; function onIceCandidate1(evt) { if (evt.candidate) { pc2.addIceCandidate(new RTCIceCandidate(evt.candidate)); } }
受信側にもICEの候補が取得できるイベントをハンドリングしておきます。 ICEの候補が見つかったら送信側に設定します。
pc2.onicecandidate = onIceCandidate2; function onIceCandidate2(event){ if (event.candidate) { pc1.addIceCandidate(new RTCIceCandidate(event.candidate)); } }
次に受信側は、ストリームを受け取った時のハンドリングを行います。
pc2.onaddstream = onRemoteStreamAdded function onRemoteStreamAdded(event) { video2.src = URL.createObjectURL(event.stream); }
次に送信側は、事前に取得しておいたMediaStreamを設定します。
pc1.addStream(localMediaStream);
これで準備が整ったので、オファーを作成して受信側に設定します。 受信側は、オファーに応答するためのアンサーを作成して送信側に設定します。
pc1.createOffer(gotOffer); function gotOffer(description){ pc1.setLocalDescription(description); pc2.setRemoteDescription(description); pc2.createAnswer(gotAnswer); } function gotAnswer(description){ pc2.setLocalDescription(description); pc1.setRemoteDescription(description); }
上記で説明した接続するまでのソースです。 この処理の前にMediaStreamを取得しておく必要があります。詳しくはこちら
var pc1; var pc2; function createPeerConnection() { pc1 = new RTCPeerConnection(); pc1.onicecandidate = onIceCandidate1; pc2 = new RTCPeerConnection(); pc2.onicecandidate = onIceCandidate2; pc2.onaddstream = onRemoteStreamAdded; pc1.addStream(localMediaStream); pc1.createOffer(gotOffer); } function onIceCandidate1(evt) { if (evt.candidate) { pc2.addIceCandidate(new RTCIceCandidate(evt.candidate)); } } function onIceCandidate2(event){ if (event.candidate) { pc1.addIceCandidate(new RTCIceCandidate(event.candidate)); } } function onRemoteStreamAdded(event) { remoteVideo.src = URL.createObjectURL(event.stream); } function gotOffer(description){ pc1.setLocalDescription(description); pc2.setRemoteDescription(description); pc2.createAnswer(gotAnswer); } function gotAnswer(description){ pc2.setLocalDescription(description); pc1.setRemoteDescription(description); }
ライブデモ
ローカルのみでRTCPeerConnectionを試すデモです。ライブデモ
サンプル:ライブチャット
WebRTCをつかったライブチャットを作成してみましょう。
事前準備
WebRTCは、インターネット超えたP2P接続を行うためにNAT越えするためのサーバが必要になります。これは、P2P通信を開始するためには、お互いの端末のグローバルアドレスを知る必要があるからです。
そのために必要なのが、ICE( Interactive Connectivity Establishment )と呼ばれる仕組みです。
ICEは、STUNやTURNなどのNAT越えの手順をまとめたものです。ICEで取得したグローバルIPアドレスとポート番号を通信するホスト間で交換するとNAT越えすることが可能です。
STUNサーバやTURNサーバは、自作できますが、今回は、STUNサーバーとして、googleが公開しているサーバーを利用します。stun.l.google.com です。
そして、STUNサーバから受け取ったICE情報を受け渡しするためのWebアプリケーションが必要になります。今後チャットサーバと呼びます。
オファー側
まずは、googleが公開しているSTUNサーバーを定義しておきます。
var peerConnectionConfig = { "iceServers" : [ { "url" : "stun:stun.l.google.com:19302" } ] };
次にピアコネクション間のデータチャンネルを使用する設定を定義しておきます。
var peerDataConnectionConfig = { "optional" : [ { "RtpDataChannels" : true } ] };
チャットを開始する前に前回の解説したMediaStreamを取得しておきます。
function requireUserMedia() { navigator.getUserMedia({ video : true }, gotUserMedia, error); }
MediaStreamの取得成功のコールバックでWebRTCの設定を行います。
1.ピアコネクションの生成
2.メッセージ用のDataChannelの生成
3.オファーを生成します。
function gotUserMedia(stream) { localVideo.src = window.URL.createObjectURL(stream); localMediaStream = stream; createPeerConnection(); //1 sendChannel = peerCon.createDataChannel("sendDataChannel", {reliable: false}); //2 peerCon.createOffer(gotOffer, error); //3 }
ピアコネクションの生成する引数に、STUNサーバーを定義とデータチャンネルを使用する設定を指定します。
function createPeerConnection() { peerCon = new RTCPeerConnection(peerConnectionConfig,peerDataConnectionConfig); peerCon.onicecandidate = peerCon_onIceCandidate; peerCon.onaddstream = peerCon_onAddStream; peerCon.addStream(localMediaStream); }
オファーが生成できたらピアコネクションのsetLocalDescriptionにオファーを設定しておきます。 それが成功したら、チャットサーバにオファーを送信します。
function gotOffer(description) { peerCon.setLocalDescription(description, function() { sendMessage({ type : 'offer', offer : description }); }, error); }
アンサーが返ってきたらピアコネクションのsetRemoteDescriptionにアンサーを設定しておきます。 これでハンドシェイクが完了します。
function setupAnswer(answer) { peerCon.setRemoteDescription(new RTCSessionDescription(answer)); }
アンサー側
アンサー側も同様にMediaStreamの取得成功のコールバックでWebRTCのピアコネクションの生成しておきます。
そして、オファーを受け取るとピアコネクションのsetRemoteDescriptionにオファーを設定しておきます。 オファーを設定したらその応答となるアンサーを生成します。
function createAnswer(offer) { peerCon.setRemoteDescription(new RTCSessionDescription(offer)); peerCon.createAnswer(gotAnswer, error); }
アンサーの生成が成功したらピアコネクションのsetLocalDescriptionにオファーを設定しておきます。
function gotAnswer(answer) { peerCon.setLocalDescription(answer, function() { sendMessage({ type : 'answer', answer : answer }); }, error); }
データ送受信
データ送受信するためには、データチャンネルを取得します。
sendChannel = peerCon.createDataChannel(...);
送信は、データチャンネルのsendメソッドつかって送信します。
sendChannel.send(value);
受信は、データチャンネルのonmessageのイベントで取得します。
sendChannel.onmessage = function (event) { console.log( event.data ); };
ライブチャットデモ
名称とルーム名を入れて参加ボタンをクリックしてください。1ルームにつき2人までは入れます。ライブチャットデモ
まとめ
今回は、WebRTCを使ってリアルタイムコミュニケーション機能をつかってみました。 まだ全てのブラウザでは使えませんが、サーバなしでP2P機能を使えるとなるとビデオ会議室にデータ交換などに応用してみてはいかがでしょうか。
また、WebRTCのAPIは、複雑なのでライブラリを使うことをお勧めします。
- webRTC.io (https://github.com/webRTC/webRTC.io)
- simpleWebRTC (https://github.com/HenrikJoreteg/SimpleWebRTC)