WebRTC meetup Tokyo 1

3,400 views

Published on

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

Published in: Internet
1 Comment
11 Likes
Statistics
Notes
  • 当日の模様はこちらです。
    https://www.youtube.com/watch?v=fFkblIemBS0
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
3,400
On SlideShare
0
From Embeds
0
Number of Embeds
258
Actions
Shares
0
Downloads
29
Comments
1
Likes
11
Embeds 0
No embeds

No notes for slide

WebRTC meetup Tokyo 1

  1. 1. WebRTC Meetup #1 ハンズオン インフォコム株式会社 がねこまさし
  2. 2. 今日のテーマ • シグナリングの話だけ、します – Peer-to-Peer がつながる前の話です • UserMediaの話はしません。ごめんなさい • STUN/TURN、DataChannelの話もありません
  3. 3. 元ネタ • HTML5Experts.jp に書いた記事がベース – WebRTCに触ってみたいエンジニア必見!手動で WebRTC通信をつなげてみよう • http://html5experts.jp/mganeko/5181/ – WebRTC初心者でも簡単にできる!Node.jsで仲 介(シグナリング)を作ってみよう • http://html5experts.jp/mganeko/5349/ • すでに試した方は同じ話です。ごめんなさい
  4. 4. WebRTCの通信はどうなっているの? • 映像や音声などリアルタイムに取得されたデー タを、ブラウザ間で送受信 • RTCPeerConnectionが行う – Peer-to-Peerの通信 • ブラウザとブラウザの間で直接通信する – UDP/IPを使用 • TCP/IPのようにパケットの到着は保障しない • オーバーヘッドが少ない • 通信のリアルタイム性を重視 • UDPのポート番号は動的に割り振られる(49152 ~ 65535)
  5. 5. Peer-to-Peer通信が確立するまで(1) • Peer-to-Peerを行うには – 相手のIPアドレスを知る必要がある – 動的に割り振られるUDPのポート番号も知る必要が ある • Session Description Protocol (SDP)の交換 – WebRTC専用ではなく、VoIP等で利用されている – 各エンドポイント(ブラウザ)の情報を示す。例えば、 • メディアの種類(音声、映像)、メディアの形式(コーデック) • データ転送プロトコル → WebRTCでは Secure RTP • 通信で使用する帯域
  6. 6. Peer-to-Peer通信が確立するまで(2) • Interactive Connectivity Establishment (ICE)の交換 – WebRTC専用ではなく、P2Pで利用されている – 途中経路の情報を示す。複数ある場合も多い • P2Pによる直接通信 • STUNによる、NAT通過のためのポートマッピング – → 最終的にはP2Pになる • TURNによる、リレーサーバーを介した中継通信 SDP SDPICE
  7. 7. 手動編
  8. 8. ということで、やってみましょう • WebRTCに触ってみたいエンジニア必見!手動でWebRTC通 信をつなげてみよう – http://html5experts.jp/mganeko/5181/ – 一番下の方の「手動シグナリングの改良版ソース(2014年4月21日追 加)」のソース • 手動シグナリングは操作が面倒 • 必要なテキストを自動で選択するように DEMO
  9. 9. ということで、やってみましょう • WebRTCに触ってみたいエンジニア必見!手動でWebRTC通 信をつなげてみよう – http://html5experts.jp/mganeko/5181/ – 一番下の方の「手動シグナリングの改良版ソース(2014年4月21日追 加)」のソース • みなさんも、一緒にやってみましょう – ソースを自分のマシンにコピーして、Chromeでアクセス – 自前のWebサーバーが必要です – ※file:// ~ ではなく、 http:// ~ の必要があります • ※手動シグナリングは、なぜか動作が不安定 – 端末によっては通信が確立しないケースあり • 今のところ成功は4台/7台 – 原因がさっぱりわからない … 情報求む! • もし心当たりがあったら教えていただけると助かります
  10. 10. カメラ(UserMedia)を取得
  11. 11. SDPのやりとり 11 PeerConnectionApplication PeerConnection Application new
  12. 12. 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; }
  13. 13. SDPのやりとり 13 PeerConnectionApplication PeerConnection Application new createOffer() setLocalDescription(sdp) offer sdp
  14. 14. 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); }
  15. 15. offer SDP を生成
  16. 16. SDPのやりとり 16 PeerConnectionApplication PeerConnection Application new createOffer() setLocalDescription(sdp) offer sdp sdp Copy & Paste setRemoteDescription(sdp) new
  17. 17. setOffer() function setOffer(evt) { peerConnection = prepareNewConnection(); peerConnection.setRemoteDescription( new RTCSessionDescription(evt) ); }
  18. 18. SDPを手動でコピー(offer)
  19. 19. SDPのやりとり 19 PeerConnectionApplication PeerConnection Application new createOffer() setLocalDescription(sdp) offer sdp sdp Copy & Paste createAnswer() answer sdp setLocalDescription(sdp) setRemoteDescription(sdp) new
  20. 20. 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); }
  21. 21. answer SDPを生成
  22. 22. SDPのやりとり 22 PeerConnectionApplication PeerConnection Application new createOffer() setLocalDescription(sdp) offer sdp sdp Copy & Paste createAnswer() answer sdp setLocalDescription(sdp) setRemoteDescription(sdp) new sdp Copy & Paste setRemoteDescription(sdp)
  23. 23. setAnswer() function setAnswer(evt) { peerConnection.setRemoteDescription( new RTCSessionDescription(evt) ); }
  24. 24. SDPを手動でコピー(answer)
  25. 25. SDPのやりとり(全体) 25 PeerConnectionApplication PeerConnection Application new createOffer() setLocalDescription(sdp) offer sdp sdp Copy & Paste createAnswer() answer sdp setLocalDescription(sdp) setRemoteDescription(sdp) new sdp Copy & Paste setRemoteDescription(sdp)
  26. 26. ICE Candidateのやりとり 26 PeerConnectionApplication PeerConnection Application onIceCandidate(ice)
  27. 27. 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; }
  28. 28. ICE Candidateのやりとり 28 PeerConnectionApplication PeerConnection Application addIceCandidate(ice) onIceCandidate(ice) ice Copy & Paste
  29. 29. addIceCandidate() function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate); }
  30. 30. ICEを手動でコピー
  31. 31. ICEを手動でコピー
  32. 32. ICE Candidateのやりとり 32 PeerConnectionApplication PeerConnection Application onIceCandidate(ice) addIceCandidate(ice) addIceCandidate(ice) onIceCandidate(ice) ice Copy & Paste ice Copy & Paste
  33. 33. 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; }
  34. 34. addIceCandidate() ※同じ function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate); }
  35. 35. ICEを手動でコピー(帰り)
  36. 36. 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
  37. 37. ICEを手動でコピー(帰り)
  38. 38. 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
  39. 39. 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
  40. 40. シグナリングサーバー編
  41. 41. シグナリングサーバーはどうして必要なの? • シグナリングの過程で、情報を受け渡したい – お互いのIPアドレス – お互いのポート番号 • この段階ではお互いIPアドレスを知らない – 直接やりとりでない • 仲介役となるシグナリングサーバーが必要 – どちらブラウザもサーバーのIPアドレスを知って いることが前提
  42. 42. Peer-to-Peer通信の開始前に、普通のサーバー/クライアント型の通信が行われる
  43. 43. 準備 • Node.jsをインストール – http://nodejs.jp/nodejs.org_ja/docs/v0.10/ • socket.ioもインストール $ sudo npm install socket.io
  44. 44. シグナリングサーバー • WebRTC…Node.jsで仲介(シグナリング)を作ってみよう – http://html5experts.jp/mganeko/5349/ • 例えば、signaling.jsに記述、起動 $ node signaling.js var port = 9001; // as you like var 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'); }); });
  45. 45. 動かしてみます DEMO
  46. 46. みなさんも、やってみてください • スタートは、先ほどの手動用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>
  47. 47. ソケットの確立 49 PeerConnection socket Application Signaling Server PeerConnection socket Application connect() connect connect() connect
  48. 48. connect() var socketReady = false; var port = 9001; var socket = io.connect('http://localhost:' + port + '/'); // socket: channel connected socket.on('connect', onOpened) .on('message', onMessage); function onOpened(evt) { console.log('socket opened.'); socketReady = true; }
  49. 49. メッセージ処理 // socket: accept connection request 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(); } }
  50. 50. SDPのやりとり 52 PeerConnection socket Application Signaling Server PeerConnection socket Application connect() connect connect() connect createOffer() offer sdp setLocalDescription(sdp) send(sdp) send sdp send sdp onMessage(sdp) setRemoteDescription(sdp)
  51. 51. 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); }
  52. 52. 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(); } }
  53. 53. onOffer(), setOffer() function onOffer(evt) { setOffer(evt); sendAnswer(evt); } function setOffer(evt) { peerConnection = prepareNewConnection(); peerConnection.setRemoteDescription( new RTCSessionDescription(evt) ); }
  54. 54. SDPのやりとり 56 PeerConnection socket Application Signaling Server PeerConnection socket Application connect() connect connect() connect createOffer() offer sdp setLocalDescription(sdp) send(sdp) send sdp send sdp onMessage(sdp) setRemoteDescription(sdp) createAnswer() answer sdp send sdp send(sdp) send sdp onMessage(sdp) setRemoteDescription(sdp) setLocalDescription(sdp)
  55. 55. 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); }
  56. 56. 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(); } }
  57. 57. onAnswer(), setAnswer () function onAnswer(evt) { setAnswer(evt); } function setAnswer(evt) { peerConnection.setRemoteDescription( new RTCSessionDescription(evt) ); }
  58. 58. SDPのやりとり(全体) 60 PeerConnection socket Application Signaling Server PeerConnection socket Application connect() connect connect() connect createOffer() offer sdp setLocalDescription(sdp) send(sdp) send sdp send sdp onMessage(sdp) setRemoteDescription(sdp) createAnswer() answer sdp send sdp send(sdp) send sdp onMessage(sdp) setRemoteDescription(sdp) setLocalDescription(sdp)
  59. 59. ICE Candidateのやりとり 61 PeerConnection socket Application Signaling Server PeerConnection socket Application send(ice) send ice send ice onMessage(ice) addIceCandidate(ice) onIceCandidate(ice)
  60. 60. 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; }
  61. 61. sendCandidate() function sendCandidate(candidate) { // send via socket socket.json.send(candidate); }
  62. 62. 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(); } }
  63. 63. onCandidate(), addIceCandidate() function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate); }
  64. 64. ICE Candidateのやりとり 66 PeerConnection socket Application Signaling Server PeerConnection socket Application onIceCandidate(ice) send(ice) send ice send ice onMessage(ice) addIceCandidate(ice) send ice send(ice) send ice onMessage(ice) addIceCandidate(ice) onIceCandidate(ice)
  65. 65. 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; }
  66. 66. 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(); } }
  67. 67. onCandidate(), addIceCandidate() ※同じ function onCandidate(evt) { var candidate = new RTCIceCandidate({ sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate }); peerConnection.addIceCandidate(candidate); }
  68. 68. ICE Candidateのやりとり 70 PeerConnection socket Application Signaling Server PeerConnection socket Application onIceCandidate(ice) send(ice) send ice send ice onMessage(ice) addIceCandidate(ice) send ice send(ice) send ice onMessage(ice) addIceCandidate(ice) onIceCandidate(ice) onIceCandidate() : end of candidate onIceCandidate() : end of candidate P2P stream transfer
  69. 69. ICE Candidateのやりとり(全体) 71 PeerConnection socket Application Signaling Server PeerConnection socket Application onIceCandidate(ice) send(ice) send ice send ice onMessage(ice) addIceCandidate(ice) send ice send(ice) send ice onMessage(ice) addIceCandidate(ice) onIceCandidate(ice) onIceCandidate() : end of candidate onIceCandidate() : end of candidate P2P stream transfer
  70. 70. Peer-to-Peer 通信確立
  71. 71. なぜWebRTCに注目するのか? 通信手段の破壊的進化 キャリア型通信 固定電話 携帯電話 (TV放送) 手段の例 Over The Top Skype, WebEx (YouTube, USTREAM) Webブラウザ型 WebRTC 世界中の人と会話 できる ユーザメリット 世界中の人と無料/ 安価で会話できる 専用アプリ無しで 会話できる インフラを持つ キャリアが支配 市場 キャリアに縛られない 独自の仕組みを提供 する少数のベンダー が参加可能 特別な仕組みは不要 誰でも参加可能 ×事業者メリット 限定的なAPI提供 連携可能 完全にプログラマブル 部品として利用可能 単独で利用利用方法 ユーザが組み合わ せて利用 製品/サービスに 組み込んで利用 コールセンター、ECサイト、情報共有システム、など
  72. 72. WebRTCをどんな風に使うかは、 みなさんのアイデア次第です! 74
  73. 73. Thank you! 75 END

×