blob: 2ffa13aeedaf34487f8f1f30015fb7ea1f6c87cf [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebRTC Simulcast Test</title>
<style>
video {
border:5px solid black;
}
button {
font: 18px sans-serif;
padding: 8px;
}
</style>
</head>
<body>
<video id="localVideo" autoplay></video>
<!-- These video tags and canvases should match the stream labels returned by
PC_SERVER_REMOTE_OFFER. The canvases are there for video detection. --!>
<video id="remoteVideo1" autoplay></video>
<video id="remoteVideo2" autoplay></video>
<video id="remoteVideo3" autoplay></video>
<canvas id="remoteVideo1-canvas" autoplay style="display:none"></video>
<canvas id="remoteVideo2-canvas" autoplay style="display:none"></video>
<canvas id="remoteVideo3-canvas" autoplay style="display:none"></video>
<script type="text/javascript" src="webrtc_test_utilities.js"></script>
<script type="text/javascript">
var pcClient, pcServer;
var localStream;
var remoteVideoUrls = [];
var serverAnswer;
// When all required video tags are playing video, succeed the test.
setAllEventsOccuredHandler(function() {
returnToTest('OK');
});
// Checks that we can get a simulcast stream call up on VGA.
function testVgaReturnsTwoSimulcastStreams() {
initialize();
openCamera(640, 480);
// For VGA we should get a QVGA and VGA stream. The video tags are named after
// the stream IDs which are defined in PC_SERVER_REMOTE_OFFER.
waitForVideo('remoteVideo1');
waitForVideo('remoteVideo2');
}
// Template for the local offer, representing a single input stream backing
// 3 different SSRCs, all in one SIM ssrc-group.
function makeClientOffer() {
var lines = [
'v=0',
'o=- 0 3 IN IP4 127.0.0.1',
's=-',
't=0 0',
'm=video 1 RTP/SAVPF 100',
'a=rtcp:1 IN IP4 0.0.0.0',
'a=ice-ufrag:6HHHdzzeIhkE0CKj',
'a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew',
'a=sendonly',
'a=mid:video',
'a=crypto:1 AES_CM_128_HMAC_SHA1_80 ' +
'inline:Rlz8z1nMtwq9VF7j06kTc7uyio1iYuEdeZ7z1P9E',
'a=rtpmap:100 VP8/30',
'a=fmtp:100 x-google-start-bitrate=100000',
'a=fmtp:100 x-google-min-bitrate=80000',
'a=x-google-flag:conference'
];
if (localStream) {
var videoTracks = localStream.getVideoTracks();
if (videoTracks.length > 0) {
trace('Using Video device: ' + videoTracks[0].id);
} else {
trace('WARNING: No video device!');
return lines.join('\n');
}
lines = lines.concat([
'a=ssrc-group:SIM 1 2 3',
'a=ssrc:1 cname:localVideo',
'a=ssrc:1 msid:' + localStream.id + ' ' + videoTracks[0].id,
'a=ssrc:2 cname:localVideo',
'a=ssrc:2 msid:' + localStream.id + ' ' + videoTracks[0].id,
'a=ssrc:3 cname:localVideo',
'a=ssrc:3 msid:' + localStream.id + ' ' + videoTracks[0].id
]);
}
lines.push('');
return new RTCSessionDescription({
'type': 'offer',
'sdp': lines.join('\n')
});
}
// Remote perspective on that offer, representing each SSRC as a distinct
// (non-synchronized) output video stream.
var PC_SERVER_REMOTE_OFFER = [
'v=0',
'o=- 0 3 IN IP4 127.0.0.1',
's=-',
't=0 0',
'm=video 1 RTP/SAVPF 100',
'a=sendonly',
'a=mid:video',
'a=rtcp:1 IN IP4 0.0.0.0',
'a=ice-ufrag:6HHHdzzeIhkE0CKj',
'a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew',
'a=crypto:1 AES_CM_128_HMAC_SHA1_80 ' +
'inline:Rlz8z1nMtwq9VF7j06kTc7uyio1iYuEdeZ7z1P9E',
'a=rtpmap:100 VP8/30',
'a=x-google-flag:conference',
'a=fmtp:100 x-google-start-bitrate=100000',
'a=fmtp:100 x-google-min-bitrate=80000',
'a=ssrc:1 cname:remoteVideo1',
'a=ssrc:1 msid:remoteVideo1 remoteVideo1v0',
'a=ssrc:2 cname:remoteVideo2',
'a=ssrc:2 msid:remoteVideo2 remoteVideo2v0',
'a=ssrc:3 cname:remoteVideo3',
'a=ssrc:3 msid:remoteVideo3 remoteVideo3v0',
''
].join('\n');
function trace(text) {
// This function is used for logging.
if (text[text.length - 1] == '\n') {
text = text.substring(0, text.length - 1);
}
console.log((performance.now() / 1000).toFixed(3) + ': ' + text);
}
function initialize() {
trace('Setting up for a new call.');
var configs = {iceServers:[], rtcpMuxPolicy:'negotiate'};
var constraints = {'mandatory': {'DtlsSrtpKeyAgreement': false}};
pcClient = new webkitRTCPeerConnection(configs, constraints);
trace('Created local peer connection object pcClient');
pcClient.onicecandidate = onClientIceCandidate;
pcServer = new webkitRTCPeerConnection(configs, constraints);
trace('Created remote peer connection object pcServer');
pcServer.onicecandidate = onServerIceCandidate;
pcServer.onaddstream = onServerGotStream;
var pcClientInitialOffer = makeClientOffer();
trace('Setting initial local Offer to:\n' + pcClientInitialOffer);
pcClient.setLocalDescription(pcClientInitialOffer,
setServerRemoteDescription);
}
function gotStream(stream) {
trace('Received local stream');
localVideo.src = webkitURL.createObjectURL(stream);
localStream = stream;
pcClient.addStream(localStream);
renegotiateClient();
}
function didntGetStream(err) {
returnToTest('Unexpectedly failed to acquire user media: ' + err);
}
function openCamera(width, height) {
if (localStream) {
pcClient.removeStream(localStream);
localStream.getVideoTracks()[0].stop();
localStream = null;
}
navigator.webkitGetUserMedia({
audio: false,
video: {'mandatory': {'minWidth': width, 'maxWidth': width,
'minHeight': height, 'maxHeight': height}}
}, gotStream, didntGetStream);
}
function renegotiateClient() {
pcClient.setLocalDescription(makeClientOffer(), function() {
pcClient.setRemoteDescription(serverAnswer);
});
}
function setServerRemoteDescription() {
trace('Setting remote Offer to:\n' + PC_SERVER_REMOTE_OFFER);
pcServer.setRemoteDescription(new RTCSessionDescription({
'type': 'offer',
'sdp': PC_SERVER_REMOTE_OFFER
}), afterSetServerRemoteDescription);
}
function afterSetServerRemoteDescription() {
pcServer.createAnswer(onServerAnswer, function(error) {});
}
function onServerAnswer(desc) {
desc.sdp += 'a=x-google-flag:conference\n';
serverAnswer = desc;
trace('Setting both Answers to:\n' + desc.sdp);
pcServer.setLocalDescription(desc);
pcClient.setRemoteDescription(desc);
}
function onServerGotStream(e) {
trace('Received remote stream: ' + e.stream.id +
'; looking up corresponding video tag.');
var remoteVideo = $(e.stream.id);
if (!remoteVideo) {
// All streams we receive must have a corresponding video tag defined in the
// html, otherwise we can't detect video in it.
throw 'Received video with unexpected id ' + e.stream.id;
}
remoteVideo.src = webkitURL.createObjectURL(e.stream);
}
function onClientIceCandidate(event) {
if (event.candidate) {
pcServer.addIceCandidate(event.candidate);
trace('Local ICE candidate:\n' + event.candidate.candidate);
}
}
function onServerIceCandidate(event) {
if (event.candidate) {
pcClient.addIceCandidate(event.candidate);
trace('Remote ICE candidate:\n' + event.candidate.candidate);
}
}
function returnToTest(message) {
if (!window.domAutomationController)
throw 'Expected to run in an automated context.';
window.domAutomationController.send(message);
}
$ = function(id) {
return document.getElementById(id);
};
</script>
</body>