X-Git-Url: https://git.r.bdr.sh/rbdr/junction/blobdiff_plain/02071d8e6e45dd253298d2e450ecfffacccaec19..284fc661dc7f18aa32d0dbcd8e7f98cb16af4bb7:/extension/content_script.js diff --git a/extension/content_script.js b/extension/content_script.js index 84a2fd3..8ca721a 100644 --- a/extension/content_script.js +++ b/extension/content_script.js @@ -1,96 +1,158 @@ -(() => { +import { io } from 'socket.io-client'; +import Peers from './peers'; +import Media from './media'; - const io = require('socket.io-client'); +const internals = { - const internals = { + kSocketUrl: 'https://junction.tranquil.services', + kIceServers: [ + {url:"stun:stun.l.google.com:19302"} + ], - kSocketUrl: 'https://junction.unlimited.pizza/', + port: null, + socket: null, + peers: {}, - port: null, - socket: null, - peers: 0, + onMessage(message) { + internals[message.action](message.data); + }, - onMessage(message) { - internals[message.action](message.data); - }, + async joinAudioCall(data) { - async joinAudioCall(data) { + internals.tada = data.tada; // Keeping for fun - try { - const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true }); + try { + const mediaStream = await Media.start(); - internals.socket = io(internals.kSocketUrl, { - transports: ['websocket'] - }); + internals.socket = io(internals.kSocketUrl, { + transports: ['websocket'] + }); - internals.socket.on('error', function(error) { + internals.socket.on('error', function(error) { - console.error('GENERAL ERROR', error); - }); + console.error('GENERAL ERROR', error); + }); + + internals.socket.on('connect_error', function(error) { + + console.error('CONNNECT ERROR', error); + }); - internals.socket.on('connect_error', function(error) { + internals.socket.on('connect', function() { - console.error('CONNNECT ERROR', error); + console.log('Connected to signaling server, group: ', data.currentUrl); + internals.socket.emit('join', { + room: data.currentUrl, }); + }); + + internals.socket.on('disconnect', function() { + + console.log("disconnected from signaling server"); + }); + + internals.socket.on('addPeer', function(data) { - internals.socket.on('connect', function() { + Peers.add(data.peerId, internals.tada); + const peerId = data.peerId; - console.log("Connected to signaling server, group: ", data.currentUrl); - internals.socket.emit('join', { - 'url': data.currentUrl, + const peerConnection = new RTCPeerConnection( + { iceServers: internals.kIceServers }, + { optional: [{ DtlsSrtpKeyAgreement: true }] } + ); + + internals.peers[peerId] = peerConnection; + mediaStream.getTracks().forEach((track) => { + peerConnection.addTrack(track, localStream); }); - }); - internals.socket.on('disconnect', function() { + peerConnection.onicecandidate = (event) => { + if (event.candidate) { + internals.socket.emit('relayICECandidate', { + peerId: peerId, + candidate: event.candidate + }); + } + } - console.log("disconnected from signaling server"); - }); + const remoteStream = new MediaStream(); + peerConnection.ontrack = (event) => { + remoteStream.addTrack(event.track); + const remoteAudioElement = new Audio(); + remoteAudioElement.srcObject = remoteStream; + remoteAudioElement.play(); + }; - internals.socket.on('addPeer', function(data) { + peerConnection.onnegotiationneeded = async () => { + console.log("Creating RTC offer to ", peerId); + const offer = await peerConnection.createOffer(); + await peerConnection.setLocalDescription(offer); - console.log(data); - internals.peers++; - console.log(`There are now ${internals.peers} participants`); - }); + // Emit the offer to the peer + socket.emit('relayOffer', { offer, peerId }); + }; - internals.socket.on('removePeer', function() { + console.log(`There are now ${Peers.count()} participants`); + }); - internals.peers--; - console.log(`There are now ${internals.peers} participants`); - }); + socket.on('offerReceived', async (data) => { - internals.createAudioElement(data.tada); - } - catch (err) { + const peerConnection = internals.peers[data.peerId]; - internals.port.postMessage({ - action: 'error' - }); - internals.port.disconnect(); - internals.createAudioElement(data.tada); - } - }, - - hangUp() { - document.querySelectorAll('.junction-call-audio').forEach((audioElement) => audioElement.remove()); - internals.socket.close(); - internals.port.disconnect(); - }, + const offer = new RTCSessionDescription(data.offer); + await peerConnection.setRemoteDescription(offer); - createAudioElement(source, type = 'audio/wav') { + const answer = await peerConnection.createAnswer(); + await peerConnection.setLocalDescription(answer); - 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); + // Send the answer to the peer + socket.emit('relayAnswer', { answer, peerId: data.peerId }); + }); + + socket.on('answerReceived', async (data) => { + + const peerConnection = internals.peers[data.peerId]; + const answer = new RTCSessionDescription(data.answer); + await peerConnection.setRemoteDescription(answer); + }); + + socket.on('ICECandidateReceived', async (data) => { + + const peerConnection = internals.peers[data.peerId]; + const candidate = new RTCIceCandidate(data.candidate); + await peerConnection.addIceCandidate(candidate); + }); + + + internals.socket.on('removePeer', function() { + + delete internals.peers[data.peerId]; + Peers.remove('id-'+(Peers.count() - 1)); // This is only for testing, don't use count to remove ids. + 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;