Skip to content

Instantly share code, notes, and snippets.

@nestarz
Last active March 1, 2020 14:20
Show Gist options
  • Save nestarz/98caa99bb3cd8f22763f7bf064d3b2d6 to your computer and use it in GitHub Desktop.
Save nestarz/98caa99bb3cd8f22763f7bf064d3b2d6 to your computer and use it in GitHub Desktop.
Websockets (socket.io) + WebRTC
let log_verbose = 0;
export const log = (...args) => {
if (log_verbose) {
const div = document.createElement("div");
div.innerText = args.join(", ");
document.body.appendChild(div);
console.log(...args);
}
};
async function iceGathering(socket, peerConnection, peer_id) {
peerConnection.addEventListener("icecandidate", event => {
if (event.candidate) {
socket.emit("signal", {
signal: { iceCandidate: event.candidate },
id: peer_id
});
}
});
socket.on("signal", async ({ signal: message, id }) => {
if (id === peer_id && message.iceCandidate) {
peerConnection.addIceCandidate(new RTCIceCandidate(message.iceCandidate));
}
});
}
async function makeCall(webRTCconfig, socket, peer_id, fn) {
const peerConnection = new RTCPeerConnection(webRTCconfig);
peerConnection.oniceconnectionstatechange = () =>
log("iceconnectionstatechange", peerConnection.iceConnectionState);
await fn(peerConnection);
iceGathering(socket, peerConnection, peer_id);
socket.on("signal", async ({ signal: { answer }, id }) => {
if (answer && id === peer_id) {
log(`[Initiator] Receiving signal from the other peer ${id}`, answer);
const remoteDesc = new RTCSessionDescription(answer);
await peerConnection.setRemoteDescription(remoteDesc);
}
});
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
log(`[Initiator] Sending signal to the other peer ${peer_id}`, offer);
socket.emit("signal", { signal: { offer }, id: peer_id });
return peerConnection;
}
async function receiveCall(webRTCconfig, socket, fn) {
socket.on("signal", async ({ signal: message, id }) => {
if (message.offer) {
const peerConnection = new RTCPeerConnection(webRTCconfig);
await new Promise((resolve, reject) => {
fn({
id,
message,
accept: () => {
resolve();
return peerConnection;
},
reject
});
});
peerConnection.oniceconnectionstatechange = () =>
log("iceconnectionstatechange", peerConnection.iceConnectionState);
iceGathering(socket, peerConnection, id);
log(`Receiving signal (offer) from the other peer ${id}`, message.offer);
peerConnection.setRemoteDescription(
new RTCSessionDescription(message.offer)
);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
log(`Sending signal (answer) to the other peer ${id}`, answer);
socket.emit("signal", { signal: { answer: answer }, id });
}
});
}
const webRTCconfig_default = {
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
};
export default (socket, webRTCconfig = webRTCconfig_default, config = {}) => {
log_verbose = config.verbose;
let conn;
return {
discover: data => socket.emit("discover-query", data),
onDiscover: fn => socket.on("discover-results", fn),
connect: async (to, fn) => {
conn = true;
return await makeCall(webRTCconfig, socket, to, fn);
},
onRequest: async fn => {
if (conn) return;
receiveCall(webRTCconfig, socket, fn);
}
};
};
<!DOCTYPE html>
<html>
<body>
<h1>TEST</h1>
<div id="app"></div>
<button onclick="signal.discover()">Stream</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script type="module">
import Signal, { log } from "./src/client.js";
import webRTCconfig from "./src/config.js";
const socket = io("wss://db.eliasrhouzlane.com");
const signal = Signal(socket, webRTCconfig, { verbose: 1 });
signal.onDiscover(async peers => {
peers.forEach(async peer_id => {
const stream = await navigator.mediaDevices.getUserMedia({
video: true
});
const beforeOffer = peer =>
stream.getTracks().forEach(track => peer.addTrack(track, stream));
const peer1 = await signal.connect(peer_id, beforeOffer);
});
});
signal.onRequest(async request => {
const peer2 = await request.accept();
peer2.addEventListener("track", e => {
if (!document.querySelector("video")) {
const video = document.createElement("video");
document.body.querySelector("#app").appendChild(video);
}
log("Creating the Video !!!!!!", e.streams[0]);
const video = document.querySelector("video");
video.srcObject = e.streams[0];
video.autoplay = true;
video.play();
});
});
window.signal = signal;
</script>
</body>
</html>
const app = require("express")();
const http = require("http").createServer(app);
const io = require("socket.io")(http);
const Signal = io => {
const connection = socket => {
socket.on("signal", data => {
const peer_socket = io.sockets.connected[data.peerId];
if (peer_socket)
peer_socket.emit("signal", {
signal: data.signal,
peerId: socket.id
});
});
socket.on("discover-query", () => {
const ids = Object.values(io.sockets.connected)
.filter(curr => curr.id !== socket.id)
.map(socket => socket.id);
socket.emit("discover-results", ids);
});
};
return {
start: () => {
io.on("connection", connection);
io.on("connection", socket => socket.emit("connected"));
}
};
};
Signal(io).start();
http.listen(3000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment