您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

127 行
3.6KB

  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. if(info.kind === kind && info.target === target) {
  20. info.rpc.close()
  21. delete allRPCs[uid]
  22. }
  23. }
  24. }
  25. addEventListener('rpc-needed', ({detail}) => {
  26. const {kind, target} = detail.value
  27. const isInitiatedLocally = !detail.source
  28. const uid = detail.value.uid || uuidv4()
  29. const rpc = new RTCPeerConnection(rpcConfig)
  30. rpc.onicecandidate = ({candidate}) => {
  31. if(candidate && candidate.candidate) {
  32. wire({kind: 'ice-candidate', value: {...K(candidate), uid}, target})
  33. }
  34. }
  35. rpc.ontrack = ({streams: [stream]}) => {
  36. stream.getTracks().forEach(track => {
  37. allRPCs[uid].receiver.addTrack(track, stream)
  38. })
  39. }
  40. rpc.oniceconnectionstatechange = (e) => {
  41. console.log(`${target} ${kind} ${rpc.iceConnectionState}`)
  42. }
  43. rpc.onnegotiationneeded = (e) => {
  44. // if(isInitiatedLocally) {
  45. // signal({kind: 'rpc-initiate', value: {uid}})
  46. // }
  47. }
  48. rpcCleanUp(kind, target)
  49. allRPCs[uid] = {kind, target, rpc, isInitiatedLocally}
  50. signal({kind: 'rpc-new', value: {kind, target, uid}})
  51. if(isInitiatedLocally) {
  52. wire({kind: 'rpc-needed', value: {kind, target: State.username, uid}, target})
  53. }
  54. })
  55. addEventListener('rpc-setup', async ({detail}) => {
  56. const {uid, sender, receiver} = detail.value
  57. const {rpc, isInitiatedLocally, hasOffer} = allRPCs[uid]
  58. allRPCs[uid].sender = sender
  59. allRPCs[uid].receiver = receiver
  60. if(sender) {
  61. sender.getTracks().forEach(tr => rpc.addTrack(tr, sender))
  62. }
  63. allRPCs[uid].isSetup = true
  64. if(isInitiatedLocally) {
  65. signal({kind: 'rpc-initiate', value: {uid}})
  66. }
  67. else if(hasOffer) {
  68. signal({kind: 'rpc-respond', value: {uid}})
  69. }
  70. })
  71. addEventListener('rpc-initiate', async({detail}) => {
  72. const {uid} = detail.value
  73. const {rpc, target} = allRPCs[uid]
  74. const localOffer = await rpc.createOffer()
  75. await rpc.setLocalDescription(localOffer)
  76. wire({kind: 'rpc-offer', value: {...K(localOffer), uid}, target})
  77. })
  78. addEventListener('rpc-offer', async ({detail}) => {
  79. const {uid} = detail.value
  80. const {rpc, isSetup} = allRPCs[uid]
  81. await rpc.setRemoteDescription(detail.value)
  82. allRPCs[uid].hasOffer = true
  83. if(isSetup) {
  84. signal({kind: 'rpc-respond', value: {uid}})
  85. }
  86. })
  87. addEventListener('rpc-respond', async({detail}) => {
  88. const {uid} = detail.value
  89. const {rpc, target} = allRPCs[uid]
  90. const localAnswer = await rpc.createAnswer()
  91. await rpc.setLocalDescription(localAnswer)
  92. wire({kind: 'rpc-answer', value: {...K(localAnswer), uid}, target})
  93. })
  94. addEventListener('rpc-answer', async ({detail}) => {
  95. const {uid} = detail.value
  96. await allRPCs[uid].rpc.setRemoteDescription(detail.value)
  97. })
  98. addEventListener('ice-candidate', async ({detail}) => {
  99. const {uid} = detail.value
  100. await allRPCs[uid].rpc.addIceCandidate(detail.value)
  101. })
  102. addEventListener('load', () => {
  103. doNotLog.add('rpc-needed')
  104. doNotLog.add('rpc-offer')
  105. doNotLog.add('rpc-answer')
  106. doNotLog.add('ice-candidate')
  107. })