|
- const connections = {}
- const datachannels = {}
- const videoElements = {}
-
- function setStream({source, stream}) {
- const element = videoElements[source]
- const active = element && element.srcObject
- if(active && active.id !== stream.id) {
- videoElements[source].srcObject.getTracks().forEach(tr => tr.stop())
- }
-
- element.srcObject = stream
-
- if(source === State.username) {
- signal({kind: 'stream-refresh'})
- }
- }
-
- function reloadAllStreams() {
- State.online.forEach(username => {
- const rpc = connections[username]
- if(rpc) {
- rpc.getSenders().map(s => console.log(s) || rpc.removeTrack(s))
- }
- signal({kind: 'rpc', value: {type: 'request'}, source: username})
- })
- }
-
- function createConnection(target) {
- const rpc = new RTCPeerConnection(rpcConfig)
-
- rpc.onicecandidate = ({candidate}) => {
- if(candidate && candidate.candidate) {
- const value = {type: 'candidate', candidate}
- wire({kind: 'rpc', value, target})
- }
- }
- rpc.ontrack = ({streams: [stream]}) => {
- setStream({source: target, stream})
- }
- rpc.onconnectionstatechange = () => {
- if(rpc.connectionState === 'failed') {
- console.log(target, 'failed, retry!')
- wire({kind: 'rpc', value: {type: 'request'}, target})
- }
- }
- rpc.ondatachannel = ({channel}) => {
- datachannels[target] = channel
- datachannels[target].onmessage = ({data}) => console.log(data)
-
- // for testing purposes
- const msg = `rpc established from ${target} to ${State.username}`
- datachannels[target].send(msg)
- console.log(msg)
- }
-
- rpc.onnegotiationneeded = () => {
- console.log('lmao renegotiate bi')
- }
-
- connections[target] = rpc
- if(State.username > target) {
- datachannels[target] = rpc.createDataChannel('test')
- datachannels[target].onmessage = ({data}) => console.log(data)
- signal({kind: 'rpc', value: {type: 'request'}, source: target})
- }
- }
-
- function setSenders(rpc, username) {
- const element = videoElements[username]
- const stream = element && element.srcObject
- rpc.getSenders().forEach(se => rpc.removeTrack(se))
- if(stream) {
- stream.getTracks().forEach(tr => rpc.addTrack(tr, stream))
- }
- }
-
- async function handlePeerInfo({source: target, value, kind}) {
- const rpc = connections[target]
-
- if(!rpc) {
- return
- }
-
- if(value.type === 'request') {
- const localOffer = await rpc.createOffer()
- await rpc.setLocalDescription(localOffer)
- wire({kind, value: localOffer, target})
- }
- else if(value.type === 'offer') {
- const remoteOffer = new RTCSessionDescription(value)
- await rpc.setRemoteDescription(remoteOffer)
- const localAnswer = await rpc.createAnswer()
- await rpc.setLocalDescription(localAnswer)
- wire({kind, value: localAnswer, target})
- }
- else if(value.type === 'answer') {
- const remoteAnswer = new RTCSessionDescription(value)
- await rpc.setRemoteDescription(remoteAnswer).catch(e => e)
- }
- else if(value.type === 'candidate') {
- const candidate = new RTCIceCandidate(value.candidate)
- await rpc.addIceCandidate(candidate).catch(e => e)
- }
- }
-
- function destroyConnection(username) {
- if(datachannels[username]) {
- datachannels[username].close()
- delete datachannels[username]
- }
- if(connections[username]) {
- connections[username].getReceivers().forEach(r => r.track.stop())
- connections[username].close()
- delete connections[username]
- }
- }
-
- function destroyAll() {
- const people = new Set()
- const collect = [connections, datachannels, streams, screen]
- .map(collection => Object.keys(collection))
- .forEach(keys => keys.forEach(key => people.add(key)))
- people.forEach(destroyConnection)
- }
-
- addEventListener('stream-refresh', reloadAllStreams)
- addEventListener('stream', (e) => setStream(e.detail.value))
- addEventListener('rpc', (e) => handlePeerInfo(e.detail))
- addEventListener('join', (e) => createConnection(e.detail.value))
- addEventListener('leave', (e) => destroyConnection(e.detail.value))
- addEventListener('logout', () => destroyAll())
- addEventListener('load', () => doNotLog.add('rpc'))
|