зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1443628 [wpt PR 9883] - Upstream AudioWorklet tests to WPT suite, a=testonly
Automatic update from web-platform-testsUpstream AudioWorklet tests to WPT suite 1. Tests moved: From - src/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/ to - src/third_party/WebKit/LayoutTests/external/wpt/webaudio/ 2. All tests were renamed because of the SecureContext requirement. 3. Updated the script paths. 4. Used a variable for the processor script path. Bug: 817869 Test: All existing tests are passing after updating paths. Change-Id: I7bd6c91c365730e453205f2241cb45986e2c7d3b Reviewed-on: https://chromium-review.googlesource.com/944847 Reviewed-by: Raymond Toy <rtoy@chromium.org> Reviewed-by: Kent Tamura <tkent@chromium.org> Commit-Queue: Kent Tamura <tkent@chromium.org> Cr-Commit-Position: refs/heads/master@{#541281} wpt-commits: a075d92a0c9a272c4140ab66a94db93aa630e355 wpt-pr: 9883 wpt-commits: a075d92a0c9a272c4140ab66a94db93aa630e355 wpt-pr: 9883
This commit is contained in:
Родитель
43da93bc8b
Коммит
1fd3eec3ea
|
@ -294373,6 +294373,41 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-biquadfilternode-interface/.gitkeep": [
|
||||
[
|
||||
{}
|
||||
|
@ -363480,6 +363515,72 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html": [
|
||||
[
|
||||
"/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html",
|
||||
|
@ -599253,6 +599354,78 @@
|
|||
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html": [
|
||||
"d8f2e2d2f6592718f329c1727b63d69035965973",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html": [
|
||||
"de9ecb9c7d9a65052a7a795b0f13c73ed31dbe7b",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html": [
|
||||
"e14996a4d8cd2765d9b78b7ec6d4350dc54bb8da",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html": [
|
||||
"8228071abd6c36908a8b31372185dc0f2dfcdd0a",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html": [
|
||||
"ef7c004225bbb5e6d289a990191b22e2faeabcf3",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html": [
|
||||
"b6701142fd660a6a29fbfc68cb530b70817b3a44",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html": [
|
||||
"b2513b4b5f37b906250b4e1f78eaec80bdc41ef6",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html": [
|
||||
"99284ab790c09dd7a23a6fa5022e8b08b9e3947d",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html": [
|
||||
"a1cd969fe32a5aca7cd90d0d0955132fd1660b9c",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html": [
|
||||
"b70c4e78f5b816a5af789660285ceb91f5dddbfa",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html": [
|
||||
"526bcd8fd99ea61564432ca3026a2b6a0b7315b9",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js": [
|
||||
"6c985b8281cc9aa25eb61fdb436e6cc36f48bb5b",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js": [
|
||||
"0859e9f7bbaf00853f85bbb0e2d6eb4db85578b3",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js": [
|
||||
"1561b9eede1ee15126fdd9674a6d9d63194b66c2",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js": [
|
||||
"80b817db4e8d3f49e4f5fe6e97f8e687d16f3159",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js": [
|
||||
"c2f028c2be836cad2c38a71f96246f84c04323a5",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js": [
|
||||
"47092e4372a196e47612388602b6a3876deb653a",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js": [
|
||||
"c93a76f097b441aaec052516256cc922089b4b75",
|
||||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-biquadfilternode-interface/.gitkeep": [
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"support"
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test the invocation order of AudioWorklet.addModule() and BaseAudioContext
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let sampleRate = 48000;
|
||||
let realtimeContext = new AudioContext();
|
||||
let offlineContext = new OfflineAudioContext(1, sampleRate, sampleRate);
|
||||
|
||||
let filePath = 'processors/dummy-processor.js';
|
||||
|
||||
// Test if the browser does not crash upon addModule() call after the
|
||||
// realtime context construction.
|
||||
audit.define(
|
||||
{label: 'module-loading-after-realtime-context-creation'},
|
||||
(task, should) => {
|
||||
let dummyWorkletNode =
|
||||
new AudioWorkletNode(realtimeContext, 'dummy');
|
||||
dummyWorkletNode.connect(realtimeContext.destination);
|
||||
should(dummyWorkletNode instanceof AudioWorkletNode,
|
||||
'"dummyWorkletNode" is an instance of AudioWorkletNode ' +
|
||||
'from realtime context')
|
||||
.beTrue();
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test if the browser does not crash upon addModule() call after the
|
||||
// offline context construction.
|
||||
audit.define(
|
||||
{label: 'module-loading-after-offline-context-creation'},
|
||||
(task, should) => {
|
||||
let dummyWorkletNode =
|
||||
new AudioWorkletNode(offlineContext, 'dummy');
|
||||
dummyWorkletNode.connect(offlineContext.destination);
|
||||
should(dummyWorkletNode instanceof AudioWorkletNode,
|
||||
'"dummyWorkletNode" is an instance of AudioWorkletNode ' +
|
||||
'from offline context')
|
||||
.beTrue();
|
||||
task.done();
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
realtimeContext.audioWorklet.addModule(filePath),
|
||||
offlineContext.audioWorklet.addModule(filePath)
|
||||
]).then(() => {
|
||||
audit.run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,85 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test AudioWorkletNode's basic AudioParam features
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let sampleRate = 48000;
|
||||
let renderLength = 48000 * 0.6;
|
||||
let context;
|
||||
|
||||
let filePath = 'processors/gain-processor.js';
|
||||
|
||||
// Sets up AudioWorklet and OfflineAudioContext.
|
||||
audit.define('Initializing AudioWorklet and Context', (task, should) => {
|
||||
context = new OfflineAudioContext(1, renderLength, sampleRate);
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
// Verifies the functionality of AudioParam in AudioWorkletNode by
|
||||
// comparing (canceling out) values from GainNode and AudioWorkletNode
|
||||
// with simple gain computation code by AudioParam.
|
||||
audit.define(
|
||||
'Verifying AudioParam in AudioWorkletNode',
|
||||
(task, should) => {
|
||||
let constantSourceNode = new ConstantSourceNode(context);
|
||||
let gainNode = new GainNode(context);
|
||||
let inverterNode = new GainNode(context, {gain: -1});
|
||||
let gainWorkletNode = new AudioWorkletNode(context, 'gain');
|
||||
let gainWorkletParam = gainWorkletNode.parameters.get('gain');
|
||||
|
||||
// Test default value and setter/getter functionality.
|
||||
should(gainWorkletParam.value,
|
||||
'Default gain value of gainWorkletNode')
|
||||
.beEqualTo(Math.fround(0.707));
|
||||
gainWorkletParam.value = 0.1;
|
||||
should(gainWorkletParam.value,
|
||||
'Value of gainWorkletParam after setter = 0.1')
|
||||
.beEqualTo(Math.fround(0.1));
|
||||
|
||||
constantSourceNode.connect(gainNode)
|
||||
.connect(inverterNode)
|
||||
.connect(context.destination);
|
||||
constantSourceNode.connect(gainWorkletNode)
|
||||
.connect(context.destination);
|
||||
|
||||
// With arbitrary times and values, test all possible AudioParam
|
||||
// automations.
|
||||
[gainNode.gain, gainWorkletParam].forEach((param) => {
|
||||
param.setValueAtTime(0, 0);
|
||||
param.linearRampToValueAtTime(1, 0.1);
|
||||
param.exponentialRampToValueAtTime(0.5, 0.2);
|
||||
param.setValueCurveAtTime([0, 2, 0.3], 0.2, 0.1);
|
||||
param.setTargetAtTime(0.01, 0.4, 0.5);
|
||||
});
|
||||
|
||||
// Test if the setter works correctly in the middle of rendering.
|
||||
context.suspend(0.5).then(() => {
|
||||
gainNode.gain.value = 1.5;
|
||||
gainWorkletParam.value = 1.5;
|
||||
context.resume();
|
||||
});
|
||||
|
||||
constantSourceNode.start();
|
||||
context.startRendering().then((renderedBuffer) => {
|
||||
should(renderedBuffer.getChannelData(0),
|
||||
'The rendered buffer')
|
||||
.beConstantValueOf(0);
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test MessagePort in AudioWorkletNode and AudioWorkletProcessor
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let context = new AudioContext();
|
||||
|
||||
let filePath = 'processors/port-processor.js';
|
||||
|
||||
// Creates an AudioWorkletNode and sets an EventHandler on MessagePort
|
||||
// object. The associated PortProcessor will post a message upon its
|
||||
// construction. Test if the message is received correctly.
|
||||
audit.define(
|
||||
'Test postMessage from AudioWorkletProcessor to AudioWorkletNode',
|
||||
(task, should) => {
|
||||
let porterWorkletNode =
|
||||
new AudioWorkletNode(context, 'port-processor');
|
||||
|
||||
// Upon the creation of PortProcessor, it will post a message to the
|
||||
// node with 'created' status.
|
||||
porterWorkletNode.port.onmessage = (event) => {
|
||||
should(event.data.state,
|
||||
'The initial message from PortProcessor')
|
||||
.beEqualTo('created');
|
||||
task.done();
|
||||
};
|
||||
});
|
||||
|
||||
// PortProcessor is supposed to echo the message back to the
|
||||
// AudioWorkletNode.
|
||||
audit.define(
|
||||
'Test postMessage from AudioWorkletNode to AudioWorkletProcessor',
|
||||
(task, should) => {
|
||||
let porterWorkletNode =
|
||||
new AudioWorkletNode(context, 'port-processor');
|
||||
|
||||
porterWorkletNode.port.onmessage = (event) => {
|
||||
// Ignore if the delivered message has |state|. This is already
|
||||
// tested in the previous task.
|
||||
if (event.data.state)
|
||||
return;
|
||||
|
||||
should(event.data.message,
|
||||
'The response from PortProcessor')
|
||||
.beEqualTo('hello');
|
||||
task.done();
|
||||
};
|
||||
|
||||
porterWorkletNode.port.postMessage('hello');
|
||||
});
|
||||
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
audit.run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test sampleRate in AudioWorkletGlobalScope
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let sampleRate = 48000;
|
||||
let renderLength = 512;
|
||||
let context = new OfflineAudioContext(1, renderLength, sampleRate);
|
||||
|
||||
let filePath = 'processors/one-pole-processor.js';
|
||||
|
||||
// Without rendering the context, attempt to access |sampleRate| in the
|
||||
// global scope as soon as it is created.
|
||||
audit.define(
|
||||
'Query |sampleRate| upon AudioWorkletGlobalScope construction',
|
||||
(task, should) => {
|
||||
let onePoleFilterNode =
|
||||
new AudioWorkletNode(context, 'one-pole-filter');
|
||||
let frequencyParam = onePoleFilterNode.parameters.get('frequency');
|
||||
|
||||
should(frequencyParam.maxValue,
|
||||
'frequencyParam.maxValue')
|
||||
.beEqualTo(0.5 * context.sampleRate);
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
audit.run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test currentTime and currentFrame in AudioWorkletGlobalScope
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let sampleRate = 48000;
|
||||
let renderLength = 512;
|
||||
let context = new OfflineAudioContext(1, renderLength, sampleRate);
|
||||
|
||||
let filePath = 'processors/timing-info-processor.js';
|
||||
|
||||
audit.define(
|
||||
'Check the timing information from AudioWorkletProcessor',
|
||||
(task, should) => {
|
||||
let portWorkletNode =
|
||||
new AudioWorkletNode(context, 'timing-info-processor');
|
||||
portWorkletNode.connect(context.destination);
|
||||
|
||||
// Suspend at render quantum boundary and check the timing
|
||||
// information between the main thread and the rendering thread.
|
||||
[0, 128, 256, 384].map((suspendFrame) => {
|
||||
context.suspend(suspendFrame/sampleRate).then(() => {
|
||||
portWorkletNode.port.onmessage = (event) => {
|
||||
should(event.data.currentFrame,
|
||||
'currentFrame from the processor at ' + suspendFrame)
|
||||
.beEqualTo(suspendFrame);
|
||||
should(event.data.currentTime,
|
||||
'currentTime from the processor at '
|
||||
+ context.currentTime)
|
||||
.beEqualTo(context.currentTime);
|
||||
context.resume();
|
||||
};
|
||||
|
||||
portWorkletNode.port.postMessage('query-timing-info');
|
||||
});
|
||||
});
|
||||
|
||||
context.startRendering().then(() => {
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
audit.run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test AudioWorkletNode's dynamic channel count feature
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
<script src="/webaudio/resources/audit-util.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Arbitrary numbers used to align the test with render quantum boundary.
|
||||
let sampleRate = RENDER_QUANTUM_FRAMES * 100;
|
||||
let renderLength = RENDER_QUANTUM_FRAMES * 2;
|
||||
let context;
|
||||
|
||||
let filePath = 'processors/gain-processor.js';
|
||||
|
||||
let testChannelValues = [1, 2, 3];
|
||||
|
||||
// Creates a 3-channel buffer and play with BufferSourceNode. The source
|
||||
// goes through a bypass AudioWorkletNode (gain value of 1).
|
||||
audit.define('setup-buffer-and-worklet', (task, should) => {
|
||||
context = new OfflineAudioContext(testChannelValues.length,
|
||||
renderLength,
|
||||
sampleRate);
|
||||
|
||||
// Explicitly sets the destination channelCountMode and
|
||||
// channelInterpretation to make sure the result does no mixing.
|
||||
context.channeCountMode = 'explicit';
|
||||
context.channelInterpretation = 'discrete';
|
||||
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
let testBuffer = createConstantBuffer(context, 1, testChannelValues);
|
||||
let sourceNode = new AudioBufferSourceNode(context);
|
||||
let gainWorkletNode = new AudioWorkletNode(context, 'gain');
|
||||
|
||||
gainWorkletNode.parameters.get('gain').value = 1.0;
|
||||
sourceNode.connect(gainWorkletNode).connect(context.destination);
|
||||
|
||||
// Suspend the context at 128 sample frames and play the source with
|
||||
// the assigned buffer.
|
||||
context.suspend(RENDER_QUANTUM_FRAMES/sampleRate).then(() => {
|
||||
sourceNode.buffer = testBuffer;
|
||||
sourceNode.loop = true;
|
||||
sourceNode.start();
|
||||
context.resume();
|
||||
});
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
// Verifies if the rendered buffer has all zero for the first half (before
|
||||
// 128 samples) and the expected values for the second half.
|
||||
audit.define('verify-rendered-buffer', (task, should) => {
|
||||
context.startRendering().then(renderedBuffer => {
|
||||
testChannelValues.forEach((value, index) => {
|
||||
let channelData = renderedBuffer.getChannelData(index);
|
||||
should(channelData.subarray(0, RENDER_QUANTUM_FRAMES),
|
||||
'First half of Channel #' + index)
|
||||
.beConstantValueOf(0);
|
||||
should(channelData.subarray(RENDER_QUANTUM_FRAMES, renderLength),
|
||||
'Second half of Channel #' + index)
|
||||
.beConstantValueOf(value);
|
||||
});
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test the construction of AudioWorkletNode with real-time context
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let realtimeContext = new AudioContext();
|
||||
|
||||
let filePath = 'processors/dummy-processor.js';
|
||||
|
||||
// Test if an exception is thrown correctly when AWN constructor is
|
||||
// invoked before resolving |.addModule()| promise.
|
||||
audit.define(
|
||||
{label: 'construction-before-module-loading'},
|
||||
(task, should) => {
|
||||
should(() => new AudioWorkletNode(realtimeContext, 'dummy'),
|
||||
'Creating a node before loading a module should throw.')
|
||||
.throw('InvalidStateError');
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test the construction of AudioWorkletNode after the resolution of
|
||||
// |.addModule()|. Also the constructor must throw an exception when
|
||||
// a unregistered node name was given.
|
||||
audit.define(
|
||||
{label: 'construction-after-module-loading'},
|
||||
(task, should) => {
|
||||
realtimeContext.audioWorklet.addModule(filePath).then(() => {
|
||||
let dummyWorkletNode =
|
||||
new AudioWorkletNode(realtimeContext, 'dummy');
|
||||
should(dummyWorkletNode instanceof AudioWorkletNode,
|
||||
'"dummyWorkletNode" is an instance of AudioWorkletNode')
|
||||
.beTrue();
|
||||
should(() => new AudioWorkletNode(realtimeContext, 'foobar'),
|
||||
'Unregistered name "foobar" must throw an exception.')
|
||||
.throw();
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,149 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test of AudioWorkletNodeOptions
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
const sampleRate = 48000;
|
||||
|
||||
const audit = Audit.createTaskRunner();
|
||||
let context;
|
||||
|
||||
let filePath = 'processors/dummy-processor.js';
|
||||
|
||||
// Load script file and create a OfflineAudiocontext.
|
||||
audit.define('setup', (task, should) => {
|
||||
context = new OfflineAudioContext(1, 1, sampleRate);
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
// Test AudioWorkletNode construction without AudioWorkletNodeOptions.
|
||||
audit.define('without-audio-node-options', (task, should) => {
|
||||
let testNode;
|
||||
should(
|
||||
() => testNode = new AudioWorkletNode(context, 'dummy'),
|
||||
'Creating AudioWOrkletNode without options')
|
||||
.notThrow();
|
||||
should(testNode instanceof AudioWorkletNode,
|
||||
'testNode is instance of AudioWorkletNode').beEqualTo(true);
|
||||
should(testNode.numberOfInputs,
|
||||
'testNode.numberOfInputs (default)').beEqualTo(1);
|
||||
should(testNode.numberOfOutputs,
|
||||
'testNode.numberOfOutputs (default)').beEqualTo(1);
|
||||
should(testNode.channelCount,
|
||||
'testNode.channelCount (default)').beEqualTo(2);
|
||||
should(testNode.channelCountMode,
|
||||
'testNode.channelCountMode (default)').beEqualTo('max');
|
||||
should(testNode.channelInterpretation,
|
||||
'testNode.channelInterpretation (default)')
|
||||
.beEqualTo('speakers');
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test AudioWorkletNode constructor with AudioNodeOptions.
|
||||
audit.define('audio-node-options', (task, should) => {
|
||||
const options = {
|
||||
numberOfInputs: 7,
|
||||
numberOfOutputs: 18,
|
||||
channelCount: 4,
|
||||
channelCountMode: 'clamped-max',
|
||||
channelInterpretation: 'discrete'
|
||||
};
|
||||
const optionsString = JSON.stringify(options);
|
||||
|
||||
let testNode;
|
||||
should(
|
||||
() => testNode = new AudioWorkletNode(context, 'dummy', options),
|
||||
'Creating AudioWOrkletNode with options: ' + optionsString)
|
||||
.notThrow();
|
||||
should(testNode.numberOfInputs,
|
||||
'testNode.numberOfInputs').beEqualTo(options.numberOfInputs);
|
||||
should(testNode.numberOfOutputs,
|
||||
'testNode.numberOfOutputs').beEqualTo(options.numberOfOutputs);
|
||||
should(testNode.channelCount,
|
||||
'testNode.channelCount').beEqualTo(options.channelCount);
|
||||
should(testNode.channelCountMode,
|
||||
'testNode.channelCountMode').beEqualTo(options.channelCountMode);
|
||||
should(testNode.channelInterpretation,
|
||||
'testNode.channelInterpretation')
|
||||
.beEqualTo(options.channelInterpretation);
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test AudioWorkletNode.channelCount.
|
||||
audit.define('channel-count', (task, should) => {
|
||||
const options1 = {channelCount: 17};
|
||||
let testNode = new AudioWorkletNode(context, 'dummy', options1);
|
||||
should(testNode.channelCount, 'testNode.channelCount')
|
||||
.beEqualTo(options1.channelCount);
|
||||
|
||||
const options2 = {channelCount: 0};
|
||||
should(
|
||||
() => new AudioWorkletNode(context, 'dummy', options2),
|
||||
'Creating AudioWorkletNode with channelCount 0')
|
||||
.throw('NotSupportedError');
|
||||
|
||||
const options3 = {channelCount: 33};
|
||||
should(
|
||||
() => new AudioWorkletNode(context, 'dummy', options3),
|
||||
'Creating AudioWorkletNode with channelCount 33')
|
||||
.throw('NotSupportedError');
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test AudioWorkletNode.channelCountMode.
|
||||
audit.define('channel-count-mode', (task, should) => {
|
||||
const channelCountModes = ['max', 'clamped-max', 'explicit'];
|
||||
channelCountModes.forEach((mode) => {
|
||||
const options = {channelCountMode: mode};
|
||||
let testNode = new AudioWorkletNode(context, 'dummy', options);
|
||||
should(testNode.channelCountMode,
|
||||
'testNode.channelCountMode (set via options.' + mode + ')')
|
||||
.beEqualTo(options.channelCountMode);
|
||||
});
|
||||
|
||||
const options1 = {channelCountMode: 'foobar'};
|
||||
should(
|
||||
() => new AudioWorkletNode(context, 'dummy', options1),
|
||||
'Creating AudioWorkletNode with channelCountMode "foobar"')
|
||||
.throw('TypeError');
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Test AudioWorkletNode.channelInterpretation.
|
||||
audit.define('channel-interpretation', (task, should) => {
|
||||
const channelInterpretations = ['speakers', 'discrete'];
|
||||
channelInterpretations.forEach((interpretation) => {
|
||||
const options = {channelInterpretation: interpretation};
|
||||
let testNode = new AudioWorkletNode(context, 'dummy', options);
|
||||
should(
|
||||
testNode.channelInterpretation,
|
||||
'testNode.channelInterpretation (set via options.' +
|
||||
interpretation + ')')
|
||||
.beEqualTo(options.channelInterpretation);
|
||||
});
|
||||
|
||||
const options1 = {channelInterpretation: 'foobar'};
|
||||
should(
|
||||
() => new AudioWorkletNode(context, 'dummy', options1),
|
||||
'Creating AudioWorkletNode with channelCountMode "foobar"')
|
||||
.throw('TypeError');
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test onprocessorerror handler in AudioWorkletNode
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
const sampleRate = 48000;
|
||||
const renderLength = sampleRate * 0.1;
|
||||
let context = new OfflineAudioContext(1, renderLength, sampleRate);
|
||||
|
||||
let filePath = 'processors/error-processor.js';
|
||||
|
||||
// Test |onprocessorerror| called upon failure of processor constructor.
|
||||
audit.define('constructor-error',
|
||||
(task, should) => {
|
||||
let constructorErrorWorkletNode =
|
||||
new AudioWorkletNode(context, 'constructor-error');
|
||||
constructorErrorWorkletNode.onprocessorerror = () => {
|
||||
// Without 'processorerror' event callback, this test will be
|
||||
// timed out.
|
||||
task.done();
|
||||
};
|
||||
});
|
||||
|
||||
// Test |onprocessorerror| called upon failure of process() method.
|
||||
audit.define('process-error',
|
||||
(task, should) => {
|
||||
let processErrorWorkletNode =
|
||||
new AudioWorkletNode(context, 'process-error');
|
||||
processErrorWorkletNode.connect(context.destination);
|
||||
processErrorWorkletNode.onprocessorerror = () => {
|
||||
// Without 'processorerror' event callback, this test will be
|
||||
// timed out.
|
||||
task.done();
|
||||
};
|
||||
|
||||
context.startRendering();
|
||||
});
|
||||
|
||||
// 'error-processor.js' contains 2 class definitions represents an error
|
||||
// in the constructor and an error in the process method respectively.
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
audit.run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test cross-thread passing of AudioWorkletNodeOptions
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
const audit = Audit.createTaskRunner();
|
||||
const context = new AudioContext();
|
||||
|
||||
let filePath = 'processors/option-test-processor.js';
|
||||
|
||||
// Create a OptionTestProcessor and feed |processorData| to it. The
|
||||
// processor should echo the received data to the node's |onmessage|
|
||||
// handler.
|
||||
audit.define('valid-processor-data', (task, should) => {
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
let processorOptions = {
|
||||
description: 'foo',
|
||||
payload: [0, 1, 2, 3]
|
||||
};
|
||||
|
||||
let optionTestNode =
|
||||
new AudioWorkletNode(context, 'option-test-processor', {
|
||||
processorOptions: processorOptions
|
||||
});
|
||||
|
||||
optionTestNode.port.onmessage = (event) => {
|
||||
should(event.data.processorOptions.description,
|
||||
'|description| field in processorOptions from processor("' +
|
||||
event.data.processorOptions.description + '")')
|
||||
.beEqualTo(processorOptions.description,
|
||||
'the field in node constructor options ("' +
|
||||
processorOptions.description + '")');
|
||||
should(event.data.processorOptions.payload,
|
||||
'|payload| array in processorOptions from processor([' +
|
||||
event.data.processorOptions.payload + '])')
|
||||
.beEqualToArray([0, 1, 2, 3],
|
||||
'the array in node constructor options ([' +
|
||||
event.data.processorOptions.payload + '])');
|
||||
task.done();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Passing empty option dictionary should work without a problem.
|
||||
audit.define('empty-option', (task, should) => {
|
||||
context.audioWorklet.addModule(filePath).then(() => {
|
||||
let optionTestNode =
|
||||
new AudioWorkletNode(context, 'option-test-processor');
|
||||
|
||||
optionTestNode.port.onmessage = (event) => {
|
||||
should(Object.keys(event.data).length,
|
||||
'Number of properties in data from processor')
|
||||
.beEqualTo(2);
|
||||
should(event.data.numberOfInputs,
|
||||
'|numberOfInputs| field in data from processor')
|
||||
.beEqualTo(1);
|
||||
should(event.data.numberOfOutputs,
|
||||
'|numberOfOutputs| field in data from processor')
|
||||
.beEqualToArray(1);
|
||||
task.done();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Checking BaseAudioContext.audioWorklet
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
let realtimeContext = new AudioContext();
|
||||
let offlineContext = new OfflineAudioContext(1, 1, 44100);
|
||||
|
||||
// Test if AudioWorklet exists.
|
||||
audit.define('Test if AudioWorklet exists', (task, should) => {
|
||||
should(realtimeContext.audioWorklet instanceof AudioWorklet &&
|
||||
offlineContext.audioWorklet instanceof AudioWorklet,
|
||||
'BaseAudioContext.audioWorklet is an instance of AudioWorklet')
|
||||
.beTrue();
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* @class DummyProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* This processor class demonstrates the bare-bone structure of the processor.
|
||||
*/
|
||||
class DummyProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
// Doesn't do anything here.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('dummy', DummyProcessor);
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @class ConstructorErrorProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*/
|
||||
class ConstructorErrorProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
throw 'ConstructorErrorProcessor: an error thrown from constructor.';
|
||||
}
|
||||
|
||||
process() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @class ProcessErrorProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*/
|
||||
class ProcessErrorProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
process() {
|
||||
throw 'ProcessErrorProcessor: an error throw from process method.';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
registerProcessor('constructor-error', ConstructorErrorProcessor);
|
||||
registerProcessor('process-error', ProcessErrorProcessor);
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @class GainProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* This processor class demonstrates the bare-bone structure of the processor.
|
||||
*/
|
||||
class GainProcessor extends AudioWorkletProcessor {
|
||||
static get parameterDescriptors() {
|
||||
return [
|
||||
{name: 'gain', defaultValue: 0.707}
|
||||
];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
let input = inputs[0];
|
||||
let output = outputs[0];
|
||||
let gain = parameters.gain;
|
||||
for (let channel = 0; channel < input.length; ++channel) {
|
||||
let inputChannel = input[channel];
|
||||
let outputChannel = output[channel];
|
||||
for (let i = 0; i < inputChannel.length; ++i)
|
||||
outputChannel[i] = inputChannel[i] * gain[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('gain', GainProcessor);
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @class OnePoleFilter
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* A simple One-pole filter.
|
||||
*/
|
||||
|
||||
class OnePoleFilter extends AudioWorkletProcessor {
|
||||
|
||||
// This gets evaluated as soon as the global scope is created.
|
||||
static get parameterDescriptors() {
|
||||
return [{
|
||||
name: 'frequency',
|
||||
defaultValue: 250,
|
||||
minValue: 0,
|
||||
maxValue: 0.5 * sampleRate
|
||||
}];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.updateCoefficientsWithFrequency_(250);
|
||||
}
|
||||
|
||||
updateCoefficientsWithFrequency_(frequency) {
|
||||
this.b1_ = Math.exp(-2 * Math.PI * frequency / sampleRate);
|
||||
this.a0_ = 1.0 - this.b1_;
|
||||
this.z1_ = 0;
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
let input = inputs[0];
|
||||
let output = outputs[0];
|
||||
let frequency = parameters.frequency;
|
||||
for (let channel = 0; channel < output.length; ++channel) {
|
||||
let inputChannel = input[channel];
|
||||
let outputChannel = output[channel];
|
||||
for (let i = 0; i < outputChannel.length; ++i) {
|
||||
this.updateCoefficientsWithFrequency_(frequency[i]);
|
||||
this.z1_ = inputChannel[i] * this.a0_ + this.z1_ * this.b1_;
|
||||
outputChannel[i] = this.z1_;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('one-pole-filter', OnePoleFilter);
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* @class OptionTestProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* This processor class demonstrates the option passing feature by echoing the
|
||||
* received |nodeOptions| back to the node.
|
||||
*/
|
||||
class OptionTestProcessor extends AudioWorkletProcessor {
|
||||
constructor(nodeOptions) {
|
||||
super();
|
||||
this.port.postMessage(nodeOptions);
|
||||
}
|
||||
|
||||
process() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('option-test-processor', OptionTestProcessor);
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* @class PortProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* This processor class demonstrates the message port functionality.
|
||||
*/
|
||||
class PortProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.port.onmessage = this.handleMessage.bind(this);
|
||||
this.port.postMessage({
|
||||
state: 'created',
|
||||
timeStamp: currentTime
|
||||
});
|
||||
}
|
||||
|
||||
handleMessage(event) {
|
||||
this.port.postMessage({
|
||||
message: event.data,
|
||||
timeStamp: currentTime
|
||||
});
|
||||
}
|
||||
|
||||
process() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('port-processor', PortProcessor);
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @class TimingInfoProcessor
|
||||
* @extends AudioWorkletProcessor
|
||||
*
|
||||
* This processor class is to test the timing information in AWGS.
|
||||
*/
|
||||
class TimingInfoProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.port.onmessage = this.echoMessage.bind(this);
|
||||
}
|
||||
|
||||
echoMessage(event) {
|
||||
this.port.postMessage({
|
||||
currentTime: currentTime,
|
||||
currentFrame: currentFrame
|
||||
});
|
||||
}
|
||||
|
||||
process() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('timing-info-processor', TimingInfoProcessor);
|
Загрузка…
Ссылка в новой задаче