| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | 3  * Use of this source code is governed by a BSD-style license that can be | 
|  | 4  * found in the LICENSE file. | 
|  | 5  */ | 
|  | 6 'use strict'; | 
|  | 7 | 
|  | 8 var localConnection; | 
|  | 9 var remoteConnection; | 
|  | 10 var sendChannel; | 
|  | 11 var receiveChannel; | 
|  | 12 var pcConstraint; | 
|  | 13 var megsToSend = document.querySelector('input#megsToSend'); | 
|  | 14 var sendButton = document.querySelector('button#sendTheData'); | 
|  | 15 var orderedCheckbox = document.querySelector('input#ordered'); | 
|  | 16 var sendProgress = document.querySelector('progress#sendProgress'); | 
|  | 17 var receiveProgress = document.querySelector('progress#receiveProgress'); | 
|  | 18 var errorMessage = document.querySelector('div#errorMsg'); | 
|  | 19 | 
|  | 20 var receivedSize = 0; | 
|  | 21 var bytesToSend = 0; | 
|  | 22 | 
|  | 23 sendButton.onclick = createConnection; | 
|  | 24 | 
|  | 25 // Prevent data sent to be set to 0. | 
|  | 26 megsToSend.addEventListener('change', function(e) { | 
|  | 27   if (this.value <= 0) { | 
|  | 28     sendButton.disabled = true; | 
|  | 29     errorMessage.innerHTML = '<p>Please enter a number greater than zero.</p>'; | 
|  | 30   } else { | 
|  | 31     errorMessage.innerHTML = ''; | 
|  | 32     sendButton.disabled = false; | 
|  | 33   } | 
|  | 34 }); | 
|  | 35 | 
|  | 36 function createConnection() { | 
|  | 37   sendButton.disabled = true; | 
|  | 38   megsToSend.disabled = true; | 
|  | 39   var servers = null; | 
|  | 40   pcConstraint = null; | 
|  | 41 | 
|  | 42   bytesToSend = Math.round(megsToSend.value) * 1024 * 1024; | 
|  | 43 | 
|  | 44   // Add localConnection to global scope to make it visible | 
|  | 45   // from the browser console. | 
|  | 46   window.localConnection = localConnection = new RTCPeerConnection(servers, | 
|  | 47       pcConstraint); | 
|  | 48   trace('Created local peer connection object localConnection'); | 
|  | 49 | 
|  | 50   var dataChannelParams = {ordered: false}; | 
|  | 51   if (orderedCheckbox.checked) { | 
|  | 52     dataChannelParams.ordered = true; | 
|  | 53   } | 
|  | 54 | 
|  | 55   sendChannel = localConnection.createDataChannel( | 
|  | 56       'sendDataChannel', dataChannelParams); | 
|  | 57   sendChannel.binaryType = 'arraybuffer'; | 
|  | 58   trace('Created send data channel'); | 
|  | 59 | 
|  | 60   sendChannel.onopen = onSendChannelStateChange; | 
|  | 61   sendChannel.onclose = onSendChannelStateChange; | 
|  | 62   localConnection.onicecandidate = function(e) { | 
|  | 63     onIceCandidate(localConnection, e); | 
|  | 64   }; | 
|  | 65 | 
|  | 66   localConnection.createOffer().then( | 
|  | 67     gotDescription1, | 
|  | 68     onCreateSessionDescriptionError | 
|  | 69   ); | 
|  | 70 | 
|  | 71   // Add remoteConnection to global scope to make it visible | 
|  | 72   // from the browser console. | 
|  | 73   window.remoteConnection = remoteConnection = new RTCPeerConnection(servers, | 
|  | 74       pcConstraint); | 
|  | 75   trace('Created remote peer connection object remoteConnection'); | 
|  | 76 | 
|  | 77   remoteConnection.onicecandidate = function(e) { | 
|  | 78     onIceCandidate(remoteConnection, e); | 
|  | 79   }; | 
|  | 80   remoteConnection.ondatachannel = receiveChannelCallback; | 
|  | 81 } | 
|  | 82 | 
|  | 83 function onCreateSessionDescriptionError(error) { | 
|  | 84   trace('Failed to create session description: ' + error.toString()); | 
|  | 85 } | 
|  | 86 | 
|  | 87 function randomAsciiString(length) { | 
|  | 88   var result = ''; | 
|  | 89   for (var i = 0; i < length; i++) { | 
|  | 90     // Visible ASCII chars are between 33 and 126. | 
|  | 91     result += String.fromCharCode(33 + Math.random() * 93); | 
|  | 92   } | 
|  | 93   return result; | 
|  | 94 } | 
|  | 95 | 
|  | 96 function sendGeneratedData() { | 
|  | 97   sendProgress.max = bytesToSend; | 
|  | 98   receiveProgress.max = sendProgress.max; | 
|  | 99   sendProgress.value = 0; | 
|  | 100   receiveProgress.value = 0; | 
|  | 101 | 
|  | 102   var chunkSize = 16384; | 
|  | 103   var stringToSendRepeatedly = randomAsciiString(chunkSize); | 
|  | 104   var bufferFullThreshold = 5 * chunkSize; | 
|  | 105   var usePolling = true; | 
|  | 106   if (typeof sendChannel.bufferedAmountLowThreshold === 'number') { | 
|  | 107     trace('Using the bufferedamountlow event for flow control'); | 
|  | 108     usePolling = false; | 
|  | 109 | 
|  | 110     // Reduce the buffer fullness threshold, since we now have more efficient | 
|  | 111     // buffer management. | 
|  | 112     bufferFullThreshold = chunkSize / 2; | 
|  | 113 | 
|  | 114     // This is "overcontrol": our high and low thresholds are the same. | 
|  | 115     sendChannel.bufferedAmountLowThreshold = bufferFullThreshold; | 
|  | 116   } | 
|  | 117   // Listen for one bufferedamountlow event. | 
|  | 118   var listener = function() { | 
|  | 119     sendChannel.removeEventListener('bufferedamountlow', listener); | 
|  | 120     sendAllData(); | 
|  | 121   }; | 
|  | 122   var sendAllData = function() { | 
|  | 123     // Try to queue up a bunch of data and back off when the channel starts to | 
|  | 124     // fill up. We don't setTimeout after each send since this lowers our | 
|  | 125     // throughput quite a bit (setTimeout(fn, 0) can take hundreds of milli- | 
|  | 126     // seconds to execute). | 
|  | 127     while (sendProgress.value < sendProgress.max) { | 
|  | 128       if (sendChannel.bufferedAmount > bufferFullThreshold) { | 
|  | 129         if (usePolling) { | 
|  | 130           setTimeout(sendAllData, 250); | 
|  | 131         } else { | 
|  | 132           sendChannel.addEventListener('bufferedamountlow', listener); | 
|  | 133         } | 
|  | 134         return; | 
|  | 135       } | 
|  | 136       sendProgress.value += chunkSize; | 
|  | 137       sendChannel.send(stringToSendRepeatedly); | 
|  | 138     } | 
|  | 139   }; | 
|  | 140   setTimeout(sendAllData, 0); | 
|  | 141 } | 
|  | 142 | 
|  | 143 function closeDataChannels() { | 
|  | 144   trace('Closing data channels'); | 
|  | 145   sendChannel.close(); | 
|  | 146   trace('Closed data channel with label: ' + sendChannel.label); | 
|  | 147   receiveChannel.close(); | 
|  | 148   trace('Closed data channel with label: ' + receiveChannel.label); | 
|  | 149   localConnection.close(); | 
|  | 150   remoteConnection.close(); | 
|  | 151   localConnection = null; | 
|  | 152   remoteConnection = null; | 
|  | 153   trace('Closed peer connections'); | 
|  | 154 } | 
|  | 155 | 
|  | 156 function gotDescription1(desc) { | 
|  | 157   localConnection.setLocalDescription(desc); | 
|  | 158   trace('Offer from localConnection \n' + desc.sdp); | 
|  | 159   remoteConnection.setRemoteDescription(desc); | 
|  | 160   remoteConnection.createAnswer().then( | 
|  | 161     gotDescription2, | 
|  | 162     onCreateSessionDescriptionError | 
|  | 163   ); | 
|  | 164 } | 
|  | 165 | 
|  | 166 function gotDescription2(desc) { | 
|  | 167   remoteConnection.setLocalDescription(desc); | 
|  | 168   trace('Answer from remoteConnection \n' + desc.sdp); | 
|  | 169   localConnection.setRemoteDescription(desc); | 
|  | 170 } | 
|  | 171 | 
|  | 172 function getOtherPc(pc) { | 
|  | 173   return (pc === localConnection) ? remoteConnection : localConnection; | 
|  | 174 } | 
|  | 175 | 
|  | 176 function getName(pc) { | 
|  | 177   return (pc === localConnection) ? 'localPeerConnection' : | 
|  | 178       'remotePeerConnection'; | 
|  | 179 } | 
|  | 180 | 
|  | 181 function onIceCandidate(pc, event) { | 
|  | 182   getOtherPc(pc).addIceCandidate(event.candidate) | 
|  | 183   .then( | 
|  | 184     function() { | 
|  | 185       onAddIceCandidateSuccess(pc); | 
|  | 186     }, | 
|  | 187     function(err) { | 
|  | 188       onAddIceCandidateError(pc, err); | 
|  | 189     } | 
|  | 190   ); | 
|  | 191   trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ? | 
|  | 192       event.candidate.candidate : '(null)')); | 
|  | 193 } | 
|  | 194 | 
|  | 195 function onAddIceCandidateSuccess() { | 
|  | 196   trace('AddIceCandidate success.'); | 
|  | 197 } | 
|  | 198 | 
|  | 199 function onAddIceCandidateError(error) { | 
|  | 200   trace('Failed to add Ice Candidate: ' + error.toString()); | 
|  | 201 } | 
|  | 202 | 
|  | 203 function receiveChannelCallback(event) { | 
|  | 204   trace('Receive Channel Callback'); | 
|  | 205   receiveChannel = event.channel; | 
|  | 206   receiveChannel.binaryType = 'arraybuffer'; | 
|  | 207   receiveChannel.onmessage = onReceiveMessageCallback; | 
|  | 208 | 
|  | 209   receivedSize = 0; | 
|  | 210 } | 
|  | 211 | 
|  | 212 function onReceiveMessageCallback(event) { | 
|  | 213   receivedSize += event.data.length; | 
|  | 214   receiveProgress.value = receivedSize; | 
|  | 215 | 
|  | 216   if (receivedSize === bytesToSend) { | 
|  | 217     closeDataChannels(); | 
|  | 218     sendButton.disabled = false; | 
|  | 219     megsToSend.disabled = false; | 
|  | 220   } | 
|  | 221 } | 
|  | 222 | 
|  | 223 function onSendChannelStateChange() { | 
|  | 224   var readyState = sendChannel.readyState; | 
|  | 225   trace('Send channel state is: ' + readyState); | 
|  | 226   if (readyState === 'open') { | 
|  | 227     sendGeneratedData(); | 
|  | 228   } | 
|  | 229 } | 
| OLD | NEW | 
|---|