Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

144 Zeilen
4.1KB

  1. const allRPCs = {}
  2. // ensure no data gets lost when sent through the wire
  3. function K(obj) {
  4. return JSON.parse(JSON.stringify(obj))
  5. }
  6. // https://stackoverflow.com/a/2117523
  7. function uuidv4() {
  8. return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
  9. (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  10. )
  11. }
  12. function rpcStatusCheck() {
  13. console.table(Object.values(allRPCs).map(({target, kind, rpc}) =>
  14. ({target, kind, status: rpc.iceConnectionState})
  15. ))
  16. }
  17. function rpcCleanUp(kind, target) {
  18. for([uid, info] of Object.entries(allRPCs)) {
  19. const sameKind = info.kind === kind
  20. const sameTarget = info.target === target
  21. let shouldClose = false
  22. shouldClose ||= !State.online.includes(info.target)
  23. shouldClose ||= (sameKind && kind === 'screen')
  24. shouldClose ||= (sameKind && kind === 'video' && sameTarget)
  25. if(shouldClose) {
  26. info.rpc.close()
  27. delete allRPCs[uid]
  28. console.log(`${info.target} ${info.kind} closed`)
  29. }
  30. }
  31. }
  32. addEventListener('rpc-needed', ({detail}) => {
  33. const {kind, target} = detail.value
  34. const isInitiatedLocally = !detail.source
  35. const uid = detail.value.uid || uuidv4()
  36. const rpc = new RTCPeerConnection(rpcConfig)
  37. rpc.onicecandidate = ({candidate}) => {
  38. if(candidate && candidate.candidate) {
  39. wire({kind: 'ice-candidate', value: {...K(candidate), uid}, target})
  40. }
  41. }
  42. rpc.ontrack = ({streams: [stream]}) => {
  43. stream.getTracks().forEach(track => {
  44. allRPCs[uid].receiver.addTrack(track, stream)
  45. })
  46. }
  47. rpc.oniceconnectionstatechange = (e) => {
  48. console.log(`${target} ${kind} ${rpc.iceConnectionState}`)
  49. }
  50. rpc.onnegotiationneeded = (e) => {
  51. // if(isInitiatedLocally) {
  52. // signal({kind: 'rpc-initiate', value: {uid}})
  53. // }
  54. }
  55. rpcCleanUp(kind, target)
  56. allRPCs[uid] = {kind, target, rpc, isInitiatedLocally}
  57. signal({kind: 'rpc-new', value: {kind, target, uid}})
  58. if(isInitiatedLocally) {
  59. wire({kind: 'rpc-needed', value: {kind, target: State.username, uid}, target})
  60. }
  61. })
  62. addEventListener('rpc-setup', async ({detail}) => {
  63. const {uid, sender, receiver} = detail.value
  64. const {rpc, isInitiatedLocally} = allRPCs[uid]
  65. allRPCs[uid].sender = sender
  66. allRPCs[uid].receiver = receiver
  67. if(sender) {
  68. sender.getTracks().forEach(tr => rpc.addTrack(tr, sender))
  69. }
  70. allRPCs[uid].loadedMedia = true
  71. if(isInitiatedLocally) {
  72. signal({kind: 'rpc-initiate', value: {uid}})
  73. }
  74. else {
  75. signal({kind: 'rpc-respond', value: {uid}})
  76. }
  77. })
  78. addEventListener('rpc-initiate', async({detail}) => {
  79. const {uid} = detail.value
  80. const {rpc, target} = allRPCs[uid]
  81. const localOffer = await rpc.createOffer()
  82. await rpc.setLocalDescription(localOffer)
  83. wire({kind: 'rpc-offer', value: {...K(localOffer), uid}, target})
  84. })
  85. addEventListener('rpc-offer', async ({detail}) => {
  86. const {uid} = detail.value
  87. const {rpc} = allRPCs[uid]
  88. await rpc.setRemoteDescription(detail.value)
  89. allRPCs[uid].hasOffer = true
  90. signal({kind: 'rpc-respond', value: {uid}})
  91. })
  92. addEventListener('rpc-respond', async({detail}) => {
  93. const {uid} = detail.value
  94. const {rpc, target, loadedMedia, hasOffer} = allRPCs[uid]
  95. if(loadedMedia && hasOffer) {
  96. const localAnswer = await rpc.createAnswer()
  97. await rpc.setLocalDescription(localAnswer)
  98. wire({kind: 'rpc-answer', value: {...K(localAnswer), uid}, target})
  99. }
  100. })
  101. addEventListener('rpc-answer', async ({detail}) => {
  102. const {uid} = detail.value
  103. await allRPCs[uid].rpc.setRemoteDescription(detail.value)
  104. })
  105. addEventListener('ice-candidate', async ({detail}) => {
  106. const {uid} = detail.value
  107. await allRPCs[uid].rpc.addIceCandidate(detail.value)
  108. })
  109. addEventListener('leave', () => {
  110. rpcCleanUp()
  111. })
  112. addEventListener('screen-stop', () => {
  113. rpcCleanUp('screen')
  114. })
  115. addEventListener('load', () => {
  116. doNotLog.add('rpc-needed')
  117. doNotLog.add('rpc-offer')
  118. doNotLog.add('rpc-answer')
  119. doNotLog.add('ice-candidate')
  120. })