demo.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /* eslint-env browser */
  2. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  3. // SPDX-License-Identifier: MIT
  4. // cipherKey that video is encrypted with
  5. const cipherKey = 0xAA
  6. const pc = new RTCPeerConnection({ encodedInsertableStreams: true, forceEncodedVideoInsertableStreams: true })
  7. const log = msg => {
  8. document.getElementById('div').innerHTML += msg + '<br>'
  9. }
  10. // Offer to receive 1 video
  11. const transceiver = pc.addTransceiver('video')
  12. // The API has seen two iterations, support both
  13. // In the future this will just be `createEncodedStreams`
  14. const receiverStreams = getInsertableStream(transceiver)
  15. // boolean controlled by checkbox to enable/disable encryption
  16. let applyDecryption = true
  17. window.toggleDecryption = () => {
  18. applyDecryption = !applyDecryption
  19. }
  20. // Loop that is called for each video frame
  21. const reader = receiverStreams.readable.getReader()
  22. const writer = receiverStreams.writable.getWriter()
  23. reader.read().then(function processVideo ({ done, value }) {
  24. const decrypted = new DataView(value.data)
  25. if (applyDecryption) {
  26. for (let i = 0; i < decrypted.buffer.byteLength; i++) {
  27. decrypted.setInt8(i, decrypted.getInt8(i) ^ cipherKey)
  28. }
  29. }
  30. value.data = decrypted.buffer
  31. writer.write(value)
  32. return reader.read().then(processVideo)
  33. })
  34. // Fire when remote video arrives
  35. pc.ontrack = function (event) {
  36. document.getElementById('remote-video').srcObject = event.streams[0]
  37. document.getElementById('remote-video').style = ''
  38. }
  39. // Populate SDP field when finished gathering
  40. pc.oniceconnectionstatechange = e => log(pc.iceConnectionState)
  41. pc.onicecandidate = event => {
  42. if (event.candidate === null) {
  43. document.getElementById('localSessionDescription').value = btoa(JSON.stringify(pc.localDescription))
  44. }
  45. }
  46. pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log)
  47. window.startSession = () => {
  48. const sd = document.getElementById('remoteSessionDescription').value
  49. if (sd === '') {
  50. return alert('Session Description must not be empty')
  51. }
  52. try {
  53. pc.setRemoteDescription(JSON.parse(atob(sd)))
  54. } catch (e) {
  55. alert(e)
  56. }
  57. }
  58. // DOM code to show banner if insertable streams not supported
  59. let insertableStreamsSupported = true
  60. const updateSupportBanner = () => {
  61. const el = document.getElementById('no-support-banner')
  62. if (insertableStreamsSupported && el) {
  63. el.style = 'display: none'
  64. }
  65. }
  66. document.addEventListener('DOMContentLoaded', updateSupportBanner)
  67. // Shim to support both versions of API
  68. function getInsertableStream (transceiver) {
  69. let insertableStreams = null
  70. if (transceiver.receiver.createEncodedVideoStreams) {
  71. insertableStreams = transceiver.receiver.createEncodedVideoStreams()
  72. } else if (transceiver.receiver.createEncodedStreams) {
  73. insertableStreams = transceiver.receiver.createEncodedStreams()
  74. }
  75. if (!insertableStreams) {
  76. insertableStreamsSupported = false
  77. updateSupportBanner()
  78. throw new Error('Insertable Streams are not supported')
  79. }
  80. return insertableStreams
  81. }