5 <title>WebRTC Simulcast Test
</title>
8 border:
5px solid black;
11 font:
18px sans-serif;
17 <video id=
"localVideo" autoplay
></video>
18 <!-- These video tags and canvases should match the stream labels returned by
19 PC_SERVER_REMOTE_OFFER. The canvases are there for video detection. --!>
20 <video id="remoteVideo1" autoplay></video>
21 <video id="remoteVideo2" autoplay></video>
22 <video id="remoteVideo3" autoplay></video>
23 <canvas id="remoteVideo1-canvas" autoplay style="display:none"></video>
24 <canvas id="remoteVideo2-canvas" autoplay style="display:none"></video>
25 <canvas id="remoteVideo3-canvas" autoplay style="display:none"></video>
27 <script type="text/javascript" src="webrtc_test_utilities.js"></script>
28 <script type="text/javascript">
30 var pcClient, pcServer;
32 var remoteVideoUrls = [];
35 // When all required video tags are playing video, succeed the test.
36 setAllEventsOccuredHandler(function() {
40 // Checks that we can get a simulcast stream call up on VGA.
41 function testVgaReturnsTwoSimulcastStreams() {
45 // For VGA we should get a QVGA and VGA stream. The video tags are named after
46 // the stream IDs which are defined in PC_SERVER_REMOTE_OFFER.
47 waitForVideo('remoteVideo1');
48 waitForVideo('remoteVideo2');
51 // Template for the local offer, representing a single input stream backing
52 // 3 different SSRCs, all in one SIM ssrc-group.
53 function makeClientOffer() {
56 'o=- 0 3 IN IP4 127.0.0.1',
59 'm=video 1 RTP/SAVPF 100',
60 'a=rtcp:1 IN IP4 0.0.0.0',
61 'a=ice-ufrag:6HHHdzzeIhkE0CKj',
62 'a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew',
65 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 ' +
66 'inline:Rlz8z1nMtwq9VF7j06kTc7uyio1iYuEdeZ7z1P9E',
67 'a=rtpmap:100 VP8/30',
68 'a=fmtp:100 x-google-start-bitrate=100000',
69 'a=fmtp:100 x-google-min-bitrate=80000',
70 'a=x-google-flag:conference'
74 var videoTracks = localStream.getVideoTracks();
75 if (videoTracks.length > 0) {
76 trace('Using Video device: ' + videoTracks[0].id);
78 trace('WARNING: No video device!');
79 return lines.join('\n');
82 lines = lines.concat([
83 'a=ssrc-group:SIM 1 2 3',
84 'a=ssrc:1 cname:localVideo',
85 'a=ssrc:1 msid:' + localStream.id + ' ' + videoTracks[0].id,
86 'a=ssrc:2 cname:localVideo',
87 'a=ssrc:2 msid:' + localStream.id + ' ' + videoTracks[0].id,
88 'a=ssrc:3 cname:localVideo',
89 'a=ssrc:3 msid:' + localStream.id + ' ' + videoTracks[0].id
94 return new RTCSessionDescription({
96 'sdp': lines.join('\n')
100 // Remote perspective on that offer, representing each SSRC as a distinct
101 // (non-synchronized) output video stream.
102 var PC_SERVER_REMOTE_OFFER = [
104 'o=- 0 3 IN IP4 127.0.0.1',
107 'm=video 1 RTP/SAVPF 100',
110 'a=rtcp:1 IN IP4 0.0.0.0',
111 'a=ice-ufrag:6HHHdzzeIhkE0CKj',
112 'a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew',
113 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 ' +
114 'inline:Rlz8z1nMtwq9VF7j06kTc7uyio1iYuEdeZ7z1P9E',
115 'a=rtpmap:100 VP8/30',
116 'a=x-google-flag:conference',
117 'a=fmtp:100 x-google-start-bitrate=100000',
118 'a=fmtp:100 x-google-min-bitrate=80000',
119 'a=ssrc:1 cname:remoteVideo1',
120 'a=ssrc:1 msid:remoteVideo1 remoteVideo1v0',
121 'a=ssrc:2 cname:remoteVideo2',
122 'a=ssrc:2 msid:remoteVideo2 remoteVideo2v0',
123 'a=ssrc:3 cname:remoteVideo3',
124 'a=ssrc:3 msid:remoteVideo3 remoteVideo3v0',
128 function trace(text) {
129 // This function is used for logging.
130 if (text[text.length - 1] == '\n') {
131 text = text.substring(0, text.length - 1);
133 console.log((performance.now() / 1000).toFixed(3) + ': ' + text);
136 function initialize() {
137 trace('Setting up for a new call.');
139 var constraints = {'mandatory': {'DtlsSrtpKeyAgreement': false}};
140 pcClient = new webkitRTCPeerConnection(servers, constraints);
141 trace('Created local peer connection object pcClient');
142 pcClient.onicecandidate = onClientIceCandidate;
143 pcServer = new webkitRTCPeerConnection(servers, constraints);
144 trace('Created remote peer connection object pcServer');
145 pcServer.onicecandidate = onServerIceCandidate;
146 pcServer.onaddstream = onServerGotStream;
148 var pcClientInitialOffer = makeClientOffer();
149 trace('Setting initial local Offer to:\n' + pcClientInitialOffer);
150 pcClient.setLocalDescription(pcClientInitialOffer,
151 setServerRemoteDescription);
154 function gotStream(stream) {
155 trace('Received local stream');
156 localVideo.src = webkitURL.createObjectURL(stream);
157 localStream = stream;
158 pcClient.addStream(localStream);
162 function didntGetStream(err) {
163 returnToTest('Unexpectedly failed to acquire user media: ' + err);
166 function openCamera(width, height) {
168 pcClient.removeStream(localStream);
169 localStream.getVideoTracks().stop();
172 navigator.webkitGetUserMedia({
174 video: {'mandatory': {'minWidth': width, 'maxWidth': width,
175 'minHeight': height, 'maxHeight': height}}
176 }, gotStream, didntGetStream);
179 function renegotiateClient() {
180 pcClient.setLocalDescription(makeClientOffer(), function() {
181 pcClient.setRemoteDescription(serverAnswer);
185 function setServerRemoteDescription() {
186 trace('Setting remote Offer to:\n' + PC_SERVER_REMOTE_OFFER);
187 pcServer.setRemoteDescription(new RTCSessionDescription({
189 'sdp': PC_SERVER_REMOTE_OFFER
190 }), afterSetServerRemoteDescription);
193 function afterSetServerRemoteDescription() {
194 pcServer.createAnswer(onServerAnswer);
197 function onServerAnswer(desc) {
198 desc.sdp += 'a=x-google-flag:conference\n';
200 trace('Setting both Answers to:\n' + desc.sdp);
201 pcServer.setLocalDescription(desc);
202 pcClient.setRemoteDescription(desc);
205 function onServerGotStream(e) {
206 trace('Received remote stream: ' + e.stream.label +
207 '; looking up corresponding video tag.');
209 var remoteVideo = $(e.stream.label);
211 // All streams we receive must have a corresponding video tag defined in the
212 // html, otherwise we can't detect video in it.
213 throw 'Received video with unexpected id ' + e.stream.label;
215 remoteVideo.src = webkitURL.createObjectURL(e.stream);
218 function onClientIceCandidate(event) {
219 if (event.candidate) {
220 pcServer.addIceCandidate(event.candidate);
221 trace('Local ICE candidate:\n' + event.candidate.candidate);
225 function onServerIceCandidate(event) {
226 if (event.candidate) {
227 pcClient.addIceCandidate(event.candidate);
228 trace('Remote ICE candidate:\n' + event.candidate.candidate);
232 function returnToTest(message) {
233 if (!window.domAutomationController)
234 throw 'Expected to run in an automated context.';
235 window.domAutomationController.send(message);
239 return document.getElementById(id);