Compare commits

..

No commits in common. "master" and "7_ontrack" have entirely different histories.

9 changed files with 186 additions and 213 deletions

View File

@ -1,6 +1,8 @@
WebRTC Example WebRTC Example
============== ==============
#### shane tully (shanetully.com)
An 'as simple as it gets' WebRTC example. An 'as simple as it gets' WebRTC example.
See [https://shanetully.com/2014/09/a-dead-simple-webrtc-example/](https://shanetully.com/2014/09/a-dead-simple-webrtc-example/) for a detailed walkthrough of the code. See [https://shanetully.com/2014/09/a-dead-simple-webrtc-example/](https://shanetully.com/2014/09/a-dead-simple-webrtc-example/) for a detailed walkthrough of the code.
@ -16,17 +18,18 @@ $ npm install
$ npm start $ npm start
``` ```
With the server running, open Firefox/Chrome/Safari and visit `https://localhost:8443`. With the server running, open a recent version of Firefox or Chrome and visit `https://localhost:8443`.
Please note the following: * Note the HTTPS! There is no redirect from HTTP to HTTPS.
* Note the HTTPS! There is no redirect from HTTP to HTTPS.
* You\'ll need to accept the invalid TLS certificate as it is self-signed and WebRTC must be run over TLS.
* Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines. * Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines.
## TLS
Recent versions of Chrome require secure websockets for WebRTC. Thus, this example utilizes HTTPS. Included is a self-signed certificate that must be accepted in the browser for the example to work.
## Problems? ## Problems?
This is a short example that I don't check often. As such, I rely on users for reports if something breaks. Issues and pull requests are greatly appreciated. WebRTC is a rapidly evolving beast. Being an example that I don't check often, I rely on users for reports if something breaks. Issues and pull requests are greatly appreciated.
## License ## License
@ -51,3 +54,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.

View File

@ -1,32 +1,32 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFkzCCA3ugAwIBAgIUD4Vfmfwa3e7F34wp7Wl08mOXqRcwDQYJKoZIhvcNAQEL MIIFiDCCA3CgAwIBAgIJAMSEu/mdFhkUMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODAxMDcyMzQz
DTIzMDUyNTA0MDAyOVoXDTMzMDUyMjA0MDAyOVowWTELMAkGA1UEBhMCQVUxEzAR MzRaFw0yODAxMDUyMzQzMzRaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV
IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A BAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrq
MIICCgKCAgEAiKvigFwEG4ahwAUAEoBw3p8ivp5fTYsMBGN6Zw3BjCJNuDB6Dhhv 0a9LjifYP7UEn5znTCatkSMlRERb+D2Nj0JfmGki5z2E/HOS3lpoBfIFqak+/+AZ
Opin2G0XjJWsii9RR09MJbdDgT2PBvnvbNkUZwcxcIdXOlIA/krC2NVz0u8VZeMi 8Xpg7EwNRZtrUd1ubanHQocl2vCLPPSNkoUavYojIPKM0OkGaCwt7fu2Igoch080
z+6tg2sgR7/HqdDoeqw7OTAErgU7lwA28C7tGydgSbOY+8KrPH+OXRoSzZC5pE7I m1VyOCB1VX1pl/k+0lcNMlE4mBczg3HBUJL+G21zjD9T4TalyGYKrZ1wZMJ/zxT6
GLAmuYLDR0xEKjMnOww9py0gmQsT/K4Gj188QfN1Pl7kd4qURSZXbfJ1cdZ9nIIu 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 KKNHDiqV4JiP4WWFN+pc2lOVaLJwTe4FrbG7AA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -6,16 +6,12 @@
</head> </head>
<body> <body>
<video id="localVideo" autoplay playsinline muted style="width:40%;"></video> <video id="localVideo" autoplay muted style="width:40%;"></video>
<video id="remoteVideo" autoplay playsinline style="width:40%;"></video> <video id="remoteVideo" autoplay style="width:40%;"></video>
<div style="margin-top: 10px;"> <br />
Open this page in a second browser window then click below to start the WebRTC connection.
</div>
<div style="margin-top: 10px;"> <input type="button" id="start" onclick="start(true)" value="Start Video"></input>
<input type="button" id="start" onclick="start(true)" value="Start WebRTC"></input>
</div>
<script type="text/javascript"> <script type="text/javascript">
pageReady(); pageReady();

View File

@ -1,54 +1,48 @@
let localStream; var localVideo;
let localVideo; var localStream;
let peerConnection; var remoteVideo;
let remoteVideo; var peerConnection;
let serverConnection; var uuid;
let uuid; var serverConnection;
const peerConnectionConfig = { var peerConnectionConfig = {
'iceServers': [ 'iceServers': [
{'urls': 'stun:stun.stunprotocol.org:3478'}, {'urls': 'stun:stun.services.mozilla.com'},
{'urls': 'stun:stun.l.google.com:19302'}, {'urls': 'stun:stun.l.google.com:19302'},
] ]
}; };
async function pageReady() { function pageReady() {
uuid = createUUID(); uuid = createUUID();
localVideo = document.getElementById('localVideo'); localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo'); remoteVideo = document.getElementById('remoteVideo');
serverConnection = new WebSocket(`wss://${window.location.hostname}:8443`); serverConnection = new WebSocket('wss://' + window.location.hostname + ':8443');
serverConnection.onmessage = gotMessageFromServer; serverConnection.onmessage = gotMessageFromServer;
const constraints = { var constraints = {
video: true, video: true,
audio: true, audio: true,
}; };
if(!navigator.mediaDevices.getUserMedia) { if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API'); alert('Your browser does not support getUserMedia API');
return;
} }
}
try { function getUserMediaSuccess(stream) {
const stream = await navigator.mediaDevices.getUserMedia(constraints); localStream = stream;
localVideo.srcObject = stream;
localStream = stream;
localVideo.srcObject = stream;
} catch(error) {
errorHandler(error);
}
} }
function start(isCaller) { function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig); peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate; peerConnection.onicecandidate = gotIceCandidate;
peerConnection.ontrack = gotRemoteStream; peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
for(const track of localStream.getTracks()) {
peerConnection.addTrack(track, localStream);
}
if(isCaller) { if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler); peerConnection.createOffer().then(createdDescription).catch(errorHandler);
@ -58,17 +52,17 @@ function start(isCaller) {
function gotMessageFromServer(message) { function gotMessageFromServer(message) {
if(!peerConnection) start(false); if(!peerConnection) start(false);
const signal = JSON.parse(message.data); var signal = JSON.parse(message.data);
// Ignore messages from ourself // Ignore messages from ourself
if(signal.uuid == uuid) return; if(signal.uuid == uuid) return;
if(signal.sdp) { if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(() => { peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers // Only create answers in response to offers
if(signal.sdp.type !== 'offer') return; if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
peerConnection.createAnswer().then(createdDescription).catch(errorHandler); }
}).catch(errorHandler); }).catch(errorHandler);
} else if(signal.ice) { } else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler); peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
@ -84,7 +78,7 @@ function gotIceCandidate(event) {
function createdDescription(description) { function createdDescription(description) {
console.log('got description'); console.log('got description');
peerConnection.setLocalDescription(description).then(() => { peerConnection.setLocalDescription(description).then(function() {
serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid})); serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler); }).catch(errorHandler);
} }
@ -105,5 +99,5 @@ function createUUID() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
} }
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`; return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
} }

View File

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

100
key.pem
View File

@ -1,52 +1,52 @@
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
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
ZEbffYj4hKrpVVuPFYwKzuLcXP1vTFQ= BfXBs2eSpBE70GwrztgDS2fco6tzQQ==
-----END PRIVATE KEY----- -----END PRIVATE KEY-----

59
package-lock.json generated
View File

@ -1,44 +1,33 @@
{ {
"name": "WebRTC-Example", "name": "WebRTC-Example",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 2, "lockfileVersion": 1,
"requires": true, "requires": true,
"packages": {
"": {
"name": "WebRTC-Example",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"ws": "^8.13.0"
}
},
"node_modules/ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
},
"dependencies": { "dependencies": {
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
},
"ws": { "ws": {
"version": "8.13.0", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"requires": {} "requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1",
"ultron": "1.1.1"
}
} }
} }
} }

View File

@ -17,8 +17,8 @@
"bugs": { "bugs": {
"url": "https://github.com/shanet/WebRTC-Example/issues" "url": "https://github.com/shanet/WebRTC-Example/issues"
}, },
"homepage": "https://github.com/shanet/WebRTC-Example", "homepage": "https://github.com/shanet/WebRTC-Example#readme",
"dependencies": { "dependencies": {
"ws": "^8.13.0" "ws": "^3.3.2"
} }
} }

View File

@ -5,65 +5,55 @@ const https = require('https');
const WebSocket = require('ws'); const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server; const WebSocketServer = WebSocket.Server;
// Yes, TLS is required for WebRTC // Yes, TLS is required
const serverConfig = { const serverConfig = {
key: fs.readFileSync('key.pem'), key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'), cert: fs.readFileSync('cert.pem'),
}; };
function main() { // ----------------------------------------------------------------------------------------
const httpsServer = startHttpsServer(serverConfig);
startWebSocketServer(httpsServer);
printHelp();
}
function startHttpsServer(serverConfig) { // Create a server for the client html page
// Handle incoming requests from the client const handleRequest = function(request, response) {
const handleRequest = (request, response) => { // Render the single client html file for any request the HTTP server receives
console.log(`request received: ${request.url}`); console.log('request received: ' + request.url);
// This server only serves two files: The HTML page and the client JS file if(request.url === '/') {
if(request.url === '/') { response.writeHead(200, {'Content-Type': 'text/html'});
response.writeHead(200, {'Content-Type': 'text/html'}); response.end(fs.readFileSync('client/index.html'));
response.end(fs.readFileSync('client/index.html')); } else if(request.url === '/webrtc.js') {
} else if(request.url === '/webrtc.js') { response.writeHead(200, {'Content-Type': 'application/javascript'});
response.writeHead(200, {'Content-Type': 'application/javascript'}); response.end(fs.readFileSync('client/webrtc.js'));
response.end(fs.readFileSync('client/webrtc.js')); }
} };
};
const httpsServer = https.createServer(serverConfig, handleRequest); const httpsServer = https.createServer(serverConfig, handleRequest);
httpsServer.listen(HTTPS_PORT, '0.0.0.0'); httpsServer.listen(HTTPS_PORT, '0.0.0.0');
return httpsServer;
}
function startWebSocketServer(httpsServer) { // ----------------------------------------------------------------------------------------
// Create a server for handling websocket calls
const wss = new WebSocketServer({server: httpsServer});
wss.on('connection', (ws) => { // Create a server for handling websocket calls
ws.on('message', (message) => { const wss = new WebSocketServer({server: httpsServer});
// Broadcast any received message to all clients
console.log(`received: ${message}`); wss.on('connection', function(ws) {
wss.broadcast(message); ws.on('message', function(message) {
}); // Broadcast any received message to all clients
console.log('received: %s', message);
wss.broadcast(message);
}); });
});
wss.broadcast = function(data) { wss.broadcast = function(data) {
this.clients.forEach((client) => { this.clients.forEach(function(client) {
if(client.readyState === WebSocket.OPEN) { if(client.readyState === WebSocket.OPEN) {
client.send(data, {binary: false}); client.send(data);
} }
}); });
}; };
}
function printHelp() { console.log('Server running. Visit https://localhost:' + HTTPS_PORT + ' in Firefox/Chrome.\n\n\
console.log(`Server running. Visit https://localhost:${HTTPS_PORT} in Firefox/Chrome/Safari.\n`); Some important notes:\n\
console.log('Please note the following:'); * Note the HTTPS; there is no HTTP -> HTTPS redirect.\n\
console.log(' * Note the HTTPS in the URL; there is no HTTP -> HTTPS redirect.'); * You\'ll also need to accept the invalid TLS certificate.\n\
console.log(' * You\'ll need to accept the invalid TLS certificate as it is self-signed.'); * Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines.\n'
console.log(' * Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines.'); );
}
main();