webamp/js/media/detectChannels.js
2018-05-28 15:56:18 -07:00

78 lines
2 KiB
JavaScript

// Get the max value from an array-like
const max = arr => arr.reduce((acc, val) => Math.max(acc, val));
function createAnalysers(source) {
const { context } = source;
const splitter = context.createChannelSplitter();
const leftGain = context.createGain();
const rightGain = context.createGain();
const leftAnalyser = context.createAnalyser();
const rightAnalyser = context.createAnalyser();
source.connect(splitter);
splitter.connect(
leftGain,
0
);
splitter.connect(
rightGain,
1
);
leftGain.connect(leftAnalyser);
rightGain.connect(rightAnalyser);
function destroy() {
// TODO: Safari, and maybe Firefox, don't support passing the destination
// argument which means in Safari, this will disconnect `source` completely,
// which will silence the audio.
source.disconnect(splitter);
splitter.disconnect();
leftGain.disconnect();
rightGain.disconnect();
}
return { left: leftAnalyser, right: rightAnalyser, destroy };
}
const POLL_INTERVAL = 20;
const MAX_CALLS = 100;
export default async function detectChannels(source) {
return new Promise((resolve, reject) => {
const analysers = createAnalysers(source);
const dataArray = new Uint8Array(analysers.left.frequencyBinCount);
let maxLeft = 0;
let maxRight = 0;
let calls = 0;
const unsubscribe = () => {
// eslint-disable-next-line no-use-before-define
clearInterval(intervalHandle);
analysers.destroy();
};
const intervalHandle = setInterval(() => {
analysers.left.getByteFrequencyData(dataArray);
maxLeft = Math.max(maxLeft, max(dataArray));
analysers.right.getByteFrequencyData(dataArray);
maxRight = Math.max(maxRight, max(dataArray));
if (maxLeft > 0) {
if (maxRight > 0) {
resolve(2);
} else {
resolve(1);
}
unsubscribe();
}
if (calls >= MAX_CALLS) {
reject();
unsubscribe();
}
calls++;
}, POLL_INTERVAL);
});
}