Brian Mau
@basscord on all social medias
Long time Apple developer
CTO @ UenMe
How many of you have
How many of you have
How many of you have
let socket = io.connect(window.location.origin);
function broadcast() {
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
navigator.mediaDevices.getUserMedia({ video : true })
.then(function(stream) {
video.srcObject = stream;
setInterval(function() {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = canvas.toDataURL("image/jpeg", 0.4);
socket.emit('sendImage', { image : imageData });
}, 100);
}).catch(error => console.error(error));
}
function watch() {
const img = document.querySelector('img');
socket.on('getImage', data => img.src = data.image);
}function broadcast() {
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
function broadcast() {
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
/** @type {MediaStreamConstraints} */
const constraints = { video : true };
/** @type {MediaStreamConstraints} */
const constraints = {
audio: true,
video: true
};/** @type {MediaStreamConstraints} */
const constraints = {
audio: true,
video: {
facingMode: "user",
width: {
min: 1024,
ideal: 1280,
max: 1920
},
height: {
min: 576,
ideal: 720,
max: 1080
},
frameRate: { ideal: 10, max: 15 }
}
};function broadcast() {
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
/** @type {MediaStreamConstraints} */
const constraints = { video : true };
function broadcast() {
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
/** @type {MediaStreamConstraints} */
const constraints = { video : true };
// getUserMedia()
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
// ...// Promise based:
navigator.mediaDevices.getUserMedia({video: true})
.then(function(stream) {
video.srcObject = stream;
// ...
})// Callbacks, and directly on the navigator global:
navigator.getUserMedia({video: true}, success, error)
navigator.mediaDevices.getUserMedia({video: true})
.then(function(stream) {
// Streams contain 0 or more tracks
stream.getVideoTracks() // get all video tracks
stream.getAudioTracks() // get all audio tracks
stream.getTracks() // // get all the tracks
})/** @type {MediaStream} */
video.srcObject = stream; // srcObjectnavigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
// ...
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Draw the video to the canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Draw the video to the canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// Take a JPEG snapshot of the canvas (potato quality)
const imageData = canvas.toDataURL("image/jpeg", 0.4);
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Draw the video to the canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// Take a JPEG snapshot of the canvas (potato quality)
const imageData = canvas.toDataURL("image/jpeg", 0.4);
// emit the image to our Socket.io server
socket.emit('sendImage', {
image: imageData
});
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
setInterval(function() {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Draw the video to the canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// Take a JPEG snapshot of the canvas (potato quality)
const imageData = canvas.toDataURL("image/jpeg", 0.4);
// emit the image to our Socket.io server
socket.emit('sendImage', {
image: imageData
});
}, 100); // Do it 10x per second
let socket = io.connect(window.location.origin);
function watch() {
const img = document.querySelector('img');
// Every time we receive an image, display it.
socket.on('getImage', data => img.src = data.image);
}What if we could send that video stream directly to the other user's browser, without any web servers or AJAX?
const peerConnection = new RTCPeerConnection();
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
})const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer()
})
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer()
})
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer()
.then(sdp => peerConnection.setLocalDescription(sdp))
})
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer()
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
console.log(peerConnection.localDescription);
});
})
{"type":"offer","sdp":"v=0\r\no=- 8845556371065191854 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE video\r\na=msid-semantic: WMS d9MzOhvRYFeiKQSG96u54GFQpqkd6coBerZP\r\nm=video 61283 UDP/TLS/RTP/SAVPF 96 98 100 102 127 97 99 101 125\r\nc=IN IP4 192.168.1.159\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:105744546 1 udp 2122260223 192.168.1.159 61283 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:1221489746 1 tcp 1518280447 192.168.1.159 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:qfBb\r\na=ice-pwd:GdnVgPdtMJCliTbFUdYW4UYb\r\na=ice-options:trickle\r\na=fingerprint:sha-256 95:C1:36:BE:CE:62:F3:D2:22:BF:4D:19:52:2B:55:8E:3F:47:7B:6F:DF:99:D2:47:E1:27:F9:1C:71:68:A5:B4\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-...
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
video.srcObject = stream;
peerConnection.addStream(stream);
peerConnection.createOffer()
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
console.log(peerConnection.localDescription);
});
})
const peerConnection = new RTCPeerConnection();
// Combine RTCPeerConnection with getUserMedia:
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
video.srcObject = stream;
peerConnection.addStream(stream);
peerConnection.createOffer();
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
socket.emit('offer', peerConnection.localDescription);
});
})const peerConnection = new RTCPeerConnection();
const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
});const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
peerConnection.setRemoteDescription(message)
});
const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
peerConnection.setRemoteDescription(message)
.then(() => peerConnection.createAnswer())
});
const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
peerConnection.setRemoteDescription(message)
.then(() => peerConnection.createAnswer())
.then(sdp => peerConnection.setLocalDescription(sdp))
});
const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
peerConnection.setRemoteDescription(message)
.then(() => peerConnection.createAnswer())
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
socket.emit('answer', peerConnection.localDescription);
});
});
const peerConnection = new RTCPeerConnection();
socket.on('offer', function (message) {
peerConnection.setRemoteDescription(message)
.then(() => peerConnection.createAnswer())
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
socket.emit('answer', peerConnection.localDescription);
});
});
peerConnection.onaddstream = function (event) {
video.srcObject = event.stream;
};const peerConnection = new RTCPeerConnection();
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer();
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
socket.emit('offer', peerConnection.localDescription);
});
})
const peerConnection = new RTCPeerConnection();
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
peerConnection.addStream(stream);
peerConnection.createOffer();
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(function() {
socket.emit('offer', peerConnection.localDescription);
});
})
socket.on('answer', function (message) {
peerConnection.setRemoteDescription(message);
});
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['turn:54.149.135.227:3478'],
'username': 'basscord',
'credential': 'limpbizkitrulez1998',
'credentialType': 'password'
}]
};
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['turn:54.149.135.227:3478'],
'username': 'basscord',
'credential': 'limpbizkitrulez1998',
'credentialType': 'password'
}]
};
https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
const peerConnection = new RTCPeerConnection(config);
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
const peerConnection = new RTCPeerConnection(config);
peerConnection.onicecandidate = function(event) {
};
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
const peerConnection = new RTCPeerConnection(config);
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('candidate', event.candidate);
}
};
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
const peerConnection = new RTCPeerConnection(config);
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('candidate', event.candidate);
}
};
socket.on('candidate', function (candidate) {
});
/** @type {RTCConfiguration} */
const config = {
'iceServers': [{
'urls': ['stun:stun.l.google.com:19302']
}]
};
const peerConnection = new RTCPeerConnection(config);
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('candidate', event.candidate);
}
};
socket.on('candidate', function (candidate) {
const c = new RTCIceCandidate(candidate);
peerConnection.addIceCandidate(c);
});