Skip to content

Commit

Permalink
refactor: clean and test worklet error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
b-ma committed Dec 23, 2024
1 parent 2ae353a commit 9fdf51a
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 11 deletions.
11 changes: 5 additions & 6 deletions js/AudioWorklet.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ const resolveModule = async (moduleUrl) => {
const res = await fetch(moduleUrl);
code = await res.text();
} catch (err) {
throw new Error(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`);
throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
}
} else if (moduleUrl.startsWith('blob:')) {
try {
const blob = resolveObjectURL(moduleUrl);
code = await blob.text();
} catch (err) {
throw new Error(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`);
throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
}
} else {
// get caller site from error stack trace
Expand All @@ -75,7 +75,7 @@ const resolveModule = async (moduleUrl) => {
const res = await fetch(url);
code = await res.text();
} catch (err) {
throw new Error(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`);
throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
}
} else {
const dirname = callerSite.substr(0, callerSite.lastIndexOf(path.sep));
Expand All @@ -85,7 +85,7 @@ const resolveModule = async (moduleUrl) => {
if (existsSync(pathname)) {
absPathname = pathname;
} else {
throw new Error(`Failed to execute 'addModule' on 'AudioWorklet': Cannot resolve module ${moduleUrl}`);
throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': Cannot resolve module ${moduleUrl}`, 'AbortError');
}
}
}
Expand Down Expand Up @@ -128,10 +128,9 @@ class AudioWorklet {
break;
}
case 'node-web-audio-api:worklet:add-module-failed': {
const { promiseId, ctor, name, message } = event;
const { promiseId, err } = event;
const { reject } = this.#idPromiseMap.get(promiseId);
this.#idPromiseMap.delete(promiseId);
const err = new globalThis[ctor](message, name);
reject(err);
break;
}
Expand Down
5 changes: 1 addition & 4 deletions js/AudioWorkletGlobalScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,7 @@ parentPort.on('message', async event => {
parentPort.postMessage({
cmd: 'node-web-audio-api:worklet:add-module-failed',
promiseId,
ctor: err.constructor.name,
name: err.name,
message: err.message,
err,
});
}
break;
Expand All @@ -358,7 +356,6 @@ parentPort.on('message', async event => {
try {
instance = new ctor(options);
} catch (err) {
// @todo - this is not clean at all...
port.postMessage({ cmd: 'node-web-audio-api:worklet:ctor-error', err });
return;
}
Expand Down
3 changes: 2 additions & 1 deletion js/AudioWorkletNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ module.exports = (jsExport, nativeBinding) => {
);

this.#port.on('message', msg => {
// ErrorEvent named processorerror
// Handle 'processorerror' ErrorEvent
// cf. https://webaudio.github.io/web-audio-api/#dom-audioworkletnode-onprocessorerror
switch (msg.cmd) {
case 'node-web-audio-api:worklet:ctor-error': {
const message = `Failed to construct '${parsedName}' AudioWorkletProcessor: ${msg.err.message}`;
Expand Down
57 changes: 57 additions & 0 deletions tests/AudioWorklet.spec.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Blob } from 'node:buffer';
import { assert } from 'chai';
import { AudioContext, OscillatorNode, AudioWorkletNode } from '../index.mjs';
import { delay } from '@ircam/sc-utils';

const scriptTexts = `
class FirstProcessor extends AudioWorkletProcessor {
Expand Down Expand Up @@ -62,6 +63,62 @@ describe('AudioWorklet', () => {

it.skip(`should support loading from cwd relative path`, async () => {});
it.skip(`should support loading from caller relative path`, async () => {});
it.skip(`should support loading from node_modules`, async () => {});
it.skip(`should support loading from url`, async () => {});

it(`should throw clean error`, async () => {
// blob worklets do not support import
const blob = new Blob(['import stuff from "./abc"'], { type: 'application/javascript' });
const objectUrl = URL.createObjectURL(blob);

const audioContext = new AudioContext();
let errored = false;

try {
await audioContext.audioWorklet.addModule(objectUrl);
} catch (err) {
console.log(err);
errored = true;
}

await audioContext.close();
assert.isTrue(errored);
});

it(`should throw clean error`, async () => {
const audioContext = new AudioContext();
let errored = false;

try {
await audioContext.audioWorklet.addModule('./worklets/invalid.worklet.mjs');
} catch (err) {
console.log(err);
errored = true;
}

await audioContext.close();
assert.isTrue(errored);
});
});
});

describe('AudioWorkletNode', () => {
describe('# processor', () => {
it('should throw a clean error when processor constructor is invalid', async () => {
let errored = false;

const audioContext = new AudioContext();
await audioContext.audioWorklet.addModule('./worklets/invalid-ctor.worklet.mjs');

const invalid = new AudioWorkletNode(audioContext, 'invalid-ctor');
invalid.addEventListener('processorerror', (e) => {
console.log(e.error);
errored = true;
});

await delay(100);
await audioContext.close();
assert.isTrue(errored);
});
});
})
13 changes: 13 additions & 0 deletions tests/worklets/invalid-ctor.worklet.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class InvalidCtor extends AudioWorkletProcessor {
constructor() {
super();

this.stuff = invalid;
}

process(inputs, outputs, parameters) {
return true;
}
}

registerProcessor('invalid-ctor', InvalidCtor);
1 change: 1 addition & 0 deletions tests/worklets/invalid.worklet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const a = invalid;
1 change: 1 addition & 0 deletions tests/worklets/invalid.worklet.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const a = invalid;

0 comments on commit 9fdf51a

Please sign in to comment.