Skip to content

Commit

Permalink
feat: implement AudioWorkletNode's onprocessorerror
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisguttandin committed Mar 23, 2018
1 parent 49ae34b commit 49a68e0
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 77 deletions.
19 changes: 5 additions & 14 deletions src/audio-nodes/audio-worklet-node.ts
Expand Up @@ -27,6 +27,7 @@ import {
TAudioParamMap,
TChannelCountMode,
TChannelInterpretation,
TProcessorErrorEventHandler,
TUnpatchedAudioContext,
TUnpatchedOfflineAudioContext
} from '../types';
Expand Down Expand Up @@ -123,13 +124,12 @@ export class AudioWorkletNode extends NoneAudioDestinationNode<INativeAudioWorkl
}
}

get onprocessorstatechange () {
// @todo No browser does implement the processorState property yet.
return null;
public get onprocessorerror () {
return <TProcessorErrorEventHandler> (<any> this._nativeNode.onprocessorerror);
}

set onprocessorstatechange (value) {
this._nativeNode.onprocessorstatechange = <any> value;
public set onprocessorerror (value) {
this._nativeNode.onprocessorerror = <any> value;
}

get parameters (): TAudioParamMap {
Expand All @@ -144,13 +144,4 @@ export class AudioWorkletNode extends NoneAudioDestinationNode<INativeAudioWorkl
return this._nativeNode.port;
}

get processorState () {
// @todo Chrome Canary does not implement the processorState property.
if (this._nativeNode.processorState === undefined) {
return 'pending';
}

return this._nativeNode.processorState;
}

}
51 changes: 37 additions & 14 deletions src/fakers/audio-worklet-node.ts
Expand Up @@ -3,10 +3,11 @@ import { createNativeConstantSourceNode } from '../helpers/create-native-constan
import {
IAudioWorkletNodeOptions,
IAudioWorkletProcessorConstructor,
INativeAudioWorkletNode,
INativeAudioWorkletNodeFaker
} from '../interfaces';
import { ReadOnlyMap } from '../read-only-map';
import { TNativeAudioParam, TUnpatchedAudioContext, TUnpatchedOfflineAudioContext } from '../types';
import { TNativeAudioParam, TProcessorErrorEventHandler, TUnpatchedAudioContext, TUnpatchedOfflineAudioContext } from '../types';
import { ChannelMergerNodeWrapper } from '../wrappers/channel-merger-node';
import { ChannelSplitterNodeWrapper } from '../wrappers/channel-splitter-node';

Expand Down Expand Up @@ -108,6 +109,9 @@ export class AudioWorkletNodeFaker {
outputChannelSplitterNode.connect(outputChannelMergerNode, i, i);
}

let isActive = true;
let onprocessorerror: null | TProcessorErrorEventHandler = null;

scriptProcessorNode.onaudioprocess = ({ inputBuffer, outputBuffer }: AudioProcessingEvent) => {
for (let i = 0; i < bufferSize; i += 128) {
// @todo Handle multiple inputs ...
Expand All @@ -128,15 +132,31 @@ export class AudioWorkletNodeFaker {
parameters[ name ].set(slicedInputBuffer);
});

/* @todo const result = */audioWorkletProcessor.process(inputs, outputs, parameters);
try {
const activeSourceFlag = audioWorkletProcessor.process(inputs, outputs, parameters);

// @todo Handle multiple outputs ...
for (let j = 0; j < numberOfChannels; j += 1) {
// Bug #5: Safari does not support copyToChannel().
isActive = activeSourceFlag;

outputBuffer
.getChannelData(j)
.set(outputs[0][j], i);
// @todo Handle multiple outputs ...
for (let j = 0; j < numberOfChannels; j += 1) {
// Bug #5: Safari does not support copyToChannel().

outputBuffer
.getChannelData(j)
.set(outputs[0][j], i);
}
} catch (err) {
isActive = false;

if (onprocessorerror !== null) {
onprocessorerror.call(<any> null, new ErrorEvent('processorerror'));
}
}

if (!isActive) {
scriptProcessorNode.onaudioprocess = <any> null;

break;
}
}
};
Expand Down Expand Up @@ -166,19 +186,22 @@ export class AudioWorkletNodeFaker {
get numberOfOutputs () {
return gainNode.numberOfOutputs;
},
get onprocessorstatechange () {
return null;
get onprocessorerror () {
return <INativeAudioWorkletNode['onprocessorerror']> onprocessorerror;
},
set onprocessorerror (value) {
if (value === null || typeof value === 'function') {
onprocessorerror = <any> value;
} else {
onprocessorerror = null;
}
},
get parameters () {
return parameterMap;
},
get port () {
return messageChannel.port2;
},
get processorState () {
// @todo Implement processorState.
return <any> 'pending';
},
addEventListener (...args: any[]) {
return gainNode.addEventListener(args[0], args[1], args[2]);
},
Expand Down
6 changes: 2 additions & 4 deletions src/interfaces/audio-worklet-node.ts
@@ -1,14 +1,12 @@
import { TAudioParamMap, TAudioWorkletProcessorState, TProcessorStateChangeEventHandler } from '../types';
import { TAudioParamMap, TProcessorErrorEventHandler } from '../types';
import { IAudioNode } from './audio-node';

export interface IAudioWorkletNode extends IAudioNode {

onprocessorstatechange: null | TProcessorStateChangeEventHandler;
onprocessorerror: null | TProcessorErrorEventHandler;

readonly parameters: TAudioParamMap;

readonly port: MessagePort;

readonly processorState: TAudioWorkletProcessorState;

}
6 changes: 2 additions & 4 deletions src/interfaces/native-audio-worklet-node.ts
@@ -1,14 +1,12 @@
import { TNativeAudioNode, TNativeAudioParamMap, TNativeAudioWorkletProcessorState } from '../types';
import { TNativeAudioNode, TNativeAudioParamMap } from '../types';

// @todo Since there are no native types yet they need to be crafted.
export interface INativeAudioWorkletNode extends TNativeAudioNode {

onprocessorstatechange: null | ((this: INativeAudioWorkletNode, event: Event) => any);
onprocessorerror: null | ((this: INativeAudioWorkletNode, event: Event) => any);

readonly parameters: TNativeAudioParamMap;

readonly port: MessagePort;

readonly processorState: TNativeAudioWorkletProcessorState;

}
14 changes: 13 additions & 1 deletion src/renderers/audio-worklet-node.ts
Expand Up @@ -202,7 +202,19 @@ export class AudioWorkletNodeRenderer extends AudioNodeRenderer {

// @todo slice the parameters ...

/* @todo const result = */audioWorkletProcessor.process(inputs, outputs, parameters);
try {
const activeSourceFlag = audioWorkletProcessor.process(inputs, outputs, parameters);

if (!activeSourceFlag) {
break;
}
} catch (err) {
if (this._proxy.onprocessorerror !== null) {
this._proxy.onprocessorerror.call(<any> null, new ErrorEvent('processorerror'));
}

break;
}

// @todo Handle multiple outputs ...
for (let j = 0; j < numberOfChannels; j += 1) {
Expand Down
1 change: 0 additions & 1 deletion src/types/audio-worklet-processor-state.ts

This file was deleted.

4 changes: 1 addition & 3 deletions src/types/index.ts
@@ -1,7 +1,6 @@
export * from './audio-context-latency-category';
export * from './audio-context-state';
export * from './audio-param-map';
export * from './audio-worklet-processor-state';
export * from './automation';
export * from './biquad-filter-type';
export * from './channel-count-mode';
Expand All @@ -18,7 +17,6 @@ export * from './native-audio-param';
export * from './native-audio-param-map';
export * from './native-audio-worklet';
export * from './native-audio-worklet-node-options';
export * from './native-audio-worklet-processor-state';
export * from './native-biquad-filter-node';
export * from './native-channel-merger-node';
export * from './native-channel-splitter-node';
Expand All @@ -28,7 +26,7 @@ export * from './native-media-element-audio-source-node';
export * from './native-media-stream-audio-source-node';
export * from './native-oscillator-node';
export * from './oscillator-type';
export * from './processor-state-change-event-handler';
export * from './processor-error-event-handler';
export * from './state-change-event-handler';
export * from './typed-array';
export * from './unpatched-audio-context';
Expand Down
4 changes: 0 additions & 4 deletions src/types/native-audio-worklet-processor-state.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/types/processor-error-event-handler.ts
@@ -0,0 +1,3 @@
import { IAudioWorkletNode } from '../interfaces';

export type TProcessorErrorEventHandler = (this: IAudioWorkletNode, event: Event) => any;
3 changes: 0 additions & 3 deletions src/types/processor-state-change-event-handler.ts

This file was deleted.

17 changes: 17 additions & 0 deletions test/fixtures/failing-processor.js
@@ -0,0 +1,17 @@
class FailingProcessor extends AudioWorkletProcessor { // eslint-disable-line no-undef

constructor () {
super();
}

process () { // eslint-disable-line class-methods-use-this
throw new Error('This is an error thrown inside the process() method.');

return true;
}

}

FailingProcessor.parameterDescriptors = [ ];

registerProcessor('failing-processor', FailingProcessor); // eslint-disable-line no-undef

0 comments on commit 49a68e0

Please sign in to comment.