83
東東 node 東東東 2013 WebRTC 東東東東東 2013.10.26 東東東東東東東東東東 東東東東東 東東東東東東 [email protected] 1

2013 WebRTC node

  • Upload
    mganeko

  • View
    9.754

  • Download
    20

Embed Size (px)

DESCRIPTION

WebRTCについて、node学園祭2013で発表した資料です

Citation preview

Page 1: 2013 WebRTC node

東京 node 学園祭 2013WebRTC を始めよう

2013.10.26インフォコム株式会社

技術企画室がねこまさし

[email protected]

1

Page 2: 2013 WebRTC node

はじめに• 本資料は以下の情報を参考に、作成しています。

– 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

Page 3: 2013 WebRTC node

自己紹介 : 経験した開発言語仕事で使った言語 趣味で使った言語 勉強だけした言語

C

C++

Visual C++ 1.0 〜 6.0Java

PHP, JavaScriptPython, JavaScript

Objective-CRuby

JavaScript, Node.js

3

New!

Page 4: 2013 WebRTC node

What’s WebRTC

• Web Real-Time Communication の略称– Web ブラウザ上で、 Real-Time Communication

を可能にするフレームワーク– HTML5 の一部

• 複数の技術の連携で成り立っている

4

Page 5: 2013 WebRTC node

質問タイム 1• (1) WebRTC という言葉を聞いたことが

ある人は?

• (2) WebRTC のサンプルに触ったことがある人は?

• (3) WebRTC を使ったコードを書いたことがある人は?

5

Page 7: 2013 WebRTC node

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

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

手段の例

Over The Top

Skype, WebEx (YouTube, USTREAM)

Web ブラウザ型

WebRTC

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

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

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

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

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

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

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

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

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

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

Page 8: 2013 WebRTC node

利用方法のイメージ■ ユーザが組み合わせて利用 → Word で見積書作成

合計: 568,900

システムが合計を計算、自動で結果を反映する

■ 製品 / サービスに組み込んで利用 → Excel で見積書作成

合計: 568,900

電卓で計算、ワードに手動で転記

Page 9: 2013 WebRTC node

WebRTC の構成要素• ユーザーメディア

– カメラ– マイク– 画面キャプチャ

• ストリーム (MediaStream)

• P2P 通信 (RTCPeerConnection)• データ通信 (DataChannel)

• 関連する API 、 HTML 要素– JavaScript (大前提)– Video, Audio– WebScoket– WebAudio API– Canvas– WebGL 9

Page 10: 2013 WebRTC node

メディア関連

WebRTC の基本的な動きの説明カメラを使ってみる

10

Page 11: 2013 WebRTC node

では、見てみましょう• カメラいろいろ– ローカル取得版 ( Chrome 用)– http://localhost/rtc/camera.html

11

Page 12: 2013 WebRTC node

12

← ミラー(左右反転)

← 伸縮

上下反転、回転→

白黒、セピア→

※CSS との組み合わせ

Page 13: 2013 WebRTC node

自分撮りカメラ (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

Page 14: 2013 WebRTC node

バリエーションセピアカメラ <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

Page 15: 2013 WebRTC node

ミラーカメラの 2 つの video タグの意味

15

1 つの MediaStream を複数の出力先に接続することができる

MediaStream : 出力先 = 1 : n

Page 16: 2013 WebRTC node

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

Page 17: 2013 WebRTC node

WebRTC で可能な ( 通信 ) 形態• ローカルのみ– 音声取得→スピーカーで再生– 動画取得→動画再生– 画面キャプチャ取得

– 音声録音– 動画録画– 静止画保存( Canvas 使用)

17

Page 18: 2013 WebRTC node

では、見てみましょう• 10 seconds video message   ( Chrome 用)– ローカルで動画、音声、静止画を取得– サーバにアップロード– ストリーミング再生– https://localhost:1235/

18

Page 19: 2013 WebRTC node

19

Page 20: 2013 WebRTC node

CAUTION!!

20

要注意ポイント

Page 21: 2013 WebRTC node

ハウリングの発生<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

Page 22: 2013 WebRTC node

ハウリングの原理(ローカル)

22

Page 23: 2013 WebRTC node

自分でハウリングを防止

23

1 つの UserMedai( カメラ等)から、複数の MediaStream を取り出すことができる

UserMedia: MediaStream = 1 : n

Page 24: 2013 WebRTC node

WebRTC のアクセス権限(パーミッション)

24

Page 25: 2013 WebRTC node

通信関連

WebRTC を使って、ビデオチャットを作成1対 1 ・ 1 組限定

1対 1 ・複数組n対 n ・複数組

25

Page 26: 2013 WebRTC node

通信について• RTCPeerConnection– 動画、音声などの MediaStream を転送する経路– P2P (Peer to Peer) → ブラウザとブラウザ– UDP/IP を使用

26

RTCPeerConnection RTCPeerConnectionUDP/IP

Page 27: 2013 WebRTC node

P2P 通信を始めるには• お互い、相手の IP アドレスを知る必要がある• 使用するポート番号を知る必要がある

– 利用する UDP のポートはダイナミックに割り振られる• RTCPeerConnection の通信を始める前に、何らかの手段でネゴ

シエーション、合意が必要– この手順を”シグナリング: Signaling” と呼びます

27

RTCPeerConnection RTCPeerConnectionUDP/IP

お互いの IP アドレス利用する UDP ポート

Page 28: 2013 WebRTC node

P2P 開始前のシグナリング• どちらのブラウザからもわかる、中継役が必要

– →普通はシグナリングサーバーを立てる

• シグナリングのプロトコルは標準化されていない– 独自の方式

• WebSocket 利用 (TCP/IP)• Ajax 利用 (HTTP, HTTPS)

– 既存のプロトコル• SIP(VoIP 用 ) with WebSocket(TCP/IP)• XMPP(IM 用) with WebSocket(TCP/IP)

28

Page 29: 2013 WebRTC node

P2P 開始前のシグナリング• どちらのブラウザからもわかる、中継役が必要

– →普通はシグナリングサーバーを立てる

• シグナリングのプロトコルは標準化されていない– 独自の方式

• WebSocket 利用 (TCP/IP)• Ajax 利用 (HTTP, HTTPS)

– 既存のプロトコル• SIP(VoIP 用 ) with WebSocket(TCP/IP)• XMPP(IM 用) with WebSocket(TCP/IP)

29

ようやくNode.js 登場( + socket.io )

Page 30: 2013 WebRTC node

シグナリングで交換される情報• Session Description Protocol (SDP)

– セッションが含むメディアの種類(音声、映像)、メディアの形式(コーデック)

– IP アドレス、ポート番号– P2P のデータ転送プロトコル → WebRTC では Secure RTP– 通信で使用する帯域– セッションの属性(名前、識別子、アクティブな時間、など)

• Interactive Connectivity Establishment (ICE)– 通信経路の候補をリストアップするためのプロトコル

• P2P による直接通信• STUN による、 NAT 通過のためのポートマッピング(→ P2P になる)• TRUN による、リレーサーバーを介した中継通信

– ネットワーク的に近い経路(上から順)が選ばれる30

Page 31: 2013 WebRTC node

P2P 通信確立までの流れ (1)

31

PeerConnectionsocket

Application SignalingServer

PeerConnectionsocket

Application

connect()connect connect()

connect

Page 32: 2013 WebRTC node

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)

Page 33: 2013 WebRTC node

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)

Page 34: 2013 WebRTC node

P2P 通信確立までの流れ (2)

35

PeerConnectionsocket

Application SignalingServer

PeerConnectionsocket

Application

send(ice) send icesend ice

onMessage(ice)

addIceCandidate(ice)

onIceCandidate(ice)

Page 35: 2013 WebRTC node

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)

Page 36: 2013 WebRTC node

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

Page 37: 2013 WebRTC node

WebRTC で可能な ( 通信 ) 形態• 双方向通信 1 to 1– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ

通信(と音声通信)

39

シングルテナントこのサーバで 1 組さま限定

Page 38: 2013 WebRTC node

では、見てみましょう• WebRTC 1 to 1 Video Chat (Chrome 用 )– http://localhost/rtc/rtc11.html

–※Simple WebRTC を全面的に参考にしています• http://simplewebrtc.com/

– サーバ側は、 Node.js + socket.io を使っています

40

Page 39: 2013 WebRTC node

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

Page 40: 2013 WebRTC node

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)

Page 41: 2013 WebRTC node

1 to 1 ブラウザ側 (2) JavaScriptconnection handling

43

// 通信開始function connect() { sendOffer();}

// 通信終了function hangUp() { socket.json.send({type: "bye"}); stop();}

function stop() { peerConn.close(); peerConn = null;}

Page 42: 2013 WebRTC node

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); }

Page 43: 2013 WebRTC node

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)

Page 44: 2013 WebRTC node

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();}

Page 45: 2013 WebRTC node

質問タイム 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

Page 46: 2013 WebRTC node

質問タイム 2 回答編• Socket.io のプロトコル– https://github.com/Jxck/socket.io-spec– Socket.io のクライアントは最初に接続に利用する通信

方法を決定します– Socket.IO の接続の最初には、シンプルな HTTP ハンド

シェイクが実行されます (※または HTTPS )– ハンドシェイクが成功すると、以下の結果がクライアン

トに送られます• 通信が接続を開始する時に渡される session id• ハードビートの送信が期待される間隔の秒数 (heartbeat timeout)• 通信コネクションが応答しなくなり、ソケットが閉じられたと判断し

て 通信コネクションを閉じるまでの秒数 (close timeout)

48

Page 47: 2013 WebRTC node

WebRTC で可能な ( 通信 ) 形態• 双方向通信– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ

通信(と音声通信)

49

マルチテナント化(複数会議室)

Socket.io の room 機能 (join() / leave()) を利用

Page 48: 2013 WebRTC node

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";}

Page 49: 2013 WebRTC node

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');});

Page 50: 2013 WebRTC node

CAUTION!!

52

はまりポイント 1

Page 51: 2013 WebRTC node

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 を交互に送信

Page 52: 2013 WebRTC node

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 を片方が連続して送信

Page 53: 2013 WebRTC node

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ヶ月

Page 54: 2013 WebRTC node

WebRTC で可能な ( 通信 ) 形態• 双方向通信

– 1 to 1 の音声通信– 1 to 1 の映像通信– 1 to 1 のスクリーンキャプチャ通信(と

音声通信)

– n to n の音声通信– n to n の映像通信– n to n のスクリーンキャプチャ

通信(と音声通信)56

1 会議室に複数人、かつ複数会議室

Page 55: 2013 WebRTC node

では、見てみましょう• WebRTC 4 people Video Chat (Chrome 用 )– http://localhost/rtc/rtc4.html

57

Page 56: 2013 WebRTC node

CAUTION!!

58

はまりポイント 2

Page 57: 2013 WebRTC node

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

Page 58: 2013 WebRTC node

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 ヶ月

Page 59: 2013 WebRTC node

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)

Page 60: 2013 WebRTC node

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; }}

Page 61: 2013 WebRTC node

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;}

Page 62: 2013 WebRTC node

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;}

Page 63: 2013 WebRTC node

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 } }; …

Page 64: 2013 WebRTC node

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.

Page 65: 2013 WebRTC node

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);});

Page 66: 2013 WebRTC node

WebRTC で可能な ( 通信 ) 形態 (2)

• 片方向通信– 1 → 1 の音声通信– 1 → 1 の映像通信– 1 → 1 のスクリーンキャプチャ

通信(と音声通信)

– 1 → n の音声通信– 1 → n の映像通信– 1 → n のスクリーンキャプチャ

通信(と音声通信)68

Page 67: 2013 WebRTC node

P2P型のメリット、デメリット• メリット

– サーバを仲介しないので、オーバーヘッドがない

– 高スペックのサーバー不要• 社内では、 Raspberry Pi で稼働中

• デメリット– 通信相手が多いと組み合わ

せ爆発で通信経路が増える• 2 人 → 1 経路• 3 人 → 3 経路• 4 人 → 6 経路• 5 人 → 10 経路• 6 人 → 15 経路

69

P2P型

サーバー型

P2P型 4 人サーバー型 4 人

Page 68: 2013 WebRTC node

70

ちなみに、 node.js のビルドには一晩かかりました…

Page 69: 2013 WebRTC node

やっかいな問題 1

71

Page 70: 2013 WebRTC node

直接 P2P の経路(同一ネットワーク内)

72

動的 UDP ポート (50000 〜 65535)

Page 71: 2013 WebRTC node

STUN を使った、ポート情報交換その後の P2P の経路( NAT越え)

73

Page 72: 2013 WebRTC node

TURN サーバによるリレー中継経路( Firewall抜け)

74

Page 73: 2013 WebRTC node

TURN サーバによるリレー中継経路( Firewall抜け)

75

まだ動作せず

Firewall越え、鋭意調査中

Page 74: 2013 WebRTC node

質問タイム 3• 誰か、 TURN サーバーを自分で稼働させたことあります

か?– http://code.google.com/p/rfc5766-turn-server/

• そのとき、 Firewall, proxy 等の設定はどうすれば良いの?

76

どなたか、知ってたら教えてください!!

Page 75: 2013 WebRTC node

やっかいな問題 2

77

Page 76: 2013 WebRTC node

自分でハウリングを防止

78

Page 77: 2013 WebRTC node

相手とのハウリングの抑止?

79自動ミュートや、特定音域減衰などの音声処理が必要 → JavaScript では不可能??

Page 78: 2013 WebRTC node

質問タイム 4

• JavaScript でのやり方、ライブラリ知りませんか?– 音声波形の減算  or 位相反転+加算– ノイズキャンセリングヘッドホンみたいなことがやりた

80

どなたか、知ってたら教えてください!!

Page 79: 2013 WebRTC node

まとめ• WebRTC はパワフル

– カメラ、マイク、画面キャプチャなど、ブラウザの能力を大きく拡大する

– HTML5 の他の機能との相乗効果• Canvas, CSS, WebAudio API, WebGL

• WebRTC はフレキシブル– ローカルのみ、 1対 1 、 n対 n– 双方向、片方向(ブロードキャスト型)

• WebRTC は破壊的技術– だれでも市場 / アプリに参入できる

• WebRTC はプログラマブル– 自分たちの製品 / サービスに組み込める

84

Page 80: 2013 WebRTC node

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

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

85

今日のソースはこちらhttps://github.com/mganeko/mgrtc

参考資料はこちらhttp://www.slideshare.net/mganeko/2013-web-rtctechcross

質問、情報、アイデアは → [email protected]

Page 81: 2013 WebRTC node

おまけ: socket.io 豆知識• サーバー側で、クライアントの情報を取得• IP アドレス

ip = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address.address;

• トランスポート  (websocket, ajax …)tr = io.transports[socket.id].name;

86

Page 82: 2013 WebRTC node

おまけ: インフォコムグループ紹介

87

http://www.infocom.co.jp

Page 83: 2013 WebRTC node

Thank you!

88

END