Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

132 lines
4.1KB

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