webrtcの技術解説 第二版 公開版 本編
DESCRIPTION
第1回NTT-WEST学生向けアプリ開発コンテスト(WebRTC)の勉強会資料です。 ※コンテスト情報はFacebookページよりご覧ください! https://www.facebook.com/nttw.w.con 各資料のURL WebRTCの技術解説 第二版 公開版 完全版 http://www.slideshare.net/nttwestcon/20140805-technical-description-of-webrtc-second-edition-public-edition-full-version WebRTCの技術解説 第二版 公開版 本編 http://www.slideshare.net/nttwestcon/20140805-technical-description-of-webrtc-second-edition-public-edition-main-presentation-38236711 WebRTCの技術解説 第二版 公開版 サンプルコード編 http://www.slideshare.net/nttwestcon/20140805-technical-description-of-webrtc-second-edition-public-edition-sample-code-38236761TRANSCRIPT
WebRTCの技術解説 第二版WebRTC 勉強会 @ 第1回 NTT-WEST学生向けアプリ開発コンテストhttps://www.facebook.com/nttw.w.con
2014/08/05
NTT西日本http://ntt-west.co.jp/
公開版
本編
資料公開にあたり当資料は学生向けWebRTCコンテストの関連イベントであるWebRTC勉強会で使用されたものです。コンテストの詳細については、下記URLをご参照下さい。
第1回 NTT-WEST学生向けアプリ開発コンテストhttps://www.facebook.com/nttw.w.con
勉強会に参加された方へ勉強会では完全版と分割した本編とサンプルコード編を使用しましたが、第二版でも同様に3種類用意しています。
きんじょう ゆう
金城 雄 Twitter @youkinjoh GitHub @youkinjoh SlideShare @You_Kinjoh
講師紹介
gihyo.jpJettyで始めるWebSocket超入門http://gihyo.jp/dev/feature/01/websocket/0001
デモ参加のお願い
INFORMATION
INFORMATION
参加型デモカメラ付きの端末でお願いします。
できるだけ新しい
Chrome
Androidパソコン
INFORMATION
INFORMATION
WebRTCの概要WebRTCの2つの仕様PeerJSSkyWayユーザメディアを操作するその他雑多な内容
今日お話しすること
質疑応答について
WebRTC
Web Real-Time CommunicationリアルタイムコミュニケーションのAPIボイスチャット・ビデオチャットがプラグインなしにブラウザでできるテキストデータ・バイナリデータも送信可P2P
WebRTC
これまでのリアルタイム
コミュニケーションとの違い
http://www.slideshare.net/mganeko/2013-web-rtctechcross/6 より引用
キャリア型通信
手段の例
市場
ユーザメリット事業者メリット
利用方法
固定電話 携帯電話 (TV放送)
インフラを持つキャリアが支配
世界中の人と会話できる
×
単独で利用
http://www.slideshare.net/mganeko/2013-web-rtctechcross/6 より改変して引用
Over The Top
手段の例
市場
ユーザメリット事業者メリット
利用方法
Skype, WebEx(YouTube, Ustream)キャリアに縛られない独自の仕組みを提供する少数のベンダーが参加可能
世界中の人と無料/安価で会話できる
限定的なAPI提供一部連携可能
ユーザが組み合わせて利用
http://www.slideshare.net/mganeko/2013-web-rtctechcross/6 より改変して引用
Webブラウザ型
手段の例
市場
ユーザメリット事業者メリット
利用方法
WebRTC
特別な仕組みは不要誰でも参加可能
専用アプリ無しで会話できる
完全にプログラマブル部品として利用可能
製品/サービスに組み込んで利用
http://www.slideshare.net/mganeko/2013-web-rtctechcross/6 より改変して引用
キャリア型通信 Over The TopWebブラウザ型
手段の例
市場
ユーザメリット
事業者メリット
利用方法
固定電話携帯電話(TV放送)
Skype, WebEx(Youtube, Ustream)
WebRTC
インフラを持つキャリアが支配
キャリアに縛られない独自の仕組みを提供する少数のベンダーが参加可能
特別な仕組みは不要誰でも参加可能
世界中の人と会話できる
世界中の人と無料/安価で会話できる
専用アプリ無しで会話できる
× 限定的なAPI提供一部連携可能
完全にプログラマブル部品として利用可能
単独で利用 ユーザが組み合わせて利用
製品/サービスに組み込んで利用
http://www.slideshare.net/mganeko/2013-web-rtctechcross/6 より改変して引用
対応ブラウザ
※ 但し、iOSのブラウザは全て未対応
(2014/07現在)
今後もまだ仕様が変更になる可能性があるベンダープレフィックスが必要先行したバージョンの使用がお勧めGoogle Chrome CanaryFirefox BataFirefox Aurora
まだ策定中
ベンダープレフィックス先行実装であることを示す慣習ブラウザベンダーによって違うメソッドの挙動が同じであれば、代入してメソッド名の違いを吸収できる
navigator.getUserMedia = navigator.getUserMedia || //Specification navigator.webkitGetUserMedia || //for Chrome navigator.mozGetUserMedia ; //for Firefoxベンダープレフィックスの現状は以下を参照のこと。https://plus.google.com/app/basic/stream/z121hnjxtqq2svgni23mznm4cxnctznc5
主な2つの仕様Media Capture and Streamsブラウザからカメラやマイクのメディアストリームを取得するための仕様WebRTC 1.0: Real-time Communication Between BrowsersブラウザとブラウザをP2Pで接続し通信を行なうための仕様
Media Capture and Streams(getUserMedia)
ブラウザからマイクやカメラにアクセス利用範囲はWebRTC以外とも音声処理(with Web Audio API)ボイスチェンジャー etc.画像処理(with Canvas)顔検出 etc.
顔認識ができるようになるのも時間の問題。
DEMO
SAMPLE
音声と映像を取得
Media Capture and Streams
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
window.URL = window.URL || window.webkitURL ;
window.addEventListener('load', function() { navigator.getUserMedia( {video: true, audio: true}, function(stream) { var video = document.getElementById('video'); video.src = window.URL.createObjectURL(stream); video.play(); }, function(error) { console.error(error); } );});
<!DOCTYPE html><html><head><meta charset="utf-8"><script src="script.js"></script><title>getUserMedia Sample</title></head><body><video id="video"></video></body></html>
WebRTC 1.0: Real-time Communication Between
BrowsersブラウザとブラウザをP2Pで接続通信は全て暗号化されるP2Pの前に要シグナリングシグナリングサーバが必要WebSocketが良く使われているNode.jsならSocket.IO
WebRTC 1.0: Real-time Communication Between
BrowsersAPIが複雑でわかりにくい抽象化した仕様の多いHTML5の他のAPIと比べると非常に複雑それでも、従来のリアルタイム通信の処理よりは断然楽ジッタやパケットロス等の対策は、ブラウザが全て対応してくれる
DEMO
WebRTC 1.0: Real-time Communication Between
BrowsersICE (STUN + TURN + α)NAT通過・ネゴシエーションSTUNP2P・UDPホールパンチングTURNP2Pが不可能ならサーバ経由で通信
WebRTC 1.0: Real-time Communication Between
BrowsersSDPセッションプロトコルを記述セッション開始に必要な情報
DTLS (UDP等のデータグラム向けのTLS)データ通信は全て暗号化される
WebRTC 1.0: Real-time Communication Between
BrowsersMediaStream (SRTP・SRTCP)音声データ・映像データ
SRTP (RTPのセキュア版)リアルタイムデータ配信の仕様
SRTCP (RTCPのセキュア版)配信用制御プロトコル
WebRTC 1.0: Real-time Communication Between
BrowsersDataChannel (SCTP)テキストデータ・バイナリデータ
SCTPTCPとUDPの良いところ取りをしたプロトコル標準ではTCPに似た動作をする設定により信頼性と引き換えにリアルタイム性の向上が可能で、UDPに似た動作にできる
どの処理をブラウザが勝手にやってくれるのか、どの処理を自分で実装する必要があるのかを把握しないと実装時に大変混乱する。
どうやってブラウザでP2Pを
実現しているのか
?????????? ??????????
画面上部にメソッド名等のキーワードが表示されます。実装時にご活用下さい。
Browser Browser
NAT NAT
NATが邪魔して直接通信ができない。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
HTML+JS+CSS
Global IP/Port
signaling
HTML+JS+CSS
Global IP/Port
signaling
data
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ブラウザでWebRTCを使ったページにアクセス。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
HTML+JS+CSS
HTTP RequestHTTP Response
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Signaling Serverとして利用するWebSocket Serverに接続。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
signaling
WebSocket open
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
signaling
対向のブラウザもWebRTCを使ったページにアクセス。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
HTML+JS+CSS
HTTP RequestHTTP Response
signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
signaling
対向のブラウザもWebSocket Serverに接続。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
signaling signaling
WebSocket open
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
signaling signaling
以後、WebSocketは接続を継続する。この先、説明の都合上、接続中でもグレーアウトします。データが流れる時だけ色がつきます。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
接続を開始する側でoffer開始。SDPを生成・自身に登録後送信。対向のブラウザは受け取ったSDPを登録。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Offer SDP
createOffer
SDPは以下の情報を含む。メディアタイプコーデック帯域幅 etc.
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Offer SDP
setLocalDescription
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
WebSocket send
Offer SDPsignaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Offer SDP
signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
setRemoteDescription
Offer SDP
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
受け取ったofferに対してanswer開始。SDPを生成・自身に登録後送信。offerした側でも対向のSDPを登録。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
createAnswer
SDPは以下の情報を含む。
メディアタイプコーデック帯域幅 etc.
Answer SDP
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
setLocalDescription
Answer SDP
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
WebSocket send
Answer SDP signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Answer SDP
signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
setRemoteDescription
Answer SDP
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
P2Pの為に相手にIPを伝える必要がある。その為にSTUNを使い自身のIPを調べる。ブラウザが裏で処理してくれる。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ここのGlobal IP/Port
を知りたい
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Global IP/Port
GlobalIP/Port
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Global IP/Port
GlobalIP/Port
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ここのGlobal IP/Port
を知りたい
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Global IP/Port
GlobalIP/Port
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
Global IP/Port
GlobalIP/Port
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
自身のIP/Portは把握。自身に接続できそうな経路の候補を相手側に伝える必要がある。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ICEcandidate
ブラウザはこれまでの情報を元に裏で経路候補(candidate)を生成。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ICEcandidate
icecandidate Event
イベントに登録したハンドラ経由で経路候補を取得。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
WebSocket send
ICEcandidatesignaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ICEcandidate
signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
addIceCandidate
ICEcandidate
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ブラウザはSTUNからの情報を元に
裏で経路候補(candidate)を
生成。
ICEcandidate
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
icecandidate Event
ICEcandidate
イベントに登録した
ハンドラ経由で経路候補を取得。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
WebSocket send
ICEcandidate signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
ICEcandidate
signaling
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
addIceCandidate
ICEcandidate
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
P2Pで通信する為の情報が(やっと)整った。通信開始。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NATdata
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
それでもP2Pが無理だった場合、TURNサーバが中継を行なう。TURN経由でもデータの暗号化は解かれずセキュア。
Web Server
WebSocketServer
ICE Server(STUN + TURN)
Browser Browser
NAT NAT
data data
RTCPeerConnectionストリーミングを扱うためのWebRTCの中心となるオブジェクトRTCSessionDescriptionSDPを扱うオブジェクトRTCIceCandidate経路候補を扱うオブジェクトRTCDataChannelテキスト・バイナリ用のデータチャネル
SAMPLE
このサンプルでは細かい制御は行なっていないので注意してください。
ビデオチャット(二者間通信)
WebRTC 1.0: Real-time Communication Between
Browsers
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
window.URL = window.URL || window.webkitURL ;
window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection ;
window.RTCSessionDescription = window.RTCSessionDescription || window.webkitRTCSessionDescription || window.mozRTCSessionDescription ;
window.RTCIceCandidate = window.RTCIceCandidate || window.webkitRTCIceCandidate || window.mozRTCIceCandidate ;
var ws = null;
var peer = null;
function initialize() {
var secure = location.protocol === 'https:'; var protocol = secure ? 'wss' : 'ws'; var url = protocol + '://' + location.host + '/'; ws = new WebSocket(url);
peer = new RTCPeerConnection({ iceServers: [ {url: 'stun:stun.l.google.com:19302'}, {url: 'stun:23.21.150.121'} ] });
navigator.getUserMedia( {audio: true, video: true}, function(stream) { var video = document.getElementById('local'); video.src = URL.createObjectURL(stream); video.play(); peer.addStream(stream); }, function(error) { console.error(error); } );
ws.addEventListener('message', function(evt) { var data = JSON.parse(evt.data); if (!data.sdp) {return;} var sdp = data.sdp; var description = new RTCSessionDescription(sdp); peer.setRemoteDescription(description, function() { if (description.type === 'offer') { answer(); } }); });
ws.addEventListener('message', function(evt) { var data = JSON.parse(evt.data); if (!data.candidate) {return;} var candidate = new RTCIceCandidate(data.candidate); peer.addIceCandidate(candidate); });
peer.addEventListener('icecandidate', function(evt) { if (!evt.candidate) {return;} var candidate = evt.candidate; ws.send(JSON.stringify({candidate: candidate})); });
peer.addEventListener('addstream', function(evt) { var video = document.getElementById('remote'); video.src = URL.createObjectURL(evt.stream); video.play(); });
var offerbtn = document.getElementById('offer_button'); offerbtn.addEventListener('click', offer);
}
function offer() { peer.createOffer( function(offer) { peer.setLocalDescription(offer, function() { ws.send(JSON.stringify({sdp: offer})); }); }, function(error) { console.error(error); } );}
function answer() { peer.createAnswer( function(answer) { peer.setLocalDescription(answer, function() { ws.send(JSON.stringify({sdp: answer})); }); }, function(error) { console.error(error); } );}
window.addEventListener('load', initialize);
<!DOCTYPE html><html><head><meta charset="utf-8"><link rel="stylesheet" href="styles/style.css" /><script src="scripts/script.js"></script><title>WebRTC Sample</title></head><body><input type="button" value="offer" id="offer_button" /><video id="local" autoplay="autoplay"></video><video id="remote" autoplay="autoplay"></video></body></html>
Library / PaaSAPIのWrapperや、Signaling Server機能を含むもの、room機能の有無など様々。ICE Serverを提供しているものも。クライアント側の実装に集中したい場合は、導入の価値あり。サーバ側を細かく制御したい場合は使わないという選択肢も。
Library / PaaSsimpleRTCroom機能ありPeerJS日本のドキュメントあり(SkyWay内)SkyWayPeerJSを使ったPaaS
他にもたくさんあります。コンテストで提供する実行環境には、PeerServerがインストールされています。
PeerJSOffer/AnswerはPeerJSが裏でやってくれる。接続先を制御するために、新たにID(PeerID)の概念が増える。(電話番号の概念に近い。)通信開始には相手のIDが必要。IDを意識させずに自動接続するには、WebSocket等でID交換の必要がある。
PeerPeerJSの本体。MediaConnectionMediaStreamのWrapper。DataConnectionDataChannelのWrapper。
PeerJS
SAMPLE
ビデオチャット(多者間通信)
PeerJS版with PeerServer Cloud
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
window.URL = window.URL || window.webkitURL ;
var PEERJS_API_KEY = '[PEERJS_API_KEY]';
var ws = null;var peer = null;var selfid = null;var localStream = null;
function initializePeer(callback) { peer = new Peer({key: PEERJS_API_KEY}); peer.on('open', function(id) { selfid = id; callback(); }); peer.on('call', function(mediaConnection) { mediaConnection.answer(localStream); settingMediaConnection(mediaConnection); }); peer.on('close', function() { peer.destroy(); }); peer.on('error', function(err) { console.error(err); });}
function initializeMedia(callback) { navigator.getUserMedia( {audio: true, video: true}, function(stream) { localStream = stream; var video = document.getElementById('local'); video.src = URL.createObjectURL(stream); video.play(); callback(); }, function(error) { console.error(error); } );}
function initializeWebSocket(callback) { var secure = location.protocol === 'https:'; var protocol = secure ? 'wss' : 'ws'; var url = protocol + '://' + location.host + '/'; ws = new WebSocket(url); ws.addEventListener('open', function() { callback(); }); ws.addEventListener('message', function(evt) { var remoteid = evt.data; var mediaConnection = peer.call(remoteid, localStream); settingMediaConnection(mediaConnection); });}
function settingMediaConnection(mediaConnection) { var remoteid = mediaConnection.peer; var remoteStream = null; var video = null; mediaConnection.on('stream', function(stream) { video = document.createElement('video'); video.src = URL.createObjectURL(stream); video.play(); var parent = document.getElementById('remotes'); parent.appendChild(video); }); mediaConnection.on('close', function() { URL.revokeObjectURL(video.src); video.parentNode.removeChild(video); }); mediaConnection.on('error', function() { console.error(err); });}
function initialize() { initializePeer(function() { initializeMedia(function() { initializeWebSocket(function() { ws.send(selfid); }); }); });}
window.addEventListener('load', initialize);
<!DOCTYPE html><html><head><meta charset="utf-8"><link rel="stylesheet" href="styles/style.css" /><script src="http://cdn.peerjs.com/0.3/peer.js"></script><script src="scripts/script.js"></script><title>PeerJS Sample</title></head><body><video id="local"></video><div id="remotes"></div></body></html>
SkyWayPeerJSを使ったPaaS。PeerServer Cloudでできることに加え、接続しているRemoteの一覧をRestAPIで取得可能。IDを意識させずに自動接続する場合でも、RestAPIでIDを取得できるため、静的ファイルのみで構築可能。
RestAPI接続しているPeerIDの一覧を取得接続しているPeerの数を取得
SkyWay
PeerServerでも、起動時に allowDiscovery オプションを指定すると、同様のことが可能。
SAMPLE
ビデオチャット(多者間通信)
SkyWay版(静的ファイルのみで動作可能)
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
window.URL = window.URL || window.webkitURL ;
var SKYWAY_API_KEY = '[SKYWAY_API_KEY]';var REST_API_LIST = 'https://skyway.io/v2/active/list/';
var peer = null;var selfid = null;var localStream = null;
function initializePeer(callback) { peer = new Peer({key: SKYWAY_API_KEY}); peer.on('open', function(id) { selfid = id; callback(); }); peer.on('call', function(mediaConnection) { mediaConnection.answer(localStream); settingMediaConnection(mediaConnection); }); peer.on('close', function() { peer.destroy(); }); peer.on('error', function(err) { console.error(err); });}
function initializeMedia(callback) { navigator.getUserMedia( {audio: true, video: true}, function(stream) { localStream = stream; var video = document.getElementById('local'); video.src = URL.createObjectURL(stream); video.play(); callback(); }, function(error) { console.error(error); } );}
function callRemoteAll() { var url = REST_API_LIST + SKYWAY_API_KEY; var xhr = new XMLHttpRequest(); xhr.addEventListener('readystatechange', function() { if (xhr.readyState != 4) {return;} if (xhr.status != 200) {return;} var remoteids = JSON.parse(xhr.responseText); for (var i = 0; i < remoteids.length; i++) { var remoteid = remoteids[i]; var mediaConnection = peer.call(remoteid, localStream); settingMediaConnection(mediaConnection); } }); xhr.open('GET', url); xhr.send();}
function settingMediaConnection(mediaConnection) { var remoteid = mediaConnection.peer; var remoteStream = null; var video = null; mediaConnection.on('stream', function(stream) { video = document.createElement('video'); video.src = URL.createObjectURL(stream); video.play(); var parent = document.getElementById('remotes'); parent.appendChild(video); }); mediaConnection.on('close', function() { URL.revokeObjectURL(video.src); video.parentNode.removeChild(video); }); mediaConnection.on('error', function() { console.error(err); });}
function initialize() { initializePeer(function() { initializeMedia(function() { callRemoteAll(); }); });}
window.addEventListener('load', initialize);
<!DOCTYPE html><html><head><meta charset="utf-8"><link rel="stylesheet" href="styles/style.css" /><script src="https://skyway.io/dist/v2/0.3/peer.js"></script><script src="scripts/script.js"></script><title>SkyWay Sample</title></head><body><video id="local"></video><div id="remotes"></div></body></html>
ユーザメディアを操作する
Canvas
Web AudioAPI
MediaStream
MediaStream
音声処理
画像処理
現在の実装状況
MediaStream Processing APIの中にCanvas RecordingというCanvas要素からstreamを取得する仕様案があったが進展なし?
Canvas
Web AudioAPI
MediaStream
MediaStream
音声処理
画像処理
処理した音声は送信可能処理した映像は送信不可
受信側ではどちらも処理可能画像をバイナリデータとしてDataChannelで送信・連続して表示することは可能ですが、ジッタ処理等のWebRTCのメディア処理の恩恵を受けることができません。必要であれば、ジッタ処理等を自分で実装することになります。
Canvas
Web AudioAPI 再生
MediaStream
音声処理
画像処理
表示
MediaStream
Web Audio API
SAMPLE簡易
ボイスチェンジャーMediaStream <=> Web Audio API
当ボイスチェンジャーで変換した音声は、音声解析によりほぼ元の音声を復元可能であり、匿名性を担保するものではありません。
navigator.getUserMedia({audio: true}, function(inputStream) { var audioContext = new AudioContext(); // 要ベンダープレフィックス var mediastreamsource = audioContext.createMediaStreamSource(inputStream); var scriptProcessor = audioContext.createScriptProcessor(bufferSize, 1, 1); var mediastreamdestination = audioContext.createMediaStreamDestination(); scriptProcessor.addEventListener('audioprocess', onAudioProcess); mediastreamsource.connect(scriptProcessor); scriptProcessor.connect(mediastreamdestination); var outputStream = mediastreamdestination.stream; peer.addStream(outputStream); }, function(error) {});
function onAudioProcess(evt) { var input = evt.inputBuffer.getChannelData(0); var output = evt.outputBuffer.getChannelData(0); var bufferData = new Float32Array(bufferSize); for (var i = 0; i < bufferSize; i++) { bufferData[i] = ( (input[(i * 2) % bufferSize] + input[(i * 2 + 1) % bufferSize]) / 2 + input[Math.floor(i / 2) % bufferSize] ) / 2; } output.set(bufferData);}
MediaStream
Canvas
SAMPLE
色調反転
MediaStream => Canvas
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
window.URL = window.URL || window.webkitURL ;
function initialize() { navigator.getUserMedia( {audio: true, video: true}, function(stream) { var video = document.getElementById('video'); video.src = URL.createObjectURL(stream); video.play(); renderStart(); }, function(error) { console.error(error); } );}
function renderStart() { var video = document.getElementById('video'); var buffer = document.getElementById('buffer_canvas'); var display = document.getElementById('display_canvas'); var bufferContext = buffer.getContext('2d'); var displayContext = display.getContext('2d'); var render = function() { requestAnimationFrame(render); var width = video.videoWidth; var height = video.videoHeight; if (width == 0 || height == 0) {return;} buffer.width = display.width = width; buffer.height = display.height = height; bufferContext.drawImage(video, 0, 0); var imageData = bufferContext.getImageData(0, 0, width, height); var data = imageData.data; for (var i = 0; i < data.length; i += 4) { data[i + 0] = 255 - data[i + 0]; // Red data[i + 1] = 255 - data[i + 1]; // Green data[i + 2] = 255 - data[i + 2]; // Blue } imageData.data = data; displayContext.putImageData(imageData, 0, 0); }; render();}
window.addEventListener('load', initialize);
<!DOCTYPE html><html><head><meta charset="utf-8"><link rel="stylesheet" href="styles/style.css" /><script type="text/javascript" src="scripts/script.js"></script><title>Reverse with getUserMedia</title></head><body><video id="video"></video><canvas id="buffer_canvas"></canvas><canvas id="display_canvas"></canvas></body></html>
アイディアがあればそれを。なければ考える。何も思いつかなければ、他のAPIとの組み合わせから考える方法も。
WebRTCを使って何を作るのか
日常の中で、WebRTCを使うと解決する問題や、便利になることはありませんか?
HTML5系 API
http://platform.html5.org/http://caniuse.com/
Web API
HOT! API総務省 次世代統計利用システム(国勢調査、人口推計、就業構造、企業統計、物価統計 etc.)NHK番組表(※未公開)
行政・自治体・公共サービス郵便番号郵便番号検索API(郵便番号 → 住所)郵便専門ネット(郵便番号 → 住所、郵便番号の簡易存在チェック)ぽすたん(郵便番号 → 住所、住所 → 郵便番号)IW3 PROJECT(郵便番号 → 住所、住所 → 郵便番号)
宇宙Google+ JAXA PR(※現在一部の学生に限定公開、Google+にて随時情報を更新)ARTSAT 衛星API(芸術衛星・ARTSATの位置情報、高度、角速度 etc.)
図書館国立国会図書館サーチカーリル(全国各地の図書館の所蔵・貸出状況)
テレビテレビ局日テレ アプリ
テレビ関連アニメマップ(アニメ番組情報)
インフラTwilio(電話)FullCourt(音声通話、SMS)NTT docomo(電話帳、文字認識、音声認識、知識Q&A)
SNSTwitterHootSuite(SNS管理、メッセージ投稿)Google+LinkedInInstagrammixiYammerはてなハイクKlout(影響力解析)Qrust(影響力解析)iddyAbout.mePinterest(※Facebookグループにて仕様策定中)TimelogYahoo!Japan(※新規申し込み停止中)プーペガールyouRoomdoodle
ソーシャルブックマークはてなブックマークはてなブックマーク iPhoneアプリケーションはてなスターDelicious楽天ブックマーク
スライドSlideShare
音楽Last.fmiTunes、App Store、 iBookstore、、Mac App StoreYahoo! Music
動画動画ホスティングYouTubeVimeo Developer APIニコニコ動画PANDORA.TVWoopie
動画配信Ustreamニコニコ実況ニコ生アニメ動画APIStickamTwitCastingSOBA Web API
写真FlickrPicasaフォト蔵はてなフォトライフZorgPanoramiofotochan(写真補正)MyPix(画像に文字を入れる)
ゲームSteam
ブログ・グループウェアTumblrはてなダイアリーはてなexistBizPalRetired(ブログ引退マークを付ける)Google サイト
プラットフォームOpenSocialMobageGREEFacebookmixiOpenSocialOpenSocial HostinfoScoopOpenSocial Pages for Google Apps
認証Yahoo!Japan OpenID 2.0livedoorはてなはてな Android認証mixiJugem
地図・位置情報
地図Google MapsYOLPYahoo!Japanジオターゲティング(IP → 住所)どこどこJP(IP → アクセス元地域・組織)HeartRails Geo APIWindows Virtual EarthマピオンGeocodingLocoSticker.jpMaxmind
地図関連住所パワープロジェクト:位置情報ジオどす(京都の通り名 → 緯度経度)逆ジオコーディングAPI(緯度経度 → ランドマーク)簡易逆ジオコーディング携帯Art Mapインクカートリッジ里帰りAPI(インクカートリッジ回収ボックス)送料の虎Webサービス ‒ 送料の虎(送料計算)準天頂衛星システム特設サイト QZ-vision(GPS衛星群の位置、個数、角度、周波数をプロット)
位置情報サービスfoursquareロケタッチはてなココ
地理国土地理院 電子国土Webシステム(PDF)
http://www.find-job.net/startup/api-2013 より引用
一覧内のサービス名のクリックで、各サービスのページが開きます。
交通車・ナビゲーションドコイク?-リクルートナビタイムジャパンガソリン価格情報
鉄道RailGoHeartRails Express駅データ.jp
バス鯖江市 つつじバス
高速道路高速.jp
自転車自転車大好きマップ
気象・災害天気livedoor 天気情報天気予報APIOpenWeatherMap天気API コンテンツポケットgoo天気コンテンツポケット 指数API(雨傘指数、洗濯指数 etc.)コンテンツポケット 美容天気API
波浪・潮汐Wave Hunter(波浪予測)全国潮汐データ
日の出・日の入時刻おはこん番地は!?
環境環境省大気汚染物質広域監視システムAPI
災害対策Yahoo!Japan 震災関連情報J-SHIS Web API(地震ハザード情報、表層地盤データ)復旧・復興支援制度データベースNDL東日本大震災アーカイブ気象庁防災情報
ニュースYahoo! Japan ニュース東京証券取引所アキバ総研
書籍・論文書籍・雑誌版元ドットコム(書誌情報、書影)hon.jp(書誌情報、書影)web R25(R25一部のタイトル・本文・画像)楽天ブックスFujisan(書誌情報、書影)Making OPAC 2.0(大手4書店、紀伊國屋書店・旭屋書店・ジュンク堂書店・丸善の書店在庫)The Code4Lib Journal(海外書籍・雑誌)Open Library(海外書籍・雑誌)Springer(海外書籍・雑誌)
出版社
出版社検索API(出版社コード・ISBN → 出版社名や連絡先 etc.)
論文検索CiNii(論文)AIRwayプロジェクト(論文)Elsevier Article API Profile(海外大手出版社・エルゼビア社の論文)
アルバムTOLOT+アプリ マネタイズAPI、OEM プリントAPI
辞書辞書Wikipediaデ辞蔵ソシオヘルス(医者からもらった薬がわかる本 etc.)トレンドワードはてなキーワードkizasi.jp「今日は何の日」API
IMEATOKダイレクト API
メール・メッセージングメールOutlook.comGmailYahoo! Japan メールLobi(認証なしでチャット可能)
メッセージングSkypeWindows MessengerはてなメッセージChatWork
検索BingLive SearchYahoo! Japan カテゴリ検索検索順位取得API.comAPI比較・マッチングサービスAPI(API自体の検索)reflexa(連想検索)goo検索
ナレッジベースQiitaStack Overflow(エンジニア向け英語Q&A)人力検索はてなYahoo! Japan 知恵袋教えて!goo
言語・テキスト解析テキスト解析SumibiWebAPIYahoo! Japan テキスト解析日本語解析エンジン「なずき」(感性抽出)有害情報フィルタAPI個人情報フィルタAPI5W1H抽出API大人なツイートAPI(アダルトな表現を含むツイートの抽出)
hotaru / mushikago.org翻訳Google TranslateMicrosoft TranslatorGengo(人力翻訳)
アカウントアグリゲーションZaim(家計簿)
決済クレジットカードVisaMasterCard
Web決済PayPalWebPayソフトバンク・ペイメントGoogle Commerce API
スマホ決済Square APICoiney(※公開予定)
EコマースショッピングAmazon.co.jpYahoo!ショッピング楽天市場DMMgooショッピングNTT-Xストア(PC、家電)apicos(@cosmeのクチコミ、商品情報)coneco.netYahoo! Japanマーケット(Androidアプリケーション)カラーミーショップ
オークションYahoo!オークション楽天オークション
アフィリエイトバリューコマース楽天アフィリエイトDWS3.0
チケットチケットぴあ
旅行楽天トラベルAPI一覧じゃらんAPI(国内ホテル空室検索、温泉検索、海外ホテル検索)AB-ROADyoyaQ.comJTB WEBサービス
http://www.find-job.net/startup/api-2013 より引用
一覧内のサービス名のクリックで、各サービスのページが開きます。
料理楽天レシピコンテンツポケット-栄養学
レストランぐるなびWebサービス食べログAPIホットペッパーロケタッチグルメBAR-NAVI(バー検索)
ゴルフ楽天GORAゴルフ(ゴルフ場検索)
中古車検索カーセンサーラボ.netgoo自動車&バイク
不動産不動産検索住まい探しノートgoo住宅・不動産
住宅・家電ダイワハウス(住宅内の家電・設備機器のコントロール)ガラポンTV(機器に録画された映像の活用)
占い・心理学Web ad Fortune(占い)コンテンツポケット-心理学API
バラエティクイズ研(クイズの出題)みんなのはなもげら(はなもげら短歌の生成)
学習ケイコとマナブケイコとマナブ 通信講座リクナビ進学
求人フロム・エー ナビしごとナビ
クーポングルーポンくまポンオールクーポンポンパレクーポンサイトjpShareee
イベントATNDconnpassお見合い・婚活パーティー日程情報API(婚活・お見合いパーティー)
ファッションホットペッパーBeautyArt Beat API
スケジュール・タスクカレンダー・スケジュールGoogle CalendarGoogle Apps PlatformIW3 PROJECT CALENDARサイボウズLive
サイボウズ ガルーン 3Backlog曜日・祝日計算サービス
タスクGoogle Tasks
コンタクトリストGoogle Contacts
デザインDribbble
エンジニアリングDeployGate(Android開発、自動ビルドと自動配布をラクに)lleval(JavaScript以外の言語をブラウザーで実行できる)Dozens(Dozenで管理しているドメインのゾーン、レコード etc.)
バージョン管理システムGitHubBitbucketAssemblaStash
クラウドストレージGoogle DriveGoogle AppsDropboxSugarsyncSkyDriveBitcasa(※公開予定)Evernote
クラウドサービスIaaS・VPSAmazon Web サービスさくらのクラウドニフティクラウドクラウド・エヌWindows Azure Service Management API
PaaSHerokuforce.comGoogle App EngineCloud FoundryOpenShiftAWS Elastic BeanstalkdotCloudmitsubachi
BaaSParseappiariesKiiクラウド(モバイル専用)Appcelerator Cloud ServiceDropbox Datastore API
広告Google Advertise
RSSRSSナビ RSET APIlivedoor Reader
アクセス解析Google Analytics
画像認識顔検出顔ラボ(顔検出)PUX(顔検出、顔認識、ペット検出、オブジェクト認識、手書き文字認識)detectFace();(顔認識)
音声認識Web Speech APIw3voice Laboratory
計算計算式構文解析サービス
ユーティリティスパムURLチェックFC2ソーシャルスパム対策
URL短縮bitlyGoogle URL Shortener APIp.tl
ワイヤフレーム作成Cacoo
グラフ生成Google Charts(グラフやチャートを画像で取得)はてなグラフJSChart(円グラフ、棒グラフ、選グラフ、積み上げ棒グラフ、百分率棒グラフ)HeartRails Graph(キュートな円グラフ)
Webサイトサムネイル生成thumbalizrSimpleAPIKikker WebAPIを強化 ‒ Ryoの開発日記HeartRails Capture(サムネイル画像生成、PDF ファイル生成)Mozshot
PDF生成HTML2PDF.BIZ
はんこ画像生成はんこAPI
http://www.find-job.net/startup/api-2013 より引用
一覧内のサービス名のクリックで、各サービスのページが開きます。
Hardware
Raspberry Pi mbed
Arduino BeagleBoardBeagleBone
Chromecast
Leap Motion Controller
WebRTCはファイルをWebサーバ上に置かないと動作しない。アドレスが http:// か https:// で始まる必要がある。送られてくる映像の表示サイズは、端末のカメラ性能だけでなく、帯域の状態によって動的に変わる。表示サイズをCSSで指定しておくと良い。
補足情報
その他の情報
Node.jsによる簡単なWeb Server + WebSocket Server(Signaling Server)
server/├── app.js├── node_modules/├── package.json└── public/ ├── index.html ├── scripts/ │ └── script.js └── styles/ └── style.css
// app.jsvar WebSocketServer = require('ws').Server , express = require('express') , http = require('http') , path = require('path') , logger = require('morgan');
var app = express();
app.set('port', process.env.PORT || 3000);app.use(logger());app.use(express.static(path.join(__dirname, 'public')));
var conns = [];var server = http.createServer(app);var wss = new WebSocketServer({server: server});
wss.on('connection', function(ws) { conns.push(ws); ws.on('message', function(data) { conns .filter(function(conn) {return conn != ws;}) .forEach(function(conn) {conn.send(data);}); }); ws.on('close', function() { conns.splice(conns.indexOf(ws), 1); });});
server.listen(app.get('port'), function() { console.log('Express server listening on port ' + app.get('port'));});
// package.json{ "name": "SignalingServer", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "ws": "*", "express": "4.*.*", "morgan": "*" }, "engines": { "node": "0.10.*", "npm": "1.*.*" }}
レビュアーとして参加していますが、宣伝ではありません。念のため。http://www.oreilly.co.jp/books/9784873116761/
ハイパフォーマンスブラウザネットワーキング
WebRTCの下回りを理解したい人にお勧め。#HPBNj
完
質疑応答
付録
chrome://webrtc-internals/
ChromeのWebRTCの接続状態を確認するツール
chrome://webrtc-logs/
about:webrtc
FirefoxのWebRTCの接続状態を確認するツール
getUserMediaのオプション例
音量映像の縦横最大 / 最小
フレームレート最大 / 最小
アスペクト比
利用するカメラuser(前面)environment(背面)leftright
etc.
まだ仕様が固まってない? 動作が不安定。
navigator.getUserMedia( constraints, onSuccess, onError);
// HPBNに載っている指定方法// Chrome : エラー / Firefox : 無視var constraints = { audio: true, video: { mandatory: { width: { min: 320 }, height: { min: 180 } }, optional: [ { width: { max: 1280 }}, { frameRate: 30 }, { facingMode: "user" } ] }};
// 仕様書に載っている指定方法// Chrome : エラー / Firefox : 無視var constraints = { video: { mandatory: { width: { min: 640 }, height: { min: 480 } }, optional: [ { width: 650 }, { width: { min: 650 }}, { frameRate: 60 }, { width: { max: 800 }}, { facingMode: "user" } ] }};
// 一般的な指定方法var constraints = { audio: true, video: true};
// 動作が確認できた指定方法// Chrome : 成功 / Firefox : 無視var constraints = { video: { mandatory: { maxWidth: 320, maxHeight: 320, maxFrameRate: 15 }, optional: [ {facingMode: 'user'} ] }, audio: true};
まだ仕様が固まってない? 動作が不安定。
createOfferのオプション例
// データ通信専用のコネクション作成var mediaConstraints = {offerToReceiveAudio: false, offerToReceiveVideo: false};
// 音声用のコネクション作成(DataChannelを使わなければ音声専用)var mediaConstraints = {offerToReceiveAudio: true, offerToReceiveVideo: false};
// 映像用のコネクション作成(DataChannelを使わなければ映像専用)var mediaConstraints = {offerToReceiveAudio: false, offerToReceiveVideo: true};
まだ仕様が固まってない様子。Working DraftとEditor's Draftで指定方法が違う。指定できるオプションは他にもある。
peer.createOffer(onSuccess, onError, mediaConstraints);
createDataChannelのオプション例
// 順序通り 信頼性有 (like TCP)var dataChannelInit = {};
// 順不同 信頼性無 (like UDP)var dataChannelInit = {ordered: false, maxRetransmits: 0};
// 順不同 信頼性有var dataChannelInit = {ordered: false};
// 順序通り 部分的信頼性(再送カウンタの上限あり:3回)var dataChannelInit = {ordered: true, maxRetransmits: 3};
// 順不同 部分的信頼性(タイムアウトあり:1000ms)var dataChannelInit = {ordered: false, maxRetransmitTime: 1000};
peer.createDataChannel('DataChannel', dataChannelInit);
指定できるオプションは他にもある。
WebRTChttp://www.webrtc.org/
Media Capture and StreamsWorking Draft
http://www.w3.org/TR/mediacapture-streams/Editor's Draft
http://dev.w3.org/2011/webrtc/editor/getusermedia.htmlWebRTC 1.0: Real-time Communication Between Browsers
Working Drafthttp://www.w3.org/TR/webrtc/
Editor's Drafthttp://dev.w3.org/2011/webrtc/editor/webrtc.html
High Performance Browser Networking - Chapter 18. WebRTCハイパフォーマンス ブラウザネットワーキングの原著のオンライン版内 (英語)http://chimera.labs.oreilly.com/books/1230000000545/ch18.html
WebRTC | HTML5Experts.jphttp://html5experts.jp/tag/webrtc/
情報源
WebRTCのオープンソースソフトウェアまとめ - Qiitahttp://qiita.com/atskimura/items/97b2cc04e19781f4a4e6
PeerJSPeerJS - Simple peer-to-peer with WebRTC
http://peerjs.com/PeerJS Documentation
http://peerjs.com/docs/#apiPeerJS ドキュメント(SkyWayのサイト内)
http://nttcom.github.io/skyway/docs/SkyWay
SkyWay - WebRTCを簡単&柔軟に使えるプラットフォームhttp://nttcom.github.io/skyway/
PeerJS ドキュメント(SkyWayのサイト内)http://nttcom.github.io/skyway/docs/
情報源
getUserMediaPitch Detector with getUserMediahttp://webaudiodemos.appspot.com/pitchdetect/index.html
PhiloGL - Real time color 3D histogramhttp://www.senchalabs.org/philogl/PhiloGL/examples/histogram/
An AR Gamehttps://developer.mozilla.org/ja/demos/detail/an-ar-game/launch
Facetracking examplehttp://auduno.github.io/clmtrackr/clm_video.html
Emotion detection examplehttp://auduno.github.io/clmtrackr/examples/clm_emotiondetection.html
Face substitutionhttp://auduno.github.io/clmtrackr/examples/facesubstitution.html
Real-time Communication Between BrowsersVideo Chat with getUserMedia
https://apprtc.appspot.com/VCMap - Video Chat on The Map
http://vcmap.net/Cube Slam
https://www.cubeslam.com/
デモ一覧