| /* |
| * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. |
| */ |
| /* global TimelineDataSeries, TimelineGraphView */ |
| |
| 'use strict'; |
| |
| var remoteVideo = document.querySelector('video#remoteVideo'); |
| var localVideo = document.querySelector('video#localVideo'); |
| var callButton = document.querySelector('button#callButton'); |
| var hangupButton = document.querySelector('button#hangupButton'); |
| var bandwidthSelector = document.querySelector('select#bandwidth'); |
| hangupButton.disabled = true; |
| callButton.onclick = call; |
| hangupButton.onclick = hangup; |
| |
| var pc1; |
| var pc2; |
| var localStream; |
| |
| var bitrateGraph; |
| var bitrateSeries; |
| |
| var packetGraph; |
| var packetSeries; |
| |
| var lastResult; |
| |
| var offerOptions = { |
| offerToReceiveAudio: 0, |
| offerToReceiveVideo: 1 |
| }; |
| |
| function gotStream(stream) { |
| hangupButton.disabled = false; |
| trace('Received local stream'); |
| localStream = stream; |
| localVideo.srcObject = stream; |
| pc1.addStream(localStream); |
| trace('Adding Local Stream to peer connection'); |
| |
| pc1.createOffer( |
| offerOptions |
| ).then( |
| gotDescription1, |
| onCreateSessionDescriptionError |
| ); |
| |
| bitrateSeries = new TimelineDataSeries(); |
| bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas'); |
| bitrateGraph.updateEndDate(); |
| |
| packetSeries = new TimelineDataSeries(); |
| packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas'); |
| packetGraph.updateEndDate(); |
| } |
| |
| function onCreateSessionDescriptionError(error) { |
| trace('Failed to create session description: ' + error.toString()); |
| } |
| |
| function call() { |
| callButton.disabled = true; |
| bandwidthSelector.disabled = false; |
| trace('Starting call'); |
| var servers = null; |
| var pcConstraints = { |
| 'optional': [] |
| }; |
| pc1 = new RTCPeerConnection(servers, pcConstraints); |
| trace('Created local peer connection object pc1'); |
| pc1.onicecandidate = iceCallback1; |
| pc2 = new RTCPeerConnection(servers, pcConstraints); |
| trace('Created remote peer connection object pc2'); |
| pc2.onicecandidate = iceCallback2; |
| pc2.onaddstream = gotRemoteStream; |
| trace('Requesting local stream'); |
| navigator.mediaDevices.getUserMedia({ |
| video: true |
| }) |
| .then(gotStream) |
| .catch(function(e) { |
| alert('getUserMedia() error: ' + e.name); |
| }); |
| } |
| |
| function gotDescription1(desc) { |
| trace('Offer from pc1 \n' + desc.sdp); |
| pc1.setLocalDescription(desc).then( |
| function() { |
| pc2.setRemoteDescription(desc).then( |
| function() { |
| pc2.createAnswer().then( |
| gotDescription2, |
| onCreateSessionDescriptionError |
| ); |
| }, |
| onSetSessionDescriptionError |
| ); |
| }, |
| onSetSessionDescriptionError |
| ); |
| } |
| |
| function gotDescription2(desc) { |
| pc2.setLocalDescription(desc).then( |
| function() { |
| trace('Answer from pc2 \n' + desc.sdp); |
| // insert b=AS after c= line. |
| desc.sdp = desc.sdp.replace(/c=IN IP4 (.*)\r\n/, |
| 'c=IN IP4 $(1)\r\nb=AS:512\r\n'); |
| pc1.setRemoteDescription(desc).then( |
| function() { |
| }, |
| onSetSessionDescriptionError |
| ); |
| }, |
| onSetSessionDescriptionError |
| ); |
| } |
| |
| function hangup() { |
| trace('Ending call'); |
| localStream.getTracks().forEach(function(track) { |
| track.stop(); |
| }); |
| pc1.close(); |
| pc2.close(); |
| pc1 = null; |
| pc2 = null; |
| hangupButton.disabled = true; |
| callButton.disabled = false; |
| bandwidthSelector.disabled = true; |
| } |
| |
| function gotRemoteStream(e) { |
| remoteVideo.srcObject = e.stream; |
| trace('Received remote stream'); |
| } |
| |
| function iceCallback1(event) { |
| if (event.candidate) { |
| pc2.addIceCandidate( |
| new RTCIceCandidate(event.candidate) |
| ).then( |
| onAddIceCandidateSuccess, |
| onAddIceCandidateError |
| ); |
| trace('Local ICE candidate: \n' + event.candidate.candidate); |
| } |
| } |
| |
| function iceCallback2(event) { |
| if (event.candidate) { |
| pc1.addIceCandidate( |
| new RTCIceCandidate(event.candidate) |
| ).then( |
| onAddIceCandidateSuccess, |
| onAddIceCandidateError |
| ); |
| trace('Remote ICE candidate: \n ' + event.candidate.candidate); |
| } |
| } |
| |
| function onAddIceCandidateSuccess() { |
| trace('AddIceCandidate success.'); |
| } |
| |
| function onAddIceCandidateError(error) { |
| trace('Failed to add ICE Candidate: ' + error.toString()); |
| } |
| |
| function onSetSessionDescriptionError(error) { |
| trace('Failed to set session description: ' + error.toString()); |
| } |
| |
| // renegotiate bandwidth on the fly. |
| bandwidthSelector.onchange = function() { |
| bandwidthSelector.disabled = true; |
| var bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex] |
| .value; |
| pc1.setLocalDescription(pc1.localDescription) |
| .then(function() { |
| var desc = pc1.remoteDescription; |
| desc.sdp = desc.sdp.replace(/b=AS:(.*)\r\n/, 'b=AS:' + bandwidth + '\r\n'); |
| return pc1.setRemoteDescription(desc); |
| }) |
| .then(function() { |
| bandwidthSelector.disabled = false; |
| }) |
| .catch(onSetSessionDescriptionError); |
| }; |
| |
| // query getStats every second |
| window.setInterval(function() { |
| if (!window.pc1) { |
| return; |
| } |
| window.pc1.getStats(null).then(function(res) { |
| Object.keys(res).forEach(function(key) { |
| var report = res[key]; |
| var bytes; |
| var packets; |
| var now = report.timestamp; |
| if ((report.type === 'outboundrtp') || |
| (report.type === 'outbound-rtp') || |
| (report.type === 'ssrc' && report.bytesSent)) { |
| bytes = report.bytesSent; |
| packets = report.packetsSent; |
| if (lastResult && lastResult[report.id]) { |
| // calculate bitrate |
| var bitrate = 8 * (bytes - lastResult[report.id].bytesSent) / |
| (now - lastResult[report.id].timestamp); |
| |
| // append to chart |
| bitrateSeries.addPoint(now, bitrate); |
| bitrateGraph.setDataSeries([bitrateSeries]); |
| bitrateGraph.updateEndDate(); |
| |
| // calculate number of packets and append to chart |
| packetSeries.addPoint(now, packets - |
| lastResult[report.id].packetsSent); |
| packetGraph.setDataSeries([packetSeries]); |
| packetGraph.updateEndDate(); |
| } |
| } |
| }); |
| lastResult = res; |
| }); |
| }, 1000); |