0

WebAudio/AudioBuffer tests: Audit.js to testharness.js

This change migrates WebAudio tests from the custom `audit.js` framework
to the W3C-standard `testharness.js` specifically targeting dir
third_party/blink/web_tests/webaudio/AudioBuffer/ , supporting
Chromium's ongoing effort to deprecate `audit.js` in favor of a more
consistent testing approach.

The following test files have been updated:
- audiobuffer-resample.html

These updates remove the dependency on `audit.js`, improving
maintainability and aligning Chromium's web tests with the W3C test
harness.

Bug: 396477778
Change-Id: Ia2e9c862a6d07ecf979e7ee99a8fc7b8aef7a52d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6342655
Commit-Queue: Michael Wilson <mjwilson@chromium.org>
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1432878}
This commit is contained in:
Muhammad Saqlain
2025-03-14 11:10:53 -07:00
committed by Chromium LUCI CQ
parent 1c5a3e0a2b
commit a4efd11d2b
2 changed files with 71 additions and 90 deletions
AUTHORS
third_party/blink/web_tests/webaudio/AudioBuffer

@@ -1042,6 +1042,7 @@ Momoko Hattori <momohatt10@gmail.com>
Mostafa Sedaghat joo <mostafa.sedaghat@gmail.com> Mostafa Sedaghat joo <mostafa.sedaghat@gmail.com>
Mrunal Kapade <mrunal.kapade@intel.com> Mrunal Kapade <mrunal.kapade@intel.com>
Muhammad Mahad <mahadtxt@gmail.com> Muhammad Mahad <mahadtxt@gmail.com>
Muhammad Saqlain <2mesaqlain@gmail.com>
Munira Tursunova <moonira@google.com> Munira Tursunova <moonira@google.com>
Myeongjin Cho <myeongjin.cho@navercorp.com> Myeongjin Cho <myeongjin.cho@navercorp.com>
Myles C. Maxfield <mymax@amazon.com> Myles C. Maxfield <mymax@amazon.com>

@@ -1,115 +1,95 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title> <title>AudioBuffer Resampling</title>
audiobuffer-resample.html
</title>
<script src="../../resources/testharness.js"></script> <script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script> <script src="../../resources/testharnessreport.js"></script>
<script src="../resources/audit-util.js"></script> <script src="../resources/audit-util.js"></script>
<script src="../resources/audit.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script>
let audit = Audit.createTaskRunner(); "use strict";
// These are global to make debugging a little easier.
let context; let context;
let buffer; // Frequency of the sine wave.
let source; const TONE_FREQUENCY = 440;
let renderedData; // Duration of the test.
let trueData; const LENGTH_SECONDS = 0.5;
let signalEnergy;
let noiseEnergy;
let maxError;
// Context sample rate. /**
let sampleRate = 48000; * Generates a sine wave in a mono AudioBuffer.
// The sample rate of the buffer. * @param {BaseAudioContext} context - The audio context.
let bufferRate = 3000; * @param {number} frequency - Frequency of the sine wave.
// The audio buffer is a sine wave of this frequency. * @param {number} sampleRate - Sample rate for the buffer.
let toneFrequency = 440; * @return {AudioBuffer} The generated AudioBuffer.
// How long test is */
let lengthInSeconds = 0.5; function createSineBuffer(context, frequency, sampleRate) {
// The maximum allowed peak error between the actual and true output. This const buffer = new AudioBuffer({
// value was experimentally determined for the given bufferRate. numberOfChannels: 1,
let peakThreshold = 0.11; length: LENGTH_SECONDS * sampleRate,
// The minimum SNR allowed between the actual and true output. sampleRate: sampleRate
let snrThreshold = 22.35; });
const omega = 2 * Math.PI * frequency / sampleRate;
// Generate a sine wave in an AudioBuffer using the given |freq|. The const channelData = buffer.getChannelData(0);
// AudioBuffer has the sample rate of |rate|. for (let k = 0; k < channelData.length; ++k) {
function createSineBuffer(context, freq, rate) { channelData[k] = Math.sin(omega * k);
let buf = context.createBuffer(1, lengthInSeconds * rate, rate); }
let omega = 2 * Math.PI * freq / rate; return buffer;
let signal = buf.getChannelData(0);
let length = signal.length;
for (let k = 0; k < length; ++k)
signal[k] = Math.sin(omega * k);
return buf;
} }
// Check the output against the expected output. /**
function checkResult(buffer, should) { * Checks the rendered audio against a reference sine wave.
renderedData = buffer.getChannelData(0); * Computes peak error and SNR, and asserts that they meet thresholds.
let length = renderedData.length; * @param {AudioBuffer} buffer - The rendered audio buffer.
// Generate a reference sine wave at the context rate */
let trueReference = function checkResult(buffer) {
createSineBuffer(context, toneFrequency, context.sampleRate); let renderedData = buffer.getChannelData(0);
trueData = trueReference.getChannelData(0); // Generate reference sine wave at the context's sample rate.
const referenceBuffer = createSineBuffer(
// To compare the actual output against the reference, we compute the context, TONE_FREQUENCY, context.sampleRate);
// peak error and the SNR between the two. const referenceData = referenceBuffer.getChannelData(0);
signalEnergy = 0; let signalEnergy = 0;
noiseEnergy = 0; let noiseEnergy = 0;
maxError = -1; let maxError = -1;
const halfLength = Math.floor(renderedData.length / 2);
let success = true; for (let k = 0; k < halfLength; ++k) {
const diff = renderedData[k] - referenceData[k];
// Compute the peak error and the SNR.
for (let k = 0; k < length / 2; ++k) {
let diff = renderedData[k] - trueData[k];
noiseEnergy += diff * diff; noiseEnergy += diff * diff;
signalEnergy += trueData[k] * trueData[k]; signalEnergy += referenceData[k] * referenceData[k];
if (Math.abs(diff) > maxError) maxError = Math.max(maxError, Math.abs(diff));
maxError = Math.abs(diff);
} }
let snr; // Minimum allowed signal-to-noise ratio.
const SNR_THRESHOLD = 22.35;
if (noiseEnergy == 0) // Maximum allowed peak error.
snr = 1000; const PEAK_THRESHOLD = 0.11;
else const snr =
snr = 10 * Math.log10(signalEnergy / noiseEnergy); noiseEnergy === 0
? 1000
should(maxError, 'Peak error between actual and reference data') : 10 * Math.log10(signalEnergy / noiseEnergy);
.beLessThan(peakThreshold); assert_less_than(
maxError, PEAK_THRESHOLD, "Peak error should be within threshold");
should(snr, 'SNR').beGreaterThan(snrThreshold); assert_greater_than(
snr, SNR_THRESHOLD, "SNR should be above threshold");
} }
audit.define('Test resampling of an AudioBuffer', function(task, should) { // Define the asynchronous test using promise_test().
promise_test(async () => {
// Context sample rate.
const SAMPLE_RATE = 48000;
// Buffer's sample rate.
const BUFFER_RATE = 3000;
context = new OfflineAudioContext( context = new OfflineAudioContext(
1, lengthInSeconds * sampleRate, sampleRate); 1, LENGTH_SECONDS * SAMPLE_RATE, SAMPLE_RATE);
// Create a sine buffer at a different sample rate to force resampling.
// Create a sine wave in a buffer that's different from the context rate const buffer = createSineBuffer(context, TONE_FREQUENCY, BUFFER_RATE);
// to test resampling. let source = new AudioBufferSourceNode(context);
buffer = createSineBuffer(context, toneFrequency, bufferRate);
source = context.createBufferSource();
source.buffer = buffer; source.buffer = buffer;
source.connect(context.destination); source.connect(context.destination);
source.start(); source.start();
const renderedBuffer = await context.startRendering();
context.startRendering() checkResult(renderedBuffer);
.then(function(buffer) { }, "Resampling of an AudioBuffer");
checkResult(buffer, should);
})
.then(task.done.bind(task));
});
audit.run();
</script> </script>
</body> </body>
</html> </html>