X-Git-Url: https://git.r.bdr.sh/rbdr/junction/blobdiff_plain/b9a2baf2a7c957089e63844b857e05c07b87c2fb..HEAD:/extension/peers.js diff --git a/extension/peers.js b/extension/peers.js index 2b4e3d6..5ba5c48 100644 --- a/extension/peers.js +++ b/extension/peers.js @@ -5,13 +5,7 @@ const internals = { const audioElement = document.createElement("audio"); audioElement.setAttribute("class", "junction-call-audio"); audioElement.autoplay = "autoplay"; - - // WE WILL NOT LOSE TADA SUPPORT - if (typeof source === "string") { - audioElement.src = source; - } else { - audioElement.srcObject = source; - } + audioElement.srcObject = source; document.querySelector("body").appendChild(audioElement); @@ -19,25 +13,96 @@ const internals = { }, }; -export default { - add(id, source) { - internals.peers[id] && this.remove(id); - internals.peers[id] = internals.createAudioElement(source); - }, +export function addPeer({ + peerId, + shouldCreateOffer, + mediaStream, + onOffer, + socket, +}) { + const peerConnection = new RTCPeerConnection( + { iceServers: internals.kIceServers }, + { optional: [{ DtlsSrtpKeyAgreement: true }] }, + ); - remove(id) { - internals.peers[id] && internals.peers[id].remove(); - delete internals.peers[id]; - }, + internals.peers[peerId] = peerConnection; + mediaStream.getTracks().forEach((track) => { + peerConnection.addTrack(track, mediaStream); + }); - count() { - return Object.keys(internals.peers).length; - }, + peerConnection.onicecandidate = (event) => { + if (event.candidate) { + socket.emit("relayICECandidate", { + peerId: peerId, + candidate: event.candidate, + }); + } + }; - reset() { - internals.peers = {}; - document - .querySelectorAll(".junction-call-audio") - .forEach((audioElement) => audioElement.remove()); - }, -}; + const remoteStream = new MediaStream(); + peerConnection.ontrack = (event) => { + remoteStream.addTrack(event.track); + const remoteAudioElement = new Audio(); + remoteAudioElement.srcObject = remoteStream; + remoteAudioElement.play(); + }; + + peerConnection.onnegotiationneeded = async () => { + if (shouldCreateOffer) { + console.debug("Creating RTC offer to ", peerId); + const offer = await peerConnection.createOffer(); + await peerConnection.setLocalDescription(offer); + + 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`); +} + +export async function answerPeerOffer({ peerId, offer }) { + console.info(`Answering peer ${peerId}`); + const peerConnection = internals.peers[peerId]; + + 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()); +}