| <html> |
| <head> |
| <script type="text/javascript" src="webrtc_test_utilities.js"></script> |
| <script type="text/javascript"> |
| $ = function(id) { |
| return document.getElementById(id); |
| }; |
| |
| var gLocalStream = null; |
| |
| setAllEventsOccuredHandler(function() { |
| gLocalStream.stop(); |
| reportTestSuccess(); |
| }); |
| |
| function getSources() { |
| MediaStreamTrack.getSources(function(devices) { |
| document.title = 'Media devices available'; |
| sendValueToTest(JSON.stringify(devices)); |
| }); |
| } |
| |
| // Creates a MediaStream and renders it locally. When the video is detected to |
| // be rolling, the stream should be stopped. |
| function getUserMediaAndStop(constraints) { |
| console.log('Calling getUserMediaAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { displayAndDetectVideo(stream, stopVideoTrack); }, |
| failedCallback); |
| } |
| |
| // Requests getusermedia and expects it to fail. The error name is returned |
| // to the test. |
| function getUserMediaAndExpectFailure(constraints) { |
| console.log('Calling getUserMediaAndExpectFailure.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { failTest('Unexpectedly succeeded getUserMedia.'); }, |
| function(error) { sendValueToTest(error.name); }); |
| } |
| |
| function renderClonedMediastreamAndStop(constraints, waitTimeInSeconds) { |
| console.log('Calling renderClonedMediastreamAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| var s = stream.clone(); |
| assertEquals(stream.getVideoTracks().length, 1); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertNotEquals(stream.getVideoTracks()[0].id, |
| s.getVideoTracks()[0].id); |
| displayAndDetectVideo( |
| s, |
| function() { |
| reportTestSuccess(); |
| }); |
| }, |
| failedCallback); |
| } |
| |
| function renderDuplicatedMediastreamAndStop(constraints, waitTimeInSeconds) { |
| console.log('Calling renderDuplicateMediastreamAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| s = new webkitMediaStream(stream); |
| assertEquals(stream.getVideoTracks().length, 1); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertEquals(stream.getVideoTracks()[0].id, |
| s.getVideoTracks()[0].id); |
| displayAndDetectVideo( |
| s, |
| function() { |
| reportTestSuccess(); |
| }); |
| }, |
| failedCallback); |
| } |
| |
| function renderSameTrackMediastreamAndStop(constraints, waitTimeInSeconds) { |
| console.log('Calling renderSameTrackMediastreamAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| s = new webkitMediaStream(); |
| s.addTrack(stream.getVideoTracks()[0]); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertEquals(stream.getVideoTracks()[0].id, s.getVideoTracks()[0].id); |
| displayAndDetectVideo( |
| s, |
| function() { |
| reportTestSuccess(); |
| }); |
| }, |
| failedCallback); |
| } |
| |
| function renderClonedTrackMediastreamAndStop(constraints, waitTimeInSeconds) { |
| console.log('Calling renderClonedTrackMediastreamAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| s = new webkitMediaStream(); |
| s.addTrack(stream.getVideoTracks()[0].clone()); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertEquals(s.getVideoTracks().length, 1); |
| assertNotEquals(stream.getVideoTracks()[0].id, |
| s.getVideoTracks()[0].id) |
| displayAndDetectVideo( |
| s, |
| function() { |
| reportTestSuccess(); |
| }); |
| }, |
| failedCallback); |
| } |
| |
| // Creates a MediaStream and renders it locally. When the video is detected to |
| // be rolling we return ok-stream-running through the automation controller. |
| function getUserMediaAndGetStreamUp(constraints, waitTimeInSeconds) { |
| console.log('Calling getUserMediaAndGetStreamUp.'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| displayAndDetectVideo( |
| stream, |
| function() { |
| reportTestSuccess(); |
| }); |
| }, |
| failedCallback); |
| } |
| |
| function getUserMediaAndRenderInSeveralVideoTags() { |
| navigator.webkitGetUserMedia( |
| {video: true}, |
| createMultipleVideoRenderersAndPause, |
| function(error) { failedCallback(); }); |
| } |
| |
| // Gets a video stream up, analyses it and returns the aspect ratio to the |
| // test through the automation controller. |
| function getUserMediaAndAnalyseAndStop(constraints) { |
| console.log('Calling getUserMediaAndAnalyseAndStop.'); |
| navigator.webkitGetUserMedia( |
| constraints, displayDetectAndAnalyzeVideo, failedCallback); |
| } |
| |
| // This test that a MediaStream can be cloned and that the clone can |
| // be rendered. |
| function getUserMediaAndClone() { |
| console.log('Calling getUserMediaAndClone.'); |
| navigator.webkitGetUserMedia({video: true, audio: true}, |
| createAndRenderClone, failedCallback); |
| } |
| |
| // Creates two MediaStream and renders them locally. When the video of both |
| // streams are detected to be rolling, we stop the local video tracks one at |
| // the time. |
| function twoGetUserMediaAndStop(constraints) { |
| console.log('Calling Two GetUserMedia'); |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| displayAndDetectVideo(stream, requestSecondGetUserMedia); |
| }, |
| failedCallback); |
| var requestSecondGetUserMedia = function() { |
| navigator.webkitGetUserMedia( |
| constraints, |
| function(stream) { |
| displayIntoVideoElement(stream, |
| function() { |
| stopBothVideoTracksAndVerify(stream); |
| }, |
| 'local-view-2'); |
| }, |
| failedCallback); |
| }; |
| |
| var stopBothVideoTracksAndVerify = function(streamPlayingInLocalView2) { |
| streamPlayingInLocalView2.getVideoTracks()[0].stop(); |
| waitForVideoToStop('local-view-2'); |
| // Make sure the video track in gLocalStream is still playing in |
| // 'local-view1' and then stop it. |
| displayAndDetectVideo(gLocalStream, stopVideoTrack); |
| }; |
| } |
| |
| function twoGetUserMedia(constraints1, |
| constraints2) { |
| var result=""; |
| navigator.webkitGetUserMedia( |
| constraints1, |
| function(stream) { |
| displayDetectAndAnalyzeVideoInElement( |
| stream, |
| function(aspectRatio) { |
| result = aspectRatio; |
| requestSecondGetUserMedia(); |
| }, |
| 'local-view'); |
| }, |
| failedCallback); |
| var requestSecondGetUserMedia = function() { |
| navigator.webkitGetUserMedia( |
| constraints2, |
| function(stream) { |
| displayDetectAndAnalyzeVideoInElement( |
| stream, |
| function(aspectRatio) { |
| result = result + '-' + aspectRatio; |
| sendValueToTest(result); |
| }, |
| 'local-view-2'); |
| }, |
| failedCallback); |
| } |
| } |
| |
| // Calls GetUserMedia twice and verify that the frame rate is as expected for |
| // both streams. |
| function twoGetUserMediaAndVerifyFrameRate(constraints1, |
| constraints2, |
| expected_frame_rate1, |
| expected_frame_rate2) { |
| addExpectedEvent(); |
| addExpectedEvent(); |
| var validateFrameRateCallback = function (success) { |
| if (!success) |
| failTest("Failed to validate frameRate."); |
| eventOccured(); |
| }; |
| |
| navigator.webkitGetUserMedia( |
| constraints1, |
| function(stream) { |
| requestSecondGetUserMedia(); |
| plugStreamIntoVideoElement(stream, 'local-view'); |
| detectVideoPlaying('local-view', |
| function() { |
| validateFrameRate('local-view', expected_frame_rate1, |
| validateFrameRateCallback); |
| }); |
| }, |
| failedCallback); |
| var requestSecondGetUserMedia = function() { |
| navigator.webkitGetUserMedia( |
| constraints2, |
| function(stream) { |
| plugStreamIntoVideoElement(stream, 'local-view-2'); |
| detectVideoPlaying('local-view-2', |
| function() { |
| validateFrameRate('local-view-2', expected_frame_rate2, |
| validateFrameRateCallback); |
| }); |
| }, |
| failedCallback); |
| } |
| } |
| |
| function failedCallback(error) { |
| failTest('GetUserMedia call failed with code ' + error.code); |
| } |
| |
| function plugStreamIntoVideoElement(stream, videoElement) { |
| gLocalStream = stream; |
| var localStreamUrl = URL.createObjectURL(stream); |
| $(videoElement).src = localStreamUrl; |
| } |
| |
| function displayIntoVideoElement(stream, callback, videoElement) { |
| plugStreamIntoVideoElement(stream, videoElement); |
| detectVideoPlaying(videoElement, callback); |
| } |
| |
| function displayAndDetectVideo(stream, callback) { |
| displayIntoVideoElement(stream, callback, 'local-view'); |
| } |
| |
| function displayDetectAndAnalyzeVideo(stream) { |
| displayDetectAndAnalyzeVideoInElement(stream, |
| function(aspectRatio) { |
| sendValueToTest(aspectRatio); |
| }, |
| 'local-view'); |
| } |
| |
| function displayDetectAndAnalyzeVideoInElement( |
| stream, callback, videoElement) { |
| plugStreamIntoVideoElement(stream, videoElement); |
| detectAspectRatio(callback, videoElement); |
| } |
| |
| function createAndRenderClone(stream) { |
| gLocalStream = stream; |
| // TODO(perkj): --use-fake-device-for-media-stream do not currently |
| // work with audio devices and not all bots has a microphone. |
| new_stream = new webkitMediaStream(); |
| new_stream.addTrack(stream.getVideoTracks()[0]); |
| assertEquals(new_stream.getVideoTracks().length, 1); |
| if (stream.getAudioTracks().length > 0) { |
| new_stream.addTrack(stream.getAudioTracks()[0]); |
| assertEquals(new_stream.getAudioTracks().length, 1); |
| new_stream.removeTrack(new_stream.getAudioTracks()[0]); |
| assertEquals(new_stream.getAudioTracks().length, 0); |
| } |
| |
| var newStreamUrl = URL.createObjectURL(new_stream); |
| $('local-view').src = newStreamUrl; |
| waitForVideo('local-view'); |
| } |
| |
| function stopVideoTrack() { |
| gLocalStream.getVideoTracks()[0].stop(); |
| waitForVideoToStop('local-view'); |
| } |
| |
| function waitAndStopVideoTrack(waitTimeInSeconds) { |
| setTimeout(stopVideoTrack, waitTimeInSeconds * 1000); |
| } |
| |
| // This test make sure multiple video renderers can be created for the same |
| // local video track and make sure a renderer can still render if other |
| // renderers are paused. See http://crbug/352619. |
| function createMultipleVideoRenderersAndPause(stream) { |
| function createDetectableRenderer(stream, id) { |
| var video = document.createElement('video'); |
| document.body.appendChild(video); |
| var localStreamUrl = URL.createObjectURL(stream); |
| video.id = id; |
| video.src = localStreamUrl; |
| video.autoplay = true; |
| video.play(); |
| // The detector needs a canvas. |
| var canvas = document.createElement('canvas'); |
| canvas.id = video.id + "-canvas"; |
| document.body.appendChild(canvas); |
| }; |
| |
| // Once 3 renderers are created and paused, create one last renderer and |
| // make sure it can play video. |
| setAllEventsOccuredHandler(function() { |
| var id = "lastVideoTag"; |
| createDetectableRenderer(stream, id); |
| detectVideoPlaying(id, function () { reportTestSuccess(); }); |
| }); |
| |
| // Create 3 video renderers and pause them once video is playing. |
| for (var i = 0; i < 3; ++i) { |
| var id = "video" + i; |
| createDetectableRenderer(stream, id); |
| addExpectedEvent(); |
| // |video_detected_function| creates a new function that pause the video |
| // tag |id|. |
| var video_detected_function = |
| function (j) { |
| return function () { |
| console.log("pause " + j); |
| $(j).pause(); |
| eventOccured(); |
| }; |
| }; |
| // Detect video id |id| and trigger the function returned by |
| // |video_detected_function| when video is playing. |
| detectVideoPlaying(id, video_detected_function(id)); |
| } |
| } |
| |
| // This function tries to calculate the aspect ratio shown by the fake capture |
| // device in the video tag. For this, we count the amount of light green |
| // pixels along |aperture| pixels on the positive X and Y axis starting from |
| // the center of the image. In this very center there should be a time-varying |
| // pacman; the algorithm counts for a couple of iterations and keeps the |
| // maximum amount of light green pixels on both directions. From this data |
| // the aspect ratio is calculated and the test fails if the number of green |
| // pixels are not the same along the X and Y axis. |
| // The result of the analysis is sent back to the test as a string on the |
| // format "w=xxx:h=yyy". |
| function detectAspectRatio(callback, videoElementName) { |
| var videoElement = $(videoElementName); |
| var canvas = $(videoElementName + '-canvas'); |
| |
| var maxLightGreenPixelsX = 0; |
| var maxLightGreenPixelsY = 0; |
| |
| var iterations = 0; |
| var maxIterations = 10; |
| |
| var detectorFunction = function() { |
| var width = videoElement.videoWidth; |
| var height = videoElement.videoHeight; |
| if (width == 0 || height == 0) |
| return; |
| |
| canvas.width = width; |
| canvas.height = height; |
| var aperture = Math.min(width, height) / 2; |
| var context = canvas.getContext('2d'); |
| context.drawImage(videoElement, 0, 0, width, height); |
| |
| // We are interested in a window starting from the center of the image |
| // where we expect the circle from the fake video capture to be rolling. |
| var pixels = context.getImageData(width / 2, height / 2, |
| aperture, aperture); |
| |
| var lightGreenPixelsX = 0; |
| var lightGreenPixelsY = 0; |
| |
| // Walk horizontally counting light green pixels. |
| for (var x = 0; x < aperture; ++x) { |
| if (pixels.data[4 * x + 1] != COLOR_BACKGROUND_GREEN) |
| lightGreenPixelsX++; |
| } |
| // Walk vertically counting light green pixels. |
| for (var y = 0; y < aperture; ++y) { |
| if (pixels.data[4 * y * aperture + 1] != COLOR_BACKGROUND_GREEN) |
| lightGreenPixelsY++; |
| } |
| if (lightGreenPixelsX > maxLightGreenPixelsX) |
| maxLightGreenPixelsX = lightGreenPixelsX; |
| if (lightGreenPixelsY > maxLightGreenPixelsY) |
| maxLightGreenPixelsY = lightGreenPixelsY; |
| |
| if (++iterations > maxIterations) { |
| clearInterval(detectorInterval); |
| // Allow maxLightGreenPixelsY = maxLightGreenPixelsX +-1 due to |
| // possible subpixel rendering on Mac and Android. |
| if (maxLightGreenPixelsY > maxLightGreenPixelsX + 1 || |
| maxLightGreenPixelsY < maxLightGreenPixelsX -1 || |
| maxLightGreenPixelsY == 0 || |
| maxLightGreenPixelsX == width / 2 || |
| maxLightGreenPixelsY == height / 2) { |
| failTest("Aspect ratio corrupted. X " + maxLightGreenPixelsX + |
| " Y " + maxLightGreenPixelsY); |
| } |
| |
| var result = "w=" + width + ":h=" + height; |
| console.log(result); |
| callback(result); |
| } |
| } |
| var detectorInterval = setInterval(detectorFunction, 50); |
| } |
| </script> |
| </head> |
| <body> |
| <table border="0"> |
| <tr> |
| <td>Local Preview</td> |
| </tr> |
| <tr> |
| <td><video width="320" height="240" id="local-view" |
| autoplay="autoplay"></video></td> |
| <td><canvas id="local-view-canvas" |
| style="display:none"></canvas></td> |
| </tr> |
| <tr> |
| <td>Local Preview 2</td> |
| </tr> |
| <tr> |
| <td><video width="320" height="240" id="local-view-2" |
| autoplay="autoplay"></video></td> |
| <!-- Canvases are named after their corresponding video elements. --> |
| <td><canvas width="320" height="240" id="local-view-2-canvas" |
| style="display:none"></canvas></td> |
| </tr> |
| </table> |
| </body> |
| </html> |