Last active
March 1, 2020 14:20
-
-
Save nestarz/98caa99bb3cd8f22763f7bf064d3b2d6 to your computer and use it in GitHub Desktop.
Websockets (socket.io) + WebRTC
This file contains hidden or 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
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); | |
} | |
}; | |
}; |
This file contains hidden or 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> | |
<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> |
This file contains hidden or 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 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