Reputation: 51
I’m trying to understand how AudioWorklet
is working and made some tests.
So far, I have a huge “cracking” problem when I let the browser play the sound in the background and do something else (e.g. opening a CPU-heavy application like Photoshop or VSCode and move the window around).
At first I thought it was a hardware problem. I upgraded to Catalina, removed any system audio extension I found, but it’s the same on Android, and some other friends’ computers (Mac, PC).
I’m using Version 1.0.1 Chromium: 78.0.3904.108 (Official Build) (64-bit) myself.
This YouTube video demonstrates the cracking audio issue.
I made two CodePen demos you can test here:
Web Audio Cracks (Vanila + no Worklet):
const ctx = new(window.AudioContext || window.webkitAudioContext)();
const request = new XMLHttpRequest();
const gainNode = ctx.createGain();
const sourceNode = ctx.createBufferSource();
request.open('GET', 'https://poppublic.s3.amazonaws.com/other/2.mp3', true);
request.responseType = 'arraybuffer';
request.onload = () => {
ctx.decodeAudioData(request.response, buffer => {
sourceNode.buffer = buffer;
console.log(sourceNode.buffer.sampleRate);
});
};
request.onerror = function(e) {
console.log('HTTP error', e);
};
request.send();
play = () => {
sourceNode.connect(gainNode);
gainNode.connect(ctx.destination);
sourceNode.start(0);
}
stop = () => {
sourceNode.stop(0);
}
<button onClick="play()">Play</button>
<button onClick="stop()">Stop</button>
Web Audio Cracks (Vanila + Worklet):
const ctx = new(window.AudioContext || window.webkitAudioContext)();
const request = new XMLHttpRequest();
let gainNode = null;
let sourceNode = null;
let buffer = null;
let worklet = null;
try {
const script = 'https://poppublic.s3.amazonaws.com/other/worklet/processor.js';
ctx.audioWorklet.addModule(script).then(() => {
worklet = new AudioWorkletNode(ctx, 'popscord-processor')
request.open('GET', 'https://poppublic.s3.amazonaws.com/other/2.mp3', true);
request.responseType = 'arraybuffer';
request.onload = () => {
ctx.decodeAudioData(request.response, buff => {
buffer = buff;
console.log(buff.sampleRate);
});
};
request.onerror = function(e) {
console.log('HTTP error', e);
};
request.send();
});
} catch (e) {
this.setState({
moduleLoaded: false
});
console.log('Failed to load module', e);
}
play = () => {
stop();
gainNode = ctx.createGain();
sourceNode = ctx.createBufferSource();
sourceNode.buffer = buffer;
sourceNode.connect(gainNode);
gainNode.connect(ctx.destination);
sourceNode.start(0);
}
stop = () => {
try {
sourceNode.disconnect();
gainNode.disconnect();
sourceNode.stop(0);
} catch (e) {
console.log(e.message)
}
}
<button onClick="play()">Play</button>
<button onClick="stop()">Stop</button>
The piano MP3 you’ll hear is a 48000Hz / 32bits / 320kb audio recorded in studio.
Before filing any bugs, I need to make sure my code is correct. Maybe I’m not chaining the things the way it should.
Upvotes: 5
Views: 1898
Reputation: 6048
When using a worklet, the default priority of the audio thread is normal. This is not good for audio as you've seen by running webaudio and then moving a window around.
What you can do is go to chrome://flags, search for worklet and enable the flag named "Use realtime priority thread for Audio Worklet". This should help on mac and windows. I don't know if it will make a difference on Android.
If you are hearing cracks with WebAudio without a worklet, as you do in your first codepen example, then that's unexpected and you really should file an issue on that.
Upvotes: 3