Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

128 linhas
3.9KB

  1. const connections = {}
  2. const datachannels = {}
  3. const streams = {}
  4. const screen = {}
  5. function setStream({source, stream}) {
  6. streams[source] = stream
  7. m.redraw()
  8. if(source === State.username) {
  9. reloadAllStreams()
  10. }
  11. }
  12. function reloadAllStreams() {
  13. State.online.forEach(username => {
  14. const rpc = connections[username]
  15. if(rpc) {
  16. rpc.getSenders().map(s => rpc.removeTrack(s))
  17. }
  18. signal({kind: 'rpc', value: {type: 'request'}, source: username})
  19. })
  20. }
  21. function createConnection(target) {
  22. const rpc = new RTCPeerConnection(rpcConfig)
  23. rpc.onicecandidate = ({candidate}) => {
  24. if(candidate && candidate.candidate) {
  25. const value = {type: 'candidate', candidate}
  26. wire({kind: 'rpc', value, target})
  27. }
  28. }
  29. rpc.ontrack = ({streams: [stream]}) => {
  30. setStream({source: target, stream})
  31. }
  32. rpc.onconnectionstatechange = () => {
  33. if(rpc.connectionState === 'failed') {
  34. console.log(target, 'failed, retry!')
  35. wire({kind: 'rpc', value: {type: 'request'}, target})
  36. }
  37. }
  38. rpc.ondatachannel = ({channel}) => {
  39. datachannels[target] = channel
  40. datachannels[target].onmessage = ({data}) => console.log(data)
  41. // for testing purposes
  42. const msg = `rpc established from ${target} to ${State.username}`
  43. datachannels[target].send(msg)
  44. console.log(msg)
  45. }
  46. connections[target] = rpc
  47. if(State.username > target) {
  48. datachannels[target] = rpc.createDataChannel('test')
  49. datachannels[target].onmessage = ({data}) => console.log(data)
  50. signal({kind: 'rpc', value: {type: 'request'}, source: target})
  51. }
  52. }
  53. async function handlePeerInfo({source: target, value}) {
  54. const rpc = connections[target]
  55. if(!rpc) {
  56. return
  57. }
  58. const stream = streams[State.username]
  59. if(stream) {
  60. stream.getTracks().forEach(track => {
  61. try {rpc.addTrack(track, stream) }
  62. catch { }
  63. })
  64. }
  65. if(value.type === 'request') {
  66. const localOffer = await rpc.createOffer()
  67. await rpc.setLocalDescription(localOffer)
  68. wire({kind: 'rpc', value: localOffer, target})
  69. }
  70. else if(value.type === 'offer') {
  71. const remoteOffer = new RTCSessionDescription(value)
  72. await rpc.setRemoteDescription(remoteOffer)
  73. const localAnswer = await rpc.createAnswer()
  74. await rpc.setLocalDescription(localAnswer)
  75. wire({kind: 'rpc', value: localAnswer, target})
  76. }
  77. else if(value.type === 'answer') {
  78. const remoteAnswer = new RTCSessionDescription(value)
  79. await rpc.setRemoteDescription(remoteAnswer).catch(e => e)
  80. }
  81. else if(value.type === 'candidate') {
  82. const candidate = new RTCIceCandidate(value.candidate)
  83. await rpc.addIceCandidate(candidate).catch(e => e)
  84. }
  85. }
  86. function destroyConnection(username) {
  87. if(streams[username]) {
  88. streams[username].getTracks().forEach(t => t.stop())
  89. delete streams[username]
  90. }
  91. if(datachannels[username]) {
  92. datachannels[username].close()
  93. delete datachannels[username]
  94. }
  95. if(connections[username]) {
  96. connections[username].getReceivers().forEach(r => r.track.stop())
  97. connections[username].close()
  98. delete connections[username]
  99. }
  100. }
  101. function destroyAll() {
  102. const people = new Set()
  103. const collect = [connections, datachannels, streams, screen]
  104. .map(collection => Object.keys(collection))
  105. .forEach(keys => keys.forEach(key => people.add(key)))
  106. people.forEach(destroyConnection)
  107. }
  108. addEventListener('stream', (e) => setStream(e.detail.value))
  109. addEventListener('rpc', (e) => handlePeerInfo(e.detail))
  110. addEventListener('join', (e) => createConnection(e.detail.value))
  111. addEventListener('leave', (e) => destroyConnection(e.detail.value))
  112. addEventListener('logout', () => destroyAll())
  113. addEventListener('load', () => doNotLog.add('rpc'))