選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

rpc.js 3.6KB

4年前
4年前
4年前
5年前
5年前
4年前
4年前
4年前
5年前
4年前
4年前
5年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
5年前
4年前
5年前
5年前
4年前
4年前
4年前
5年前
4年前
5年前
4年前
4年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. })