X-Git-Url: https://git.r.bdr.sh/rbdr/junction/blobdiff_plain/d38261f11a1fa6d922cf1a7a52601c282d0a8527..refs/heads/main:/extension/peers.js diff --git a/extension/peers.js b/extension/peers.js index 2d74fad..5ba5c48 100644 --- a/extension/peers.js +++ b/extension/peers.js @@ -1,49 +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; + + document.querySelector("body").appendChild(audioElement); - const audioElement = document.createElement('audio'); - audioElement.setAttribute('class', 'junction-call-audio'); - audioElement.autoplay = 'autoplay'; + return audioElement; + }, +}; - // WE WILL NOT LOSE TADA SUPPORT - if (typeof source === 'string') { - audioElement.src = source; +export function addPeer({ + peerId, + shouldCreateOffer, + mediaStream, + onOffer, + socket, +}) { + const peerConnection = new RTCPeerConnection( + { iceServers: internals.kIceServers }, + { optional: [{ DtlsSrtpKeyAgreement: true }] }, + ); + + internals.peers[peerId] = peerConnection; + mediaStream.getTracks().forEach((track) => { + peerConnection.addTrack(track, mediaStream); + }); + + peerConnection.onicecandidate = (event) => { + if (event.candidate) { + socket.emit("relayICECandidate", { + peerId: peerId, + candidate: event.candidate, + }); } - else { - audoElement.srcObject = source; + }; + + 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 }); } + }; - document.querySelector('body').appendChild(audioElement); + console.info(`There are now ${countPeers()} participants`); +} - return audioElement; - } -}; +export function removePeer({ peerId }) { + delete internals.peers[peerId]; + console.info(`There are now ${countPeers()} participants`); +} -module.exports = { - add(id, source) { +export async function answerPeerOffer({ peerId, offer }) { + console.info(`Answering peer ${peerId}`); + const peerConnection = internals.peers[peerId]; - internals.peers[id] && this.remove(id); - internals.peers[id] = internals.createAudioElement(source) - }, + const remoteDescription = new RTCSessionDescription(offer); + await peerConnection.setRemoteDescription(remoteDescription); - remove(id) { + const answer = await peerConnection.createAnswer(); + await peerConnection.setLocalDescription(answer); - internals.peers[id] && internals.peers[id].remove(); - delete internals.peers[id]; - }, + return { peerId, answer }; +} - count() { +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); +} - return Object.keys(internals.peers).length; - }, +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); +} - reset() { +export function countPeers() { + return Object.keys(internals.peers).length; +} - internals.peers = {}; - document.querySelectorAll('.junction-call-audio').forEach((audioElement) => audioElement.remove()); +export function resetPeers() { + for (const connection of Object.values(internals.peers)) { + connection.close(); } -}; + internals.peers = {}; + document + .querySelectorAll(".junction-call-audio") + .forEach((audioElement) => audioElement.remove()); +}