Skip to content

Commit cf4d073

Browse files
padenotmoz-wptsync-bot
authored andcommitted
Add a WPT to check that various iterable work to specify AudioParam descriptors in AudioWorkletProcessor definition.
Differential Revision: https://phabricator.services.mozilla.com/D65004 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1565464 gecko-commit: 1c13ea72af533273736f64f1da55e6e183def8bc gecko-integration-branch: autoland gecko-reviewers: karlt
1 parent 87d5aa9 commit cf4d073

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed

webaudio/js/helpers.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,35 @@ function runTest(name)
216216

217217
runTestFunction();
218218
}
219+
220+
// Simpler than audit.js, but still logs the message. Requires
221+
// `setup("explicit_done": true)` if testing code that runs after the "load"
222+
// event.
223+
function equals(a, b, msg) {
224+
test(function() {
225+
assert_equals(a, b);
226+
}, msg);
227+
}
228+
function is_true(a, msg) {
229+
test(function() {
230+
assert_true(a);
231+
}, msg);
232+
}
233+
234+
// This allows writing AudioWorkletProcessor code in the same file as the rest
235+
// of the test, for quick one off AudioWorkletProcessor testing.
236+
function URLFromScriptsElements(ids)
237+
{
238+
var scriptTexts = [];
239+
for (let id of ids) {
240+
241+
const e = document.querySelector("script#"+id)
242+
if (!e) {
243+
throw id+" is not the id of a <script> tag";
244+
}
245+
scriptTexts.push(e.innerText);
246+
}
247+
const blob = new Blob(scriptTexts, {type: "application/javascript"});
248+
249+
return URL.createObjectURL(blob);
250+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>
6+
Test get parameterDescriptor as various iterables
7+
</title>
8+
<script src="/resources/testharness.js"></script>
9+
<script src="/resources/testharnessreport.js"></script>
10+
<script src="/webaudio/js/helpers.js"></script>
11+
</head>
12+
13+
<body>
14+
<script id="params">
15+
// A series of AudioParamDescriptors, copied one by one into various iterable
16+
// data structures. This is used by both the processor side and the main
17+
// thread side, so is in a different script tag.
18+
const PARAMS = [
19+
{
20+
name: "a control-rate parameter",
21+
defaultValue: 0.5,
22+
minValue: 0,
23+
maxValue: 1,
24+
automationRate: "a-rate",
25+
},
26+
{
27+
name: "你好",
28+
defaultValue: 2.5,
29+
minValue: 0,
30+
maxValue: 7,
31+
automationRate: "a-rate",
32+
},
33+
{
34+
name: "🎶",
35+
defaultValue: 8.5,
36+
minValue: 0,
37+
maxValue: 11115,
38+
automationRate: "k-rate",
39+
},
40+
];
41+
</script>
42+
<script id="processors" type="worklet">
43+
44+
registerProcessor("set",
45+
class SetParamProcessor extends AudioWorkletProcessor {
46+
static get parameterDescriptors() {
47+
var s = new Set();
48+
s.add(PARAMS[0]);
49+
s.add(PARAMS[1]);
50+
s.add(PARAMS[2]);
51+
return s;
52+
}
53+
constructor() { super(); }
54+
process() {
55+
}
56+
});
57+
58+
registerProcessor("array",
59+
class ArrayParamProcessor extends AudioWorkletProcessor {
60+
static get parameterDescriptors() {
61+
return PARAMS;
62+
}
63+
constructor() { super(); }
64+
process() { }
65+
});
66+
67+
function* gen() {
68+
yield PARAMS[0];
69+
yield PARAMS[1];
70+
yield PARAMS[2];
71+
}
72+
registerProcessor("generator",
73+
class GeneratorParamProcessor extends AudioWorkletProcessor {
74+
static get parameterDescriptors() {
75+
return gen();
76+
}
77+
constructor() { super(); }
78+
process() { }
79+
});
80+
// Test a processor that has a get parameterDescriptors, but it returns
81+
// something that is not iterable.
82+
try {
83+
registerProcessor("invalid",
84+
class InvalidParamProcessor extends AudioWorkletProcessor {
85+
static get parameterDescriptors() {
86+
return 4;
87+
}
88+
constructor() { super(); }
89+
process() { }
90+
});
91+
throw "This should not have been reached.";
92+
} catch (e) {
93+
// unclear how to signal success here, but we can signal failure in the
94+
// developer console
95+
if (e.name != "TypeError") {
96+
throw "This should be TypeError";
97+
}
98+
}
99+
</script>
100+
<script>
101+
setup({ explicit_done: true });
102+
// Mangle the PARAMS object into a map that has the same shape as what an
103+
// AudioWorkletNode.parameter property would
104+
var PARAMS_MAP = new Map();
105+
for (var param of PARAMS) {
106+
var o = param;
107+
var name = o.name;
108+
delete o.name;
109+
PARAMS_MAP.set(name, o);
110+
}
111+
112+
// This compares `lhs` and `rhs`, that are two maplike with the same shape
113+
// as PARAMS_MAP.
114+
function compare(testname, lhs, rhs) {
115+
equals(lhs.size, rhs.size, "Map match in size for " + testname);
116+
var i = 0;
117+
for (var [k, v] of lhs) {
118+
is_true(rhs.has(k), testname + ": " + k + " exists in both maps");
119+
var vrhs = rhs.get(k);
120+
["defaultValue", "minValue", "maxValue", "automationRate"].forEach(
121+
paramKey => {
122+
equals(
123+
v[paramKey],
124+
vrhs[paramKey],
125+
`Values for ${k}.${paramKey} match for ${testname}`
126+
);
127+
}
128+
);
129+
}
130+
}
131+
var ac = new AudioContext();
132+
var url = URLFromScriptsElements(["params", "processors"]);
133+
ac.audioWorklet
134+
.addModule(url)
135+
.then(() => {
136+
["set", "array", "generator"].forEach(iterable => {
137+
test(() => {
138+
var node = new AudioWorkletNode(ac, iterable);
139+
compare(iterable, node.parameters, PARAMS_MAP);
140+
}, `Creating an AudioWorkletNode with a ${iterable} for
141+
parameter descriptor worked`);
142+
});
143+
})
144+
.then(function() {
145+
test(function() {
146+
assert_throws_dom("InvalidStateError", function() {
147+
new AudioWorkletNode(ac, "invalid");
148+
});
149+
}, `Attempting to create an AudioWorkletNode with an non
150+
iterable for parameter descriptor should not work`);
151+
})
152+
.then(function() {
153+
done();
154+
});
155+
</script>
156+
</body>
157+
</html>

0 commit comments

Comments
 (0)