main.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. (function() {
  2. // Define "global" variables
  3. var connectButton = null;
  4. var disconnectButton = null;
  5. var sendButton = null;
  6. var messageInputBox = null;
  7. var receiveBox = null;
  8. var localConnection = null; // RTCPeerConnection for our "local" connection
  9. var remoteConnection = null; // RTCPeerConnection for the "remote"
  10. var sendChannel = null; // RTCDataChannel for the local (sender)
  11. var receiveChannel = null; // RTCDataChannel for the remote (receiver)
  12. // Functions
  13. // Set things up, connect event listeners, etc.
  14. function startup() {
  15. connectButton = document.getElementById('connectButton');
  16. disconnectButton = document.getElementById('disconnectButton');
  17. sendButton = document.getElementById('sendButton');
  18. messageInputBox = document.getElementById('message');
  19. receiveBox = document.getElementById('receivebox');
  20. // Set event listeners for user interface widgets
  21. connectButton.addEventListener('click', connectPeers, false);
  22. disconnectButton.addEventListener('click', disconnectPeers, false);
  23. sendButton.addEventListener('click', sendMessage, false);
  24. }
  25. // Connect the two peers. Normally you look for and connect to a remote
  26. // machine here, but we're just connecting two local objects, so we can
  27. // bypass that step.
  28. function connectPeers() {
  29. // Create the local connection and its event listeners
  30. localConnection = new RTCPeerConnection();
  31. // Create the data channel and establish its event listeners
  32. sendChannel = localConnection.createDataChannel("sendChannel");
  33. sendChannel.onopen = handleSendChannelStatusChange;
  34. sendChannel.onclose = handleSendChannelStatusChange;
  35. // Create the remote connection and its event listeners
  36. remoteConnection = new RTCPeerConnection();
  37. remoteConnection.ondatachannel = receiveChannelCallback;
  38. // Set up the ICE candidates for the two peers
  39. localConnection.onicecandidate = e => !e.candidate
  40. || remoteConnection.addIceCandidate(e.candidate)
  41. .catch(handleAddCandidateError);
  42. remoteConnection.onicecandidate = e => !e.candidate
  43. || localConnection.addIceCandidate(e.candidate)
  44. .catch(handleAddCandidateError);
  45. // Now create an offer to connect; this starts the process
  46. localConnection.createOffer()
  47. .then(offer => localConnection.setLocalDescription(offer))
  48. .then(() => remoteConnection.setRemoteDescription(localConnection.localDescription))
  49. .then(() => remoteConnection.createAnswer())
  50. .then(answer => remoteConnection.setLocalDescription(answer))
  51. .then(() => localConnection.setRemoteDescription(remoteConnection.localDescription))
  52. .catch(handleCreateDescriptionError);
  53. }
  54. // Handle errors attempting to create a description;
  55. // this can happen both when creating an offer and when
  56. // creating an answer. In this simple example, we handle
  57. // both the same way.
  58. function handleCreateDescriptionError(error) {
  59. console.log("Unable to create an offer: " + error.toString());
  60. }
  61. // Handle successful addition of the ICE candidate
  62. // on the "local" end of the connection.
  63. function handleLocalAddCandidateSuccess() {
  64. connectButton.disabled = true;
  65. }
  66. // Handle successful addition of the ICE candidate
  67. // on the "remote" end of the connection.
  68. function handleRemoteAddCandidateSuccess() {
  69. disconnectButton.disabled = false;
  70. }
  71. // Handle an error that occurs during addition of ICE candidate.
  72. function handleAddCandidateError() {
  73. console.log("Oh noes! addICECandidate failed!");
  74. }
  75. // Handles clicks on the "Send" button by transmitting
  76. // a message to the remote peer.
  77. function sendMessage() {
  78. var message = messageInputBox.value;
  79. sendChannel.send(message);
  80. // Clear the input box and re-focus it, so that we're
  81. // ready for the next message.
  82. messageInputBox.value = "";
  83. messageInputBox.focus();
  84. }
  85. // Handle status changes on the local end of the data
  86. // channel; this is the end doing the sending of data
  87. // in this example.
  88. function handleSendChannelStatusChange(event) {
  89. if (sendChannel) {
  90. var state = sendChannel.readyState;
  91. if (state === "open") {
  92. messageInputBox.disabled = false;
  93. messageInputBox.focus();
  94. sendButton.disabled = false;
  95. disconnectButton.disabled = false;
  96. connectButton.disabled = true;
  97. } else {
  98. messageInputBox.disabled = true;
  99. sendButton.disabled = true;
  100. connectButton.disabled = false;
  101. disconnectButton.disabled = true;
  102. }
  103. }
  104. }
  105. // Called when the connection opens and the data
  106. // channel is ready to be connected to the remote.
  107. function receiveChannelCallback(event) {
  108. receiveChannel = event.channel;
  109. receiveChannel.onmessage = handleReceiveMessage;
  110. receiveChannel.onopen = handleReceiveChannelStatusChange;
  111. receiveChannel.onclose = handleReceiveChannelStatusChange;
  112. }
  113. // Handle onmessage events for the receiving channel.
  114. // These are the data messages sent by the sending channel.
  115. function handleReceiveMessage(event) {
  116. var el = document.createElement("p");
  117. var txtNode = document.createTextNode(event.data);
  118. el.appendChild(txtNode);
  119. receiveBox.appendChild(el);
  120. }
  121. // Handle status changes on the receiver's channel.
  122. function handleReceiveChannelStatusChange(event) {
  123. if (receiveChannel) {
  124. console.log("Receive channel's status has changed to " +
  125. receiveChannel.readyState);
  126. }
  127. // Here you would do stuff that needs to be done
  128. // when the channel's status changes.
  129. }
  130. // Close the connection, including data channels if they're open.
  131. // Also update the UI to reflect the disconnected status.
  132. function disconnectPeers() {
  133. // Close the RTCDataChannels if they're open.
  134. sendChannel.close();
  135. receiveChannel.close();
  136. // Close the RTCPeerConnections
  137. localConnection.close();
  138. remoteConnection.close();
  139. sendChannel = null;
  140. receiveChannel = null;
  141. localConnection = null;
  142. remoteConnection = null;
  143. // Update user interface elements
  144. connectButton.disabled = false;
  145. disconnectButton.disabled = true;
  146. sendButton.disabled = true;
  147. messageInputBox.value = "";
  148. messageInputBox.disabled = true;
  149. }
  150. // Set up an event listener which will run the startup
  151. // function once the page is done loading.
  152. window.addEventListener('load', startup, false);
  153. })();