|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- const allRPCs = {}
-
- // ensure no data gets lost when sent through the wire
- function K(obj) {
- return JSON.parse(JSON.stringify(obj))
- }
-
- // https://stackoverflow.com/a/2117523
- function uuidv4() {
- return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
- (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
- )
- }
-
- function rpcStatusCheck() {
- console.table(Object.values(allRPCs).map(({target, kind, rpc}) =>
- ({target, kind, status: rpc.iceConnectionState})
- ))
- }
-
- function rpcCleanUp(kind, target) {
- for([uid, info] of Object.entries(allRPCs)) {
- const sameKind = info.kind === kind
- const sameTarget = info.target === target
- const shouldClose = (false
- || !State.online.includes(info.target)
- || (sameKind && kind === 'screen')
- || (sameKind && kind === 'video' && sameTarget)
- )
-
- if(shouldClose) {
- info.rpc.close()
- delete allRPCs[uid]
- console.log(`${info.target} ${info.kind} closed`)
- }
- }
- }
-
- addEventListener('rpc-needed', ({detail}) => {
- const {kind, target} = detail.value
- const isInitiatedLocally = !detail.source
- const uid = detail.value.uid || uuidv4()
- const rpc = new RTCPeerConnection(rpcConfig)
- rpc.onicecandidate = ({candidate}) => {
- if(candidate && candidate.candidate) {
- wire({kind: 'ice-candidate', value: {...K(candidate), uid}, target})
- }
- }
- rpc.ontrack = ({streams: [stream]}) => {
- stream.getTracks().forEach(track => {
- allRPCs[uid].receiver.addTrack(track, stream)
- })
- }
- rpc.oniceconnectionstatechange = (e) => {
- console.log(`${target} ${kind} ${rpc.iceConnectionState}`)
- }
- rpc.onnegotiationneeded = (e) => {
- // if(isInitiatedLocally) {
- // signal({kind: 'rpc-initiate', value: {uid}})
- // }
- }
- rpcCleanUp(kind, target)
- allRPCs[uid] = {kind, target, rpc, isInitiatedLocally}
- signal({kind: 'rpc-new', value: {kind, target, uid}})
- if(isInitiatedLocally) {
- wire({kind: 'rpc-needed', value: {kind, target: State.username, uid}, target})
- }
- })
-
- addEventListener('rpc-setup', async ({detail}) => {
- const {uid, sender, receiver} = detail.value
- const {rpc, isInitiatedLocally} = allRPCs[uid]
- allRPCs[uid].sender = sender
- allRPCs[uid].receiver = receiver
- if(sender) {
- sender.getTracks().forEach(tr => rpc.addTrack(tr, sender))
- }
- allRPCs[uid].loadedMedia = true
-
- if(isInitiatedLocally) {
- signal({kind: 'rpc-initiate', value: {uid}})
- }
- else {
- signal({kind: 'rpc-respond', value: {uid}})
- }
- })
-
- addEventListener('rpc-initiate', async({detail}) => {
- const {uid} = detail.value
- const {rpc, target} = allRPCs[uid]
-
- const localOffer = await rpc.createOffer()
- await rpc.setLocalDescription(localOffer)
-
- wire({kind: 'rpc-offer', value: {...K(localOffer), uid}, target})
- })
-
- addEventListener('rpc-offer', async ({detail}) => {
- const {uid} = detail.value
- const {rpc} = allRPCs[uid]
-
- await rpc.setRemoteDescription(detail.value)
- allRPCs[uid].hasOffer = true
-
- signal({kind: 'rpc-respond', value: {uid}})
- })
-
- addEventListener('rpc-respond', async({detail}) => {
- const {uid} = detail.value
- const {rpc, target, loadedMedia, hasOffer} = allRPCs[uid]
-
- if(loadedMedia && hasOffer) {
- const localAnswer = await rpc.createAnswer()
- await rpc.setLocalDescription(localAnswer)
-
- wire({kind: 'rpc-answer', value: {...K(localAnswer), uid}, target})
- }
- })
-
- addEventListener('rpc-answer', async ({detail}) => {
- const {uid} = detail.value
- await allRPCs[uid].rpc.setRemoteDescription(detail.value)
- })
-
- addEventListener('ice-candidate', async ({detail}) => {
- const {uid} = detail.value
- await allRPCs[uid].rpc.addIceCandidate(detail.value)
- })
-
- addEventListener('leave', () => {
- rpcCleanUp()
- })
-
- addEventListener('screen-stop', () => {
- rpcCleanUp('screen')
- })
-
- addEventListener('load', () => {
- doNotLog.add('rpc-needed')
- doNotLog.add('rpc-offer')
- doNotLog.add('rpc-answer')
- doNotLog.add('ice-candidate')
- })
|