Home | History | Annotate | Download | only in media
      1 <html>
      2 <head>
      3   <script type="text/javascript" src="webrtc_test_utilities.js"></script>
      4   <script type="text/javascript">
      5   $ = function(id) {
      6     return document.getElementById(id);
      7   };
      8 
      9   var gLocalStream = null;
     10 
     11   setAllEventsOccuredHandler(function() {
     12     gLocalStream.stop();
     13     reportTestSuccess();
     14   });
     15 
     16   function getSources() {
     17     MediaStreamTrack.getSources(function(devices) {
     18       document.title = 'Media devices available';
     19       sendValueToTest(JSON.stringify(devices));
     20     });
     21   }
     22 
     23   // Creates a MediaStream and renders it locally. When the video is detected to
     24   // be rolling, the stream should be stopped.
     25   function getUserMediaAndStop(constraints) {
     26     console.log('Calling getUserMediaAndStop.');
     27     navigator.webkitGetUserMedia(
     28         constraints,
     29         function(stream) { displayAndDetectVideo(stream, stopVideoTrack); },
     30         failedCallback);
     31   }
     32 
     33   // Requests getusermedia and expects it to fail. The error name is returned
     34   // to the test.
     35   function getUserMediaAndExpectFailure(constraints) {
     36     console.log('Calling getUserMediaAndExpectFailure.');
     37     navigator.webkitGetUserMedia(
     38         constraints,
     39         function(stream) { failTest('Unexpectedly succeeded getUserMedia.'); },
     40         function(error) { sendValueToTest(error.name); });
     41   }
     42 
     43   function renderClonedMediastreamAndStop(constraints, waitTimeInSeconds) {
     44     console.log('Calling renderClonedMediastreamAndStop.');
     45     navigator.webkitGetUserMedia(
     46         constraints,
     47         function(stream) {
     48           var s = stream.clone();
     49           assertEquals(stream.getVideoTracks().length, 1);
     50           assertEquals(s.getVideoTracks().length, 1);
     51           assertNotEquals(stream.getVideoTracks()[0].id,
     52                           s.getVideoTracks()[0].id);
     53           displayAndDetectVideo(
     54             s,
     55             function() {
     56               reportTestSuccess();
     57             });
     58         },
     59         failedCallback);
     60   }
     61 
     62   function renderDuplicatedMediastreamAndStop(constraints, waitTimeInSeconds) {
     63     console.log('Calling renderDuplicateMediastreamAndStop.');
     64     navigator.webkitGetUserMedia(
     65         constraints,
     66         function(stream) {
     67           s = new webkitMediaStream(stream);
     68           assertEquals(stream.getVideoTracks().length, 1);
     69           assertEquals(s.getVideoTracks().length, 1);
     70           assertEquals(stream.getVideoTracks()[0].id,
     71                        s.getVideoTracks()[0].id);
     72           displayAndDetectVideo(
     73             s,
     74             function() {
     75               reportTestSuccess();
     76             });
     77         },
     78         failedCallback);
     79   }
     80 
     81   function renderSameTrackMediastreamAndStop(constraints, waitTimeInSeconds) {
     82     console.log('Calling renderSameTrackMediastreamAndStop.');
     83     navigator.webkitGetUserMedia(
     84         constraints,
     85         function(stream) {
     86           s = new webkitMediaStream();
     87           s.addTrack(stream.getVideoTracks()[0]);
     88           assertEquals(s.getVideoTracks().length, 1);
     89           assertEquals(s.getVideoTracks().length, 1);
     90           assertEquals(stream.getVideoTracks()[0].id, s.getVideoTracks()[0].id);
     91           displayAndDetectVideo(
     92             s,
     93             function() {
     94               reportTestSuccess();
     95             });
     96         },
     97         failedCallback);
     98   }
     99 
    100   function renderClonedTrackMediastreamAndStop(constraints, waitTimeInSeconds) {
    101     console.log('Calling renderClonedTrackMediastreamAndStop.');
    102     navigator.webkitGetUserMedia(
    103         constraints,
    104         function(stream) {
    105           s = new webkitMediaStream();
    106           s.addTrack(stream.getVideoTracks()[0].clone());
    107           assertEquals(s.getVideoTracks().length, 1);
    108           assertEquals(s.getVideoTracks().length, 1);
    109           assertNotEquals(stream.getVideoTracks()[0].id,
    110                           s.getVideoTracks()[0].id)
    111           displayAndDetectVideo(
    112             s,
    113             function() {
    114               reportTestSuccess();
    115             });
    116         },
    117         failedCallback);
    118   }
    119 
    120   // Creates a MediaStream and renders it locally. When the video is detected to
    121   // be rolling we return ok-stream-running through the automation controller.
    122   function getUserMediaAndGetStreamUp(constraints, waitTimeInSeconds) {
    123     console.log('Calling getUserMediaAndGetStreamUp.');
    124     navigator.webkitGetUserMedia(
    125         constraints,
    126         function(stream) {
    127           displayAndDetectVideo(
    128             stream,
    129             function() {
    130               reportTestSuccess();
    131             });
    132         },
    133         failedCallback);
    134   }
    135 
    136   function getUserMediaAndRenderInSeveralVideoTags() {
    137     navigator.webkitGetUserMedia(
    138         {video: true},
    139         createMultipleVideoRenderersAndPause,
    140         function(error) { failedCallback(); });
    141   }
    142 
    143   // Gets a video stream up, analyses it and returns the aspect ratio to the
    144   // test through the automation controller.
    145   function getUserMediaAndAnalyseAndStop(constraints) {
    146     console.log('Calling getUserMediaAndAnalyseAndStop.');
    147     navigator.webkitGetUserMedia(
    148         constraints, displayDetectAndAnalyzeVideo, failedCallback);
    149   }
    150 
    151   // This test that a MediaStream can be cloned and that the clone can
    152   // be rendered.
    153   function getUserMediaAndClone() {
    154     console.log('Calling getUserMediaAndClone.');
    155     navigator.webkitGetUserMedia({video: true, audio: true},
    156         createAndRenderClone, failedCallback);
    157   }
    158 
    159   // Creates two MediaStream and renders them locally. When the video of both
    160   // streams are detected to be rolling, we stop the local video tracks one at
    161   // the time.
    162   function twoGetUserMediaAndStop(constraints) {
    163     console.log('Calling Two GetUserMedia');
    164     navigator.webkitGetUserMedia(
    165         constraints,
    166         function(stream) {
    167           displayAndDetectVideo(stream, requestSecondGetUserMedia);
    168         },
    169         failedCallback);
    170     var requestSecondGetUserMedia = function() {
    171       navigator.webkitGetUserMedia(
    172           constraints,
    173           function(stream) {
    174             displayIntoVideoElement(stream,
    175                                     function() {
    176                                       stopBothVideoTracksAndVerify(stream);
    177                                     },
    178                                     'local-view-2');
    179           },
    180           failedCallback);
    181     };
    182 
    183     var stopBothVideoTracksAndVerify = function(streamPlayingInLocalView2) {
    184       streamPlayingInLocalView2.getVideoTracks()[0].stop();
    185       waitForVideoToStop('local-view-2');
    186       // Make sure the video track in gLocalStream is still playing in
    187       // 'local-view1' and then stop it.
    188       displayAndDetectVideo(gLocalStream, stopVideoTrack);
    189     };
    190   }
    191 
    192   function twoGetUserMedia(constraints1,
    193                            constraints2) {
    194     var result="";
    195     navigator.webkitGetUserMedia(
    196         constraints1,
    197         function(stream) {
    198           displayDetectAndAnalyzeVideoInElement(
    199               stream,
    200               function(aspectRatio) {
    201                 result = aspectRatio;
    202                 requestSecondGetUserMedia();
    203                },
    204               'local-view');
    205         },
    206         failedCallback);
    207     var requestSecondGetUserMedia = function() {
    208       navigator.webkitGetUserMedia(
    209           constraints2,
    210           function(stream) {
    211             displayDetectAndAnalyzeVideoInElement(
    212                 stream,
    213                 function(aspectRatio) {
    214                   result = result + '-' + aspectRatio;
    215                   sendValueToTest(result);
    216                 },
    217                 'local-view-2');
    218           },
    219           failedCallback);
    220     }
    221   }
    222 
    223   // Calls GetUserMedia twice and verify that the frame rate is as expected for
    224   // both streams.
    225   function twoGetUserMediaAndVerifyFrameRate(constraints1,
    226                                              constraints2,
    227                                              expected_frame_rate1,
    228                                              expected_frame_rate2) {
    229     addExpectedEvent();
    230     addExpectedEvent();
    231     var validateFrameRateCallback = function (success) {
    232       if (!success)
    233         failTest("Failed to validate frameRate.");
    234       eventOccured();
    235     };
    236 
    237     navigator.webkitGetUserMedia(
    238         constraints1,
    239         function(stream) {
    240           requestSecondGetUserMedia();
    241           plugStreamIntoVideoElement(stream, 'local-view');
    242           detectVideoPlaying('local-view',
    243               function() {
    244                 validateFrameRate('local-view', expected_frame_rate1,
    245                     validateFrameRateCallback);
    246               });
    247         },
    248         failedCallback);
    249     var requestSecondGetUserMedia = function() {
    250       navigator.webkitGetUserMedia(
    251           constraints2,
    252           function(stream) {
    253             plugStreamIntoVideoElement(stream, 'local-view-2');
    254             detectVideoPlaying('local-view-2',
    255                 function() {
    256                   validateFrameRate('local-view-2', expected_frame_rate2,
    257                       validateFrameRateCallback);
    258                 });
    259           },
    260           failedCallback);
    261     }
    262   }
    263 
    264   function failedCallback(error) {
    265     failTest('GetUserMedia call failed with code ' + error.code);
    266   }
    267 
    268   function plugStreamIntoVideoElement(stream, videoElement) {
    269     gLocalStream = stream;
    270     var localStreamUrl = URL.createObjectURL(stream);
    271     $(videoElement).src = localStreamUrl;
    272   }
    273 
    274   function displayIntoVideoElement(stream, callback, videoElement) {
    275     plugStreamIntoVideoElement(stream, videoElement);
    276     detectVideoPlaying(videoElement, callback);
    277   }
    278 
    279   function displayAndDetectVideo(stream, callback) {
    280     displayIntoVideoElement(stream, callback, 'local-view');
    281   }
    282 
    283   function displayDetectAndAnalyzeVideo(stream) {
    284     displayDetectAndAnalyzeVideoInElement(stream,
    285         function(aspectRatio) {
    286           sendValueToTest(aspectRatio);
    287         },
    288         'local-view');
    289   }
    290 
    291   function displayDetectAndAnalyzeVideoInElement(
    292       stream, callback, videoElement) {
    293     plugStreamIntoVideoElement(stream, videoElement);
    294     detectAspectRatio(callback, videoElement);
    295   }
    296 
    297   function createAndRenderClone(stream) {
    298     gLocalStream = stream;
    299     // TODO(perkj):  --use-fake-device-for-media-stream do not currently
    300     // work with audio devices and not all bots has a microphone.
    301     new_stream = new webkitMediaStream();
    302     new_stream.addTrack(stream.getVideoTracks()[0]);
    303     assertEquals(new_stream.getVideoTracks().length, 1);
    304     if (stream.getAudioTracks().length > 0) {
    305       new_stream.addTrack(stream.getAudioTracks()[0]);
    306       assertEquals(new_stream.getAudioTracks().length, 1);
    307       new_stream.removeTrack(new_stream.getAudioTracks()[0]);
    308       assertEquals(new_stream.getAudioTracks().length, 0);
    309     }
    310 
    311     var newStreamUrl = URL.createObjectURL(new_stream);
    312     $('local-view').src = newStreamUrl;
    313     waitForVideo('local-view');
    314   }
    315 
    316   function stopVideoTrack() {
    317     gLocalStream.getVideoTracks()[0].stop();
    318     waitForVideoToStop('local-view');
    319   }
    320 
    321   function waitAndStopVideoTrack(waitTimeInSeconds) {
    322     setTimeout(stopVideoTrack, waitTimeInSeconds * 1000);
    323   }
    324 
    325   // This test make sure multiple video renderers can be created for the same
    326   // local video track and make sure a renderer can still render if other
    327   // renderers are paused. See http://crbug/352619.
    328   function createMultipleVideoRenderersAndPause(stream) {
    329     function createDetectableRenderer(stream, id) {
    330       var video = document.createElement('video');
    331       document.body.appendChild(video);
    332       var localStreamUrl = URL.createObjectURL(stream);
    333       video.id = id;
    334       video.src = localStreamUrl;
    335       video.autoplay = true;
    336       video.play();
    337       // The detector needs a canvas.
    338       var canvas = document.createElement('canvas');
    339       canvas.id = video.id + "-canvas";
    340       document.body.appendChild(canvas);
    341     };
    342 
    343     // Once 3 renderers are created and paused, create one last renderer and
    344     // make sure it can play video.
    345     setAllEventsOccuredHandler(function() {
    346       var id = "lastVideoTag";
    347       createDetectableRenderer(stream, id);
    348       detectVideoPlaying(id, function () { reportTestSuccess(); });
    349     });
    350 
    351     // Create 3 video renderers and pause them once video is playing.
    352     for (var i = 0; i < 3; ++i) {
    353       var id = "video" + i;
    354       createDetectableRenderer(stream, id);
    355       addExpectedEvent();
    356       // |video_detected_function| creates a new function that pause the video
    357       // tag |id|.
    358       var video_detected_function =
    359           function (j) {
    360             return function () {
    361               console.log("pause " + j);
    362               $(j).pause();
    363               eventOccured();
    364            };
    365           };
    366       // Detect video id |id| and trigger the function returned by
    367       // |video_detected_function| when video is playing.
    368       detectVideoPlaying(id, video_detected_function(id));
    369      }
    370    }
    371 
    372   // This function tries to calculate the aspect ratio shown by the fake capture
    373   // device in the video tag. For this, we count the amount of light green
    374   // pixels along |aperture| pixels on the positive X and Y axis starting from
    375   // the center of the image. In this very center there should be a time-varying
    376   // pacman; the algorithm counts for a couple of iterations and keeps the
    377   // maximum amount of light green pixels on both directions. From this data
    378   // the aspect ratio is calculated and the test fails if the number of green
    379   // pixels are not the same along the X and Y axis.
    380   // The result of the analysis is sent back to the test as a string on the
    381   // format "w=xxx:h=yyy".
    382   function detectAspectRatio(callback, videoElementName) {
    383     var videoElement = $(videoElementName);
    384     var canvas = $(videoElementName + '-canvas');
    385 
    386     var maxLightGreenPixelsX = 0;
    387     var maxLightGreenPixelsY = 0;
    388 
    389     var iterations = 0;
    390     var maxIterations = 10;
    391 
    392     var detectorFunction = function() {
    393       var width = videoElement.videoWidth;
    394       var height = videoElement.videoHeight;
    395       if (width == 0 || height == 0)
    396         return;
    397 
    398       canvas.width = width;
    399       canvas.height = height;
    400       var aperture = Math.min(width, height) / 2;
    401       var context = canvas.getContext('2d');
    402       context.drawImage(videoElement, 0, 0, width, height);
    403 
    404       // We are interested in a window starting from the center of the image
    405       // where we expect the circle from the fake video capture to be rolling.
    406       var pixels = context.getImageData(width / 2, height / 2,
    407                                         aperture, aperture);
    408 
    409       var lightGreenPixelsX = 0;
    410       var lightGreenPixelsY = 0;
    411 
    412       // Walk horizontally counting light green pixels.
    413       for (var x = 0; x < aperture; ++x) {
    414         if (pixels.data[4 * x + 1] != COLOR_BACKGROUND_GREEN)
    415           lightGreenPixelsX++;
    416       }
    417       // Walk vertically counting light green pixels.
    418       for (var y = 0; y < aperture; ++y) {
    419         if (pixels.data[4 * y * aperture + 1] != COLOR_BACKGROUND_GREEN)
    420           lightGreenPixelsY++;
    421       }
    422       if (lightGreenPixelsX > maxLightGreenPixelsX)
    423         maxLightGreenPixelsX = lightGreenPixelsX;
    424       if (lightGreenPixelsY > maxLightGreenPixelsY)
    425         maxLightGreenPixelsY = lightGreenPixelsY;
    426 
    427       if (++iterations > maxIterations) {
    428         clearInterval(detectorInterval);
    429         // Allow maxLightGreenPixelsY = maxLightGreenPixelsX +-1 due to
    430         // possible subpixel rendering on Mac and Android.
    431         if (maxLightGreenPixelsY > maxLightGreenPixelsX + 1 ||
    432             maxLightGreenPixelsY < maxLightGreenPixelsX -1 ||
    433             maxLightGreenPixelsY == 0 ||
    434             maxLightGreenPixelsX == width / 2 ||
    435             maxLightGreenPixelsY == height / 2) {
    436           failTest("Aspect ratio corrupted. X " + maxLightGreenPixelsX  +
    437             " Y " + maxLightGreenPixelsY);
    438         }
    439 
    440         var result = "w=" + width + ":h=" + height;
    441         console.log(result);
    442         callback(result);
    443       }
    444     }
    445     var detectorInterval = setInterval(detectorFunction, 50);
    446   }
    447   </script>
    448 </head>
    449 <body>
    450   <table border="0">
    451     <tr>
    452       <td>Local Preview</td>
    453     </tr>
    454     <tr>
    455       <td><video width="320" height="240" id="local-view"
    456           autoplay="autoplay"></video></td>
    457       <td><canvas id="local-view-canvas"
    458           style="display:none"></canvas></td>
    459     </tr>
    460     <tr>
    461       <td>Local Preview 2</td>
    462     </tr>
    463     <tr>
    464       <td><video width="320" height="240" id="local-view-2"
    465           autoplay="autoplay"></video></td>
    466       <!-- Canvases are named after their corresponding video elements. -->
    467       <td><canvas width="320" height="240" id="local-view-2-canvas"
    468           style="display:none"></canvas></td>
    469     </tr>
    470   </table>
    471 </body>
    472 </html>
    473