main.html 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>libdatachannel media SFU example</title>
  6. </head>
  7. <body>
  8. <div style="display:inline-block; width:40%;">
  9. <h1>SENDER</h1>
  10. <p id="send-help">Please enter the offer provided to you by the application: </p>
  11. <textarea style="width:100%;" id="send-text" cols="40" rows="25"></textarea>
  12. <button id="send-button">Submit</button>
  13. </div>
  14. <div style="display:inline-block; width:40%;">
  15. <h1>RECEIVER</h1>
  16. <p id="recv-help">Please enter the offer provided to you by the application: </p>
  17. <textarea id="recv-text" style="width:100%;" cols="40" rows="25"></textarea>
  18. <button id="recv-button">Submit</button>
  19. </div>
  20. <div id="videos">
  21. </div>
  22. <script>
  23. document.getElementById('send-button').addEventListener('click', async () => {
  24. const pc = new RTCPeerConnection({
  25. // Recommended for libdatachannel
  26. bundlePolicy: 'max-bundle',
  27. });
  28. pc.onicegatheringstatechange = (state) => {
  29. if (pc.iceGatheringState === 'complete') {
  30. // We only want to provide an answer once all of our candidates have been added to the SDP.
  31. const answer = pc.localDescription;
  32. document.getElementById('send-text').value = JSON.stringify({
  33. type: answer.type,
  34. sdp: answer.sdp
  35. });
  36. document.getElementById('send-help').value = 'Please paste the answer in the application.';
  37. alert('Please paste the answer in the application.');
  38. }
  39. }
  40. const offer = JSON.parse(document.getElementById('send-text').value);
  41. await pc.setRemoteDescription(offer);
  42. const media = await navigator.mediaDevices.getUserMedia({
  43. video: {
  44. width: 1280,
  45. height: 720
  46. }
  47. });
  48. media.getTracks().forEach(track => pc.addTrack(track, media));
  49. const answer = await pc.createAnswer();
  50. await pc.setLocalDescription(answer);
  51. });
  52. document.getElementById('recv-button').addEventListener('click', async () => {
  53. const pc = new RTCPeerConnection({
  54. // Recommended for libdatachannel
  55. bundlePolicy: 'max-bundle',
  56. });
  57. pc.onicegatheringstatechange = (state) => {
  58. if (pc.iceGatheringState === 'complete') {
  59. // We only want to provide an answer once all of our candidates have been added to the SDP.
  60. const answer = pc.localDescription;
  61. document.getElementById('recv-text').value = JSON.stringify({
  62. type: answer.type,
  63. sdp: answer.sdp
  64. });
  65. document.getElementById('recv-help').value = 'Please paste the answer in the application.';
  66. alert('Please paste the answer in the application.');
  67. }
  68. }
  69. let trackCount = 0;
  70. pc.ontrack = (evt) => {
  71. const id = trackCount++;
  72. document.getElementById('videos').innerHTML += `<video width="100%" height="100%" id="video-${id}"></video>`;
  73. const video = document.getElementById(`video-${id}`);
  74. video.srcObject = evt.streams[0];
  75. video.play();
  76. };
  77. const offer = JSON.parse(document.getElementById('recv-text').value);
  78. await pc.setRemoteDescription(offer);
  79. const answer = await pc.createAnswer();
  80. await pc.setLocalDescription(answer);
  81. });
  82. </script>
  83. </body>
  84. </html>