X-Git-Url: https://git.r.bdr.sh/rbdr/junction/blobdiff_plain/4757c4616d5d7106cd023f06e5e5ba04d01bbb07..b9a2baf2a7c957089e63844b857e05c07b87c2fb:/extension/content_script.js diff --git a/extension/content_script.js b/extension/content_script.js index 4a6c7e6..26da2b0 100644 --- a/extension/content_script.js +++ b/extension/content_script.js @@ -1,47 +1,145 @@ -(() => { +import { io } from "socket.io-client"; +import Peers from "./peers"; +import Media from "./media"; - const internals = { - port: null, +const internals = { + kSocketUrl: "https://junction.tranquil.services", + kIceServers: [{ urls: "stun:stun.l.google.com:19302" }], - onMessage(message) { - internals[message.action](message.data); - }, + port: null, + socket: null, + peers: {}, - async joinAudioCall(data) { + onMessage(message) { + internals[message.action](message.data); + }, - try { - const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true }); - internals.createAudioElement(data.tada); - } - catch (err) { + async joinAudioCall({ currentUrl, tada }) { + try { + const mediaStream = await Media.start(); - internals.port.postMessage({ - action: 'error' + 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.port.disconnect(); - internals.createAudioElement(data.tada); - } - }, + }); - hangUp() { - document.querySelectorAll('.junction-call-audio').forEach((audioElement) => audioElement.remove()); - internals.port.disconnect(); - }, + 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); - createAudioElement(source, type = 'audio/wav') { + // Emit the offer to the peer + internals.socket.emit("relayOffer", { offer, peerId }); + }; - const audioElement = document.createElement('audio'); - audioElement.setAttribute('class', 'junction-call-audio'); - audioElement.src = source; - audioElement.autoplay = 'autoplay'; - audioElement.type = type; - document.querySelector('body').appendChild(audioElement); + 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); - 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;