28 | 29 | Local 30 | 31 | 32 |
33 |36 | 37 | Remote 38 | 39 | 40 |
41 |" + text + ""; 42 | _chatChannel.send(text); 43 | sendTxt.value = ""; 44 | return false; 45 | } 46 | pc.ondatachannel = function (e) { 47 | if (e.channel.label == "fileChannel") { 48 | console.log('fileChannel Received -', e); 49 | _fileChannel = e.channel; 50 | fileChannel(e.channel); 51 | } 52 | if (e.channel.label == "chatChannel") { 53 | console.log('chatChannel Received -', e); 54 | _chatChannel = e.channel; 55 | chatChannel(e.channel); 56 | } 57 | }; 58 | 59 | pc.onicecandidate = function (e) { 60 | var cand = e.candidate; 61 | if (!cand) { 62 | console.log('iceGatheringState complete\n', pc.localDescription.sdp); 63 | localOffer.value = JSON.stringify(pc.localDescription); 64 | } else { 65 | console.log(cand.candidate); 66 | } 67 | } 68 | pc.oniceconnectionstatechange = function () { 69 | console.log('iceconnectionstatechange: ', pc.iceConnectionState); 70 | } 71 | 72 | pc.ontrack = function (e) { 73 | console.log('remote ontrack', e.streams); 74 | remote.srcObject = e.streams[0]; 75 | } 76 | pc.onconnection = function (e) { 77 | console.log('onconnection ', e); 78 | } 79 | 80 | remoteOfferGot.onclick = function () { 81 | var _remoteOffer = new RTCSessionDescription(JSON.parse(remoteOffer.value)); 82 | console.log('remoteOffer \n', _remoteOffer); 83 | pc.setRemoteDescription(_remoteOffer).then(function () { 84 | console.log('setRemoteDescription ok'); 85 | if (_remoteOffer.type == "offer") { 86 | pc.createAnswer().then(function (description) { 87 | console.log('createAnswer 200 ok \n', description); 88 | pc.setLocalDescription(description).then(function () { }).catch(errHandler); 89 | }).catch(errHandler); 90 | } 91 | }).catch(errHandler); 92 | } 93 | localOfferSet.onclick = function () { 94 | if (chatEnabled) { 95 | _chatChannel = pc.createDataChannel('chatChannel'); 96 | _fileChannel = pc.createDataChannel('fileChannel'); 97 | // _fileChannel.binaryType = 'arraybuffer'; 98 | chatChannel(_chatChannel); 99 | fileChannel(_fileChannel); 100 | } 101 | pc.createOffer().then(des => { 102 | console.log('createOffer ok '); 103 | pc.setLocalDescription(des).then(() => { 104 | setTimeout(function () { 105 | if (pc.iceGatheringState == "complete") { 106 | return; 107 | } else { 108 | console.log('after GetherTimeout'); 109 | localOffer.value = JSON.stringify(pc.localDescription); 110 | } 111 | }, 2000); 112 | console.log('setLocalDescription ok'); 113 | }).catch(errHandler); 114 | // For chat 115 | }).catch(errHandler); 116 | } 117 | 118 | //File transfer 119 | fileTransfer.onchange = function (e) { 120 | var files = fileTransfer.files; 121 | if (files.length > 0) { 122 | file = files[0]; 123 | sendFileDom.name = file.name; 124 | sendFileDom.size = file.size; 125 | sendFileDom.type = file.type; 126 | sendFileDom.fileInfo = "areYouReady"; 127 | console.log(sendFileDom); 128 | } else { 129 | console.log('No file selected'); 130 | } 131 | } 132 | 133 | function sendFile() { 134 | if (!fileTransfer.value) return; 135 | var fileInfo = JSON.stringify(sendFileDom); 136 | _fileChannel.send(fileInfo); 137 | console.log('file info sent'); 138 | } 139 | 140 | 141 | function fileChannel(e) { 142 | _fileChannel.onopen = function (e) { 143 | console.log('file channel is open', e); 144 | } 145 | _fileChannel.onmessage = function (e) { 146 | // Figure out data type 147 | var type = Object.prototype.toString.call(e.data), 148 | data; 149 | if (type == "[object ArrayBuffer]") { 150 | data = e.data; 151 | receiveBuffer.push(data); 152 | receivedSize += data.byteLength; 153 | recFileProg.value = receivedSize; 154 | if (receivedSize == recFileDom.size) { 155 | var received = new window.Blob(receiveBuffer); 156 | file_download.href = URL.createObjectURL(received); 157 | file_download.innerHTML = "download"; 158 | file_download.download = recFileDom.name; 159 | // rest 160 | receiveBuffer = []; 161 | receivedSize = 0; 162 | // clearInterval(window.timer); 163 | } 164 | } else if (type == "[object String]") { 165 | data = JSON.parse(e.data); 166 | } else if (type == "[object Blob]") { 167 | data = e.data; 168 | file_download.href = URL.createObjectURL(data); 169 | file_download.innerHTML = "download"; 170 | file_download.download = recFileDom.name; 171 | } 172 | 173 | // Handle initial msg exchange 174 | if (data.fileInfo) { 175 | if (data.fileInfo == "areYouReady") { 176 | recFileDom = data; 177 | recFileProg.max = data.size; 178 | var sendData = JSON.stringify({ fileInfo: "readyToReceive" }); 179 | _fileChannel.send(sendData); 180 | // window.timer = setInterval(function(){ 181 | // Stats(); 182 | // },1000) 183 | } else if (data.fileInfo == "readyToReceive") { 184 | sendFileProg.max = sendFileDom.size; 185 | sendFileinChannel(); // Start sending the file 186 | } 187 | console.log('_fileChannel: ', data.fileInfo); 188 | } 189 | } 190 | _fileChannel.onclose = function () { 191 | console.log('file channel closed'); 192 | } 193 | } 194 | 195 | function chatChannel(e) { 196 | _chatChannel.onopen = function (e) { 197 | console.log('chat channel is open', e); 198 | } 199 | _chatChannel.onmessage = function (e) { 200 | chat.innerHTML = chat.innerHTML + "
" + e.data + "" 201 | } 202 | _chatChannel.onclose = function () { 203 | console.log('chat channel closed'); 204 | } 205 | } 206 | 207 | function sendFileinChannel() { 208 | var chunkSize = 16384; 209 | var sliceFile = function (offset) { 210 | var reader = new window.FileReader(); 211 | reader.onload = (function () { 212 | return function (e) { 213 | _fileChannel.send(e.target.result); 214 | if (file.size > offset + e.target.result.byteLength) { 215 | window.setTimeout(sliceFile, 0, offset + chunkSize); 216 | } 217 | sendFileProg.value = offset + e.target.result.byteLength 218 | }; 219 | })(file); 220 | var slice = file.slice(offset, offset + chunkSize); 221 | reader.readAsArrayBuffer(slice); 222 | }; 223 | sliceFile(0); 224 | } 225 | 226 | function Stats() { 227 | pc.getStats(null, function (stats) { 228 | for (var key in stats) { 229 | var res = stats[key]; 230 | console.log(res.type, res.googActiveConnection); 231 | if (res.type === 'googCandidatePair' && 232 | res.googActiveConnection === 'true') { 233 | // calculate current bitrate 234 | var bytesNow = res.bytesReceived; 235 | console.log('bit rate', (bytesNow - bytesPrev)); 236 | bytesPrev = bytesNow; 237 | } 238 | } 239 | }); 240 | } 241 | 242 | streamAudioFile.onchange = function () { 243 | console.log('streamAudioFile'); 244 | context = new AudioContext(); 245 | var file = streamAudioFile.files[0]; 246 | if (file) { 247 | if (file.type.match('audio*')) { 248 | var reader = new FileReader(); 249 | reader.onload = (function (readEvent) { 250 | context.decodeAudioData(readEvent.target.result, function (buffer) { 251 | // create an audio source and connect it to the file buffer 252 | source = context.createBufferSource(); 253 | source.buffer = buffer; 254 | source.start(0); 255 | 256 | // connect the audio stream to the audio hardware 257 | source.connect(context.destination); 258 | 259 | // create a destination for the remote browser 260 | var remote = context.createMediaStreamDestination(); 261 | 262 | // connect the remote destination to the source 263 | source.connect(remote); 264 | 265 | local.srcObject = remote.stream 266 | local.muted = true; 267 | // add the stream to the peer connection 268 | remote.stream.getTracks().forEach((track) => { 269 | pc.addTrack(track, stream); 270 | }); 271 | 272 | // create a SDP offer for the new stream 273 | // pc.createOffer(setLocalAndSendMessage); 274 | }); 275 | }); 276 | 277 | reader.readAsArrayBuffer(file); 278 | } 279 | } 280 | } 281 | 282 | var audioRTC = function (cb) { 283 | console.log('streamAudioFile'); 284 | window.context = new AudioContext(); 285 | var file = streamAudioFile.files[0]; 286 | if (file) { 287 | if (file.type.match('audio*')) { 288 | var reader = new FileReader(); 289 | reader.onload = (function (readEvent) { 290 | context.decodeAudioData(readEvent.target.result, function (buffer) { 291 | // create an audio source and connect it to the file buffer 292 | var source = context.createBufferSource(); 293 | source.buffer = buffer; 294 | source.start(0); 295 | 296 | // connect the audio stream to the audio hardware 297 | source.connect(context.destination); 298 | 299 | // create a destination for the remote browser 300 | var remote = context.createMediaStreamDestination(); 301 | 302 | // connect the remote destination to the source 303 | source.connect(remote); 304 | window.localStream = remote.stream; 305 | cb({ 'status': 'success', 'stream': true }); 306 | }); 307 | }); 308 | 309 | reader.readAsArrayBuffer(file); 310 | } 311 | } 312 | } 313 | 314 | /* Summary 315 | //setup your video 316 | pc = new RTCPeerConnection 317 | navigator.mediaDevices.getUserMedia({ audio: true, video: true }) 318 | pc.addStream(stream) 319 | 320 | //prepare your sdp1 321 | pc.createOffer() - des 322 | pc.setLocalDescription(des) 323 | pc.onicecandidate 324 | pc.localDescription 325 | 326 | //create sdp from sdp1 327 | _remoteOffer = new RTCSessionDescription sdp 328 | pc.setRemoteDescription(_remoteOffer) 329 | _remoteOffer.type == "offer" && pc.createAnswer() - desc 330 | pc.setLocalDescription(description) 331 | pc.onaddstream 332 | */ -------------------------------------------------------------------------------- /snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svarunan/serverless-webrtc/211c8fc7036e9ab92cb9e967a0bcafc7e0ca1567/snap.png --------------------------------------------------------------------------------