Advertisement
Guest User

Untitled

a guest
Apr 14th, 2023
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @license
  3.  * Copyright 2018 Google Inc. All rights reserved.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *    http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17.  
  18. 'use strict';
  19.  
  20. /**
  21.  * MSE Conformance Test Suite.
  22.  * @class
  23.  */
  24. var ConformanceTest = function() {
  25.  
  26. var mseVersion = 'Current Editor\'s Draft';
  27. var webkitPrefix = MediaSource.prototype.version.indexOf('webkit') >= 0;
  28. var tests = [];
  29. var info = 'No MSE Support!';
  30. if (window.MediaSource) {
  31.   info = 'MSE Spec Version: ' + mseVersion;
  32.   info += ' | webkit prefix: ' + webkitPrefix.toString();
  33. }
  34. info += ' | Default Timeout: ' + TestBase.timeout + 'ms';
  35.  
  36. /**
  37.  * @param {!string} name
  38.  * @param {?string} category
  39.  * @param {?boolean} mandatory
  40.  * @param {?Array<Object>} streams If any stream is unsupported, test is marked
  41.  *     optional and fails.
  42.  */
  43. var createConformanceTest =
  44.     function (testId, name, category = 'General', mandatory = true,
  45.         streams = []) {
  46.   var t = createMSTest(testId, name, category, mandatory, 'MSE Conformance Tests');
  47.   t.prototype.index = tests.length;
  48.   t.prototype.setStreams(streams);
  49.   tests.push(t);
  50.   return t;
  51. };
  52.  
  53. /**
  54.  * Test if the value of video state is expected when onsourceopen
  55.  * event happens.
  56.  */
  57. var createInitialMediaStateTest = function (testId, state, value, check) {
  58.   var test = createConformanceTest(testId,
  59.       'InitialMedia' + util.MakeCapitalName(state), 'Media Element Core');
  60.   check = typeof(check) === 'undefined' ? 'checkEq' : check;
  61.   test.prototype.title = 'Test if the state ' + state +
  62.       ' is correct when onsourceopen is called';
  63.   test.prototype.onsourceopen = function() {
  64.     this.runner[check](this.video[state], value, state);
  65.     this.runner.succeed();
  66.   };
  67. };
  68.  
  69. createInitialMediaStateTest('1.1.1.1', 'duration', NaN);
  70. createInitialMediaStateTest('1.1.2.1', 'videoWidth', 0);
  71. createInitialMediaStateTest('1.1.3.1', 'videoHeight', 0);
  72. createInitialMediaStateTest('1.1.4.1', 'readyState', HTMLMediaElement.HAVE_NOTHING);
  73. createInitialMediaStateTest('1.1.5.1', 'src', '', 'checkNE');
  74. createInitialMediaStateTest('1.1.6.1', 'currentSrc', '', 'checkNE');
  75.  
  76. /**
  77.  * Validate the XHR request can send Uint8Array.
  78.  */
  79. var testXHRUint8Array = createConformanceTest('1.2.1.1', 'XHRUint8Array', 'XHR');
  80. testXHRUint8Array.prototype.title = 'Ensure that XHR can send an Uint8Array';
  81. testXHRUint8Array.prototype.timeout = 10000;
  82. testXHRUint8Array.prototype.start = function(runner, video) {
  83.   var s = 'XHR DATA';
  84.   var buf = new ArrayBuffer(s.length);
  85.   var view = new Uint8Array(buf);
  86.   for (var i = 0; i < s.length; i++) {
  87.     view[i] = s.charCodeAt(i);
  88.   }
  89.  
  90.   var xhr = runner.XHRManager.createPostRequest('/echo',
  91.     function(e) {
  92.       runner.checkEq(String.fromCharCode.apply(null, xhr.getResponseData()),
  93.                      s, 'XHR response');
  94.       runner.succeed();
  95.     },
  96.     view.length);
  97.   xhr.send(view);
  98. };
  99.  
  100. /**
  101.  * Ensure that XHR aborts actually abort by issuing an absurd number of them
  102.  * and then aborting all but one.
  103.  */
  104. var testXHRAbort = createConformanceTest('1.2.2.1', 'XHRAbort', 'XHR');
  105. testXHRAbort.prototype.title = 'Ensure that XHR aborts actually abort by ' +
  106.     'issuing an absurd number of them and then aborting all but one.';
  107. testXHRAbort.prototype.start = function(runner, video) {
  108.   var N = 100;
  109.   var startTime = Date.now();
  110.   var lastAbortTime;
  111.   function startXHR(i) {
  112.     var xhr = runner.XHRManager.createRequest(
  113.         Media.VP9.VideoNormal.src + '?x=' + Date.now() + '.' + i, function() {
  114.       if (i >= N) {
  115.         xhr.getResponseData();  // This will verify status internally.
  116.         runner.succeed();
  117.       }
  118.     });
  119.     if (i < N) {
  120.       runner.timeouts.setTimeout(xhr.abort.bind(xhr), 10);
  121.       runner.timeouts.setTimeout(startXHR.bind(null, i + 1), 1);
  122.       lastAbortTime = Date.now();
  123.     }
  124.     xhr.send();
  125.   };
  126.   startXHR(0);
  127. };
  128.  
  129. /**
  130.  * Ensure XMLHttpRequest.open does not reset XMLHttpRequest.responseType.
  131.  */
  132. var testXHROpenState = createConformanceTest('1.2.3.1', 'XHROpenState', 'XHR');
  133. testXHROpenState.prototype.title = 'Ensure XMLHttpRequest.open does not ' +
  134.     'reset XMLHttpRequest.responseType';
  135. testXHROpenState.prototype.start = function(runner, video) {
  136.   var xhr = new XMLHttpRequest;
  137.   // It should not be an error to set responseType before calling open
  138.   xhr.responseType = 'arraybuffer';
  139.   xhr.open('GET', 'http://google.com', true);
  140.   runner.checkEq(xhr.responseType, 'arraybuffer', 'XHR responseType');
  141.   runner.succeed();
  142. };
  143.  
  144. /**
  145.  * Validate existence of MediaSource object.
  146.  */
  147. var testPresence = createConformanceTest('1.3.1.1', 'Presence', 'MSE Core');
  148. testPresence.prototype.title = 'Test if MediaSource object is present.';
  149. testPresence.prototype.start = function(runner, video) {
  150.   if (!window.MediaSource)
  151.     return runner.fail('No MediaSource object available.');
  152.  
  153.   var ms = new MediaSource();
  154.   if (!ms)
  155.     return runner.fail('Found MediaSource but could not create one');
  156.  
  157.   if (ms.version)
  158.     this.log('Media source version reported as ' + ms.version);
  159.   else
  160.     this.log('No media source version reported');
  161.  
  162.   runner.succeed();
  163. };
  164.  
  165. /**
  166.  * Ensure MediaSource object can be attached to video.
  167.  */
  168. var testAttach = createConformanceTest('1.3.2.1', 'Attach', 'MSE Core');
  169. testAttach.prototype.timeout = 2000;
  170. testAttach.prototype.title =
  171.     'Test if MediaSource object can be attached to video.';
  172. testAttach.prototype.start = function(runner, video) {
  173.   this.ms = new MediaSource();
  174.   this.ms.addEventListener('sourceopen', function() {
  175.     runner.succeed();
  176.   });
  177.   video.src = window.URL.createObjectURL(this.ms);
  178.   video.load();
  179. };
  180.  
  181. /**
  182.  * Test addSourceBuffer is working correctly.
  183.  */
  184. var testAddSourceBuffer = createConformanceTest('1.3.3.1', 'AddSourceBuffer',
  185.     'MSE Core');
  186. testAddSourceBuffer.prototype.title =
  187.     'Test if we can add source buffer';
  188. testAddSourceBuffer.prototype.onsourceopen = function() {
  189.   try {
  190.     this.runner.checkEq(
  191.         this.ms.sourceBuffers.length, 0, 'Source buffer number');
  192.     this.ms.addSourceBuffer(Media.AAC.mimetype);
  193.     this.runner.checkEq(
  194.         this.ms.sourceBuffers.length, 1, 'Source buffer number');
  195.     this.ms.addSourceBuffer(Media.VP9.mimetype);
  196.     this.runner.checkEq(
  197.         this.ms.sourceBuffers.length, 2, 'Source buffer number');
  198.   } catch (e) {
  199.     this.runner.fail(e);
  200.   }
  201.   this.runner.succeed();
  202. };
  203.  
  204. /**
  205.  * Ensure add incorrect source buffer type will fire the correct exceptions.
  206.  */
  207. var testAddSourceBufferException =
  208.     createConformanceTest('1.3.4.1', 'AddSBException', 'MSE Core');
  209. testAddSourceBufferException.prototype.title = 'Test if add incorrect ' +
  210.     'source buffer type will fire the correct exceptions.';
  211. testAddSourceBufferException.prototype.onsourceopen = function() {
  212.   var runner = this.runner;
  213.   var self = this;
  214.   runner.checkException(function() {
  215.     self.ms.addSourceBuffer('^^^');
  216.   }, DOMException.NOT_SUPPORTED_ERR);
  217.  
  218.   runner.checkException(function() {
  219.     var ms = new MediaSource;
  220.     ms.addSourceBuffer(Media.AAC.mimetype);
  221.   }, DOMException.INVALID_STATE_ERR);
  222.  
  223.   runner.succeed();
  224. };
  225.  
  226. /**
  227.  * Test addSourceBuffer and removeSourceBuffer are working correctly.
  228.  */
  229. var testSourceRemove = createConformanceTest('1.3.5.1', 'RemoveSourceBuffer',
  230.     'MSE Core');
  231. testSourceRemove.prototype.title = 'Test if we can add/remove source buffers';
  232. testSourceRemove.prototype.onsourceopen = function() {
  233.   var sb = this.ms.addSourceBuffer(Media.AAC.mimetype);
  234.   this.ms.removeSourceBuffer(sb);
  235.   this.runner.checkEq(this.ms.sourceBuffers.length, 0, 'Source buffer number');
  236.   this.ms.addSourceBuffer(Media.AAC.mimetype);
  237.   this.runner.checkEq(this.ms.sourceBuffers.length, 1, 'Source buffer number');
  238.   for (var i = 0; i < 10; ++i) {
  239.     try {
  240.       sb = this.ms.addSourceBuffer(Media.VP9.mimetype);
  241.       this.runner.checkEq(this.ms.sourceBuffers.length, 2,
  242.                           'Source buffer number');
  243.       this.ms.removeSourceBuffer(sb);
  244.       this.runner.checkEq(this.ms.sourceBuffers.length, 1,
  245.                           'Source buffer number');
  246.     } catch (e) {
  247.       return this.runner.fail(e);
  248.     }
  249.   }
  250.   this.runner.succeed();
  251. };
  252.  
  253. /**
  254.  * Ensure MediaSource state has the expected value when onsourceopen happens.
  255.  */
  256. var createInitialMSStateTest = function(testId, state, value, check) {
  257.   var test = createConformanceTest(testId,
  258.       'InitialMS' + util.MakeCapitalName(state), 'MSE Core');
  259.  
  260.   check = typeof(check) === 'undefined' ? 'checkEq' : check;
  261.   test.prototype.title = 'Test if the state ' + state +
  262.       ' is correct when onsourceopen is called';
  263.   test.prototype.onsourceopen = function() {
  264.     this.runner[check](this.ms[state], value, state);
  265.     this.runner.succeed();
  266.   };
  267. };
  268.  
  269. createInitialMSStateTest('1.3.6.1', 'duration', NaN);
  270. createInitialMSStateTest('1.3.7.1', 'readyState', 'open');
  271.  
  272. /**
  273.  * Ensure we can set MediaSource.duration.
  274.  */
  275. var testDuration = createConformanceTest('1.3.8.1', 'Duration', 'MSE Core');
  276. testDuration.prototype.title =
  277.     'Test if we can set duration.';
  278. testDuration.prototype.onsourceopen = function() {
  279.   this.ms.duration = 10;
  280.   this.runner.checkEq(this.ms.duration, 10, 'ms.duration');
  281.   this.runner.succeed();
  282. };
  283.  
  284. /**
  285.  * Test events on the MediaElement.
  286.  */
  287. var mediaElementEvents =
  288.     createConformanceTest('1.3.9.1', 'MediaElementEvents', 'MSE Core');
  289. mediaElementEvents.prototype.title = 'Test events on the MediaElement.';
  290. mediaElementEvents.prototype.onsourceopen = function() {
  291.   var runner = this.runner;
  292.   var media = this.video;
  293.   var ms = this.ms;
  294.   var audioStream = Media.AAC.Audio1MB;
  295.   var videoStream = Media.VP9.Video1MB;
  296.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  297.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  298.   var self = this;
  299.   var videoXhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  300.     self.log('onload called');
  301.     var onUpdate = function() {
  302.       videoSb.removeEventListener('update', onUpdate);
  303.       setDuration(1.0, ms, [videoSb, audioSb], function() {
  304.         if (audioSb.updating || videoSb.updating) {
  305.           runner.fail('Source buffers are updating on duration change.');
  306.           return;
  307.         }
  308.         ms.endOfStream();
  309.         media.play();
  310.       });
  311.     }
  312.     videoSb.addEventListener('update', onUpdate);
  313.     videoSb.appendBuffer(videoXhr.getResponseData());
  314.   });
  315.   var audioXhr = runner.XHRManager.createRequest(audioStream.src, function(e) {
  316.     self.log('onload called');
  317.     var onAudioUpdate =  function() {
  318.       audioSb.removeEventListener('update', onAudioUpdate);
  319.       videoXhr.send();
  320.     }
  321.     audioSb.addEventListener('update', onAudioUpdate);
  322.     audioSb.appendBuffer(audioXhr.getResponseData());
  323.   });
  324.  
  325.   media.addEventListener('ended', function() {
  326.     self.log('onended called');
  327.     runner.succeed();
  328.   });
  329.  
  330.   audioXhr.send();
  331. };
  332.  
  333. /**
  334.  * Test if the events on MediaSource are correct.
  335.  */
  336. var mediaSourceEvents = createConformanceTest('1.3.10.1', 'MediaSourceEvents',
  337.     'MSE Core');
  338. mediaSourceEvents.prototype.title =
  339.     'Test if the events on MediaSource are correct.';
  340. mediaSourceEvents.prototype.onsourceopen = function() {
  341.   var runner = this.runner;
  342.   var media = this.video;
  343.   var ms = this.ms;
  344.   var audioStream = Media.AAC.Audio1MB;
  345.   var videoStream = Media.VP9.Video1MB;
  346.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  347.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  348.   var lastState = 'open';
  349.   var self = this;
  350.   var videoXhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  351.       self.log('onload called');
  352.       videoSb.appendBuffer(videoXhr.getResponseData());
  353.       videoSb.abort();
  354.       ms.endOfStream();
  355.     });
  356.   var audioXhr = runner.XHRManager.createRequest(audioStream.src, function(e) {
  357.       self.log('onload called');
  358.       audioSb.appendBuffer(audioXhr.getResponseData());
  359.       audioSb.abort();
  360.       videoXhr.send();
  361.     });
  362.  
  363.   ms.addEventListener('sourceclose', function() {
  364.     self.log('onsourceclose called');
  365.     runner.checkEq(lastState, 'ended', 'The previous state');
  366.     runner.succeed();
  367.   });
  368.  
  369.   ms.addEventListener('sourceended', function() {
  370.     self.log('onsourceended called');
  371.     runner.checkEq(lastState, 'open', 'The previous state');
  372.     lastState = 'ended';
  373.     media.removeAttribute('src');
  374.     media.load();
  375.   });
  376.  
  377.   audioXhr.send();
  378. };
  379.  
  380. /**
  381.  * Append to buffer until exceeding the quota error.
  382.  */
  383. var testBufferSize = createConformanceTest('1.3.11.1', 'VideoBufferSize',
  384.     'MSE Core');
  385. testBufferSize.prototype.title = 'Determines video buffer sizes by ' +
  386.     'appending incrementally until discard occurs, and tests that it meets ' +
  387.     'the minimum requirements for streaming.';
  388. testBufferSize.prototype.onsourceopen = function() {
  389.   var runner = this.runner;
  390.   // The test clip has a bitrate which is nearly exactly 1MB/sec, and
  391.   // lasts 1s. We start appending it repeatedly until we get eviction.
  392.   var videoStream = Media.VP9.Video1MB;
  393.   var sb = this.ms.addSourceBuffer(videoStream.mimetype);
  394.   var audioStream = Media.AAC.Audio1MB;
  395.   var unused_audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  396.   var self = this;
  397.   var MIN_SIZE = 12 * 1024 * 1024;
  398.   var ESTIMATED_MIN_TIME = 12;
  399.   var xhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  400.     var onBufferFull = function() {
  401.       runner.checkGE(expectedTime - sb.buffered.start(0), ESTIMATED_MIN_TIME,
  402.                      'Estimated source buffer size');
  403.       runner.succeed();
  404.     };
  405.     var expectedTime = 0;
  406.     var expectedSize = 0;
  407.     var appendCount = 0;
  408.     sb.addEventListener('updateend', function onUpdate() {
  409.       appendCount++;
  410.       self.log('Append count ' + appendCount);
  411.       if (sb.buffered.start(0) > 0 || expectedTime > sb.buffered.end(0)) {
  412.         sb.removeEventListener('updateend', onUpdate);
  413.         onBufferFull();
  414.       } else {
  415.         expectedTime += videoStream.duration;
  416.         expectedSize += videoStream.size;
  417.         // Pass the test if the UA can handle 10x more than expected.
  418.         if (expectedSize > (10 * MIN_SIZE)) {
  419.           sb.removeEventListener('updateend', onUpdate);
  420.           onBufferFull();
  421.           return;
  422.         }
  423.         sb.timestampOffset = expectedTime;
  424.         try {
  425.           sb.appendBuffer(xhr.getResponseData());
  426.         } catch (e) {
  427.           var QUOTA_EXCEEDED_ERROR_CODE = 22;
  428.           if (e.code == QUOTA_EXCEEDED_ERROR_CODE) {
  429.             sb.removeEventListener('updateend', onUpdate);
  430.             onBufferFull();
  431.           } else {
  432.             runner.fail(e);
  433.           }
  434.         }
  435.       }
  436.     });
  437.     sb.appendBuffer(xhr.getResponseData());
  438.   });
  439.   xhr.send();
  440. };
  441.  
  442. /**
  443.  * Ensure we can start play before feeding any data. The play should
  444.  * start automatically after data is appended.
  445.  */
  446. var testStartPlayWithoutData = createConformanceTest('1.3.12.1',
  447.     'StartPlayWithoutData', 'MSE Core');
  448. testStartPlayWithoutData.prototype.title =
  449.     'Test if we can start play before feeding any data. The play should ' +
  450.     'start automatically after data is appended';
  451. testStartPlayWithoutData.prototype.onsourceopen = function() {
  452.   var runner = this.runner;
  453.   var media = this.video;
  454.   var audioStream = Media.AAC.AudioHuge;
  455.   var videoStream = Media.VP9.VideoHuge;
  456.   var videoChain = new ResetInit(
  457.       new FileSource(videoStream.src, runner.XHRManager, runner.timeouts));
  458.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  459.   var audioChain = new ResetInit(
  460.       new FileSource(audioStream.src, runner.XHRManager, runner.timeouts));
  461.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  462.  
  463.   media.play();
  464.   appendUntil(runner.timeouts, media, videoSb, videoChain, 1, function() {
  465.     appendUntil(runner.timeouts, media, audioSb, audioChain, 1, function() {
  466.       playThrough(
  467.           runner.timeouts, media, 1, 2,
  468.           videoSb, videoChain, audioSb, audioChain, function() {
  469.         runner.checkGE(media.currentTime, 2, 'currentTime');
  470.         runner.succeed();
  471.       });
  472.     });
  473.   });
  474. };
  475.  
  476. /**
  477.  * Ensure we can start playback from a non-zero position.
  478.  */
  479. var createStartPlayAtNonZeroPositionTest = function(
  480.     testId, audioStream, audioSegments, videoStream, videoSegments, startAtSec) {
  481.   var test = createConformanceTest(testId,
  482.       `StartPlayAtTimeGt0${videoStream.codec}+${audioStream.codec}`, 'MSE Core',
  483.       true, [videoStream,
  484.         audioStream]);
  485.   test.prototype.title =
  486.       'Test if we can start playback from time > 0.';
  487.   test.prototype.onsourceopen = function() {
  488.     var runner = this.runner;
  489.     var video = this.video;
  490.     var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  491.     var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  492.  
  493.     var fetchStream = function(stream, callBack, start, end) {
  494.       var xhr =
  495.           runner.XHRManager.createRequest(stream.src, callBack, start, end);
  496.       xhr.send();
  497.     }
  498.     var appendLoop = function(stream, sourceBuffer, segments, playAndSeek) {
  499.       var parsedData;
  500.       var segmentIdx = 0;
  501.       var maxSegments = segments.length;
  502.  
  503.       fetchStream(stream, function() {
  504.         if (stream.codec == 'H264' || stream.codec == 'AAC') {
  505.           parsedData = parseMp4(this.getResponseData());
  506.         } else if(stream.codec == 'VP9' || stream.codec == 'Opus') {
  507.           parsedData = parseWebM(this.getResponseData().buffer);
  508.         } else {
  509.           runner.fail('Unsupported codec in appendLoop.');
  510.         }
  511.         fetchStream(stream, function() {
  512.           sourceBuffer.addEventListener('updateend', function append() {
  513.             if (playAndSeek && segmentIdx == 0) {
  514.               video.play();
  515.             }
  516.             if (maxSegments - segmentIdx <= 0) {
  517.               sourceBuffer.removeEventListener('updateend', append);
  518.               if (playAndSeek) {
  519.                 video.currentTime = playAndSeek;
  520.               }
  521.               return;
  522.             }
  523.             fetchStream(stream, function() {
  524.               sourceBuffer.appendBuffer(this.getResponseData());
  525.               segmentIdx += 1;
  526.             },
  527.             parsedData[segments[segmentIdx]].offset,
  528.             parsedData[segments[segmentIdx]].size);
  529.           });
  530.           sourceBuffer.appendBuffer(this.getResponseData());
  531.         }, 0, parsedData[0].offset); // Init segment.
  532.       }, 0, 32 * 1024); // Enough data to parse the stream.
  533.     };
  534.     video.addEventListener('timeupdate', function timeupdate() {
  535.       if (!video.paused && video.currentTime > startAtSec + 5) {
  536.         runner.succeed();
  537.       }
  538.     });
  539.     appendLoop(audioStream, audioSb, audioSegments);
  540.     appendLoop(videoStream, videoSb, videoSegments, startAtSec);
  541.   };
  542. };
  543.  
  544. createStartPlayAtNonZeroPositionTest(
  545.     '1.3.13.1', Media.AAC.AudioNormal, [1, 2], Media.H264.VideoNormal, [2, 3, 4], 12);
  546. createStartPlayAtNonZeroPositionTest(
  547.     '1.3.14.1', Media.Opus.CarLow, [1, 2], Media.VP9.VideoNormal, [2, 3, 4], 12);
  548.  
  549. /**
  550.  * Ensure event timestamp is relative to the initial page load.
  551.  */
  552. var testEventTimestamp = createConformanceTest('1.3.15.1', 'EventTimestamp',
  553.     'MSE Core');
  554. testEventTimestamp.prototype.title = 'Test Event Timestamp is relative to ' +
  555.     'the initial page load';
  556. testEventTimestamp.prototype.onsourceopen = function() {
  557.   var runner = this.runner;
  558.   var video = this.video;
  559.   var videoStream = Media.VP9.VideoTiny;
  560.   var audioStream = Media.AAC.AudioTiny;
  561.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  562.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  563.   runner.checkGr(Date.now(), 1360000000000, 'Date.now()');
  564.   var lastTime = 0.0;
  565.   var requestCounter = 0;
  566.  
  567.   var audioXhr = runner.XHRManager.createRequest(audioStream.src, function(e) {
  568.     audioSb.appendBuffer(this.getResponseData());
  569.     video.addEventListener('timeupdate', function(e) {
  570.       runner.checkGE(e.timeStamp, lastTime, 'event.timeStamp');
  571.       lastTime = e.timeStamp;
  572.       if (!video.paused && video.currentTime >= 2 && requestCounter >= 3) {
  573.         runner.succeed();
  574.       }
  575.       requestCounter++;
  576.     });
  577.     video.play();
  578.   }, 0, 500000);
  579.  
  580.   var videoXhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  581.     videoSb.appendBuffer(this.getResponseData());
  582.     audioXhr.send();
  583.   }, 0, 1500000);
  584.   videoXhr.send();
  585. };
  586.  
  587. /**
  588.  * Ensure timeupdate event fired with correct currentTime value after seeking.
  589.  */
  590. var testSeekTimeUpdate = createConformanceTest('1.3.16.1', 'SeekTimeUpdate',
  591.     'MSE Core');
  592. testSeekTimeUpdate.prototype.title =
  593.   'Timeupdate event fired with correct currentTime after seeking.';
  594. testSeekTimeUpdate.prototype.onsourceopen = function() {
  595.   var runner = this.runner;
  596.   var media = this.video;
  597.   var videoStream = Media.VP9.VideoNormal;
  598.   var audioStream = Media.AAC.AudioNormal;
  599.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  600.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  601.   var lastTime = 0;
  602.   var updateCount = 0;
  603.   var xhr = runner.XHRManager.createRequest(videoStream.src, function() {
  604.     videoSb.appendBuffer(xhr.getResponseData());
  605.     var xhr2 = runner.XHRManager.createRequest(audioStream.src, function() {
  606.       audioSb.appendBuffer(xhr2.getResponseData());
  607.       callAfterLoadedMetaData(media, function() {
  608.         media.addEventListener('timeupdate', function(e) {
  609.           if (!media.paused) {
  610.             ++updateCount;
  611.             runner.checkGE(media.currentTime, lastTime, 'media.currentTime');
  612.             if (updateCount > 3) {
  613.               updateCount = 0;
  614.               lastTime += 10;
  615.               if (lastTime >= 35)
  616.                 runner.succeed();
  617.               else
  618.                 media.currentTime = lastTime + 6;
  619.             }
  620.           }
  621.         });
  622.         media.play();
  623.       });
  624.     }, 0, 1000000);
  625.     xhr2.send();
  626.   }, 0, 5000000);
  627.   this.ms.duration = 100000000;  // Ensure that we can seek to any position.
  628.   xhr.send();
  629. };
  630.  
  631. /**
  632.  * Test SourceBuffer.appendWindowStart can be correctly set and applied.
  633.  */
  634. var testAppendWindowStart =
  635.   createConformanceTest('1.3.17.1', 'AppendWindowStart', 'MSE Core');
  636. testAppendWindowStart.prototype.title =
  637.   'Test if SourceBuffer respects appendWindowStart for appending.';
  638. testAppendWindowStart.prototype.onsourceopen = function() {
  639.   var runner = this.runner;
  640.   var start = 3.4;
  641.   var videoStream = Media.VP9.VideoNormal;
  642.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  643.   // appendWindowStart cannot be smaller than 0
  644.   // or greater than or equal to appendWindowEnd.
  645.   try {
  646.     videoSb.appendWindowStart = -1;
  647.   } catch (e) {
  648.     runner.checkEq(e.name, 'TypeError', 'Expected error');
  649.   }
  650.   try {
  651.     videoSb.appendWindowEnd = 10;
  652.     videoSb.appendWindowStart = 11;
  653.   } catch (e) {
  654.     runner.checkEq(e.name, 'TypeError', 'Expected error');
  655.   }
  656.   runner.checkEq(videoSb.appendWindowStart, 0, 'appendWindowStart');
  657.  
  658.   videoSb.appendWindowStart = start;
  659.   var xhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  660.     videoSb.appendBuffer(this.getResponseData());
  661.  
  662.     videoSb.addEventListener('updateend', function() {
  663.       runner.checkEq(videoSb.appendWindowStart, start, 'appendWindowStart');
  664.       // More frames maybe dropped due to missing key frame.
  665.       runner.checkGE(videoSb.buffered.start(0), start, 'Buffered range start');
  666.       runner.succeed();
  667.     });
  668.   }, 0, 3000000);
  669.   xhr.send();
  670. };
  671.  
  672. /**
  673.  * Test SourceBuffer.appendWindowEnd can be correctly set and applied.
  674.  */
  675. var testAppendWindowEnd =
  676.   createConformanceTest('1.3.18.1', 'AppendWindowEnd', 'MSE Core');
  677. testAppendWindowEnd.prototype.title =
  678.   'Test if SourceBuffer respects appendWindowEnd for appending.';
  679. testAppendWindowEnd.prototype.onsourceopen = function() {
  680.   var runner = this.runner;
  681.   var end = 5.3;
  682.   var videoStream = Media.VP9.VideoNormal;
  683.   var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  684.   // appendWindowEnd cannot be smaller than appendWindowStart.
  685.   try {
  686.     videoSb.appendWindowStart = 2;
  687.     videoSb.appendWindowEnd = 1;
  688.   } catch (e) {
  689.     runner.checkEq(e.name, 'TypeError', 'Expected error');
  690.   }
  691.   runner.checkEq(videoSb.appendWindowEnd, 'Infinity', 'appendWindowEnd');
  692.  
  693.   videoSb.appendWindowStart = 0;
  694.   videoSb.appendWindowEnd = end;
  695.   var xhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  696.     videoSb.appendBuffer(this.getResponseData());
  697.  
  698.     videoSb.addEventListener('updateend', function() {
  699.       runner.checkEq(videoSb.appendWindowEnd, end, 'appendWindowEnd');
  700.       runner.checkApproxEq(
  701.           videoSb.buffered.end(0), end, 'Buffered range end', 0.05);
  702.       runner.succeed();
  703.     });
  704.   }, 0, 3000000);
  705.   xhr.send();
  706. };
  707.  
  708. var createSourceBufferChangeTypeTest = function(testId, fromStream, toStream) {
  709.   var test = createConformanceTest(testId,
  710.       `ChangeType.${fromStream.codec}.${toStream.codec}`, 'MSE Core', false, [fromStream,
  711.         toStream]);
  712.   test.prototype.title =
  713.       `Test SourceBuffer.changeType() from ${fromStream.codec} ` +
  714.       `to ${toStream.codec}`;
  715.   test.prototype.onsourceopen = function() {
  716.     var video = this.video;
  717.     var ms = this.ms;
  718.     var runner = this.runner;
  719.     var videoStreams = [fromStream, toStream];
  720.     function feedVideoElement(streamIndex) {
  721.       var secondsToBuffer = 2;
  722.       if (streamIndex == videoStreams.length) {
  723.         ms.endOfStream();
  724.         video.addEventListener('timeupdate', function(e) {
  725.           if (!video.paused && video.currentTime >= secondsToBuffer * 2) {
  726.             runner.succeed();
  727.           }
  728.         });
  729.         video.play();
  730.         return;
  731.       }
  732.  
  733.       try {
  734.         var sourceBuffer;
  735.         var videoStream = videoStreams[streamIndex];
  736.  
  737.         if (ms.sourceBuffers.length == 0) {
  738.           sourceBuffer = ms.addSourceBuffer(videoStream.mimetype);
  739.           sourceBuffer.mode = 'sequence';
  740.         } else {
  741.           sourceBuffer = ms.sourceBuffers[0];
  742.           sourceBuffer.changeType(videoStream.mimetype);
  743.         }
  744.  
  745.         var xhr = runner.XHRManager.createRequest(videoStream.src, function(e) {
  746.           sourceBuffer.appendBuffer(this.getResponseData());
  747.           sourceBuffer.addEventListener('updateend', function() {
  748.             feedVideoElement(++streamIndex);
  749.           }, { once: true });
  750.         }, 0, videoStream.bps * secondsToBuffer);
  751.         xhr.send();
  752.  
  753.       } catch(error) {
  754.         runner.fail(error);
  755.       }
  756.     }
  757.     feedVideoElement(0);
  758.   }
  759. }
  760.  
  761. createSourceBufferChangeTypeTest('1.3.19.1', Media.H264.VideoTiny, Media.VP9.VideoTiny);
  762. createSourceBufferChangeTypeTest('1.3.20.1', Media.H264.VideoTiny,
  763.     Media.AV1.Bunny144p30fps);
  764. createSourceBufferChangeTypeTest('1.3.21.1', Media.VP9.VideoTiny, Media.H264.VideoTiny);
  765. createSourceBufferChangeTypeTest('1.3.22.1', Media.VP9.VideoTiny,
  766.     Media.AV1.Bunny144p30fps);
  767. createSourceBufferChangeTypeTest('1.3.23.1', Media.AV1.Bunny144p30fps,
  768.     Media.H264.VideoTiny);
  769. createSourceBufferChangeTypeTest('1.3.24.1', Media.AV1.Bunny144p30fps,
  770.     Media.VP9.VideoTiny);
  771.  
  772. const testPlaybackRateChange = createConformanceTest('1.3.25.1',
  773.                                                    'PlaybackRateChange',
  774.                                                    'MSE Core');
  775. testPlaybackRateChange.prototype.title =
  776.   'Test if playback rate can be changed in the middle of stream.';
  777. testPlaybackRateChange.prototype.onsourceopen = function() {
  778.   const runner = this.runner;
  779.   const media = this.video;
  780.   const videoStream = Media.VP9.VideoNormal;
  781.   const audioStream = Media.AAC.AudioNormal;
  782.   const videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  783.   const audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  784.   let baseMediaTime = 0.0;
  785.   let baseRealTime = 0.0;
  786.   const videoPerfMetrics = new VideoPerformanceMetrics(media);
  787.   let isBaseCaptured = false;
  788.   let isRateChanged = false;
  789.   let isBaseUpdated = false;
  790.   let updateCount = 0;
  791.   const xhr = runner.XHRManager.createRequest(videoStream.src, function() {
  792.     videoSb.appendBuffer(xhr.getResponseData());
  793.     const xhr2 = runner.XHRManager.createRequest(audioStream.src, function() {
  794.       audioSb.appendBuffer(xhr2.getResponseData());
  795.       callAfterLoadedMetaData(media, function() {
  796.         media.addEventListener('timeupdate', function(e) {
  797.           // Limit updates to once every 500ms (once every 2 events).
  798.           updateCount++;
  799.           if (updateCount % 2 === 0) {
  800.             return;
  801.           }
  802.  
  803.           let time = media.currentTime;
  804.           if (time < 0.5) {
  805.             if(!isBaseCaptured) {
  806.               isBaseCaptured = true;
  807.               baseRealTime = Date.now();
  808.               baseMediaTime = time;
  809.               console.log(`Starting measurements at mediaTime ${baseMediaTime}`);
  810.             }
  811.           } else if (time < 1.5) {
  812.             console.log(`Taking playback measurement at mediaTime ${time}`);
  813.             let playbackRate1x =
  814.                 getActualPlaybackRate(time, Date.now(), baseMediaTime,
  815.                                       baseRealTime);
  816.             runner.checkLE(playbackRate1x, 1.05, 'Playback rate');
  817.           } else if (time < 4) {
  818.             if (!isRateChanged) {
  819.               isRateChanged = true;
  820.               media.playbackRate = 2.0;
  821.               console.log(`Changing playback rate to 2x at mediaTime ${time}`);
  822.             }
  823.           } else if (time < 5) {
  824.             if (!isBaseUpdated) {
  825.               isBaseUpdated = true;
  826.               baseRealTime = Date.now();
  827.               baseMediaTime = time;
  828.               console.log(`Recapturing baseline measurements at mediaTime ${baseMediaTime}`);
  829.             }
  830.           } else if (time < 7) {
  831.             console.log(`Taking playback measurement at mediaTime ${time}`);
  832.             let playbackRate2x =
  833.                 getActualPlaybackRate(time, Date.now(), baseMediaTime,
  834.                                       baseRealTime);
  835.             runner.checkGE(playbackRate2x, 1.95, 'Playback rate');
  836.           } else {
  837.             runner.checkLE(videoPerfMetrics.getDroppedVideoFrames(), 1,
  838.               'Total dropped frames');
  839.             runner.succeed();
  840.           }
  841.         });
  842.         media.play();
  843.       });
  844.     }, 0, 1000000);
  845.     xhr2.send();
  846.   }, 0, 5000000);
  847.   xhr.send();
  848. };
  849.  
  850. function getActualPlaybackRate(currentMediaTime, currentRealTime, baseMediaTime, baseRealTime) {
  851.   let mediaTimeElapsed = currentMediaTime - baseMediaTime;
  852.   let realTimeElapsed = (currentRealTime - baseRealTime) / 1000.0;
  853.   return (mediaTimeElapsed / realTimeElapsed).toFixed(3);
  854.  
  855. }
  856.  
  857. /**
  858.  * Creates a MSE currentTime Accuracy test to validate if the media.currentTime
  859.  * is accurate to within 250 milliseconds during active playback. This can
  860.  * be used for video features a standard frame rate or a high frame rate.
  861.  */
  862. var createCurrentTimeAccuracyTest =
  863.     function(testId, videoStream, audioStream, frameRate) {
  864.   var test = createConformanceTest(testId, frameRate + 'Accuracy',
  865.       'MSE currentTime');
  866.   test.prototype.title = 'Test the currentTime granularity.';
  867.   test.prototype.onsourceopen = function() {
  868.     var runner = this.runner;
  869.     var video = this.video;
  870.     var maxTimeDiff = 0;
  871.     var baseTimeDiff = 0;
  872.     let zeroTimeDiff = 0;
  873.     var times = 0;
  874.     var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  875.     var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  876.  
  877.     var videoXhr = runner.XHRManager.createRequest(
  878.         videoStream.src, function(e) {
  879.       videoSb.appendBuffer(this.getResponseData());
  880.       video.addEventListener('timeupdate', function(e) {
  881.         if (times === 0) {
  882.           zeroTimeDiff = util.ElapsedTimeInS() - video.currentTime;
  883.         }
  884.         else if (times === 1) {
  885.           baseTimeDiff = util.ElapsedTimeInS() - video.currentTime;
  886.           // Make sure the warmup time is less than 500 ms as stated in the
  887.           // spec.
  888.           runner.checkLE(
  889.             baseTimeDiff - zeroTimeDiff, 0.50, 'intial warm up time');
  890.         } else {
  891.           let timeDiff = util.ElapsedTimeInS() - video.currentTime;
  892.           maxTimeDiff = Math.max(
  893.               Math.abs(timeDiff - baseTimeDiff), maxTimeDiff);
  894.         }
  895.         if (times > 500 || video.currentTime > 10) {
  896.           runner.checkLE(
  897.               maxTimeDiff, 0.25, 'media.currentTime diff during playback');
  898.           runner.succeed();
  899.         }
  900.         ++times;
  901.       });
  902.       video.addEventListener('canplaythrough', function(e) {
  903.         video.play();
  904.       });
  905.     }, 0, 2500000);
  906.     var audioXhr = runner.XHRManager.createRequest(
  907.         audioStream.src, function(e) {
  908.       audioSb.appendBuffer(this.getResponseData());
  909.       videoXhr.send();
  910.     }, 0, 2500000);
  911.     audioXhr.send();
  912.   };
  913. };
  914.  
  915. createCurrentTimeAccuracyTest(
  916.     '1.4.1.1', Media.H264.Webgl720p30fps, Media.AAC.AudioNormal, 'SFR');
  917. createCurrentTimeAccuracyTest(
  918.     '1.4.2.1', Media.H264.Webgl720p60fps, Media.AAC.AudioNormal, 'HFR');
  919.  
  920. /**
  921.  * Creates a copy of the currentTimeAccuracy test due to b/266064197.
  922.  * The spec of when the first timeUpdate should be fired is not clear,
  923.  * so we kept a separate test to keep track of that. This test can be
  924.  * waived, but we should still run this against all partners.
  925.  * b/270470795 is filed for tracking future changes.
  926.  */
  927. let createCurrentTimeAccuracySpecTest =
  928.     function(testId, videoStream, audioStream, frameRate) {
  929.   let test = createConformanceTest(testId, frameRate + 'SpecAccuracy',
  930.       'MSE currentTime');
  931.   test.prototype.title = 'Test the currentTime granularity.';
  932.   test.prototype.onsourceopen = function() {
  933.     let runner = this.runner;
  934.     let video = this.video;
  935.     let maxTimeDiff = 0;
  936.     let baseTimeDiff = 0;
  937.     let times = 0;
  938.     let videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  939.     let audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  940.  
  941.     let videoXhr = runner.XHRManager.createRequest(
  942.         videoStream.src, function(e) {
  943.       videoSb.appendBuffer(this.getResponseData());
  944.       video.addEventListener('timeupdate', function(e) {
  945.         if (times === 0) {
  946.           baseTimeDiff = util.ElapsedTimeInS() - video.currentTime;
  947.         } else {
  948.           let timeDiff = util.ElapsedTimeInS() - video.currentTime;
  949.           maxTimeDiff = Math.max(
  950.               Math.abs(timeDiff - baseTimeDiff), maxTimeDiff);
  951.           runner.checkLE(
  952.             maxTimeDiff, 0.25, 'media.currentTime diff during playback');
  953.           runner.succeed();
  954.         }
  955.         ++times;
  956.       });
  957.       video.addEventListener('canplaythrough', function(e) {
  958.         video.play();
  959.       });
  960.     }, 0, 2500000);
  961.     let audioXhr = runner.XHRManager.createRequest(
  962.         audioStream.src, function(e) {
  963.       audioSb.appendBuffer(this.getResponseData());
  964.       videoXhr.send();
  965.     }, 0, 2500000);
  966.     audioXhr.send();
  967.   };
  968. };
  969.  
  970. createCurrentTimeAccuracySpecTest(
  971.   '1.4.1.2', Media.H264.Webgl720p30fps, Media.AAC.AudioNormal, 'SFR');
  972.   createCurrentTimeAccuracySpecTest(
  973.   '1.4.2.2', Media.H264.Webgl720p60fps, Media.AAC.AudioNormal, 'HFR');
  974.  
  975. /**
  976.  * Creates a MSE currentTime PausedAccuracy test to validate if
  977.  * the media.currentTime is accurate to within the given threshold when content
  978.  * is paused. This can be used for video features a standard frame rate
  979.  * or a high frame rate. Test checks the accuracy of media.currentTime at
  980.  * two events: when content is paused and when content is played again after
  981.  * the pause, if either one meets the threshold, test passes.
  982.  */
  983. var createCurrentTimePausedAccuracyTest =
  984.     function(testId, videoStream, audioStream, frameRate, maxDiffInS) {
  985.   const testName = frameRate + 'PausedAccuracy'
  986.       + parseFloat(maxDiffInS * 1000).toFixed(0) + 'ms';
  987.  
  988.   var test = createConformanceTest(testId, testName, 'MSE currentTime', false);
  989.   test.prototype.title = 'Test the currentTime granularity when pause.';
  990.   test.prototype.onsourceopen = function() {
  991.     var runner = this.runner;
  992.     var video = this.video;
  993.     var baseTimeDiff = 0;
  994.     var times = 0;
  995.     var assertTimeAtPlay = false;
  996.     var currentTimeIsAccurate = false;
  997.     var self = this;
  998.     var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  999.     var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  1000.  
  1001.     var videoXhr = runner.XHRManager.createRequest(
  1002.         videoStream.src, function(e) {
  1003.       videoSb.appendBuffer(this.getResponseData());
  1004.  
  1005.       function onTimeUpdate(e) {
  1006.         if (times === 1) {
  1007.           baseTimeDiff = util.ElapsedTimeInS() - video.currentTime;
  1008.         }
  1009.         if (times > 500 || video.currentTime > 10) {
  1010.           video.removeEventListener('timeupdate', onTimeUpdate);
  1011.           video.pause();
  1012.         }
  1013.         ++times;
  1014.       };
  1015.       video.addEventListener('play', function() {
  1016.         if (assertTimeAtPlay) {
  1017.           var timeDiff = util.ElapsedTimeInS() - video.currentTime;
  1018.           var currentTimeDiff = Math.abs(baseTimeDiff - timeDiff);
  1019.           self.log('media.currentTime is ' + currentTimeDiff + 's different' +
  1020.               ' from actual time when video is played after a pause.');
  1021.           currentTimeIsAccurate =
  1022.               currentTimeIsAccurate || (currentTimeDiff <= maxDiffInS);
  1023.           runner.checkEq(
  1024.               currentTimeIsAccurate,
  1025.               true,
  1026.               'media.currentTime diff is within ' + maxDiffInS + 's');
  1027.           assertTimeAtPlay = false;
  1028.           runner.succeed();
  1029.         }
  1030.       });
  1031.       video.addEventListener('pause', function(e) {
  1032.         var timeDiff = util.ElapsedTimeInS() - video.currentTime;
  1033.         var currentTimeDiff = Math.abs(baseTimeDiff - timeDiff);
  1034.         runner.checkEq(video.paused, true, 'media.paused');
  1035.         self.log('meida.currentTime is ' + currentTimeDiff +
  1036.             's different from actual time when video is paused.');
  1037.         currentTimeIsAccurate = currentTimeDiff <= maxDiffInS;
  1038.         assertTimeAtPlay = true;
  1039.         video.play();
  1040.       });
  1041.       video.addEventListener('timeupdate', onTimeUpdate);
  1042.  
  1043.       video.addEventListener('canplaythrough', function(e) {
  1044.         video.play();
  1045.       })
  1046.     }, 0, 2500000);
  1047.     var audioXhr = runner.XHRManager.createRequest(
  1048.         audioStream.src, function(e) {
  1049.       audioSb.appendBuffer(this.getResponseData());
  1050.       videoXhr.send();
  1051.     }, 0, 2500000);
  1052.     audioXhr.send();
  1053.   };
  1054. };
  1055.  
  1056. createCurrentTimePausedAccuracyTest(
  1057.     '1.4.3.1', Media.VP9.Webgl720p30fps, Media.AAC.AudioNormal, 'SFR', 0.032);
  1058. createCurrentTimePausedAccuracyTest(
  1059.     '1.4.3.2', Media.VP9.Webgl720p30fps, Media.AAC.AudioNormal, 'SFR', 0.100);
  1060. createCurrentTimePausedAccuracyTest(
  1061.     '1.4.4.1', Media.VP9.Webgl720p60fps, Media.AAC.AudioNormal, 'HFR', 0.032);
  1062. createCurrentTimePausedAccuracyTest(
  1063.     '1.4.4.2', Media.VP9.Webgl720p60fps, Media.AAC.AudioNormal, 'HFR', 0.100);
  1064.  
  1065. /**
  1066.  * Validate specified mimetype is supported.
  1067.  */
  1068. var createSupportTest = function(testId, mimetype, desc, mandatory) {
  1069.   var test = createConformanceTest(testId, desc + 'Support', 'MSE Formats',
  1070.       mandatory);
  1071.   test.prototype.title =
  1072.       'Test if we support ' + desc + ' with mimetype: ' + mimetype;
  1073.   test.prototype.onsourceopen = function() {
  1074.     try {
  1075.       this.log('Trying format ' + mimetype);
  1076.       var src = this.ms.addSourceBuffer(mimetype);
  1077.     } catch (e) {
  1078.       return this.runner.fail(e);
  1079.     }
  1080.     this.runner.succeed();
  1081.   };
  1082. };
  1083.  
  1084. createSupportTest('1.5.1.1', Media.AAC.mimetype, 'AAC');
  1085. createSupportTest('1.5.2.1', Media.H264.mimetype, 'H264');
  1086. createSupportTest('1.5.3.1', Media.VP9.mimetype, 'VP9');
  1087. createSupportTest('1.5.4.1', Media.Opus.mimetype, 'Opus');
  1088. createSupportTest('1.5.5.1', Media.AV1.mimetype, 'AV1', true);
  1089.  
  1090. /**
  1091.  * Test media with mismatched frame duration and segment timing.
  1092.  */
  1093. var frameTestOnSourceOpen = function() {
  1094.   var runner = this.runner;
  1095.   var media = this.video;
  1096.   var audioStream = Media.AAC.AudioNormal;
  1097.   var videoChain = new FixedAppendSize(new ResetInit(
  1098.       new FileSource(this.filename, runner.XHRManager, runner.timeouts)));
  1099.   var videoSb = this.ms.addSourceBuffer(Media.H264.mimetype);
  1100.   var audioChain = new FixedAppendSize(new ResetInit(
  1101.       new FileSource(audioStream.src, runner.XHRManager, runner.timeouts)));
  1102.   var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  1103.   media.play();
  1104.   playThrough(runner.timeouts, media, 5, 18, videoSb, videoChain,
  1105.               audioSb, audioChain, runner.succeed.bind(runner));
  1106. };
  1107.  
  1108.  
  1109. var testFrameGaps = createConformanceTest('1.8.1.1', 'H264FrameGaps', 'Media');
  1110. testFrameGaps.prototype.title = 'Test media with frame durations of 24FPS ' +
  1111.     'but segment timing corresponding to 23.976FPS';
  1112. testFrameGaps.prototype.filename = Media.H264.FrameGap.src;
  1113. testFrameGaps.prototype.onsourceopen = frameTestOnSourceOpen;
  1114.  
  1115.  
  1116. var testFrameOverlaps = createConformanceTest('1.8.2.1', 'H264FrameOverlaps',
  1117.     'Media');
  1118. testFrameOverlaps.prototype.title = 'Test media with frame durations of ' +
  1119.     '23.976FPS but segment timing corresponding to 24FPS';
  1120. testFrameOverlaps.prototype.filename = Media.H264.FrameOverlap.src;
  1121. testFrameOverlaps.prototype.onsourceopen = frameTestOnSourceOpen;
  1122.  
  1123. /**
  1124.  * Test playback of HE-AAC (High-Efficiency Advanced Audio Coding) with
  1125.  * specified type of SBR signaling.
  1126.  */
  1127. var createHeAacTest = function(testId, audioStream) {
  1128.   var test = createConformanceTest(testId, 'HE-AAC/' +
  1129.       audioStream.get('sbrSignaling') + 'SBR', 'Media');
  1130.   test.prototype.title = 'Test playback of HE-AAC with ' +
  1131.       audioStream.get('sbrSignaling') +  ' SBR signaling.';
  1132.   test.prototype.onsourceopen = function() {
  1133.     var runner = this.runner;
  1134.     var media = this.video;
  1135.     var ms = this.ms;
  1136.     var videoStream = Media.H264.VideoHeAac;
  1137.     var audioSb = this.ms.addSourceBuffer(audioStream.mimetype);
  1138.     var videoSb = this.ms.addSourceBuffer(videoStream.mimetype);
  1139.     var xhr = runner.XHRManager.createRequest(audioStream.src, function(e) {
  1140.       audioSb.addEventListener('update', function() {
  1141.         var xhr2 = runner.XHRManager.createRequest(videoStream.src,
  1142.             function(e) {
  1143.           videoSb.addEventListener('update', function() {
  1144.             ms.endOfStream();
  1145.             media.addEventListener('ended', function(e) {
  1146.               if (media.currentTime > audioStream.duration + 1) {
  1147.                 runner.fail();
  1148.               } else {
  1149.                 runner.checkApproxEq(media.currentTime, audioStream.duration,
  1150.                     'media.currentTime');
  1151.                 runner.succeed();
  1152.               }
  1153.             });
  1154.             media.play();
  1155.           });
  1156.           videoSb.appendBuffer(xhr2.getResponseData());
  1157.         }, 0, videoStream.size);
  1158.         xhr2.send();
  1159.       });
  1160.       audioSb.appendBuffer(xhr.getResponseData());
  1161.     }, 0, audioStream.size);
  1162.     xhr.send();
  1163.   }
  1164. }
  1165.  
  1166. createHeAacTest('1.8.3.1', Media.AAC.AudioLowExplicitHE);
  1167. createHeAacTest('1.8.4.1', Media.AAC.AudioLowImplicitHE);
  1168.  
  1169. return {tests: tests, info: info, viewType: 'default'};
  1170.  
  1171. };
  1172. window.ConformanceTest = ConformanceTest;
  1173.  
  1174. try {
  1175.   exports.getTest = ConformanceTest;
  1176. } catch (e) {
  1177.   // do nothing, this function is not supposed to work for browser, but it's for
  1178.   // Node js to generate json file instead.
  1179. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement