73
WebRTC Meetup #1 ハハハハハ ハハハハハハハハハハ ハハハハハハ

WebRTC meetup Tokyo 1

  • Upload
    mganeko

  • View
    2.561

  • Download
    2

Embed Size (px)

DESCRIPTION

WebRTC meetup 1のハンズオンの資料です。 シグナリングについてだけ、話します。 次のサイト記事をベースにしています。 http://html5experts.jp/mganeko/5181/ http://html5experts.jp/mganeko/5349/

Citation preview

Page 1: WebRTC meetup  Tokyo 1

WebRTC Meetup #1ハンズオンインフォコム株式会社

がねこまさし

Page 2: WebRTC meetup  Tokyo 1

今日のテーマ• シグナリングの話だけ、します– Peer-to-Peer がつながる前の話です

• UserMedia の話はしません。ごめんなさい• STUN/TURN 、 DataChannel の話もありませ

Page 3: WebRTC meetup  Tokyo 1

元ネタ• HTML5Experts.jp に書いた記事がベース– WebRTC に触ってみたいエンジニア必見!手動

で WebRTC 通信をつなげてみよう• http://html5experts.jp/mganeko/5181/

– WebRTC 初心者でも簡単にできる! Node.js で仲介(シグナリング)を作ってみよう• http://html5experts.jp/mganeko/5349/

• すでに試した方は同じ話です。ごめんなさい

Page 4: WebRTC meetup  Tokyo 1

WebRTC の通信はどうなっているの?

• 映像や音声などリアルタイムに取得されたデータを、ブラウザ間で送受信

• RTCPeerConnection が行う– Peer-to-Peer の通信

• ブラウザとブラウザの間で直接通信する

– UDP/IP を使用• TCP/IP のようにパケットの到着は保障しない• オーバーヘッドが少ない• 通信のリアルタイム性を重視• UDP のポート番号は動的に割り振られる( 49152 ~

65535 )

Page 5: WebRTC meetup  Tokyo 1

Peer-to-Peer 通信が確立するまで (1)

• Peer-to-Peer を行うには– 相手の IP アドレスを知る必要がある– 動的に割り振られる UDP のポート番号も知る必要が

ある

• Session Description Protocol (SDP) の交換– WebRTC 専用ではなく、 VoIP 等で利用されている– 各エンドポイント(ブラウザ)の情報を示す。例えば、

• メディアの種類(音声、映像)、メディアの形式(コーデック)

• データ転送プロトコル → WebRTC では Secure RTP• 通信で使用する帯域

Page 6: WebRTC meetup  Tokyo 1

Peer-to-Peer 通信が確立するまで (2)

• Interactive Connectivity Establishment (ICE) の交換– WebRTC 専用ではなく、 P2P で利用されている– 途中経路の情報を示す。複数ある場合も多い

• P2P による直接通信• STUN による、 NAT 通過のためのポートマッピング

– → 最終的には P2P になる• TURN による、リレーサーバーを介した中継通信

SDP SDPICE

Page 7: WebRTC meetup  Tokyo 1

手動編

Page 8: WebRTC meetup  Tokyo 1

ということで、やってみましょう• WebRTC に触ってみたいエンジニア必見!手動で WebRTC

通信をつなげてみよう– http://html5experts.jp/mganeko/5181/– 一番下の方の「手動シグナリングの改良版ソース (2014年 4月

21日追加)」のソース• 手動シグナリングは操作が面倒• 必要なテキストを自動で選択するように

DEMO

Page 9: WebRTC meetup  Tokyo 1

ということで、やってみましょう• WebRTC に触ってみたいエンジニア必見!手動で WebRTC

通信をつなげてみよう– http://html5experts.jp/mganeko/5181/– 一番下の方の「手動シグナリングの改良版ソース (2014 年 4 月

21 日追加)」のソース• みなさんも、一緒にやってみましょう

– ソースを自分のマシンにコピーして、 Chrome でアクセス– 自前の Web サーバーが必要です– ※file:// ~ ではなく、 http:// ~ の必要があります

• ※ 手動シグナリングは、なぜか動作が不安定– 端末によっては通信が確立しないケースあり

• 今のところ成功は 4 台 /7 台– 原因がさっぱりわからない … 情報求む!

• もし心当たりがあったら教えていただけると助かります

Page 10: WebRTC meetup  Tokyo 1

カメラ (UserMedia) を取得

Page 11: WebRTC meetup  Tokyo 1

SDP のやりとり

11

PeerConnectionApplication PeerConnection Application

new

Page 12: WebRTC meetup  Tokyo 1

new PeerConnection()

function prepareNewConnection() { var pc_config = {"iceServers":[]}; // info of STUN/TURN var peer = null; peer = new webkitRTCPeerConnection(pc_config); peer.onicecandidate = function (evt) { … } peer.addStream(localStream); peer.addEventListener("addstream", onRemoteStreamAdded, false); peer.addEventListener("removestream", onRemoteStreamRemoved, false); return peer;}

Page 13: WebRTC meetup  Tokyo 1

SDP のやりとり

13

PeerConnectionApplication PeerConnection Application

new

createOffer()

setLocalDescription(sdp)

offer sdp

Page 14: WebRTC meetup  Tokyo 1

sendOffer()

function sendOffer() { peerConnection = prepareNewConnection(); peerConnection.createOffer( function (sessionDescription) { // in case of success peerConnection.setLocalDescription(sessionDescription); sendSDP(sessionDescription); // show in textarea }, function () { // in case of error }, mediaConstraints);}

Page 15: WebRTC meetup  Tokyo 1

offer SDP  を生成

Page 16: WebRTC meetup  Tokyo 1

SDP のやりとり

16

PeerConnectionApplication PeerConnection Application

new

createOffer()

setLocalDescription(sdp)

offer sdp

sdp Copy & Paste

setRemoteDescription(sdp)

new

Page 17: WebRTC meetup  Tokyo 1

setOffer()

function setOffer(evt) { peerConnection = prepareNewConnection(); peerConnection.setRemoteDescription( new RTCSessionDescription(evt) );}

Page 18: WebRTC meetup  Tokyo 1

SDP を手動でコピー( offer )

Page 19: WebRTC meetup  Tokyo 1

SDP のやりとり

19

PeerConnectionApplication PeerConnection Application

new

createOffer()

setLocalDescription(sdp)

offer sdp

sdp Copy & Paste

createAnswer()

answer sdpsetLocalDescription(sdp)

setRemoteDescription(sdp)

new

Page 20: WebRTC meetup  Tokyo 1

sendAnswer()

function sendAnswer(evt) { peerConnection.createAnswer( function (sessionDescription) { // in case of success peerConnection.setLocalDescription(sessionDescription); sendSDP(sessionDescription); // show in textarea }, function () { // in case of error }, mediaConstraints);}

Page 21: WebRTC meetup  Tokyo 1

answer SDP を生成

Page 22: WebRTC meetup  Tokyo 1

SDP のやりとり

22

PeerConnectionApplication PeerConnection Application

new

createOffer()

setLocalDescription(sdp)

offer sdp

sdp Copy & Paste

createAnswer()

answer sdpsetLocalDescription(sdp)

setRemoteDescription(sdp)

new

sdp Copy & Paste

setRemoteDescription(sdp)

Page 23: WebRTC meetup  Tokyo 1

setAnswer()

function setAnswer(evt) { peerConnection.setRemoteDescription( new RTCSessionDescription(evt) );}

Page 24: WebRTC meetup  Tokyo 1

SDP を手動でコピー( answer )

Page 25: WebRTC meetup  Tokyo 1

SDP のやりとり(全体)

25

PeerConnectionApplication PeerConnection Application

new

createOffer()

setLocalDescription(sdp)

offer sdp

sdp Copy & Paste

createAnswer()

answer sdpsetLocalDescription(sdp)

setRemoteDescription(sdp)

new

sdp Copy & Paste

setRemoteDescription(sdp)

Page 26: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

26

PeerConnectionApplication PeerConnection Application

onIceCandidate(ice)

Page 27: WebRTC meetup  Tokyo 1

peer.onIceCandidate()function prepareNewConnection() { var pc_config = {"iceServers":[]}; var peer = null; peer = new webkitRTCPeerConnection(pc_config); peer.onicecandidate = function (evt) { if (evt.candidate) { sendCandidate({ // show in text area type: "candidate", sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate }); } else { // End of candidates. } } … return peer;}

Page 28: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

28

PeerConnectionApplication PeerConnection Application

addIceCandidate(ice)

onIceCandidate(ice)

ice Copy & Paste

Page 29: WebRTC meetup  Tokyo 1

addIceCandidate()

function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate);}

Page 30: WebRTC meetup  Tokyo 1

ICE を手動でコピー

Page 31: WebRTC meetup  Tokyo 1

ICE を手動でコピー

Page 32: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

32

PeerConnectionApplication PeerConnection Application

onIceCandidate(ice)

addIceCandidate(ice)

addIceCandidate(ice)

onIceCandidate(ice)

ice Copy & Paste

ice Copy & Paste

Page 33: WebRTC meetup  Tokyo 1

peer.onIceCandidate() ※同じfunction prepareNewConnection() { var pc_config = {"iceServers":[]}; var peer = null; peer = new webkitRTCPeerConnection(pc_config); peer.onicecandidate = function (evt) { if (evt.candidate) { sendCandidate({ // show in text area type: "candidate", sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate }); } else { // End of candidates. } } … return peer;}

Page 34: WebRTC meetup  Tokyo 1

addIceCandidate() ※同じfunction onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate);}

Page 35: WebRTC meetup  Tokyo 1

ICE を手動でコピー(帰り)

Page 36: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

36

PeerConnectionApplication PeerConnection Application

onIceCandidate(ice)

addIceCandidate(ice)

addIceCandidate(ice)

onIceCandidate(ice)

onIceCandidate() : end of candidate onIceCandidate() : end of candidate

P2P stream transfer

ice Copy & Paste

ice Copy & Paste

Page 37: WebRTC meetup  Tokyo 1

ICE を手動でコピー(帰り)

Page 38: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり (全体)

38

PeerConnectionApplication PeerConnection Application

onIceCandidate(ice)

addIceCandidate(ice)

addIceCandidate(ice)

onIceCandidate(ice)

onIceCandidate() : end of candidate onIceCandidate() : end of candidate

P2P stream transfer

ice Copy & Paste

ice Copy & Paste

Page 39: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり(今回)

39

PeerConnectionApplication PeerConnection Application

onIceCandidate(ice)

addIceCandidate(ice)

addIceCandidate(ice)

onIceCandidate(ice)

P2P stream transfer

ice, ice, ice, ice Copy & Paste

ice, ice, ice, ice Copy & Paste

Page 40: WebRTC meetup  Tokyo 1

シグナリングサーバー編

Page 41: WebRTC meetup  Tokyo 1

シグナリングサーバーはどうして必要なの?

• シグナリングの過程で、情報を受け渡したい– お互いの IP アドレス– お互いのポート番号

• この段階ではお互い IP アドレスを知らない– 直接やりとりでない

• 仲介役となるシグナリングサーバーが必要– どちらブラウザもサーバーの IP アドレスを知っ

ていることが前提

Page 42: WebRTC meetup  Tokyo 1

Peer-to-Peer 通信の開始前に、普通のサーバー / クライアント型の通信が行われる

Page 43: WebRTC meetup  Tokyo 1

準備• Node.js をインストール– http://nodejs.jp/nodejs.org_ja/docs/v0.10/

• socket.io もインストール$ sudo npm install socket.io

Page 44: WebRTC meetup  Tokyo 1

シグナリングサーバー• WebRTC…Node.js で仲介(シグナリング)を作ってみよう

– http://html5experts.jp/mganeko/5349/

• 例えば、 signaling.js に記述、起動$ node signaling.js

var port = 9001; // as you likevar io = require('socket.io').listen(port);console.log((new Date()) + " Server is listening on port " + port); 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'); });});

Page 45: WebRTC meetup  Tokyo 1

動かしてみます

DEMO

Page 46: WebRTC meetup  Tokyo 1

みなさんも、やってみてください

• スタートは、先ほどの手動用 HTML–その HTML/JavaScript を修正

• やることは、 HTML5Experts.jp の記事の内容– WebRTC 初心者でも簡単にできる! Node.js で仲

介(シグナリング)を作ってみよう– http://html5experts.jp/mganeko/5349/

• まず、 socket.io.js を読み込みます<script src="http://localhost:9001/socket.io/socket.io.js"></script>

Page 47: WebRTC meetup  Tokyo 1

ソケットの確立

49

PeerConnectionsocket

Application SignalingServer

PeerConnectionsocket

Application

connect()connect connect()

connect

Page 48: WebRTC meetup  Tokyo 1

connect()

var socketReady = false;var port = 9001;var socket = io.connect('http://localhost:' + port + '/');

// socket: channel connectedsocket.on('connect', onOpened) .on('message', onMessage); function onOpened(evt) { console.log('socket opened.'); socketReady = true;}

Page 49: WebRTC meetup  Tokyo 1

メッセージ処理// socket: accept connection requestfunction onMessage(evt) { if (evt.type === 'offer') { onOffer(evt); } else if (evt.type === 'answer' && peerStarted) { onAnswer(evt); } else if (evt.type === 'candidate' && peerStarted) { onCandidate(evt); } else if (evt.type === 'user dissconnected' && peerStarted) { stop(); }}

Page 50: WebRTC meetup  Tokyo 1

SDP のやりとり

52

PeerConnectionsocket

Application SignalingServer

PeerConnectionsocket

Application

connect()connect connect()

connectcreateOffer()

offer sdp

setLocalDescription(sdp)

send(sdp)send sdp

send sdp onMessage(sdp)

setRemoteDescription(sdp)

Page 51: WebRTC meetup  Tokyo 1

sendSDP()function sendOffer() { peerConnection = prepareNewConnection(); peerConnection.createOffer( function (sessionDescription) { // in case of success peerConnection.setLocalDescription(sessionDescription); sendSDP(sessionDescription); }, function () { // in case of error }, mediaConstraints);}

function sendSDP(sdp) { // send via socket socket.json.send(sdp);}

Page 52: WebRTC meetup  Tokyo 1

onMessage()

function onMessage(evt) { if (evt.type === 'offer') { onOffer(evt); } else if (evt.type === 'answer' && peerStarted) { onAnswer(evt); } else if (evt.type === 'candidate' && peerStarted) { onCandidate(evt); } else if (evt.type === 'user dissconnected' && peerStarted) { stop(); }}

Page 53: WebRTC meetup  Tokyo 1

onOffer(), setOffer()

function onOffer(evt) { setOffer(evt); sendAnswer(evt);}

function setOffer(evt) { peerConnection = prepareNewConnection(); peerConnection.setRemoteDescription( new RTCSessionDescription(evt) );}

Page 54: WebRTC meetup  Tokyo 1

SDP のやりとり

56

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)

Page 55: WebRTC meetup  Tokyo 1

sendSDP()

function sendAnswer(evt) { peerConnection.createAnswer( function (sessionDescription) { // in case of success peerConnection.setLocalDescription(sessionDescription); sendSDP(sessionDescription); }, function () { // in case of error }, mediaConstraints);}

function sendSDP(sdp) { // send via socket socket.json.send(sdp);}

Page 56: WebRTC meetup  Tokyo 1

onMessage()

function onMessage(evt) { if (evt.type === 'offer') { onOffer(evt); } else if (evt.type === 'answer' && peerStarted) { onAnswer(evt); } else if (evt.type === 'candidate' && peerStarted) { onCandidate(evt); } else if (evt.type === 'user dissconnected' && peerStarted) { stop(); }}

Page 57: WebRTC meetup  Tokyo 1

onAnswer(), setAnswer ()

function onAnswer(evt) { setAnswer(evt);}

function setAnswer(evt) { peerConnection.setRemoteDescription( new RTCSessionDescription(evt) );}

Page 58: WebRTC meetup  Tokyo 1

SDP のやりとり(全体)

60

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)

Page 59: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

61

PeerConnectionsocket

Application SignalingServer

PeerConnectionsocket

Application

send(ice) send icesend ice

onMessage(ice)

addIceCandidate(ice)

onIceCandidate(ice)

Page 60: WebRTC meetup  Tokyo 1

peer.onIceCandidate()function prepareNewConnection() { var pc_config = {"iceServers":[]}; var peer = null; peer = new webkitRTCPeerConnection(pc_config); peer.onicecandidate = function (evt) { if (evt.candidate) { sendCandidate({ type: "candidate", sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate }); } else { // End of candidates. } } … return peer;}

Page 61: WebRTC meetup  Tokyo 1

sendCandidate()

function sendCandidate(candidate) { // send via socket socket.json.send(candidate);}

Page 62: WebRTC meetup  Tokyo 1

onMessage()

function onMessage(evt) { if (evt.type === 'offer') { onOffer(evt); } else if (evt.type === 'answer' && peerStarted) { onAnswer(evt); } else if (evt.type === 'candidate' && peerStarted) { onCandidate(evt); } else if (evt.type === 'user dissconnected' && peerStarted) { stop(); }}

Page 63: WebRTC meetup  Tokyo 1

onCandidate(), addIceCandidate()

function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate);}

Page 64: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

66

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)

Page 65: WebRTC meetup  Tokyo 1

peer.onIceCandidate() ※同じfunction prepareNewConnection() { var pc_config = {"iceServers":[]}; var peer = null; peer = new webkitRTCPeerConnection(pc_config); peer.onicecandidate = function (evt) { if (evt.candidate) { sendCandidate({ type: "candidate", sdpMLineIndex: evt.candidate.sdpMLineIndex, sdpMid: evt.candidate.sdpMid, candidate: evt.candidate.candidate }); } else { // End of candidates. } } … return peer;}

Page 66: WebRTC meetup  Tokyo 1

onMessage() ※同じfunction onMessage(evt) { if (evt.type === 'offer') { onOffer(evt); } else if (evt.type === 'answer' && peerStarted) { onAnswer(evt); } else if (evt.type === 'candidate' && peerStarted) { onCandidate(evt); } else if (evt.type === 'user dissconnected' && peerStarted) { stop(); }}

Page 67: WebRTC meetup  Tokyo 1

onCandidate(), addIceCandidate() ※同じfunction onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate);}

Page 68: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり

70

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

Page 69: WebRTC meetup  Tokyo 1

ICE Candidate のやりとり(全体)

71

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

Page 70: WebRTC meetup  Tokyo 1

Peer-to-Peer 通信確立

Page 71: WebRTC meetup  Tokyo 1

なぜ WebRTC に注目するのか?通信手段の破壊的進化キャリア型通信

固定電話 携帯電話 (TV 放送)

手段の例

Over The Top

Skype, WebEx (YouTube, USTREAM)

Web ブラウザ型

WebRTC

世界中の人と会話 できる ユーザメリット 世界中の人と無料 /

安価で会話できる 専用アプリ無しで 会話できる

インフラを持つ キャリアが支配市場

キャリアに縛られない 独自の仕組みを提供 する少数のベンダー が参加可能

特別な仕組みは不要 誰でも参加可能

×事業者メリット 限定的な API 提供 連携可能

完全にプログラマブル 部品として利用可能

単独で利用利用方法 ユーザが組み合わ せて利用

製品 / サービスに 組み込んで利用

コールセンター、 EC サイト、情報共有システム、など

Page 72: WebRTC meetup  Tokyo 1

WebRTC をどんな風に使うかは、

みなさんのアイデア次第です!

74

Page 73: WebRTC meetup  Tokyo 1

Thank you!

75

END