Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WebブラウザでP2Pを実現する、WebRTCのAPIと周辺技術

 WebブラウザでP2Pを実現する、WebRTCのAPIと周辺技術

ysugimoto

June 27, 2017
Tweet

More Decks by ysugimoto

Other Decks in Technology

Transcript

  1. P2P Connection P2Pͷ઀ଓཱ֬ϑϩʔ PeerʢϐΞʣͷੜ੒ σʔλɾϏσΦετϦʔϜͷ઀ଓ Session Description Protocolͷަ׵ Offer /

    Answer Signaling P2P௨৴ܦ࿏ީิͷڞ༗ʢIceCandidateʣ σʔλૹ৴ͷڞ༗or ϏσΦετϦʔϜͷڞ༗
  2. var peer = new webkitRTCPeerConnection({ "iceServers": [{"url": "stun:stun.l.google.com:19302"}] }); Peerͷੜ੒

    “iceServers”ͱ͍͏ϓϩύςΟΛ࣋ͭΦϒδΣΫτΛҾ਺ʹ౉͢ var websocket = new WebSocket(‘ws://www.xxx.yyy.zzz’); Signalling༻ʹWebSocketͷ઀ଓ΋ߦ͏
  3. ϝσΟΞ઀ଓ // ϝσΟΞʹؔ͢Δઃఆ var constraint = { audio: true, video:

    true }; navigator.webkitGetUserMedia( constraint, successCallback, errorCallback ); constraint: audio: ϚΠΫΛ࢖͏͔Ͳ͏͔ video: ΧϝϥΛ࢖͏͔Ͳ͏͔ successCallback: ϝσΟΞ઀ଓ੒ޭ࣌ͷίʔϧόοΫ   errorCallback: ϝσΟΞ઀ଓࣦഊ࣌ͷίʔϧόοΫ  
  4. ࣗ෼ͷετϦʔϜ઀ଓ // ࣗ෼ͷετϦʔϜ͸MediaStream API͔Βऔಘ͢Δ navigator.webkitGetUserMedia( { audio: true, video: true

    }, function(stream) { // videoཁૉऔಘ var video = document.getElementById('localVideo'); // srcʹBlob URLΛࢦఆ͢ΔͱΧϝϥͷը૾͕ετϦʔϜͰྲྀΕΔ video.src = window.webkitURL.createObjectURL(stream); // ࣗ෼ͷpeerʹΧϝϥετϦʔϜΛ઀ଓͤ͞Δ peer.addStream(stream); }, function(err) { console.log(err.name + ': ' + err.message); } );
  5. ૬खͷετϦʔϜ઀ଓ // ૬खͷετϦʔϜ͸P2PͷΠϕϯτ͔Βऔಘ͢Δ peer.onaddstream = function(evt) { // ࣗ෼ͷϦϞʔτʹηοτ var

    video = document.getElementById('remoteVideo'); video.src = window.webkitURL.createObjectURL(evt.stream); }; onaddstreamΠϕϯτϋϯυϥͰ઀ଓ
  6. Offer / Answer Telephone #͞Μʹి࿩͠Α͏ "͞Μ͔Βண৴ͩ ి࿩ʹग़Α͏ ͭͳ͕ͬͨ Phone Carrier

    Server 0⒎FSૹ৴ -PDBM%FTDSJQUJPOηοτ 0⒎FSண৴ 3FNPUF%FTDSJQUJPOண৴ "OTXFSૹ৴ 3FNPUF%FTDSJQUJPOηοτ -PDBM%FTDSJQUJPOηοτ "OTXFSண৴ 3FNPUF%FTDSJQUJPOηοτ ᶃ ᶄ ᶅ ᶆ
  7. Signaling P2P #͞Μͱ௨৴͠Α͏ "͞Μ͔ΒDBMMͩ Ԡ౴͠Α͏ ͭͳ͕ͬͨ Signaling Server (WebSocket) 0⒎FSૹ৴

    -PDBM%FTDSJQUJPOηοτ 0⒎FSண৴ 3FNPUF%FTDSJQUJPOண৴ "OTXFSૹ৴ 3FNPUF%FTDSJQUJPOηοτ -PDBM%FTDSJQUJPOηοτ "OTXFSண৴ 3FNPUF%FTDSJQUJPOηοτ ᶃ ᶄ ᶅ ᶆ
  8. Offerͷૹ৴ʢൃ৴ऀʣ // Offerૹ৴ peer.createOffer(function(sdp) { // Ҿ਺ͷSDP͸ࣗ෼༻ peer.setLocalDescription(sdp, function() {

    // ηοτ׬ྃͨ͠Βɺ૬खʹࣗ෼ͷSDPΛૹΔ(signaling) websokcet.send(JSON.stringify({ "sdp": sdp, "uuid": uuid })); }); });
  9. Signaling Offer #͞Μͱ௨৴͠Α͏ "͞Μ͔ΒDBMMͩ Ԡ౴͠Α͏ ͭͳ͕ͬͨ Signaling Server (WebSocket) 0⒎FSૹ৴

    -PDBM%FTDSJQUJPOηοτ 0⒎FSண৴ 3FNPUF%FTDSJQUJPOண৴ "OTXFSૹ৴ 3FNPUF%FTDSJQUJPOηοτ -PDBM%FTDSJQUJPOηοτ "OTXFSண৴ 3FNPUF%FTDSJQUJPOηοτ ᶃ ᶄ ᶅ ᶆ
  10. Offerͷड͚औΓͱAnswerͷੜ੒ʢԠ౴ऀʣ // websocketͷϝοηʔδΠϕϯτͰड͚औΔ websocket.onmessage = function(evt) { var message =

    JSON.parse(evt.data), sdp; if ( message.sdp ) { sdp = new RTCSessionDescription(message.sdp); // ૬ख༻ʢremoteʣʹηοτ peer.setRemoteDescription(sdp, function() { // ࣗ෼΁ͷOffer-SDPͩͬͨΒAnswerΛฦ͢ if ( sdp.type === "offer" ) { peer.createAnswer(function(sdp) { peer.setLocalDescription(sdp, function() { // ηοτ׬ྃͨ͠Βɺ૬खʹࣗ෼ͷSDPΛૹΔ websokcet.send(JSON.stringify({ "sdp": sdp, "uuid": uuid })); })); }); } }); } }; ᶄɾᶆ ᶅ
  11. Signaling Signaling #͞Μͱ௨৴͠Α͏ "͞Μ͔ΒDBMMͩ Ԡ౴͠Α͏ ͭͳ͕ͬͨ Signaling Server (WebSocket) 0⒎FSૹ৴

    -PDBM%FTDSJQUJPOηοτ 0⒎FSண৴ 3FNPUF%FTDSJQUJPOண৴ "OTXFSૹ৴ 3FNPUF%FTDSJQUJPOηοτ -PDBM%FTDSJQUJPOηοτ "OTXFSண৴ 3FNPUF%FTDSJQUJPOηοτ ᶃ ᶄ ᶅ ᶆ
  12. 4JHOBMJOH4FSWFS var ws = require(‘websocket.io’); var server = ws.listen(8124); //

    ઀ଓΠϕϯτ server.on(‘connection’, function(socket) { socket.on(‘message’, function(data) { console.log(‘Message received:’ + data); ɹɹɹɹɹ//ɹ઀ଓऀશһʹϒϩʔυΩϟετ server.client.forEach(function(client) { client && client.send(data); }); }); }); γϯϓϧͳ WebSocket $ node server.js
  13. SDP SDP Sample v=0 o=- 6636874602225569115 2 IN IP4 127.0.0.1

    ... m=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126 ... m=video 1 RTP/SAVPF 100 116 117 ... a=sctpmap:5000 webrtc-datachannel 1024 a=ssrc:3712708814 cname:dgbXDOpXGNofSBNB a=ssrc:3712708814 msid:RTCDataConnection RTCDataConnection a=ssrc:3712708814 mslabel:RTCDataConnection a=ssrc:3712708814 label:RTCDataConnection
  14. ௨৴ܦ࿏ͷڞ༗ʢൃ৴ऀԠ౴ऀʣ // STUNαʔό͔Βܦ࿏ީิ͕ݟ͔ͭΔͨͼൃՐ peer.onicecandidate = function(evt) { var candidate; //

    evt.candidateϓϩύςΟʹσʔλ͕ೖ͍ͬͯΔͷͰɺWebSocketͰૹ৴ if ( evt.candiate ) { websocket.send(JSON.stringify({"candidate": evt.candidate})); } }; // websocketͷϝοηʔδϋϯυϥ಺Ͱૹ৴͞Ε͖ͯͨσʔλΛ෮ݩͯ͠ηοτ͢Δ websocket.onmessage = function(evt) { var message = JSON.parse(evt.data), candidate; // evt.candidate͕͋Ε͹Candidateͷڞ༗ if ( evt.candidate ) { candidate = new RTCIceCandidate(evt.candidate); peer.addIceCandidate(candidate); } };
  15. IceCandidate STUN Server TURN Server C1:ಉҰNAT಺(host) C1 C1 C2 C2

    C2: STUNʹΑΔNAT Traversal(srflx) C3 C3 C3: TURNʹΑΔNAT Traversal(relay)
  16. IceCandidate sample IceCandidate mid: video, candidate: a=candidate:1574647786 1 \ udp

    2113937151 xxx.xxx.xxx.xx 64219 \ typ host generation 0 mid: video, candidate: a=candidate:4102338623 1 \ udp 1845501695 yyy.yyy.yyy.yy 41073 \ typ srflx raddr xxx.xxx.xxx.xx rport 64219 generation 0
  17. Local Machine G: 192.168.0.1 Local Machine G: 192.168.0.2 Signaling Server

    STUN TURN Server P2P Mechanism Signaling SDP SDP
  18. Signaling Server STUN TURN Server P2P Mechanism Candidate Candidate Local

    Machine G:192.168.0.1 Local Machine G: 192.168.0.2
  19. UDP / unicast Signaling Server STUN TURN Server P2P Mechanism

    Connected Local Machine G: 192.168.0.1 Local Machine G: 192.168.0.2
  20. Signaling Server STUN TURN Server P2P Mechanism Connected Local Machine

    P: 192.168.0.1 Local Machine P: 192.168.0.2 G: 10.1.12.21 G:10.1.12.20 UDP / unicast
  21. Symmetric NAT NATͷछྨ ಺෦ύέοτ͸શͯ།ҰͷIP:PortʹϚοϓ ͞ΕΔNAT Local Machine P: 192.168.0.1:255 G:

    10.1.12.20:80 G:xxx.xxx.xxx.xx :60313 G:yyy.yyy.yyy.yy packet Host A Host B ಺෦͔ΒͷύέοτΛड͚औͬͨ֎෦ϗετ͔Β ͷΈͷύέοτΛड৴͢Δ
  22. STUN Algorithm ҟͳΔIP:Port͔Βͷechoཁٻ Full cone NAT ड͚औΕͨ ड͚औΕͳ͔ͬͨ ಉ͡IP:Port͔Βͷechoཁٻʢαʔόʣ PublicIP:

    xxx.xxx.xxx.xx:yy PublicIPมΘͬͯͳ͍ PublicIPมΘͬͨ Symmetric NAT ಉ͡IPҟͳΔPort͔Βͷechoཁٻ ड͚औΕͨ ड͚औΕͳ͔ͬͨ Address-Restricted NAT Port-Restricted NAT : OK : NG
  23. var PublicIP = ‘xxx.xxx.xxx.xxx’; if ( Stun.hasReceivedFrom(defferentAddr, differentPort) ) {

    return Stun.FullConeNATs; } else if ( Stun.hasReceivedFrom(sameAddr, samePort) ) { if ( Stun.isConstantIP(PublicIP) ) { return Stun.SymmetricNATs; } if ( Stun.hasReceivedFrom(sameAddr, differrentPort) ) { return Stun.AddressRestrictedNATs; } else { return Stun.PortRestrictedNATs; } } STUN Algorithm
  24. STUN UDP Hole Punching Restricted-NATͷಛੑΛར༻͠ɺSTUNαʔόʢ֎෦NAT ʹ޲͚ͯύέοτΛૹ৴ͨ͠IP:PortΛ఻͑Δ Local Machine A P:

    192.168.0.1:255 xxx.xxx.xxx.xx:3478 STUN Server ᶃύέοτૹ৴ ᶄ͜ͷૹ৴ݩIP:PortΛ Local Machineʹ఻͑Δ NAT-B΋ಉ༷ʹ IP:Port A IP:Port B NAT-A
  25. STUN UDP Hole Punching(1/3) Local Machine A P: 192.168.0.1:255 Local

    Machine B P: 192.168.0.2:255 NAT-A NAT-B IP:Port A IP:Port B IP:PortA->IP:PortB΁ύέοτΛૹ৴͢Δ͕ɺ NAT-B͸͜ͷύέοτΛഁغ͢Δ IP:PortB -> IP:PortA ΁ͷύέοτ͸ ૄ௨ՄೳʹͳΔ(NAT-A)
  26. STUN UDP Hole Punching(2/3) Local Machine A P: 192.168.0.1:255 Local

    Machine B P: 192.168.0.2:255 NAT-A NAT-B IP:Port A IP:Port B IP:PortB->IP:PortA΁ύέοτΛૹ৴͢Δͱɺ NAT-A͸͜ͷύέοτΛड৴͢Δ IP:PortA -> IP:PortB ΁ͷύέοτ͸ ૄ௨ՄೳʹͳΔ(NAT-B)
  27. STUN UDP Hole Punching(3/3) Local Machine A P: 192.168.0.1:255 Local

    Machine B P: 192.168.0.2:255 NAT-A NAT-B IP:Port A IP:Port B IP:PortA->IP:PortB΁࠶౓ύέοτΛૹ৴͢Δͱɺ NAT-B͸ࠓ౓͸ύέοτΛड৴͢Δ IP:PortA / IP:PortB ʹUDPύέοτͷ ͕݀։͍ͨঢ়ଶ
  28. NATλΠϓʹΑΔP2P NAT Type Full cone Address-Rest Port-Rest Symmetric Full cone

    Address-Rest Port-Rest Symmetric P2P Enables Using UDP Hole Punching
  29. NATλΠϓʹΑΔP2P NAT Type Full cone Address-Rest Port-Rest Symmetric Full cone

    Address-Rest Port-Rest Symmetric P2P Enables Using UDP Hole Punching Using TURN Relay
  30. DataChannelੜ੒  // SDPΛੜ੒͢Δલʹ࡞੒͓ͯ͘͠ඞཁ͕͋Δ var dataChannel = peer.createDataChannel('RTCDataChannel'); // ΠϕϯτͳͲΛॳظԽ

    initializeDataChannel(dataChannel); // ૬ख͔ΒͷDataChannelͷ઀ଓ͸ΠϕϯτͰ؂ࢹ peer.ondatachannel = function(evt) { // evt.channelʹDataChannel͕֨ೲ͞Ε͍ͯΔ dataChannel = evt.channel; initializeDataChannel(dataChannel); }; // σʔλૹ৴͸send()ϝιου dataChannel.send('some data');
  31. function initializeDataChannel(dataChannel) { dataChannel.onmessage = function(evt) { var message =

    evt.data; // do something }; dataChannel.onopen = function() { // do something }; dataChannel.onclose = function() { // do something }; dataChannel.onerror = function() { // do something }; } DataChannelੜ੒  WebSocketͱ ಉ͡Πϕϯτ*'
  32. Data Channel Transports Reliable mode SCTPϓϩτίϧͰసૹ σʔλͷॱং͸อূ͞Εɺ࠶ૹ੍ޚ΋಺෦Ͱ͔͔Δ Non-Reliable mode RTPϓϩτίϧͰసૹ

    σʔλͷॱং͸อূ͞Εͣɺ࠶ૹ੍ޚ΋࣮૷͢Δඞཁ͕͋Δ ChannelؒͰޓ׵ੑ͕อͯͳ͍ older
  33. WebRTC - Overview http:/ /www.webrtc.org/ [PDF] ICE TURN/STUN tutorial http:/

    /sdstrowes.co.uk/talks/20081031-ice-turn-stun-tutorial.pdf WebRTC 1.0: Real-time Communication Between Browsers http:/ /www.w3.org/TR/webrtc/ WebRTC in the real world: STUN, TURN and signaling http:/ /www.html5rocks.com/en/tutorials/webrtc/infrastructure/ Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal for Offer/Answer Protocols https:/ /tools.ietf.org/html/rfc5245 SDP: Session Description Protocol http:/ /tools.ietf.org/html/rfc4566 STUN - Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs http:/ /tools.ietf.org/html/rfc3489 Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN) http:/ /tools.ietf.org/html/rfc5766 Thanks! Resources