webrtc-samples
Version:
Project checking for WebRTC GitHub samples repo
301 lines (273 loc) • 10.1 kB
JavaScript
/*
* Copyright (c) 2015 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.
*/
;
var getMediaButton = document.querySelector('button#getMedia');
var connectButton = document.querySelector('button#connect');
var hangupButton = document.querySelector('button#hangup');
getMediaButton.onclick = getMedia;
connectButton.onclick = createPeerConnection;
hangupButton.onclick = hangup;
var minWidthInput = document.querySelector('div#minWidth input');
var maxWidthInput = document.querySelector('div#maxWidth input');
var minHeightInput = document.querySelector('div#minHeight input');
var maxHeightInput = document.querySelector('div#maxHeight input');
var framerateInput = document.querySelector('div#framerate input');
minWidthInput.onchange = maxWidthInput.onchange =
minHeightInput.onchange = maxHeightInput.onchange =
framerateInput.onchange = displayRangeValue;
var getUserMediaConstraintsDiv =
document.querySelector('div#getUserMediaConstraints');
var bitrateDiv = document.querySelector('div#bitrate');
var peerDiv = document.querySelector('div#peer');
var senderStatsDiv = document.querySelector('div#senderStats');
var receiverStatsDiv = document.querySelector('div#receiverStats');
var localVideo = document.querySelector('div#localVideo video');
var remoteVideo = document.querySelector('div#remoteVideo video');
var localVideoStatsDiv = document.querySelector('div#localVideo div');
var remoteVideoStatsDiv = document.querySelector('div#remoteVideo div');
var localPeerConnection;
var remotePeerConnection;
var localStream;
var bytesPrev;
var timestampPrev;
main();
function main() {
displayGetUserMediaConstraints();
}
function hangup() {
trace('Ending call');
localPeerConnection.close();
remotePeerConnection.close();
localPeerConnection = null;
remotePeerConnection = null;
localStream.getTracks().forEach(function(track) {
track.stop();
});
localStream = null;
hangupButton.disabled = true;
getMediaButton.disabled = false;
}
function getMedia() {
getMediaButton.disabled = true;
if (localStream) {
localStream.getTracks().forEach(function(track) {
track.stop();
});
var videoTracks = localStream.getVideoTracks();
for (var i = 0; i !== videoTracks.length; ++i) {
videoTracks[i].stop();
}
}
navigator.mediaDevices.getUserMedia(getUserMediaConstraints())
.then(gotStream)
.catch(function(e) {
var message = 'getUserMedia error: ' + e.name + '\n' +
'PermissionDeniedError may mean invalid constraints.';
alert(message);
console.log(message);
getMediaButton.disabled = false;
});
}
function gotStream(stream) {
connectButton.disabled = false;
console.log('GetUserMedia succeeded');
localStream = stream;
localVideo.srcObject = stream;
}
function getUserMediaConstraints() {
var constraints = {};
constraints.audio = true;
constraints.video = {};
if (minWidthInput.value !== '0') {
constraints.video.width = {};
constraints.video.width.min = minWidthInput.value;
}
if (maxWidthInput.value !== '0') {
constraints.video.width = constraints.video.width || {};
constraints.video.width.max = maxWidthInput.value;
}
if (minHeightInput.value !== '0') {
constraints.video.height = {};
constraints.video.height.min = minHeightInput.value;
}
if (maxHeightInput.value !== '0') {
constraints.video.height = constraints.video.height || {};
constraints.video.height.max = maxHeightInput.value;
}
if (framerateInput.value !== '0') {
constraints.video.frameRate = {};
constraints.video.frameRate.min = framerateInput.value;
}
return constraints;
}
function displayGetUserMediaConstraints() {
var constraints = getUserMediaConstraints();
console.log('getUserMedia constraints', constraints);
getUserMediaConstraintsDiv.textContent =
JSON.stringify(constraints, null, ' ');
}
function createPeerConnection() {
connectButton.disabled = true;
hangupButton.disabled = false;
bytesPrev = 0;
timestampPrev = 0;
localPeerConnection = new RTCPeerConnection(null);
remotePeerConnection = new RTCPeerConnection(null);
localPeerConnection.addStream(localStream);
console.log('localPeerConnection creating offer');
localPeerConnection.onnegotiationeeded = function() {
console.log('Negotiation needed - localPeerConnection');
};
remotePeerConnection.onnegotiationeeded = function() {
console.log('Negotiation needed - remotePeerConnection');
};
localPeerConnection.onicecandidate = function(e) {
console.log('Candidate localPeerConnection');
if (e.candidate) {
remotePeerConnection.addIceCandidate(new RTCIceCandidate(e.candidate),
onAddIceCandidateSuccess, onAddIceCandidateError);
}
};
remotePeerConnection.onicecandidate = function(e) {
console.log('Candidate remotePeerConnection');
if (e.candidate) {
var newCandidate = new RTCIceCandidate(e.candidate);
localPeerConnection.addIceCandidate(newCandidate,
onAddIceCandidateSuccess, onAddIceCandidateError);
}
};
remotePeerConnection.onaddstream = function(e) {
console.log('remotePeerConnection got stream');
remoteVideo.srcObject = e.stream;
};
localPeerConnection.createOffer(function(desc) {
console.log('localPeerConnection offering');
localPeerConnection.setLocalDescription(desc);
remotePeerConnection.setRemoteDescription(desc);
remotePeerConnection.createAnswer(function(desc2) {
console.log('remotePeerConnection answering');
remotePeerConnection.setLocalDescription(desc2);
localPeerConnection.setRemoteDescription(desc2);
}, function(err) {
console.log(err);
});
}, function(err) {
console.log(err);
});
}
function onAddIceCandidateSuccess() {
trace('AddIceCandidate success.');
}
function onAddIceCandidateError(error) {
trace('Failed to add Ice Candidate: ' + error.toString());
}
// Display statistics
setInterval(function() {
if (remotePeerConnection && remotePeerConnection.getRemoteStreams()[0]) {
remotePeerConnection.getStats(null, function(results) {
var statsString = dumpStats(results);
receiverStatsDiv.innerHTML = '<h2>Receiver stats</h2>' + statsString;
// calculate video bitrate
Object.keys(results).forEach(function(result) {
var report = results[result];
var now = report.timestamp;
var bitrate;
if (report.type === 'inboundrtp' && report.mediaType === 'video') {
// firefox calculates the bitrate for us
// https://bugzilla.mozilla.org/show_bug.cgi?id=951496
bitrate = Math.floor(report.bitrateMean / 1024);
} else if (report.type === 'ssrc' && report.bytesReceived &&
report.googFrameHeightReceived) {
// chrome does not so we need to do it ourselves
var bytes = report.bytesReceived;
if (timestampPrev) {
bitrate = 8 * (bytes - bytesPrev) / (now - timestampPrev);
bitrate = Math.floor(bitrate);
}
bytesPrev = bytes;
timestampPrev = now;
}
if (bitrate) {
bitrate += ' kbits/sec';
bitrateDiv.innerHTML = '<strong>Bitrate:</strong> ' + bitrate;
}
});
// figure out the peer's ip
var activeCandidatePair = null;
var remoteCandidate = null;
// search for the candidate pair
Object.keys(results).forEach(function(result) {
var report = results[result];
if (report.type === 'candidatepair' && report.selected ||
report.type === 'googCandidatePair' &&
report.googActiveConnection === 'true') {
activeCandidatePair = report;
}
});
if (activeCandidatePair && activeCandidatePair.remoteCandidateId) {
Object.keys(results).forEach(function(result) {
var report = results[result];
if (report.type === 'remotecandidate' &&
report.id === activeCandidatePair.remoteCandidateId) {
remoteCandidate = report;
}
});
}
if (remoteCandidate && remoteCandidate.ipAddress &&
remoteCandidate.portNumber) {
peerDiv.innerHTML = '<strong>Connected to:</strong> ' +
remoteCandidate.ipAddress +
':' + remoteCandidate.portNumber;
}
}, function(err) {
console.log(err);
});
localPeerConnection.getStats(null, function(results) {
var statsString = dumpStats(results);
senderStatsDiv.innerHTML = '<h2>Sender stats</h2>' + statsString;
}, function(err) {
console.log(err);
});
} else {
console.log('Not connected yet');
}
// Collect some stats from the video tags.
if (localVideo.videoWidth) {
localVideoStatsDiv.innerHTML = '<strong>Video dimensions:</strong> ' +
localVideo.videoWidth + 'x' + localVideo.videoHeight + 'px';
}
if (remoteVideo.videoWidth) {
remoteVideoStatsDiv.innerHTML = '<strong>Video dimensions:</strong> ' +
remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight + 'px';
}
}, 1000);
// Dumping a stats variable as a string.
// might be named toString?
function dumpStats(results) {
var statsString = '';
Object.keys(results).forEach(function(key, index) {
var res = results[key];
statsString += '<h3>Report ';
statsString += index;
statsString += '</h3>\n';
statsString += 'time ' + res.timestamp + '<br>\n';
statsString += 'type ' + res.type + '<br>\n';
Object.keys(res).forEach(function(k) {
if (k !== 'timestamp' && k !== 'type') {
statsString += k + ': ' + res[k] + '<br>\n';
}
});
});
return statsString;
}
// Utility to show the value of a range in a sibling span element
function displayRangeValue(e) {
var span = e.target.parentElement.querySelector('span');
span.textContent = e.target.value;
displayGetUserMediaConstraints();
}