test_mediaElementAudioSourceNodeFidelity.html (4533B)
1 <!DOCTYPE HTML> 2 <html> 3 <meta charset="utf-8"> 4 <head> 5 <title>Test MediaStreamAudioSourceNode doesn't get data from cross-origin media resources</title> 6 <script src="/tests/SimpleTest/SimpleTest.js"></script> 7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 8 </head> 9 <body> 10 <pre id="test"> 11 <script class="testbody" type="text/javascript"> 12 SimpleTest.waitForExplicitFinish(); 13 14 function binIndexForFrequency(frequency, analyser) { 15 return 1 + Math.round(frequency * 16 analyser.fftSize / 17 analyser.context.sampleRate); 18 } 19 20 function debugCanvas(analyser) { 21 var cvs = document.createElement("canvas"); 22 document.body.appendChild(cvs); 23 24 // Easy: 1px per bin 25 cvs.width = analyser.frequencyBinCount; 26 cvs.height = 256; 27 cvs.style.border = "1px solid red"; 28 29 var c = cvs.getContext('2d'); 30 var buf = new Uint8Array(analyser.frequencyBinCount); 31 32 function render() { 33 c.clearRect(0, 0, cvs.width, cvs.height); 34 analyser.getByteFrequencyData(buf); 35 for (var i = 0; i < buf.length; i++) { 36 c.fillRect(i, (256 - (buf[i])), 1, 256); 37 } 38 requestAnimationFrame(render); 39 } 40 requestAnimationFrame(render); 41 } 42 43 44 function checkFrequency(an) { 45 an.getFloatFrequencyData(frequencyArray); 46 // We should have no energy when checking the data largely outside the index 47 // for 440Hz (the frequency of the sine wave), start checking an octave above, 48 // the Opus compression can add some harmonics to the pure since wave. 49 var maxNoiseIndex = binIndexForFrequency(880, an); 50 for (var i = maxNoiseIndex + 1; i < frequencyArray.length; i++) { 51 if (frequencyArray[i] > frequencyArray[maxNoiseIndex]) { 52 maxNoiseIndex = i; 53 } 54 } 55 56 // On the other hand, we should find a peak at 440Hz. Our sine wave is not 57 // attenuated, we're expecting the peak to reach 0dBFs. 58 var index = binIndexForFrequency(440, an); 59 info("energy at 440: " + frequencyArray[index] + 60 ", threshold " + (an.maxDecibels - 10) + 61 "; max noise at index " + maxNoiseIndex + 62 ": " + frequencyArray[maxNoiseIndex] ); 63 if (frequencyArray[index] < (an.maxDecibels - 10)) { 64 return false; 65 } 66 // Let some slack, there might be some noise here because of int -> float 67 // conversion or the Opus encoding. 68 if (frequencyArray[maxNoiseIndex] > an.minDecibels + 40) { 69 return false; 70 } 71 72 return true; 73 } 74 75 var audioElement = new Audio(); 76 audioElement.src = 'sine-440-10s.opus' 77 audioElement.loop = true; 78 var ac = new AudioContext(); 79 var mediaElementSource = ac.createMediaElementSource(audioElement); 80 var an = ac.createAnalyser(); 81 // Use no smoothing as this would just average with previous 82 // getFloatFrequencyData() calls. Non-seamless looping would introduce noise, 83 // and smoothing would spread this into calls after the loop point. 84 an.smoothingTimeConstant = 0; 85 let frequencyArray = new Float32Array(an.frequencyBinCount); 86 87 // Uncomment this to check what the analyser is doing. 88 // debugCanvas(an); 89 90 mediaElementSource.connect(an) 91 92 audioElement.play(); 93 // We want to check the we have the expected audio for at least two loop of 94 // the HTMLMediaElement, piped into an AudioContext. The file is ten seconds, 95 // and we use the default FFT size. 96 var lastCurrentTime = 0; 97 var loopCount = 0; 98 audioElement.onplaying = function() { 99 audioElement.ontimeupdate = function() { 100 // We don't run the analysis when close to loop point or at the 101 // beginning, since looping is not seamless, there could be an 102 // unpredictable amount of silence 103 var rv = checkFrequency(an); 104 info("currentTime: " + audioElement.currentTime); 105 if (audioElement.currentTime < 4 || 106 audioElement.currentTime > 8){ 107 return; 108 } 109 if (!rv) { 110 ok(false, "Found unexpected noise during analysis."); 111 audioElement.ontimeupdate = null; 112 audioElement.onplaying = null; 113 ac.close(); 114 audioElement.src = ''; 115 SimpleTest.finish() 116 return; 117 } 118 ok(true, "Found correct audio signal during analysis"); 119 info(lastCurrentTime + " " + audioElement.currentTime); 120 if (lastCurrentTime > audioElement.currentTime) { 121 info("loopCount: " + loopCount); 122 if (loopCount > 1) { 123 audioElement.ontimeupdate = null; 124 audioElement.onplaying = null; 125 ac.close(); 126 audioElement.src = ''; 127 SimpleTest.finish(); 128 } 129 lastCurrentTime = audioElement.currentTime; 130 loopCount++; 131 } else { 132 lastCurrentTime = audioElement.currentTime; 133 } 134 } 135 } 136 137 </script>