import { io } from "socket.io-client"; import Peers from "./peers"; import Media from "./media"; const internals = { kSocketUrl: "https://junction.tranquil.services", kIceServers: [{ urls: "stun:stun.l.google.com:19302" }], port: null, socket: null, peers: {}, onMessage(message) { internals[message.action](message.data); }, async joinAudioCall({ currentUrl, tada }) { try { const mediaStream = await Media.start(); internals.socket = io(internals.kSocketUrl, { transports: ["websocket"], }); internals.socket.on("error", function (error) { console.error("GENERAL ERROR", error); }); internals.socket.on("connect_error", function (error) { console.error("CONNNECT ERROR", error); }); internals.socket.on("connect", function () { console.log("Connected to signaling server, group: ", currentUrl); internals.socket.emit("join", { room: currentUrl, }); }); internals.socket.on("disconnect", function () { console.log("disconnected from signaling server"); }); internals.socket.on("addPeer", function ({ peerId }) { /** * Eventually the whole rtc connection logic should be moved to Peers. * Now it only plays tadas. */ Peers.add(peerId, tada); 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) { internals.socket.emit("relayICECandidate", { peerId: peerId, candidate: event.candidate, }); } }; const remoteStream = new MediaStream(); peerConnection.ontrack = (event) => { remoteStream.addTrack(event.track); const remoteAudioElement = new Audio(); remoteAudioElement.srcObject = remoteStream; remoteAudioElement.play(); }; peerConnection.onnegotiationneeded = async () => { console.log("Creating RTC offer to ", peerId); const offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(offer); // Emit the offer to the peer internals.socket.emit("relayOffer", { offer, peerId }); }; console.log(`There are now ${Peers.count()} participants`); }); internals.socket.on("offerReceived", async ({ offer, peerId }) => { const peerConnection = internals.peers[peerId]; const remoteDescription = new RTCSessionDescription(offer); await peerConnection.setRemoteDescription(remoteDescription); const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); // Send the answer to the peer internals.socket.emit("relayAnswer", { answer, peerId }); }); internals.socket.on("answerReceived", async ({ answer, peerId }) => { const peerConnection = internals.peers[peerId]; const remoteDescription = new RTCSessionDescription(answer); await peerConnection.setRemoteDescription(remoteDescription); }); internals.socket.on( "ICECandidateReceived", async ({ candidate, peerId }) => { const peerConnection = internals.peers[peerId]; const iceCandidate = new RTCIceCandidate(candidate); await peerConnection.addIceCandidate(iceCandidate); }, ); internals.socket.on("removePeer", function ({ peerId }) { delete internals.peers[peerId]; Peers.remove(peerId); console.log(`There are now ${Peers.count()} participants`); }); } catch (err) { internals.port.postMessage({ action: "error", }); internals.port.disconnect(); } }, hangUp() { Peers.reset(); Media.stop(); internals.socket.close(); internals.port.disconnect(); }, }; internals.port = chrome.runtime.connect({ name: "content" }); internals.port.onMessage.addListener(internals.onMessage); console.log("Content Script Loaded"); // Indicates to the background script that we executed correctly true;