chromebook 「だけ」で webrtcを動かそう
TRANSCRIPT
Chromebook 「だけ」でWebRTCを動かそう
2015.03.11
インフォコム株式会社
がねこまさし
@massie_g
ChromebookでWebRTC
• Chrome動く
• カメラ、マイクついている
• getUserMeida()できる
• PeerConnectionも使える
• USBカメラも認識する
WebRTC端末として使える
※WebRTC Conference Japan のLTでも言及– 実際に遠隔作業支援にWebRTCを使ってみた– http://www.slideshare.net/hondahiroyuki/web-rtc-con
Chromebook 「だけ」でWebRTC
• どんなとき?
–ネットワークにつながらなくても、デモしたい!
問題1: Webサーバー
• 問題1
– getUserMedia()は、file:// では使えない
→ http:// にはWebサーバーが必要
Webサーバー
マッチョな対策
• Chromebookを開発者モードに変更– 時間かかります– 初期化されます– セキュリティ警告多発します
• crouton を導入– Crouton Integration Chrome Extensionを使うと、
Chrome OSのシェルと同居できるらしい– http://www.softantenna.com/wp/hard/linux-
in-chrome-os/
• Linuxをインストール
※私は怖くなって、途中で引き返しました
別の方法を探す
• Chrome App というのがある
• Chrome.sockets.tcpServer というのが使える
– https://developer.chrome.com/apps/sockets_tcpServer
• なら、Webサーバーも作れるはず!
Webサーバー作りました
• Simple Web Server (Chrome ウェブストアで)–非常に簡易的なWebサーバー
– http://goo.gl/4sxGy9静的なファイルを数個だけホストできるhttp://localhost:3000//page1.html~ /page4.html/script1.js, /script2.js/sytle1.css, /style2.css
※こちらを参考にさせていだだきました。どうもありがとうございます!Chrome Appsで簡易Webサーバ構築 http://blog.asial.co.jp/1267
Appインストールには
ネットワーク接続必要です。あしからず
DEMO
• SWS 起動
• http://localhost:3000/に Chromeでアクセス
• SWSの page1.html に、下記内容をコピー
– https://gist.github.com/mganeko/ee1f644b08fdca6970ca
• http://localhost:3000/page1.htmlに Chromeでアクセス
– Start video
問題2:シグナリング
• Peer-to-Peer通信の前に、情報交換が必要
– SDP, ICE candidate
• 手動(コピペ)で交換、という手もあるけど…
– http://html5experts.jp/mganeko/5181/
• 今回はWebSocketでやりたい
シグナリングサーバー
Webサーバー
WebScoketサーバー作りました
• Simple Message Server (Chrome ウェブストアで)
– 非常に簡易的なWebSocketサーバー
– http://goo.gl/ekvQDy簡易メッセージサーバー、WebSocketサーバー・5クライアントまで同時接続
・サーバーメッセージを送信すると、他のクライアントに配信・テキストデータのみ対応
Appインストールには
ネットワーク接続必要です。あしからず
参考にさせていただきましたどうもありがとうございます!
• Google のサンプル– Chrome Commando TCP server
– https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/tcpserver
• WebSocket サーバの実装とプロトコル解説 (by Jxckさん)
– http://jxck.hatenablog.com/entry/20120725/1343174392
– https://gist.github.com/Jxck/3171239
• RFC 6455 - The WebSocket Protocol (日本語訳)– http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html
Simple Message Serverの動き
• 3001/tcpで待ち受け• Upgradeに対応• メッセージを送ると、他のクライアントに転送
• 制約– 対応するメッセージはテキストのみ– メッセージ長は、16bitまで。64bitには未対応– フラグメントの分割には未対応
クライアント側のコード抜粋// WebSocketサーバーに接続var url = 'ws://localhost:3001/';var ws = new WebSocket(url);
// SDP送信var msg = JSON.stringify(sessionDescription);ws.send(msg);
// ICE Candidate送信var candidate = {type: "candidate",
sdpMLineIndex: evt.candidate.sdpMLineIndex,sdpMid: evt.candidate.sdpMid,candidate: evt.candidate.candidate
};var msg = JSON.stringify(candidate);ws.send(msg);
クライアント側のコード抜粋2ws.onmessage = onMessage;
// メッセージハンドラfunction onMessage(raw_evt) {
var msg = raw_evt.data;var evt = JSON.parse(msg);
if (evt.type === 'offer') {// SDP offerを受け取った場合
} else if (evt.type === 'answer' && peerStarted) {// SDP answerを受け取った場合
} else if (evt.type === 'candidate' && peerStarted) {// ICE candidate を受け取った場合
}}
DEMO
• SWS 起動, SMS起動
• SWSのpage2.htmlに、次の内容をコピー
– https://gist.github.com/mganeko/4d0f84c383722d1fb963
• http://localhost:3000/page2.html
– Chromeの2つのタブで開く
• 通信してみる
– Start video, Start video, Connect
問題3:NAT越え
• NAT越えには、STUN/TURNサーバーが必要
• Chrome.sockets.udpがある
• なら、これも作れるはず!
問題3:NAT越え
• NAT越えには、STUN/TURNサーバーが必要
• Chrome.sockets.udpがある
• なら、これも作れるはず!
→作りません!
今回はChromebook「だけ」なので、NAT越えは発生しない
※誰か挑戦してみませんか?
まとめ
• Chromebook「だけ」でWebRTC通信してみた– Chrome Appを作成– 簡易Webサーバー、簡易WebSocketサーバー
• もちろん、他のプラットフォームでも利用可能– Windows, Mac OS X
• 一般的なサーバーアプリ、サーバ言語不要– No IIS, No Apache, No Nginx, No python, No node.js
• WebRTC体験、ハンズオンにも最適
→ 社内勉強会などで、ぜひ使ってください!
おまけ
ちょっとサーバー側の
ソースを見てみましょう
Web サーバー
ソケット作成、待ち受け// serverchrome.sockets.tcpServer.create({}, function(createInfo) {
// サーバ用のソケットserverSocketId = createInfo.socketId;// 3000番ポートをlisten
chrome.sockets.tcpServer.listen(serverSocketId, '0.0.0.0', 3000, function(resultCode){if (resultCode < 0) {
console.log("Error listening:" + chrome.runtime.lastError.message); }
});});
// socketchrome.sockets.tcpServer.onAccept.addListener(function(info) {
if (info.socketId === serverSocketId) {chrome.sockets.tcp.setPaused(info.clientSocketId, false);
}});
GET Requestの処理chrome.sockets.tcp.onReceive.addListener(function(info) {
var requestText = ab2str(info.data);var getpath = splitGetPath(requestText); // GET のパスを取得var type = getMIMEType(getpath); // パスの拡張子から、MIMEタイプを推定// --- make response ---var socketId = info.socketId; var message = getContentByPath(getpath); // 内容はchrome.storage.localに保存var utf8message = unescape(encodeURIComponent(message)); // utf8に変換var responseText = [
' HTTP/1.1 200 OK','Content-Type: ' + type,'Content-Length: ' + utf8message.length,'',utf8message
].join("\n"); // --- send response ---chrome.sockets.tcp.send(socketId, str2ab(responseText), function(info) {
if (info.resultCode < 0) { console.log("Error:" + chrome.runtime.lastError.message); }chrome.sockets.tcp.disconnect(socketId); // 成功しても、すぐに切断するchrome.sockets.tcp.close(socketId);
});});
WebSokcetサーバー
コードの一部:データ長16bitまで対応
/*** Payload Length* xaaa aaaa second byte* 0111 1111 mask with 0x7f* ---------* 0000 0100 4(4)* 0111 1110 126(next UInt16)* 0111 1111 127(next UInt64)*/
var payloadLength = (secondByte & 0x7f); // 0x00~0x7c → その7bit値が長さif (payloadLength === 0x7e) { // 0x7e → 続く16bit値が長さ
console.log('next 16bit is length');payloadLength = dataView.getUint16(dataOffset); dataOffset += 2;
}if (payloadLength === 0x7f) { // 0x7f → 続く64bit値が長さ
console.error('next 64bit is length but not supported');}
コードの一部:mask処理の可変長対応
var maskingArray = new Uint8Array( [dataView.getUint8(dataOffset), dataView.getUint8(dataOffset+1), dataView.getUint8(dataOffset+2),dataView.getUint8(dataOffset+3)
]);dataOffset += 4;
for(payloadIndex = 0, maskOffset=0; payloadIndex < payloadLength; payloadIndex++, maskOffset = (maskOffset + 1) % 4) { // maskを4バイト毎に繰返す
var applicationByte = dataView.getUint8(dataOffset + payloadIndex);
/*** unmask the data* application data XOR mask
*/var unmaskedByte = applicationByte ^ maskingArray[maskOffset];applicationText += String.fromCharCode( unmaskedByte );
}
END
ありがとうございました!