Skip to content

Commit b8d668b

Browse files
authored
Merge pull request #42 from ircam-ismm/feature/wpt-harness
Some work in progress on running the web-platform-tests suite for WebAudio
2 parents 646abec + 1a3e918 commit b8d668b

31 files changed

+683
-174
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "wpt"]
2+
path = wpt
3+
url = git@github.com:orottier/wpt.git

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ version = "0.14.0"
1010
crate-type = ["cdylib"]
1111

1212
[dependencies]
13-
napi = {version="2.13", features=["napi6"]}
13+
napi = {version="2.13", features=["napi6", "tokio_rt"]}
1414
napi-derive = "2.13"
15-
web-audio-api = "0.38"
15+
web-audio-api = "0.39"
1616
# web-audio-api = { path = "../web-audio-api-rs" }
1717

1818
[target.'cfg(all(any(windows, unix), target_arch = "x86_64", not(target_env = "musl")))'.dependencies]

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ The npm `postversion` script rely on [`cargo-bump`](https://crates.io/crates/car
129129
cargo install cargo-bump
130130
```
131131

132+
## Running the web-platform-test suite
133+
134+
Follow the steps for 'Manual Build' first. Then checkout the web-platform-tests submodule with:
135+
136+
```
137+
git submodule init
138+
git submodule update
139+
```
140+
141+
Then run:
142+
143+
```
144+
npm run wpt # build in debug mode and run all wpt test
145+
npm run wpt:only # run all wpt test without build
146+
npm run wpt -- --list # list all wpt test files
147+
npm run wpt -- --filter <string> # apply <string> filter on executed/listed wpt tests
148+
```
149+
150+
Avai
151+
132152
## License
133153

134154
[BSD-3-Clause](./LICENSE)

bin/wpt-harness.mjs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import path from 'path';
2+
import wptRunner from 'wpt-runner';
3+
import chalk from 'chalk';
4+
import { program } from 'commander';
5+
6+
import * as nodeWebAudioAPI from '../index.mjs';
7+
8+
program
9+
.option('--list', 'List the name of the test files')
10+
.option('--with_crashtests', 'Also run crashtests')
11+
.option('--filter <string>', 'Filter executed OR listed test files', '.*');
12+
13+
program.parse(process.argv);
14+
15+
const options = program.opts();
16+
17+
// -------------------------------------------------------
18+
// Some helpers
19+
// -------------------------------------------------------
20+
const INDENT_SIZE = 2;
21+
22+
function indent(string, times) {
23+
const prefix = " ".repeat(times);
24+
return string.split("\n").map(l => prefix + l).join("\n");
25+
}
26+
27+
// -------------------------------------------------------
28+
// WPT Runner configuration options
29+
// -------------------------------------------------------
30+
const testsPath = 'wpt/webaudio';
31+
const rootURL = 'webaudio';
32+
33+
// monkey patch `window` with our web audio API
34+
const setup = window => {
35+
Object.assign(window, nodeWebAudioAPI);
36+
37+
// seems required (weirdly...), cf. `the-audiobuffer-interface/audiobuffer.html`
38+
window.Float32Array = Float32Array;
39+
}
40+
41+
const filterRe = new RegExp(`${options.filter}`);
42+
43+
const filter = (name) => {
44+
if (!options.with_crashtests && name.includes('/crashtests/')) {
45+
return false;
46+
}
47+
if (name.includes('/resources/')) {
48+
return false;
49+
}
50+
if (filterRe.test(name)) {
51+
if (options.list) {
52+
console.log(name);
53+
return false;
54+
} else {
55+
return true;
56+
}
57+
} else {
58+
return false;
59+
}
60+
};
61+
62+
// reporter, adapted from default console reporter
63+
// https://github.com/domenic/wpt-runner/blob/master/lib/console-reporter.js
64+
let numPass = 0;
65+
let numFail = 0;
66+
let typeErrorFail = 0;
67+
68+
const reporter = {
69+
startSuite: name => {
70+
console.log(`\n ${chalk.bold.underline(path.join(testsPath, name))}\n`);
71+
},
72+
pass: message => {
73+
numPass += 1;
74+
console.log(chalk.dim(indent(chalk.green("√ ") + message, INDENT_SIZE)));
75+
},
76+
fail: message => {
77+
if (/threw "Error" instead of/.test(message)) {
78+
typeErrorFail += 1;
79+
console.log(chalk.bold.yellow(indent(`| ${message}`, INDENT_SIZE)));
80+
} else {
81+
numFail += 1;
82+
console.log(chalk.bold.red(indent(`\u00D7 ${message}`, INDENT_SIZE)));
83+
}
84+
},
85+
reportStack: stack => {
86+
// console.log(chalk.dim(indent(stack, INDENT_SIZE * 2)))
87+
},
88+
};
89+
90+
// -------------------------------------------------------
91+
// Run test suite
92+
// -------------------------------------------------------
93+
try {
94+
const failures = await wptRunner(testsPath, { rootURL, setup, filter, reporter });
95+
96+
console.log(`\n ${chalk.bold.underline('RESULTS:')}`);
97+
console.log(chalk.bold(` - # pass: ${numPass}`));
98+
console.log(chalk.bold(` - # fail: ${numFail}`));
99+
console.log(chalk.bold(` - # type error issues: ${typeErrorFail}`));
100+
101+
process.exit(failures);
102+
} catch (e) {
103+
console.error(e.stack);
104+
process.exit(1);
105+
}

examples/offline.mjs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,55 @@
11
import { AudioContext, OfflineAudioContext } from '../index.mjs';
22

3-
const offline = new OfflineAudioContext(1, 44100, 44100);
3+
const offline = new OfflineAudioContext(1, 48000, 48000);
44

5-
const osc = offline.createOscillator();
6-
osc.connect(offline.destination);
7-
osc.frequency.value = 220;
8-
osc.start(0);
9-
osc.stop(1);
5+
offline.suspend(128 / 48000).then(() => {
6+
console.log("suspend");
7+
8+
const osc = offline.createOscillator();
9+
osc.connect(offline.destination);
10+
osc.frequency.value = 220;
11+
osc.start(0);
12+
13+
console.log("resume");
14+
offline.resume();
15+
});
1016

1117
const buffer = await offline.startRendering();
18+
console.log("buffer duration:", buffer.duration);
19+
20+
// dirty check the audio buffer
21+
const channelData = buffer.getChannelData(0);
22+
23+
for (let i = 0; i < 48000; i++) {
24+
// before suspend the graph is empty
25+
if (i < 128) {
26+
if (channelData[i] !== 0) {
27+
throw new Error('should be zero')
28+
}
29+
// first sine sample is zero
30+
} else if (i === 128) {
31+
if (channelData[i] !== 0) {
32+
throw new Error('should be zero')
33+
}
34+
} else {
35+
// should ha ve a sine wave, hopefully without zero values :)
36+
if (channelData[i] === 0) {
37+
throw new Error(`should not be zero ${i}`);
38+
console.log(channelData[i])
39+
}
40+
}
41+
}
1242

1343
const latencyHint = process.env.WEB_AUDIO_LATENCY === 'playback' ? 'playback' : 'interactive';
1444
const online = new AudioContext({ latencyHint });
1545

1646
const src = online.createBufferSource();
47+
// src.loop = true;
1748
src.buffer = buffer;
49+
src.loop = true;
1850
src.connect(online.destination);
1951
src.start();
2052

21-
await new Promise(resolve => setTimeout(resolve, 1000));
53+
await new Promise(resolve => setTimeout(resolve, 2000));
2254

2355
await online.close();

0 commit comments

Comments
 (0)