Upload
mganeko
View
9.754
Download
20
Embed Size (px)
DESCRIPTION
WebRTCについて、node学園祭2013で発表した資料です
Citation preview
はじめに• 本資料は以下の情報を参考に、作成しています。
– WebRTC 本家のサイト• http://www.webrtc.org/
– HTML5 ROCKS• http://www.html5rocks.com/en/tutorials/webrtc/basics/
– WebRTC for Beginners Muaz Khan• https://www.webrtc-experiment.com/docs/webrtc-for-beginners.html• https://github.com/muaz-khan/WebRTC-Experiment
– WebRTC Conference 2013 Atlanta• http://www.webrtcworld.com/conference/west/default.aspx• http://
images.tmcnet.com/expo/webrtc-conference/pdfs/WebRTC%20SG13AtlantaRe-CapSml.pdf
– Socket.io 関連• 本家 http://socket.io/ 日本語訳 http://jxck.github.io/socket.io/
– その他の多くのブログ• 本利用に含まれる製品名、商標、ロゴは、各権利者に帰属します。– ® 、 TM 等の表記は省略します
2
自己紹介 : 経験した開発言語仕事で使った言語 趣味で使った言語 勉強だけした言語
C
C++
Visual C++ 1.0 〜 6.0Java
PHP, JavaScriptPython, JavaScript
Objective-CRuby
JavaScript, Node.js
3
New!
昔
今
What’s WebRTC
• Web Real-Time Communication の略称– Web ブラウザ上で、 Real-Time Communication
を可能にするフレームワーク– HTML5 の一部
• 複数の技術の連携で成り立っている
4
質問タイム 1• (1) WebRTC という言葉を聞いたことが
ある人は?
• (2) WebRTC のサンプルに触ったことがある人は?
• (3) WebRTC を使ったコードを書いたことがある人は?
5
WebRTC サンプルの例• apprtc https://apprtc.appspot.com/
• Cube Slam https://www.cubeslam.com/• 紹介記事
– http://t3n.de/news/cube-slam-pong-klon-live-video-473325/– http://japanese.engadget.com/2013/06/12/google-cube-slam-we
brtc-pong/
6
ここ
なぜ WebRTC に注目するのか?通信手段の破壊的進化キャリア型通信
固定電話 携帯電話 (TV 放送)
手段の例
Over The Top
Skype, WebEx (YouTube, USTREAM)
Web ブラウザ型
WebRTC
世界中の人と会話 できる ユーザメリット 世界中の人と無料 /
安価で会話できる 専用アプリ無しで 会話できる
インフラを持つ キャリアが支配市場
キャリアに縛られない 独自の仕組みを提供 する少数のベンダー が参加可能
特別な仕組みは不要 誰でも参加可能
×事業者メリット 限定的な API 提供 連携可能
完全にプログラマブル 部品として利用可能
単独で利用利用方法 ユーザが組み合わ せて利用
製品 / サービスに 組み込んで利用
コールセンター、 EC サイト、情報共有システム、など
利用方法のイメージ■ ユーザが組み合わせて利用 → Word で見積書作成
合計: 568,900
システムが合計を計算、自動で結果を反映する
■ 製品 / サービスに組み込んで利用 → Excel で見積書作成
合計: 568,900
電卓で計算、ワードに手動で転記
WebRTC の構成要素• ユーザーメディア
– カメラ– マイク– 画面キャプチャ
• ストリーム (MediaStream)
• P2P 通信 (RTCPeerConnection)• データ通信 (DataChannel)
• 関連する API 、 HTML 要素– JavaScript (大前提)– Video, Audio– WebScoket– WebAudio API– Canvas– WebGL 9
メディア関連
WebRTC の基本的な動きの説明カメラを使ってみる
10
では、見てみましょう• カメラいろいろ– ローカル取得版 ( Chrome 用)– http://localhost/rtc/camera.html
11
12
← ミラー(左右反転)
← 伸縮
上下反転、回転→
白黒、セピア→
※CSS との組み合わせ
自分撮りカメラ (Chrome)<html> <head><title>WebRTC Camera</title></head> <body> <video id="video1" autoplay="1"></video> </body> <script> var video1 = document.getElementById('video1'); navigator.webkitGetUserMedia({audio:false, video:true}, function(stream) { // success video1.src = window.webkitURL.createObjectURL(stream); }, function(err) { // error console.log(err); } ); </script></html> 13
バリエーションセピアカメラ <video id="video1" autoplay="1" style="-webkit-filter: sepia(80%); "></video>
白黒カメラ <video id="video2" autoplay="1" style="-webkit-filter: grayscale(100%);"></video>
痩せカメラ <video id="video2" autoplay="1" style="-webkit-transform: scaleX(0.5);"></video>
貫禄カメラ <video id="video2" autoplay="1" style="-webkit-transform: scaleX(1.5);"></video>
ミラーカメラ <video id="video1" autoplay="1" ></video>
<video id="video2" autoplay="1" style="-webkit-transform: scaleX(-1);"></video>
逆さカメラ <video id="video2" autoplay="1" style="-webkit-transform: scaleY(-1);"></video>
傾奇カメラ <video id="video6" autoplay="1" style="-webkit-transform: rotate(-30deg);"></video> 14
ミラーカメラの 2 つの video タグの意味
15
1 つの MediaStream を複数の出力先に接続することができる
MediaStream : 出力先 = 1 : n
WebRTC が使えるブラウザ• Windows / Mac
– Chrome 26 〜(カメラ、マイクは OK 、画面キャプチャは要設定)– FireFox 22 〜(カメラ、マイクは OK 、画面キャプチャは NG )– Opera 15 〜 (カメラ、マイクは OK 、画面キャプチャは NG )※JavaScript には方言がある。要注意
Chrome: webkit 〜 , FireFox: moz 〜
• Android– Chrome 29 〜 (カメラ、マイクは OK 、画面キャプチャは NG )
• iOS– Google 曰く、現在開発中で近々ライブラリを出す予定とのこと
• WebRTC Conference 2013 Atlanta での発言。• → いずれ Chrome に乗るのでは? と個人的に期待しています。 16
WebRTC で可能な ( 通信 ) 形態• ローカルのみ– 音声取得→スピーカーで再生– 動画取得→動画再生– 画面キャプチャ取得
– 音声録音– 動画録画– 静止画保存( Canvas 使用)
17
では、見てみましょう• 10 seconds video message ( Chrome 用)– ローカルで動画、音声、静止画を取得– サーバにアップロード– ストリーミング再生– https://localhost:1235/
18
19
CAUTION!!
20
要注意ポイント
ハウリングの発生<html> <head><title>WebRTC Camera</title><head> <body> <video id="video1" autoplay="1"></video> </body> <script> var video1 = document.getElementById('video1'); navigator.webkitGetUserMedia({audio:true, video:true}, function(stream) { // success video1.src = window.webkitURL.createObjectURL(stream); }, function(err) { // error console.log(err); } ); </script></html> 21
ハウリングの原理(ローカル)
22
自分でハウリングを防止
23
1 つの UserMedai( カメラ等)から、複数の MediaStream を取り出すことができる
UserMedia: MediaStream = 1 : n
WebRTC のアクセス権限(パーミッション)
24
通信関連
WebRTC を使って、ビデオチャットを作成1対 1 ・ 1 組限定
1対 1 ・複数組n対 n ・複数組
25
通信について• RTCPeerConnection– 動画、音声などの MediaStream を転送する経路– P2P (Peer to Peer) → ブラウザとブラウザ– UDP/IP を使用
26
RTCPeerConnection RTCPeerConnectionUDP/IP
P2P 通信を始めるには• お互い、相手の IP アドレスを知る必要がある• 使用するポート番号を知る必要がある
– 利用する UDP のポートはダイナミックに割り振られる• RTCPeerConnection の通信を始める前に、何らかの手段でネゴ
シエーション、合意が必要– この手順を”シグナリング: Signaling” と呼びます
27
RTCPeerConnection RTCPeerConnectionUDP/IP
お互いの IP アドレス利用する UDP ポート
P2P 開始前のシグナリング• どちらのブラウザからもわかる、中継役が必要
– →普通はシグナリングサーバーを立てる
• シグナリングのプロトコルは標準化されていない– 独自の方式
• WebSocket 利用 (TCP/IP)• Ajax 利用 (HTTP, HTTPS)
– 既存のプロトコル• SIP(VoIP 用 ) with WebSocket(TCP/IP)• XMPP(IM 用) with WebSocket(TCP/IP)
28
P2P 開始前のシグナリング• どちらのブラウザからもわかる、中継役が必要
– →普通はシグナリングサーバーを立てる
• シグナリングのプロトコルは標準化されていない– 独自の方式
• WebSocket 利用 (TCP/IP)• Ajax 利用 (HTTP, HTTPS)
– 既存のプロトコル• SIP(VoIP 用 ) with WebSocket(TCP/IP)• XMPP(IM 用) with WebSocket(TCP/IP)
29
ようやくNode.js 登場( + socket.io )
シグナリングで交換される情報• Session Description Protocol (SDP)
– セッションが含むメディアの種類(音声、映像)、メディアの形式(コーデック)
– IP アドレス、ポート番号– P2P のデータ転送プロトコル → WebRTC では Secure RTP– 通信で使用する帯域– セッションの属性(名前、識別子、アクティブな時間、など)
• Interactive Connectivity Establishment (ICE)– 通信経路の候補をリストアップするためのプロトコル
• P2P による直接通信• STUN による、 NAT 通過のためのポートマッピング(→ P2P になる)• TRUN による、リレーサーバーを介した中継通信
– ネットワーク的に近い経路(上から順)が選ばれる30
P2P 通信確立までの流れ (1)
31
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
connect()connect connect()
connect
P2P 通信確立までの流れ (1)
32
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
connect()connect connect()
connectcreateOffer()
offer sdp
setLocalDescription(sdp)
send(sdp)send sdp
send sdp onMessage(sdp)
setRemoteDescription(sdp)
P2P 通信確立までの流れ (1)
33
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
connect()connect connect()
connectcreateOffer()
offer sdp
setLocalDescription(sdp)
send(sdp)send sdp
send sdp onMessage(sdp)
setRemoteDescription(sdp)
createAnswer()answer sdp
send sdpsend(sdp)
send sdponMessage(sdp)setRemoteDescription(sdp)
setLocalDescription(sdp)
P2P 通信確立までの流れ (2)
35
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
send(ice) send icesend ice
onMessage(ice)
addIceCandidate(ice)
onIceCandidate(ice)
P2P 通信確立までの流れ (2)
36
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
onIceCandidate(ice)
send(ice) send icesend ice
onMessage(ice)
addIceCandidate(ice)
send ice send(ice)send ice
onMessage(ice)
addIceCandidate(ice)
onIceCandidate(ice)
P2P 通信確立までの流れ (2)
37
PeerConnectionsocket
Application SignalingServer
PeerConnectionsocket
Application
onIceCandidate(ice)
send(ice) send icesend ice
onMessage(ice)
addIceCandidate(ice)
send ice send(ice)send ice
onMessage(ice)
addIceCandidate(ice)
onIceCandidate(ice)
onIceCandidate() : end of candidateonIceCandidate() : end of candidate
P2P stream transfer
WebRTC で可能な ( 通信 ) 形態• 双方向通信 1 to 1– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ
通信(と音声通信)
39
シングルテナントこのサーバで 1 組さま限定
では、見てみましょう• WebRTC 1 to 1 Video Chat (Chrome 用 )– http://localhost/rtc/rtc11.html
–※Simple WebRTC を全面的に参考にしています• http://simplewebrtc.com/
– サーバ側は、 Node.js + socket.io を使っています
40
1 to 1 signaling サーバー (node.js)
41
var io = require('socket.io').listen(9001);
io.sockets.on('connection', function(socket) { socket.on('message', function(message) { socket.broadcast.emit('message', message); });
socket.on('disconnect', function() { socket.broadcast.emit('user disconnected'); });
});
signaling
1 to 1 ブラウザ側 (1) JavaScriptsocket.io 関連
42
<script src="http://localhost:9001/socket.io/socket.io.js"></script><script> var socket = io.connect('http://localhost:9001/'); socket.on('connect', onChannelOpened) .on('message', onMessage);
function onChannelOpened(evt) { }
function onMessage(evt) { if (evt.type === 'offer') { sendAnswer(evt); // receive offer, send answer } else if (evt.type === 'answer') { peerConn.setRemoteDescription(new RTCSessionDescription(evt)); // receive answer } else if (evt.type === 'candidate') { var candidate = new RTCIceCandidate({sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate}); peerConn.addIceCandidate(candidate); // set and send candidate } else if (evt.type === 'bye') { stop(); } }
Signaling(1)
1 to 1 ブラウザ側 (2) JavaScriptconnection handling
43
// 通信開始function connect() { sendOffer();}
// 通信終了function hangUp() { socket.json.send({type: "bye"}); stop();}
function stop() { peerConn.close(); peerConn = null;}
1 to 1 ブラウザ側 (3) JavaScriptSDP offer / answer
44
var peerConn = null; // RTCPeerConnection
function sendOffer() { peerConn = prepareNewConnection(); peerConn.createOffer(function (sessionDescription) { // in case of success peerConn.setLocalDescription(sessionDescription); socket.json.send(sessionDescription); }, function () { // in case of error console.log("Create Offer failed"); }, mediaConstraints);}
function sendAnswer(evt) { peerConn = prepareNewConnection(); peerConn.setRemoteDescription(new RTCSessionDescription(evt)); peerConn.createAnswer(function (sessionDescription) { // in case of success peerConn.setLocalDescription(sessionDescription); socket.json.send(sessionDescription); }, function () { // in case of error console.log("Create Answer failed"); }, mediaConstraints); }
1 to 1 ブラウザ側 (4) JavaScriptRTCPeerConnection
45
function prepareNewConnection() { var pc_config = {"iceServers":[]}; var peer = new webkitRTCPeerConnection(pc_config);
peer.onicecandidate = function (evt) { if (evt.candidate) { socket.json.send({type: "candidate", sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate}); } else { } };
peer.addStream(localStream); peer.addEventListener("addstream", onRemoteStreamAdded, false); peer.addEventListener("removestream", onRemoteStreamRemoved, false)
function onRemoteStreamAdded(event) { remoteVideo.src = window.webkitURL.createObjectURL(event.stream); // set stream to video element }
function onRemoteStreamRemoved(event) { remoteVideo.src = ""; // clear stream of video element }
return peer; }
Signaling(2)
1 to 1 ブラウザ側 (5) JavaScriptVideo handling
46
var localVideo = document.getElementById('local-video');var remoteVideo = document.getElementById('remote-video');var localStream = null;
function startVideo() { navigator.webkitGetUserMedia({video: true, audio: true}, successCallback, errorCallback); function successCallback(stream) { localStream = stream; localVideo.src = window.webkitURL.createObjectURL(stream); localVideo.play(); }
function errorCallback(error) { console.error('An error occurred: [CODE ' + error.code + ']'); return; }}
function stopVideo() { localVideo.src = ""; localStream.stop();}
質問タイム 2• Socket.io とは http://jxck.github.io/socket.io/
– Socket.IO は複数の通信メカニズムを抽象化する• 全てのブラウザ、デバイスでリアルタイムアプリを実装可能にする• とても手軽にリアルタイムなアプリを 100% JavaScript で作成可能
– 複数のトランスポートをサポート(以下、優先順に)• 'websocket' , 'flashsocket' , 'htmlfile' , 'xhr-polling' , 'jsonp-polling‘
• ではなぜ、クライアントから接続するときに、こう書くの?– var socket = io.connect('http://localhost:9001/');
• WebScoket で接続したいなら、これでも良くね?– io.connect('localhost:9001/');
47
質問タイム 2 回答編• Socket.io のプロトコル– https://github.com/Jxck/socket.io-spec– Socket.io のクライアントは最初に接続に利用する通信
方法を決定します– Socket.IO の接続の最初には、シンプルな HTTP ハンド
シェイクが実行されます (※または HTTPS )– ハンドシェイクが成功すると、以下の結果がクライアン
トに送られます• 通信が接続を開始する時に渡される session id• ハードビートの送信が期待される間隔の秒数 (heartbeat timeout)• 通信コネクションが応答しなくなり、ソケットが閉じられたと判断し
て 通信コネクションを閉じるまでの秒数 (close timeout)
48
WebRTC で可能な ( 通信 ) 形態• 双方向通信– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ
通信(と音声通信)
49
マルチテナント化(複数会議室)
Socket.io の room 機能 (join() / leave()) を利用
1 to 1 multi room ブラウザ側 JavaScript
50
function onChannelOpened(evt) { console.log('Channel opened.'); channelReady = true;
var roomname = getRoomName(); socket.emit('enter', roomname);}
function getRoomName() { // たとえば、 URL に ?roomname とする var url = document.location.href; var args = url.split('?'); if (args.length > 1) { var room = args[1]; if (room != "") { return room; } } return "_defaultroom";}
1 to 1 multi room サーバー (node.js)
51
socket.on('enter', function(roomname) { socket.set('roomname', roomname); socket.join(roomname);});
function emitMessage(type, message) { var roomname; socket.get('roomname', function(err, _room) { roomname = _room; });
if (roomname) { socket.broadcast.to(roomname).emit(type, message); } else { socket.broadcast.emit(type, message); }}
socket.on('message', function(message) { emitMessage('message', message);});
socket.on('disconnect', function() { emitMessage('user disconnected');});
CAUTION!!
52
はまりポイント 1
ICE のやり取り(理想ケース)
53
User A User B
send offer sdp
setRemoteDescription(sdp)
setRemoteDescription(sdp)send answer sdp
send ice
addIceCandidate(ice)send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)send ice
addIceCandidate(ice)
end of candidate end of candidateP2P stream transfer
createNewPeercreateNewPeer
Ice を交互に送信
ICE のやり取り(想定していたケース)
54
User A User B
send offer sdp
setRemoteDescription(sdp)
setRemoteDescription(sdp)send answer sdp
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
end of candidate
end of candidate
P2P stream transfer
createNewPeercreateNewPeer
Ice を片方が連続して送信
ICE のやり取り(想定外のケース)
55
User A User Bsend offer sdp
setRemoteDescription(sdp)
setRemoteDescription(sdp)
send answer sdp
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)
end of candidate
end of candidate
P2P stream transfer
createNewPeercreateNewPeer
Answer SDPを生成前に、Ice を受け取ることも可能
※エラーとして弾いていたら嵌った…約1ヶ月
WebRTC で可能な ( 通信 ) 形態• 双方向通信
– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ通信(と
音声通信)
– n to n の音声通信– n to n の映像通信– n to n のスクリーンキャプチャ
通信(と音声通信)56
1 会議室に複数人、かつ複数会議室
では、見てみましょう• WebRTC 4 people Video Chat (Chrome 用 )– http://localhost/rtc/rtc4.html
57
CAUTION!!
58
はまりポイント 2
1対 1 の流れ
59
User A User B
send offer sdp (broadcast)
setRemoteDescription(sdp)
setRemoteDescription(sdp)send answer sdp (broadcast)
send ice
addIceCandidate(ice)send ice
addIceCandidate(ice)
send ice
addIceCandidate(ice)send ice
addIceCandidate(ice)
end of candidate end of candidateP2P stream transfer
createNewPeercreateNewPeer
n対 n の流れ: SDP 部分で衝突
60
User A User B
send offer sdp (broadcast)
setRemoteDescription(sdp)
setRemoteDescription(sdp)
send answer sdp
User C
setRemoteDescription(sdp)
send offer sdp (broadcast)
send answer sdp
createNewPeer
createNewPeer createNewPeer
no peer!→ createNewPeer
setRemoteDescription(sdp)
send offer sdp
corrupt!
OKOK OK
※この流れを理解するのに、苦労約 2 ヶ月
n対 n の流れ: Broadcast を分離
61
User A User B
send “response”
setRemoteDescription(sdp)
setRemoteDescription(sdp)
send answer sdp
User C
setRemoteDescription(sdp)
send “call” (broadcast)
send answer sdp
createNewPeer
createNewPeer
createNewPeer
setRemoteDescription(sdp)
send offer sdp
send offer sdp
OK
OK
send “response”
createNewPeer
OK
setRemoteDescription(sdp)OK
send “call” (broadcast)
4 people ブラウザ側 (1) JavaScript
62
function call() { if (! isLocalStreamStarted()) return; socket.json.send({type: "call"});}
function onMessage(evt) { var id = evt.from; var target = evt.sendto; var conn = getConnection(id);
if (evt.type === 'call') { if (! isLocalStreamStarted()) return; if (conn) return; // already connected
if (isConnectPossible()) { socket.json.send({type: "response", sendto: id }); } else { console.warn('max connections. so ignore call'); } } else if (evt.type === 'response') { sendOffer(id); return; }}
4 people ブラウザ側 (3) JavaScript
63
function sendOffer(id) { var conn = getConnection(id); if (!conn) { conn = prepareNewConnection(id); }
conn.peerconnection.createOffer(function (sessionDescription) { // in case of success conn.iceReady = true; conn.peerconnection.setLocalDescription(sessionDescription); sessionDescription.sendto = conn.id; socket.json.send(sessionDescription); }, function () { // in case of error console.log("Create Offer failed"); }, mediaConstraints); conn.iceReady = true;}
4 people ブラウザ側 (3) JavaScript
64
function sendAnswer(id, evt) { var conn = getConnection(id); if (! conn) { conn = prepareNewConnection(id); }
conn.peerconnection.setRemoteDescription(new RTCSessionDescription(evt)); conn.peerconnection.createAnswer(function (sessionDescription) { // in case of success conn.iceReady = true; conn.peerconnection.setLocalDescription(sessionDescription); sessionDescription.sendto = id; socket.json.send(sessionDescription); }, function () { // in case of error console.log("Create Answer failed"); }, mediaConstraints); conn.iceReady = true;}
4 people ブラウザ側 (4) JavaScript
65
function prepareNewConnection(id) { var pc_config = {"iceServers":[]}; var peer = null; peer = new webkitRTCPeerConnection(pc_config); var conn = new Connection(); conn.id = id; conn.peerconnection = peer; peer.id = id; addConnection(id, conn);
// send any ice candidates to the other peer peer.onicecandidate = function (evt) { if (evt.candidate) { socket.json.send({type: "candidate", sendto: conn.id, sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate}); } else { conn.established = true; // end of candidates } }; …
4 people ブラウザ側 (5) JavaScript
66
var MAX_CONNECTION_COUNT = 3;var connections = {}; // Connection hashfunction Connection() { // Connection Class var self = this; var id = ""; // socket.id of partner var peerconnection = null; // RTCPeerConnection instance var established = false; // is Already Established var iceReady = false;}
function getConnection(id) { var con = null; con = connections[id]; return con;}
function addConnection(id, connection) { connections[id] = connection;}
getConnectionCount(), isConnectPossible(), deleteConnection(id), …, etc.
4 people サーバー (node.js)
67
socket.on('message', function(message) { // set message sender message.from = socket.id;
// send to specific target var target = message.sendto; if (target) { io.sockets.socket(target).emit('message', message); return; }
// broadcast in room emitMessage('message', message);});
WebRTC で可能な ( 通信 ) 形態 (2)
• 片方向通信– 1 → 1 の音声通信– 1 → 1 の映像通信– 1 → 1 のスクリーンキャプチャ
通信(と音声通信)
– 1 → n の音声通信– 1 → n の映像通信– 1 → n のスクリーンキャプチャ
通信(と音声通信)68
P2P型のメリット、デメリット• メリット
– サーバを仲介しないので、オーバーヘッドがない
– 高スペックのサーバー不要• 社内では、 Raspberry Pi で稼働中
• デメリット– 通信相手が多いと組み合わ
せ爆発で通信経路が増える• 2 人 → 1 経路• 3 人 → 3 経路• 4 人 → 6 経路• 5 人 → 10 経路• 6 人 → 15 経路
69
P2P型
サーバー型
P2P型 4 人サーバー型 4 人
70
ちなみに、 node.js のビルドには一晩かかりました…
やっかいな問題 1
71
直接 P2P の経路(同一ネットワーク内)
72
動的 UDP ポート (50000 〜 65535)
STUN を使った、ポート情報交換その後の P2P の経路( NAT越え)
73
TURN サーバによるリレー中継経路( Firewall抜け)
74
TURN サーバによるリレー中継経路( Firewall抜け)
75
まだ動作せず
Firewall越え、鋭意調査中
質問タイム 3• 誰か、 TURN サーバーを自分で稼働させたことあります
か?– http://code.google.com/p/rfc5766-turn-server/
• そのとき、 Firewall, proxy 等の設定はどうすれば良いの?
76
どなたか、知ってたら教えてください!!
やっかいな問題 2
77
自分でハウリングを防止
78
相手とのハウリングの抑止?
79自動ミュートや、特定音域減衰などの音声処理が必要 → JavaScript では不可能??
質問タイム 4
• JavaScript でのやり方、ライブラリ知りませんか?– 音声波形の減算 or 位相反転+加算– ノイズキャンセリングヘッドホンみたいなことがやりた
い
80
どなたか、知ってたら教えてください!!
まとめ• WebRTC はパワフル
– カメラ、マイク、画面キャプチャなど、ブラウザの能力を大きく拡大する
– HTML5 の他の機能との相乗効果• Canvas, CSS, WebAudio API, WebGL
• WebRTC はフレキシブル– ローカルのみ、 1対 1 、 n対 n– 双方向、片方向(ブロードキャスト型)
• WebRTC は破壊的技術– だれでも市場 / アプリに参入できる
• WebRTC はプログラマブル– 自分たちの製品 / サービスに組み込める
84
WebRTC をどんな風に使うかは、
みなさんのアイデア次第です!
85
今日のソースはこちらhttps://github.com/mganeko/mgrtc
参考資料はこちらhttp://www.slideshare.net/mganeko/2013-web-rtctechcross
質問、情報、アイデアは → [email protected]
おまけ: socket.io 豆知識• サーバー側で、クライアントの情報を取得• IP アドレス
ip = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address.address;
• トランスポート (websocket, ajax …)tr = io.transports[socket.id].name;
86
Thank you!
88
END