Bug 1408456 - Convert test_analyserNodeOutput.html to a web-platform-test: test-analyser-output.html. r?karlt
This also brings in and convert some utilities we have in Gecko, that will ease
porting more tests.
MozReview-Commit-ID: 2yPZQO504kH
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -31,16 +31,17 @@ support-files =
sine-440-10s.opus
webaudio.js
[test_analyserNode.html]
skip-if = !asan || toolkit != android
[test_analyserScale.html]
skip-if = !asan || toolkit != android
[test_analyserNodeOutput.html]
+skip-if = !asan || toolkit != android
[test_analyserNodePassThrough.html]
[test_analyserNodeWithGain.html]
skip-if = !asan || toolkit != android
[test_analyserNodeMinimum.html]
skip-if = !asan || toolkit != android
[test_AudioBuffer.html]
[test_audioBufferSourceNode.html]
[test_audioBufferSourceNodeEnded.html]
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -380079,16 +380079,22 @@
]
],
"webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html": [
[
"/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html",
{}
]
],
+ "webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html": [
+ [
+ "/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html",
+ {}
+ ]
+ ],
"webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html": [
[
"/webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html",
{}
]
],
"webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html": [
[
@@ -631555,17 +631561,17 @@
"230684ec60fd2e408f9b6014417f3eddfe2dc95a",
"support"
],
"webaudio/js/buffer-loader.js": [
"4d564eae0b3d7d1045626d1f144cd2638dba64e5",
"support"
],
"webaudio/js/helpers.js": [
- "c5d44cf8101c50b59c366ed1971205193f32e1bf",
+ "dff18a7e57adb3847b70fa7f1f3752b591b38d6e",
"support"
],
"webaudio/js/lodash.js": [
"58c3eae918fedad54c56d488a14f99ce87943500",
"support"
],
"webaudio/js/vendor-prefixes.js": [
"3b7d06164273077415b7fc99652355bcf0e10e17",
@@ -631590,16 +631596,20 @@
"webaudio/the-audio-api/the-analysernode-interface/test-analyser-gain.html": [
"c3f5f5969ed0ab58a9df332196e138aef8e693f3",
"testharness"
],
"webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html": [
"cfbeb7283e7375974943ccf689cca73942e6259f",
"testharness"
],
+ "webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html": [
+ "f27d081b9b3df8af7449f130a455b90c6e93ca7b",
+ "testharness"
+ ],
"webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html": [
"1909a2970f0529ad0433c8e6e75733695d44d3e0",
"testharness"
],
"webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html": [
"8478aa405a4641a9c47554529762e85a37d7593a",
"testharness"
],
--- a/testing/web-platform/tests/webaudio/js/helpers.js
+++ b/testing/web-platform/tests/webaudio/js/helpers.js
@@ -16,8 +16,203 @@ function trimEmptyElements(array) {
while (end > 0) {
end--;
if (array[end] !== 0) {
break;
}
}
return array.subarray(start, end);
}
+
+
+function fuzzyCompare(a, b) {
+ return Math.abs(a - b) < 9e-3;
+}
+
+function compareChannels(buf1, buf2,
+ /*optional*/ length,
+ /*optional*/ sourceOffset,
+ /*optional*/ destOffset,
+ /*optional*/ skipLengthCheck) {
+ if (!skipLengthCheck) {
+ assert_equals(buf1.length, buf2.length, "Channels must have the same length");
+ }
+ sourceOffset = sourceOffset || 0;
+ destOffset = destOffset || 0;
+ if (length == undefined) {
+ length = buf1.length - sourceOffset;
+ }
+ var difference = 0;
+ var maxDifference = 0;
+ var firstBadIndex = -1;
+ for (var i = 0; i < length; ++i) {
+ if (!fuzzyCompare(buf1[i + sourceOffset], buf2[i + destOffset])) {
+ difference++;
+ maxDifference = Math.max(maxDifference, Math.abs(buf1[i + sourceOffset] - buf2[i + destOffset]));
+ if (firstBadIndex == -1) {
+ firstBadIndex = i;
+ }
+ }
+ };
+
+ assert_equals(difference, 0, "maxDifference: " + maxDifference +
+ ", first bad index: " + firstBadIndex +
+ " with test-data offset " + sourceOffset + " and expected-data offset " +
+ destOffset + "; corresponding values " + buf1[firstBadIndex + sourceOffset] +
+ " and " + buf2[firstBadIndex + destOffset] + " --- differences");
+}
+
+function compareBuffers(got, expected) {
+ if (got.numberOfChannels != expected.numberOfChannels) {
+ assert_equals(got.numberOfChannels, expected.numberOfChannels,
+ "Correct number of buffer channels");
+ return;
+ }
+ if (got.length != expected.length) {
+ assert_equals(got.length, expected.length,
+ "Correct buffer length");
+ return;
+ }
+ if (got.sampleRate != expected.sampleRate) {
+ assert_equals(got.sampleRate, expected.sampleRate,
+ "Correct sample rate");
+ return;
+ }
+
+ for (var i = 0; i < got.numberOfChannels; ++i) {
+ compareChannels(got.getChannelData(i), expected.getChannelData(i),
+ got.length, 0, 0, true);
+ }
+}
+
+/**
+ * This function assumes that the test is a "single page test" [0], and defines a
+ * single gTest variable with the following properties and methods:
+ *
+ * + numberOfChannels: optional property which specifies the number of channels
+ * in the output. The default value is 2.
+ * + createGraph: mandatory method which takes a context object and does
+ * everything needed in order to set up the Web Audio graph.
+ * This function returns the node to be inspected.
+ * + createGraphAsync: async version of createGraph. This function takes
+ * a callback which should be called with an argument
+ * set to the node to be inspected when the callee is
+ * ready to proceed with the test. Either this function
+ * or createGraph must be provided.
+ * + createExpectedBuffers: optional method which takes a context object and
+ * returns either one expected buffer or an array of
+ * them, designating what is expected to be observed
+ * in the output. If omitted, the output is expected
+ * to be silence. All buffers must have the same
+ * length, which must be a bufferSize supported by
+ * ScriptProcessorNode. This function is guaranteed
+ * to be called before createGraph.
+ * + length: property equal to the total number of frames which we are waiting
+ * to see in the output, mandatory if createExpectedBuffers is not
+ * provided, in which case it must be a bufferSize supported by
+ * ScriptProcessorNode (256, 512, 1024, 2048, 4096, 8192, or 16384).
+ * If createExpectedBuffers is provided then this must be equal to
+ * the number of expected buffers * the expected buffer length.
+ *
+ * + skipOfflineContextTests: optional. when true, skips running tests on an offline
+ * context by circumventing testOnOfflineContext.
+ *
+ * [0]: http://web-platform-tests.org/writing-tests/testharness-api.html#single-page-tests
+ */
+function runTest(name)
+{
+ function runTestFunction () {
+ if (!gTest.numberOfChannels) {
+ gTest.numberOfChannels = 2; // default
+ }
+
+ var testLength;
+
+ function runTestOnContext(context, callback, testOutput) {
+ if (!gTest.createExpectedBuffers) {
+ // Assume that the output is silence
+ var expectedBuffers = getEmptyBuffer(context, gTest.length);
+ } else {
+ var expectedBuffers = gTest.createExpectedBuffers(context);
+ }
+ if (!(expectedBuffers instanceof Array)) {
+ expectedBuffers = [expectedBuffers];
+ }
+ var expectedFrames = 0;
+ for (var i = 0; i < expectedBuffers.length; ++i) {
+ assert_equals(expectedBuffers[i].numberOfChannels, gTest.numberOfChannels,
+ "Correct number of channels for expected buffer " + i);
+ expectedFrames += expectedBuffers[i].length;
+ }
+ if (gTest.length && gTest.createExpectedBuffers) {
+ assert_equals(expectedFrames,
+ gTest.length, "Correct number of expected frames");
+ }
+
+ if (gTest.createGraphAsync) {
+ gTest.createGraphAsync(context, function(nodeToInspect) {
+ testOutput(nodeToInspect, expectedBuffers, callback);
+ });
+ } else {
+ testOutput(gTest.createGraph(context), expectedBuffers, callback);
+ }
+ }
+
+ function testOnNormalContext(callback) {
+ function testOutput(nodeToInspect, expectedBuffers, callback) {
+ testLength = 0;
+ var sp = context.createScriptProcessor(expectedBuffers[0].length, gTest.numberOfChannels, 0);
+ nodeToInspect.connect(sp);
+ sp.onaudioprocess = function(e) {
+ var expectedBuffer = expectedBuffers.shift();
+ testLength += expectedBuffer.length;
+ compareBuffers(e.inputBuffer, expectedBuffer);
+ if (expectedBuffers.length == 0) {
+ sp.onaudioprocess = null;
+ callback();
+ }
+ };
+ }
+ var context = new AudioContext();
+ runTestOnContext(context, callback, testOutput);
+ }
+
+ function testOnOfflineContext(callback, sampleRate) {
+ function testOutput(nodeToInspect, expectedBuffers, callback) {
+ nodeToInspect.connect(context.destination);
+ context.oncomplete = function(e) {
+ var samplesSeen = 0;
+ while (expectedBuffers.length) {
+ var expectedBuffer = expectedBuffers.shift();
+ assert_equals(e.renderedBuffer.numberOfChannels, expectedBuffer.numberOfChannels,
+ "Correct number of input buffer channels");
+ for (var i = 0; i < e.renderedBuffer.numberOfChannels; ++i) {
+ compareChannels(e.renderedBuffer.getChannelData(i),
+ expectedBuffer.getChannelData(i),
+ expectedBuffer.length,
+ samplesSeen,
+ undefined,
+ true);
+ }
+ samplesSeen += expectedBuffer.length;
+ }
+ callback();
+ };
+ context.startRendering();
+ }
+
+ var context = new OfflineAudioContext(gTest.numberOfChannels, testLength, sampleRate);
+ runTestOnContext(context, callback, testOutput);
+ }
+
+ testOnNormalContext(function() {
+ if (!gTest.skipOfflineContextTests) {
+ testOnOfflineContext(function() {
+ testOnOfflineContext(done, 44100);
+ }, 48000);
+ } else {
+ done();
+ }
+ });
+ };
+
+ runTestFunction();
+}
copy from dom/media/webaudio/test/test_analyserNodeOutput.html
copy to testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html
--- a/dom/media/webaudio/test/test_analyserNodeOutput.html
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html
@@ -1,20 +1,17 @@
-<!DOCTYPE HTML>
+<!DOCTYPE html>
<html>
<head>
- <title>Test AnalyserNode</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="text/javascript" src="webaudio.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
+ <meta charset="utf-8">
+ <title>AnalyserNode output</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/webaudio/js/helpers.js"></script>
+ <script>
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var analyser = context.createAnalyser();
@@ -23,21 +20,22 @@ var gTest = {
source.connect(analyser);
source.start(0);
return analyser;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
- this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
+ this.buffer.getChannelData(0)[i] = Math.sin(
+ 440 * 2 * Math.PI * i / context.sampleRate
+ );
}
return [this.buffer];
- },
+ }
};
-runTest();
-
-</script>
-</pre>
+runTest("AnalyserNode output");
+ </script>
+</head>
</body>
</html>