Created
October 29, 2018 11:35
-
-
Save flaviocopes/e0844d71da2348d14ec8b6742d8b2795 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ws = new WebSocket('ws://localhost:8080') | |
ws.onopen = () => { | |
console.log('Connected to the signaling server') | |
} | |
ws.onerror = err => { | |
console.error(err) | |
} | |
ws.onmessage = msg => { | |
console.log('Got message', msg.data) | |
const data = JSON.parse(msg.data) | |
switch (data.type) { | |
case 'login': | |
handleLogin(data.success) | |
break | |
case 'offer': | |
handleOffer(data.offer, data.username) | |
break | |
case 'answer': | |
handleAnswer(data.answer) | |
break | |
case 'candidate': | |
handleCandidate(data.candidate) | |
break | |
case 'close': | |
handleClose() | |
break | |
default: | |
break | |
} | |
} | |
let connection = null | |
let name = null | |
let otherUsername = null | |
const sendMessage = message => { | |
if (otherUsername) { | |
message.otherUsername = otherUsername | |
} | |
ws.send(JSON.stringify(message)) | |
} | |
document.querySelector('div#call').style.display = 'none' | |
document.querySelector('button#login').addEventListener('click', event => { | |
username = document.querySelector('input#username').value | |
if (username.length < 0) { | |
alert('Please enter a username 🙂') | |
return | |
} | |
sendMessage({ | |
type: 'login', | |
username: username | |
}) | |
}) | |
const handleLogin = async success => { | |
if (success === false) { | |
alert('😞 Username already taken') | |
} else { | |
document.querySelector('div#login').style.display = 'none' | |
document.querySelector('div#call').style.display = 'block' | |
let localStream | |
try { | |
localStream = await navigator.mediaDevices.getUserMedia({ | |
video: true, | |
audio: true | |
}) | |
} catch (error) { | |
alert(`${error.name}`) | |
console.error(error) | |
} | |
document.querySelector('video#local').srcObject = localStream | |
const configuration = { | |
iceServers: [{ url: 'stun:stun2.1.google.com:19302' }] | |
} | |
connection = new RTCPeerConnection(configuration) | |
connection.addStream(localStream) | |
connection.onaddstream = event => { | |
document.querySelector('video#remote').srcObject = event.stream | |
} | |
connection.onicecandidate = event => { | |
if (event.candidate) { | |
sendMessage({ | |
type: 'candidate', | |
candidate: event.candidate | |
}) | |
} | |
} | |
} | |
} | |
document.querySelector('button#call').addEventListener('click', () => { | |
const callToUsername = document.querySelector('input#username-to-call').value | |
if (callToUsername.length === 0) { | |
alert('Enter a username 😉') | |
return | |
} | |
otherUsername = callToUsername | |
connection.createOffer( | |
offer => { | |
sendMessage({ | |
type: 'offer', | |
offer: offer | |
}) | |
connection.setLocalDescription(offer) | |
}, | |
error => { | |
alert('Error when creating an offer') | |
console.error(error) | |
} | |
) | |
}) | |
const handleOffer = (offer, username) => { | |
otherUsername = username | |
connection.setRemoteDescription(new RTCSessionDescription(offer)) | |
connection.createAnswer( | |
answer => { | |
connection.setLocalDescription(answer) | |
sendMessage({ | |
type: 'answer', | |
answer: answer | |
}) | |
}, | |
error => { | |
alert('Error when creating an answer') | |
console.error(error) | |
} | |
) | |
} | |
const handleAnswer = answer => { | |
connection.setRemoteDescription(new RTCSessionDescription(answer)) | |
} | |
const handleCandidate = candidate => { | |
connection.addIceCandidate(new RTCIceCandidate(candidate)) | |
} | |
document.querySelector('button#close-call').addEventListener('click', () => { | |
sendMessage({ | |
type: 'close' | |
}) | |
handleClose() | |
}) | |
const handleClose = () => { | |
otherUsername = null | |
document.querySelector('video#remote').src = null | |
connection.close() | |
connection.onicecandidate = null | |
connection.onaddstream = null | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>WebRTC</title> | |
<link href="style.css" rel="stylesheet" type="text/css" /> | |
</head> | |
<body> | |
<div id="login"> | |
<label for="username">Login</label> | |
<input id="username" placeholder="Login" required="" autofocus=""> | |
<button id="login">Login</button> | |
</div> | |
<div id="call"> | |
<video id="local" autoplay></video> | |
<video id="remote" autoplay></video> | |
<div> | |
<input id="username-to-call" placeholder="Username to call" /> | |
<button id="call">Call</button> | |
<button id="close-call">Close call</button> | |
</div> | |
</div> | |
</body> | |
<script src="client.js"></script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const WebSocket = require('ws') | |
const wss = new WebSocket.Server({ port: 8080 }) | |
const users = {} | |
const sendTo = (ws, message) => { | |
ws.send(JSON.stringify(message)) | |
} | |
wss.on('connection', ws => { | |
console.log('User connected') | |
ws.on('message', message => { | |
let data = null | |
try { | |
data = JSON.parse(message) | |
} catch (error) { | |
console.error('Invalid JSON', error) | |
data = {} | |
} | |
switch (data.type) { | |
case 'login': | |
console.log('User logged', data.username) | |
if (users[data.username]) { | |
sendTo(ws, { type: 'login', success: false }) | |
} else { | |
users[data.username] = ws | |
ws.username = data.username | |
sendTo(ws, { type: 'login', success: true }) | |
} | |
break | |
case 'offer': | |
console.log('Sending offer to: ', data.otherUsername) | |
if (users[data.otherUsername] != null) { | |
ws.otherUsername = data.otherUsername | |
sendTo(users[data.otherUsername], { | |
type: 'offer', | |
offer: data.offer, | |
username: ws.username | |
}) | |
} | |
break | |
case 'answer': | |
console.log('Sending answer to: ', data.otherUsername) | |
if (users[data.otherUsername] != null) { | |
ws.otherUsername = data.otherUsername | |
sendTo(users[data.otherUsername], { | |
type: 'answer', | |
answer: data.answer | |
}) | |
} | |
break | |
case 'candidate': | |
console.log('Sending candidate to:', data.otherUsername) | |
if (users[data.otherUsername] != null) { | |
sendTo(users[data.otherUsername], { | |
type: 'candidate', | |
candidate: data.candidate | |
}) | |
} | |
break | |
case 'close': | |
console.log('Disconnecting from', data.otherUsername) | |
users[data.otherUsername].otherUsername = null | |
if (users[data.otherUsername] != null) { | |
sendTo(users[data.otherUsername], { type: 'close' }) | |
} | |
break | |
default: | |
sendTo(ws, { | |
type: 'error', | |
message: 'Command not found: ' + data.type | |
}) | |
break | |
} | |
}) | |
ws.on('close', () => { | |
if (ws.username) { | |
delete users[ws.username] | |
if (ws.otherUsername) { | |
console.log('Disconnecting from ', ws.otherUsername) | |
users[ws.otherUsername].otherUsername = null | |
if (users[ws.otherUsername] != null) { | |
sendTo(users[ws.otherUsername], { type: 'close' }) | |
} | |
} | |
} | |
}) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
div#call { | |
position: relative; | |
display: block; | |
margin: 0 auto; | |
width: 500px; | |
height: 500px; | |
} | |
video { | |
background: black; | |
border: 1px solid gray; | |
} | |
video#local { | |
width: 150px; | |
height: 150px; | |
position: absolute; | |
top: 15px; | |
right: 15px; | |
} | |
video#remote { | |
width: 500px; | |
height: 500px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment