X-Git-Url: https://git.r.bdr.sh/rbdr/junction/blobdiff_plain/e2da0c51692b64318a0f1b8d888536ee632c53d6..65b2c3feb11adffaccf2a5c49f60f738c146d910:/extension/peers.js?ds=inline diff --git a/extension/peers.js b/extension/peers.js index 41155d4..5ba5c48 100644 --- a/extension/peers.js +++ b/extension/peers.js @@ -1,41 +1,108 @@ -'use strict'; - const internals = { peers: {}, createAudioElement(source) { + const audioElement = document.createElement("audio"); + audioElement.setAttribute("class", "junction-call-audio"); + audioElement.autoplay = "autoplay"; + audioElement.srcObject = source; - const audioElement = document.createElement('audio'); - audioElement.setAttribute('class', 'junction-call-audio'); - audioElement.src = source; - audioElement.autoplay = 'autoplay'; - document.querySelector('body').appendChild(audioElement); + document.querySelector("body").appendChild(audioElement); return audioElement; - } + }, }; -module.exports = { - add(id, url) { +export function addPeer({ + peerId, + shouldCreateOffer, + mediaStream, + onOffer, + socket, +}) { + const peerConnection = new RTCPeerConnection( + { iceServers: internals.kIceServers }, + { optional: [{ DtlsSrtpKeyAgreement: true }] }, + ); - internals.peers[id] && this.remove(id); - internals.peers[id] = internals.createAudioElement(url) - }, + internals.peers[peerId] = peerConnection; + mediaStream.getTracks().forEach((track) => { + peerConnection.addTrack(track, mediaStream); + }); - remove(id) { + peerConnection.onicecandidate = (event) => { + if (event.candidate) { + socket.emit("relayICECandidate", { + peerId: peerId, + candidate: event.candidate, + }); + } + }; - internals.peers[id] && internals.peers[id].remove(); - delete internals.peers[id]; - }, + const remoteStream = new MediaStream(); + peerConnection.ontrack = (event) => { + remoteStream.addTrack(event.track); + const remoteAudioElement = new Audio(); + remoteAudioElement.srcObject = remoteStream; + remoteAudioElement.play(); + }; - count() { + peerConnection.onnegotiationneeded = async () => { + if (shouldCreateOffer) { + console.debug("Creating RTC offer to ", peerId); + const offer = await peerConnection.createOffer(); + await peerConnection.setLocalDescription(offer); - return Object.keys(internals.peers).length; - }, + onOffer({ peerId, offer }); + } + }; + + console.info(`There are now ${countPeers()} participants`); +} + +export function removePeer({ peerId }) { + delete internals.peers[peerId]; + console.info(`There are now ${countPeers()} participants`); +} - reset() { +export async function answerPeerOffer({ peerId, offer }) { + console.info(`Answering peer ${peerId}`); + const peerConnection = internals.peers[peerId]; - internals.peers = {}; - document.querySelectorAll('.junction-call-audio').forEach((audioElement) => audioElement.remove()); + const remoteDescription = new RTCSessionDescription(offer); + await peerConnection.setRemoteDescription(remoteDescription); + + const answer = await peerConnection.createAnswer(); + await peerConnection.setLocalDescription(answer); + + return { peerId, answer }; +} + +export async function processPeerAnswer({ peerId, answer }) { + console.info(`Processing answer for peer ${peerId}`); + const peerConnection = internals.peers[peerId]; + const remoteDescription = new RTCSessionDescription(answer); + await peerConnection.setRemoteDescription(remoteDescription); +} + +export async function addIceCandidate({ peerId, candidate }) { + console.info(`Adding ICE candidate for peer ${peerId}`); + const peerConnection = internals.peers[peerId]; + console.info(peerConnection.signalingState); + const iceCandidate = new RTCIceCandidate(candidate); + await peerConnection.addIceCandidate(iceCandidate); +} + +export function countPeers() { + return Object.keys(internals.peers).length; +} + +export function resetPeers() { + for (const connection of Object.values(internals.peers)) { + connection.close(); } -}; + internals.peers = {}; + document + .querySelectorAll(".junction-call-audio") + .forEach((audioElement) => audioElement.remove()); +}