3 <script type=
"text/javascript" src=
"webrtc_test_utilities.js"></script>
4 <script type=
"text/javascript">
6 return document
.getElementById(id
);
9 setAllEventsOccuredHandler(function() {
13 function getSources() {
14 MediaStreamTrack
.getSources(function(devices
) {
15 document
.title
= 'Media devices available';
17 for (var device
, i
= 0; device
= devices
[i
]; ++i
) {
21 'label': device
.label
,
22 'facing': device
.facing
25 sendValueToTest(JSON
.stringify(results
));
29 // Creates a MediaStream and renders it locally. When the video is detected to
30 // be rolling, the stream should be stopped.
31 function getUserMediaAndStop(constraints
) {
32 console
.log('Calling getUserMediaAndStop.');
33 navigator
.webkitGetUserMedia(
36 detectVideoInLocalView1(stream
, function() {
37 stream
.getVideoTracks()[0].stop();
38 waitForVideoToStop('local-view-1');
44 // Requests getusermedia and expects it to fail. The error name is returned
46 function getUserMediaAndExpectFailure(constraints
) {
47 console
.log('Calling getUserMediaAndExpectFailure.');
48 navigator
.webkitGetUserMedia(
50 function(stream
) { failTest('Unexpectedly succeeded getUserMedia.'); },
51 function(error
) { sendValueToTest(error
.name
); });
54 function renderClonedMediastreamAndStop(constraints
, waitTimeInSeconds
) {
55 console
.log('Calling renderClonedMediastreamAndStop.');
56 navigator
.webkitGetUserMedia(
59 var duplicate
= stream
.clone();
60 assertEquals(stream
.getVideoTracks().length
, 1);
61 assertEquals(duplicate
.getVideoTracks().length
, 1);
62 assertNotEquals(stream
.getVideoTracks()[0].id
,
63 duplicate
.getVideoTracks()[0].id
);
64 detectVideoInLocalView1(
73 function renderDuplicatedMediastreamAndStop(constraints
, waitTimeInSeconds
) {
74 console
.log('Calling renderDuplicateMediastreamAndStop.');
75 navigator
.webkitGetUserMedia(
78 var duplicate
= new webkitMediaStream(stream
);
79 assertEquals(stream
.getVideoTracks().length
, 1);
80 assertEquals(duplicate
.getVideoTracks().length
, 1);
81 assertEquals(stream
.getVideoTracks()[0].id
,
82 duplicate
.getVideoTracks()[0].id
);
83 detectVideoInLocalView1(
92 function renderSameTrackMediastreamAndStop(constraints
, waitTimeInSeconds
) {
93 console
.log('Calling renderSameTrackMediastreamAndStop.');
94 navigator
.webkitGetUserMedia(
97 var duplicate
= new webkitMediaStream();
98 duplicate
.addTrack(stream
.getVideoTracks()[0]);
99 assertEquals(duplicate
.getVideoTracks().length
, 1);
100 assertEquals(duplicate
.getVideoTracks().length
, 1);
101 assertEquals(stream
.getVideoTracks()[0].id
,
102 duplicate
.getVideoTracks()[0].id
);
103 detectVideoInLocalView1(
112 function renderClonedTrackMediastreamAndStop(constraints
, waitTimeInSeconds
) {
113 console
.log('Calling renderClonedTrackMediastreamAndStop.');
114 navigator
.webkitGetUserMedia(
117 var duplicate
= new webkitMediaStream();
118 duplicate
.addTrack(stream
.getVideoTracks()[0].clone());
119 assertEquals(duplicate
.getVideoTracks().length
, 1);
120 assertEquals(duplicate
.getVideoTracks().length
, 1);
121 assertNotEquals(stream
.getVideoTracks()[0].id
,
122 duplicate
.getVideoTracks()[0].id
)
123 detectVideoInLocalView1(
132 // Creates a MediaStream and renders it locally. When the video is detected to
133 // be rolling we report success. The acquired stream is stored in window
134 // under the name |streamName|.
135 function getUserMediaAndGetStreamUp(constraints
, streamName
) {
136 console
.log('Calling getUserMediaAndGetStreamUp.');
137 navigator
.webkitGetUserMedia(
140 window
[streamName
] = stream
;
141 detectVideoInLocalView1(
150 function getUserMediaAndRenderInSeveralVideoTags() {
151 navigator
.webkitGetUserMedia(
153 createMultipleVideoRenderersAndPause
,
154 function(error
) { failedCallback(); });
157 // Gets a video stream up, analyses it and returns the aspect ratio to the
158 // test through the automation controller.
159 function getUserMediaAndAnalyseAndStop(constraints
) {
160 console
.log('Calling getUserMediaAndAnalyseAndStop.');
161 navigator
.webkitGetUserMedia(
162 constraints
, displayDetectAndAnalyzeVideo
, failedCallback
);
165 // This test that a MediaStream can be cloned and that the clone can
167 function getUserMediaAndClone() {
168 console
.log('Calling getUserMediaAndClone.');
169 navigator
.webkitGetUserMedia({video
: true, audio
: true},
170 createAndRenderClone
, failedCallback
);
173 // Creates two MediaStream and renders them locally. When the video of both
174 // streams are detected to be rolling, we stop the local video tracks one at
175 // the time. In particular, we verify that stopping one track does not stop
177 function twoGetUserMediaAndStop(constraints
) {
180 navigator
.webkitGetUserMedia(
184 attachMediaStream(stream
, 'local-view-1');
185 requestSecondGetUserMedia();
188 var requestSecondGetUserMedia = function() {
189 navigator
.webkitGetUserMedia(
193 attachMediaStream(stream
, 'local-view-2');
194 stopBothVideoTracksAndVerify();
199 var stopBothVideoTracksAndVerify = function() {
200 // Stop track 2, ensure track 2 stops but not track 1, then stop track 1.
201 stream2
.getVideoTracks()[0].stop();
202 detectVideoStopped('local-view-2', function() {
203 detectVideoInLocalView1(stream1
, function() {
204 stream1
.getVideoTracks()[0].stop();
205 waitForVideoToStop('local-view-1');
211 function twoGetUserMedia(constraints1
, constraints2
) {
213 navigator
.webkitGetUserMedia(
216 displayDetectAndAnalyzeVideoInElement(
218 function(aspectRatio
) {
219 result
= aspectRatio
;
220 requestSecondGetUserMedia();
225 var requestSecondGetUserMedia = function() {
226 navigator
.webkitGetUserMedia(
229 displayDetectAndAnalyzeVideoInElement(
231 function(aspectRatio
) {
232 result
= result
+ '-' + aspectRatio
;
233 sendValueToTest(result
);
241 // Calls GetUserMedia twice and verify that the frame rate is as expected for
243 function twoGetUserMediaAndVerifyFrameRate(constraints1
,
245 expected_frame_rate1
,
246 expected_frame_rate2
) {
249 var validateFrameRateCallback = function (success
) {
251 failTest("Failed to validate frameRate.");
255 navigator
.webkitGetUserMedia(
258 requestSecondGetUserMedia();
259 attachMediaStream(stream
, 'local-view-1');
263 validateFrameRate('local-view-1', expected_frame_rate1
,
264 validateFrameRateCallback
);
268 var requestSecondGetUserMedia = function() {
269 navigator
.webkitGetUserMedia(
272 attachMediaStream(stream
, 'local-view-2');
276 validateFrameRate('local-view-2', expected_frame_rate2
,
277 validateFrameRateCallback
);
284 function getUserMediaInIframeAndCloseInSuccessCb(constraints
) {
285 var iframe
= document
.createElement('iframe');
286 iframe
.onload
= onIframeLoaded
;
287 document
.body
.appendChild(iframe
);
288 iframe
.src
= window
.location
;
290 function onIframeLoaded() {
291 var iframe
= window
.document
.querySelector('iframe');
292 iframe
.contentWindow
.navigator
.webkitGetUserMedia(
295 // Remove the iframe from the parent within the callback scope.
296 window
.parent
.document
.querySelector('iframe').remove();
297 // This function enqueues reporting test success, rather than doing
298 // it directly. We do this so we catch crashes that occur in the
299 // current execution context, but after reportTestSuccess is
301 setTimeout(function () {
302 window
.parent
.reportTestSuccess();
305 window
.parent
.failedCallback
);
309 function getUserMediaInIframeAndCloseInFailureCb(constraints
) {
310 var iframe
= document
.createElement('iframe');
311 iframe
.onload
= onIframeLoaded
;
312 document
.body
.appendChild(iframe
);
313 iframe
.src
= window
.location
;
315 function onIframeLoaded() {
316 var iframe
= window
.document
.querySelector('iframe');
317 iframe
.contentWindow
.navigator
.webkitGetUserMedia(
320 window
.parent
.failTest('GetUserMedia call succeeded unexpectedly.');
323 // Remove the iframe from the parent within the callback scope.
324 window
.parent
.document
.querySelector('iframe').remove();
325 // This function enqueues reporting test success, rather than doing
326 // it directly. We do this so we catch crashes that occur in the
327 // current execution context, but after reportTestSuccess is
329 setTimeout(function () {
330 window
.parent
.reportTestSuccess();
336 function failedCallback(error
) {
337 failTest('GetUserMedia call failed with code ' + error
.code
);
340 function attachMediaStream(stream
, videoElement
) {
341 var localStreamUrl
= URL
.createObjectURL(stream
);
342 $(videoElement
).src
= localStreamUrl
;
345 function detectVideoInLocalView1(stream
, callback
) {
346 attachMediaStream(stream
, 'local-view-1');
347 detectVideoPlaying('local-view-1', callback
);
350 function displayDetectAndAnalyzeVideo(stream
) {
351 displayDetectAndAnalyzeVideoInElement(stream
,
352 function(aspectRatio
) {
353 sendValueToTest(aspectRatio
);
358 function displayDetectAndAnalyzeVideoInElement(
359 stream
, callback
, videoElementName
) {
360 attachMediaStream(stream
, videoElementName
);
361 var videoElement
= $(videoElementName
);
362 var playbackTimeout
= setTimeout(function() {
363 failTest("VideoElement playback not working.");
365 videoElement
.onloadedmetadata = function () {
366 clearTimeout(playbackTimeout
);
367 detectAspectRatio(callback
, videoElement
);
371 function createAndRenderClone(stream
) {
372 // TODO(perkj): --use-fake-device-for-media-stream do not currently
373 // work with audio devices and not all bots has a microphone.
374 newStream
= new webkitMediaStream();
375 newStream
.addTrack(stream
.getVideoTracks()[0]);
376 assertEquals(newStream
.getVideoTracks().length
, 1);
377 if (stream
.getAudioTracks().length
> 0) {
378 newStream
.addTrack(stream
.getAudioTracks()[0]);
379 assertEquals(newStream
.getAudioTracks().length
, 1);
380 newStream
.removeTrack(newStream
.getAudioTracks()[0]);
381 assertEquals(newStream
.getAudioTracks().length
, 0);
384 detectVideoInLocalView1(newStream
, reportTestSuccess
);
387 // Calls stop on |stream|'s video track after a delay and reports success.
388 function waitAndStopVideoTrack(stream
, waitTimeInSeconds
) {
389 setTimeout(function() {
390 stream
.getVideoTracks()[0].stop();
392 }, waitTimeInSeconds
* 1000);
395 // This test makes sure multiple video renderers can be created for the same
396 // local video track, and makes sure a renderer can still render if other
397 // renderers are paused. See http://crbug/352619.
398 function createMultipleVideoRenderersAndPause(stream
) {
399 function createDetectableRenderer(stream
, id
) {
400 var video
= document
.createElement('video');
401 document
.body
.appendChild(video
);
402 var localStreamUrl
= URL
.createObjectURL(stream
);
404 video
.style
.display
= 'none'
405 video
.src
= localStreamUrl
;
406 video
.autoplay
= true;
409 // The detector needs a canvas.
410 var canvas
= document
.createElement('canvas');
411 canvas
.id
= video
.id
+ "-canvas";
412 canvas
.style
.display
= 'none'
413 document
.body
.appendChild(canvas
);
416 // Once 3 renderers are created and paused, create one last renderer and
417 // make sure it can play video.
418 setAllEventsOccuredHandler(function() {
419 var id
= "lastVideoTag";
420 createDetectableRenderer(stream
, id
);
421 detectVideoPlaying(id
, function () { reportTestSuccess(); });
424 // Create 3 video renderers and pause them once video is playing.
425 for (var i
= 0; i
< 3; ++i
) {
426 var id
= "video" + i
;
427 createDetectableRenderer(stream
, id
);
429 // |video_detected_function| creates a new function that pause the video
431 var video_detected_function
=
434 console
.log("pause " + j
);
439 // Detect video id |id| and trigger the function returned by
440 // |video_detected_function| when video is playing.
441 detectVideoPlaying(id
, video_detected_function(id
));
445 // This function tries to calculate the aspect ratio shown by the fake capture
446 // device in the video tag. For this, we count the amount of light green
447 // pixels along |aperture| pixels on the positive X and Y axis starting from
448 // the center of the image. In this very center there should be a time-varying
449 // pacman; the algorithm counts for a couple of iterations and keeps the
450 // maximum amount of light green pixels on both directions. From this data
451 // the aspect ratio is calculated and the test fails if the number of green
452 // pixels are not the same along the X and Y axis.
453 // The result of the analysis is sent back to the test as a string on the
454 // format "w=xxx:h=yyy".
455 function detectAspectRatio(callback
, videoElement
) {
456 var canvas
= $(videoElement
.id
+ '-canvas');
458 var maxLightGreenPixelsX
= 0;
459 var maxLightGreenPixelsY
= 0;
462 var maxAttempts
= 10;
464 var detectorFunction = function() {
465 var width
= videoElement
.videoWidth
;
466 var height
= videoElement
.videoHeight
;
467 if (width
== 0 || height
== 0)
468 failTest("VideoElement width and height set to 0.");
470 canvas
.width
= width
;
471 canvas
.height
= height
;
472 var aperture
= Math
.min(width
, height
) / 2;
473 var context
= canvas
.getContext('2d');
474 context
.drawImage(videoElement
, 0, 0, width
, height
);
476 // We are interested in a window starting from the center of the image
477 // where we expect the circle from the fake video capture to be rolling.
478 var pixels
= context
.getImageData(width
/ 2, height
/ 2,
481 var lightGreenPixelsX
= 0;
482 var lightGreenPixelsY
= 0;
484 // Walk horizontally counting light green pixels.
485 for (var x
= 0; x
< aperture
; ++x
) {
486 if (pixels
.data
[4 * x
+ 1] != COLOR_BACKGROUND_GREEN
)
489 // Walk vertically counting light green pixels.
490 for (var y
= 0; y
< aperture
; ++y
) {
491 if (pixels
.data
[4 * y
* aperture
+ 1] != COLOR_BACKGROUND_GREEN
)
494 if (lightGreenPixelsX
> maxLightGreenPixelsX
)
495 maxLightGreenPixelsX
= lightGreenPixelsX
;
496 if (lightGreenPixelsY
> maxLightGreenPixelsY
)
497 maxLightGreenPixelsY
= lightGreenPixelsY
;
499 // Allow maxLightGreenPixelsY = maxLightGreenPixelsX +-1 due to
500 // possible subpixel rendering on Mac and Android.
501 if (maxLightGreenPixelsY
> maxLightGreenPixelsX
+ 1 ||
502 maxLightGreenPixelsY
< maxLightGreenPixelsX
-1 ||
503 maxLightGreenPixelsY
== 0 ||
504 maxLightGreenPixelsX
== width
/ 2 ||
505 maxLightGreenPixelsY
== height
/ 2) {
506 if (++attempt
> maxAttempts
) {
507 clearInterval(detectorInterval
);
508 failTest("Aspect ratio corrupted. X " + maxLightGreenPixelsX
+
509 " Y " + maxLightGreenPixelsY
);
512 // We have a bad aspect ratio now; give a chance to shape up.
517 clearInterval(detectorInterval
);
518 var result
= "w=" + width
+ ":h=" + height
;
521 var detectorInterval
= setInterval(detectorFunction
, 50);
527 <!-- Canvases are named after their corresponding video elements. -->
529 <td><video id=
"local-view-1" width=
"320" height=
"240" autoplay
530 style=
"display:none"></video></td>
531 <td><canvas id=
"local-view-1-canvas" width=
"320" height=
"240"
532 style=
"display:none"></canvas></td>
535 <td><video id=
"local-view-2" width=
"320" height=
"240" autoplay
536 style=
"display:none"></video></td>
537 <td><canvas id=
"local-view-2-canvas" width=
"320" height=
"240"
538 style=
"display:none"></canvas></td>