WebRTC Amitesh Madhur (@amiteshawa) Cisco Systems
May 08, 2015
WebRTCAmitesh Madhur (@amiteshawa)
Cisco Systems
Agenda
1. Media Stream 2. Constraints3. RTCPeerConnection 4. Network (STUN, TURN)5. DataChannel6. Ephemeral password
Peer to peer, plugin free!
ServerX
WebRTC1. MediaStream
2. RTCPeerConnection
3. DataChannel
Media Stream
1. getUserMedia2. Collects audio, video, screen inputs3. Synchronizes Audio & Video4. Noise Cancellation5. Image Enhancement
<video id=“me" autoplay></video>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia; if (navigator.getUserMedia) navigator.getUserMedia(video: true, onSuccess, onError);
window.URL = window.URL || window.webkitURL; var me = document.getElementById('me');
function onSuccess(stream) me.src = window.URL.createObjectURL(stream); function onError(e) // error
Demo
<style> video
-webkit-transform: scaleX(-1);
</style>
<video id=“me" autoplay></video>
Confused Left/Right?
canvasContext.translate(width, 0); canvasContext.scale(-1, 1);
<video id=“me" autoplay></video>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia; if (navigator.getUserMedia) navigator.getUserMedia(video: true, onSuccess, onError);
window.URL = window.URL || window.webkitURL; var me = document.getElementById('me');
function onSuccess(stream) me.src = window.URL.createObjectURL(stream); function onError(e) // error
navigator.getUserMedia(video: true,
onSuccess, onError);
Constraints
audio: true, video: true
Constraints (audio, video)
audio: true,video:
mandatory: maxWidth: 320, maxHeight: 180
Constraints (video height, width)
getUserMedia(video: mandatory:
chromeMediaSource: 'screen'
, audio: false, onSuccess, onError);
Constraints for screen capture
1. Works only on https 2. chrome://flags/#enable-usermedia-screen-
capture
chromeMediaSource: 'screen'
Peer Connection
1. Establish a connection though Signaling2. Pass the user media stream3. Other side gets the stream4. Add the received stream to <video> tag
Demo
github.com/amiteshawa/learn-rtc
<video id=“me" autoplay></video> <video id=“other" autoplay></video>
peer = new RTCPeerConnection(servers);peer.onaddstream = gotRemoteStream;peer.addStream(localStream);
if(host) peer.createOffer(callGotOffer, null, mandatory:
OfferToReceiveAudio: true, OfferToReceiveVideo: true);
else peer.createAnswer(peer.remoteDescription, callGotOffer);function callGotOffer(sd) peer.setLocalDescription(sd); function gotAnswer(desc) peer.setRemoteDescription(new RTCSessionDescription(desc)); function gotRemoteStream(e) attachMediaStream(remoteVideo, e.stream);
<video id=“me" autoplay></video> <video id=“other" autoplay></video>
peer = new RTCPeerConnection(servers);peer.onaddstream = gotRemoteStream;peer.addStream(localStream);
if(host) peer.createOffer(callGotOffer, null, mandatory:
OfferToReceiveAudio: true, OfferToReceiveVideo: true);
else peer.createAnswer(peer.remoteDescription, callGotOffer);function callGotOffer(sd) peer.setLocalDescription(sd); function gotAnswer(desc) peer.setRemoteDescription(new RTCSessionDescription(desc)); function gotRemoteStream(e) attachMediaStream(remoteVideo, e.stream);
var STUN, TURN, config = ;STUN = url: “stun:stun.l.google.com:19302”;TURN = username: “turn-user", credential: "NGFmNGRlMOWZmMTVmZGZiNg==",
url: "turn:10.5.7.13:3333?transport=udp“ ;config.iceServers = [STUN, TURN];
User 1 User 2Page Load
Page Load
Websocket
Renders Invite Button
Renders Invite Button
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create InviteClicks Invite Button
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast Invite
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast Invite
Invite Button Changed to “Join”Ignored Invite
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast InviteInvite Button Changed to “Join”
Ignored Invite Clicked Join Button
GUMOffer SDPOffer SDP
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast InviteInvite Button Changed to “Join”
Ignored Invite Clicked Join ButtonOffer SDPOffer SDP
Answer SDP Answer SDP
Remote Desc
GUM
GUM
Remote Desc
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast InviteInvite Button Changed to “Join”
Ignored Invite Clicked Join ButtonOffer SDPOffer SDP
Answer SDP Answer SDP
Remote DescICE CandidateICE Candidate
GUM
Remote Desc
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast InviteInvite Button Changed to “Join”
Ignored Invite Clicked Join ButtonOffer SDPOffer SDP
Answer SDP Answer SDP
Remote DescICE CandidateICE Candidate
ICE Candidate ICE Candidate
Add StreamAdd Stream
GUM
Remote Desc
GUM
User 1 User 2Page Load Page Load
Websocket
Open connection Open connection
Create Invite Broadcast Invite
Broadcast InviteInvite Button Changed to “Join”
Ignored Invite Clicked Join ButtonOffer SDPOffer SDP
Answer SDP Answer SDP
Remote DescICE CandidateICE Candidate
ICE Candidate ICE Candidate
Add Stream
Add Stream
GUM
Remote Desc
GUM
STUN/TURN and ICE
NAT
STUN
NAT
NAT
STUN
NAT
Not 100% Reliable
NAT
TURN
SECURE
NAT
NAT
TURN
SECURE
NAT
Expensive & Slow
SECURE
NAT
ICE
NAT
STUNTURN
Public STUNstun.l.google.com:19302stun1.l.google.com:19302stun2.l.google.com:19302stun3.l.google.com:19302stun4.l.google.com:19302
slideshare.net/amiteshawa/web-rtc-media-stra
Wanna Setup your own?
Data Channel
RTCDataChannel
1. Peer to peer data sharing2. Works with RTCPeerConnection3. Secure4. Websocket like APIs
createOffer = function() peer = new webkitRTCPeerConnection(config,
optional: [RtpDataChannels: true]); channel = peer.createDataChannel("sendDataChannel",
reliable: false); channel.onopen = manageChannel; channel.onclose = manageChannel; , sendData = function(data) channel.send(data); , onMsg = function(e) obj.innerHTML += 'He: ' + e.data ; , manageChannel = function() if (channel.readyState === "open") channel.onmessage = onMsg; ;
Demo
Ephemeral password
IN JAVASCRIPTvar turn; turn = url: 'turn:<user-name>@<IP>:<PORT>',
credential: ‘password‘;
// for chrome 28 and aboveturn = url: 'turn:<IP-address>:<PORT>', username: ‘<user-name>‘, credential: ‘<password>' ;
Ephemeral password
1. Limited time TURN credentials2. Based on REST Service3. Webserver creates password4. Shared secret5. TURN Server does NOT implement the REST API6. Based on long-term credentials mechanism
long-term credentials
User TURNUser sends request to TURN without password
long-term credentials
User TURNUser sends request to TURN without password
TURN send Error 401, with realm and nonce
long-term credentials
User TURNUser sends request to TURN without password
TURN send Error 401, with realm and nonce
User Checks 401 and extracts realm and nonce
long-term credentials
User TURNUser sends request to TURN without password
TURN send Error 401, with realm and nonce
User Checks 401 and extracts realm and nonceUser generates MD5 key with user, realm
long-term credentials
User TURNUser sends request to TURN without password
TURN send Error 401, with realm and nonce
User Checks 401 and extracts realm and nonceUser generates MD5 key with user, realm
User sends new request to TURN with password
long-term credentials
User TURNUser sends request to TURN without password
TURN send Error 401, with realm and nonce
User Checks 401 and extracts realm and nonceUser generates MD5 key with user, realm
User sends new request to TURN with password
TURN Validates
Matches? Then connected
Long-term password alone does not solve the problem for WebRTC
Ephemeral credentials
User TURN
my-svc/get-turn-auth
REST Server
MySQL
Shared SecretCreates username, password
Sends username, password
Send connection request to TURN
Shared Secret
After this it same as long term auth
Create Tables
CREATE TABLE turnusers_lt ( name varchar(512) PRIMARY KEY, hmackey char(32));
CREATE TABLE turn_secret ( value varchar(512));
CREATE TABLE allowed_peer_ip ( ip_range varchar(256));
CREATE TABLE denied_peer_ip ( ip_range varchar(256));
Create REST API
Generate username and credential username= <USER NAME> + ":" + <timestamp>password = base64(hmac-sha1(secret, username))
"username" : "user1:1393412082", "password" : "NGFmNzUzZDIxOWE1OWI0NTBmZGZiNg==", "ttl" : 86400, "uris" : [ "turn:1.2.3.4:3333?transport=udp" ]var i, uri, iceServer, config = "iceServers": [];for (i = 0; i < response.uris.length; ++i) uri = response.uris[i]; iceServer = "username":response.username, "credential":response.password, "uri":uri ; config.iceServers.push(iceServer);var pc = new PeerConnection(config);
Config
1. In turnserver.conf Uncomment/Enable 1. lt-cred-mech2. use-auth-secret3. static-auth-secret4. mysql-userdb="host=127.0.0.1 dbname=turn
user=root password= port=3306 connect_timeout=60"
5. realm=foobar6. fingerprint7. Start turn: turnserver -c /usr/local/etc/turnserver.conf
Create User & Secret
Create Secret$ turnadmin --mysql-userdb="host=127.0.0.1 dbname=turn user=root password= connect_timeout=10" --set-secret=no1knows
>= 21 >= 20 >= 12
WebRTC4all…
Thank youTwitter: @amiteshawa