You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.6KB

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