test_playback_rate.html (5766B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test for the playbackRate property </title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 7 <script type="text/javascript" src="manifest.js"></script> 8 </head> 9 <body> 10 <pre id="test"> 11 <script class="testbody" type='application/javascript'> 12 13 let manager = new MediaTestManager; 14 15 function rangeCheck(lhs, rhs, threshold) { 16 var diff = Math.abs(lhs - rhs); 17 if (diff < threshold) { 18 return true; 19 } 20 return false; 21 } 22 23 function checkPlaybackRate(wallclock, media, expected, threshold) { 24 if (rangeCheck(media / wallclock, expected, threshold)) { 25 return true; 26 } 27 return false; 28 } 29 30 // Those value are expected to match those at the top of HTMLMediaElement.cpp. 31 let VERY_SLOW_RATE = 1 / 32, 32 SLOW_RATE = 1 / 16, 33 FAST_RATE = 16, 34 VERY_FAST_RATE = 20, 35 NULL_RATE = 0.0; 36 37 function ontimeupdate(e) { 38 var t = e.target; 39 // Skip short files for SoundTouch doesn't work well on small number of samples. 40 if (t.gotEnded || t.duration < 2) { 41 return; 42 } 43 t.testedForSlowdown = true; 44 if (t.currentTime > t.duration / 2) { 45 t.oldCurrentTime = t.currentTime; 46 t.timestamp = Date.now(); 47 var delta = t.oldCurrentTime, 48 delta_wallclock = (t.timestamp - t.startTimestamp - t.bufferingTime) / 1000; 49 50 t.preservesPitch = false; 51 is(t.preservesPitch, false, t.name + ": If we disable the pitch preservation, it should appear as such."); 52 53 t.bufferingTime = 0; 54 55 is(t.playbackRate, SLOW_RATE, t.name + ": The playback rate shoud be "+SLOW_RATE+"."); 56 ok(checkPlaybackRate(delta_wallclock, delta, SLOW_RATE, 0.25), t.name + ": We are effectively slowing down playback. (" + delta_wallclock + ", " + delta + ")"); 57 t.removeEventListener("timeupdate", ontimeupdate); 58 t.addEventListener("pause", onpaused); 59 t.playbackRate = NULL_RATE; 60 t.oldCurrentTime = t.currentTime; 61 setTimeout(function() { 62 afterNullPlaybackRate(e); 63 }, 100); 64 } 65 } 66 67 function onpaused(e) { 68 var t = e.target; 69 t.pausedReceived = true; 70 } 71 72 function afterNullPlaybackRate(e) { 73 var t = e.target; 74 75 // skip if we have received 'ended' event or 'ended' event is pending. 76 if (t.gotEnded || t.ended) { 77 return; 78 } 79 80 t.testedForNull = true; 81 82 ok(t.currentTime == t.oldCurrentTime, t.name + ": Current time should not change when playbackRate is null (" + t.currentTime + " " + t.oldCurrentTime + ")."); 83 ok(!t.paused, t.name + ": The element should not be in paused state."); 84 t.removeEventListener("paused", onpaused); 85 is(t.pausedReceived, undefined, t.name + ": Paused event should not have been received."); 86 t.timestamp = Date.now(); 87 t.oldCurrentTime = t.currentTime; 88 t.playbackRate = VERY_FAST_RATE; 89 is(t.playbackRate, VERY_FAST_RATE, t.name + ": Playback rate should be clamped to " + VERY_FAST_RATE + "."); 90 } 91 92 function onended(e) { 93 var t = e.target; 94 t.gotEnded = true; 95 96 t.bufferingTime = 0; 97 // If we got "ended" too early, skip these tests. 98 if (t.testedForSlowdown && t.testedForNull) { 99 is(t.playbackRate, FAST_RATE, t.name + ": The playback rate should still be "+FAST_RATE+"."); 100 ok(!t.muted, t.name + ": The audio should be muted when playing at high speed, but should not appear as such."); 101 is(t.currentTime, t.duration, t.name + ": Current time should be equal to the duration (not change by playback rate)."); 102 } 103 finish_test(t); 104 } 105 106 function onratechange(e) { 107 if (!e.target.ratechangecount) { 108 e.target.ratechangecount = 0; 109 } 110 e.target.ratechangecount++; 111 } 112 113 function finish_test(element) { 114 removeNodeAndSource(element); 115 manager.finished(element.token); 116 } 117 118 // These two functions handle the case when the playback pauses for buffering. It 119 // adjusts the timestamps to be accurate. Despite the fact that the web servers 120 // is supposed to be on the same machine, buffering pauses can occur (rarely, 121 // but still). 122 function onplaying(e) { 123 var t = e.target; 124 if (t.bufferingTimestamp != undefined) { 125 t.bufferingTime += (Date.now() - t.bufferingTimestamp); 126 t.bufferingTimestamp = undefined; 127 } 128 } 129 130 function onwaiting(e) { 131 var t = e.target; 132 t.bufferingTimestamp = Date.now(); 133 } 134 135 function onvolumechange(e) { 136 ok(false, e.target.name + ": We should not receive a volumechange event when changing the playback rate."); 137 } 138 139 function startTest(test, token) { 140 let elemType = /^audio/.test(test.type) ? "audio" : "video"; 141 let element = document.createElement(elemType); 142 element.src = test.name; 143 element.name = test.name; 144 element.preload = "metadata"; 145 element.token = token; 146 element.controls = true; 147 element.bufferingTime = 0; 148 document.body.appendChild(element); 149 element.addEventListener("ratechange", onratechange); 150 element.addEventListener("timeupdate", ontimeupdate); 151 element.addEventListener("ended", onended); 152 element.addEventListener("waiting", onwaiting); 153 element.addEventListener("playing", onplaying); 154 element.addEventListener("volumechange", onvolumechange); 155 manager.started(token); 156 element.startTimestamp = Date.now(); 157 is(element.preservesPitch, true, test.name + ": Pitch preservation should be enabled by default."); 158 element.addEventListener("loadedmetadata", function() { 159 is(element.playbackRate, 1.0, test.name + ": playbackRate should be initially 1.0"); 160 is(element.defaultPlaybackRate, 1.0, test.name + ": defaultPlaybackRate should be initially 1.0"); 161 element.playbackRate = VERY_SLOW_RATE; 162 is(element.playbackRate, VERY_SLOW_RATE, test.name + ": PlaybackRate should be " + VERY_SLOW_RATE + "."); 163 element.play(); 164 element.playbackRate = SLOW_RATE; 165 }); 166 } 167 168 manager.runTests(gPlayedTests, startTest); 169 170 </script> 171 </pre> 172 <div id="elements"> 173 </div> 174 </body> 175 </html>