Use same audio context/source everywhere

This commit is contained in:
TC
2023-01-08 19:17:00 +01:00
parent fcb92fda84
commit 52b67af59c
5 changed files with 135 additions and 62 deletions

View File

@ -1,53 +1,112 @@
const hark = require("hark/hark.bundle.js");
module.exports = (options) => {
let isSilent = false;
let hasAudioStarted = false;
document.addEventListener("apiLoaded", () => {
const video = document.querySelector("video");
const speechEvents = hark(video, {
threshold: -100, // dB (-100 = absolute silence, 0 = loudest)
interval: 2, // ms
});
const skipSilence = () => {
if (options.onlySkipBeginning && hasAudioStarted) {
return;
}
const smoothing = 0.1;
const threshold = -100; // dB (-100 = absolute silence, 0 = loudest)
const interval = 2; // ms
const history = 10;
const speakingHistory = Array(history).fill(0);
if (isSilent && !video.paused) {
video.currentTime += 0.2; // in s
}
};
document.addEventListener(
"audioCanPlay",
(e) => {
const video = document.querySelector("video");
const audioContext = e.detail.audioContext;
const sourceNode = e.detail.audioSource;
speechEvents.on("speaking", function () {
isSilent = false;
hasAudioStarted = true;
});
// Use an audio analyser similar to Hark
// https://github.com/otalk/hark/blob/master/hark.bundle.js
const analyser = audioContext.createAnalyser();
analyser.fftSize = 512;
analyser.smoothingTimeConstant = smoothing;
const fftBins = new Float32Array(analyser.frequencyBinCount);
speechEvents.on("stopped_speaking", function () {
if (
!(
video.paused ||
video.seeking ||
video.ended ||
video.muted ||
video.volume === 0
)
) {
isSilent = true;
sourceNode.connect(analyser);
analyser.connect(audioContext.destination);
const looper = () => {
setTimeout(() => {
const currentVolume = getMaxVolume(analyser, fftBins);
let history = 0;
if (currentVolume > threshold && isSilent) {
// trigger quickly, short history
for (
let i = speakingHistory.length - 3;
i < speakingHistory.length;
i++
) {
history += speakingHistory[i];
}
if (history >= 2) {
// Not silent
isSilent = false;
hasAudioStarted = true;
}
} else if (currentVolume < threshold && !isSilent) {
for (let i = 0; i < speakingHistory.length; i++) {
history += speakingHistory[i];
}
if (history == 0) {
// Silent
if (
!(
video.paused ||
video.seeking ||
video.ended ||
video.muted ||
video.volume === 0
)
) {
isSilent = true;
skipSilence();
}
}
}
speakingHistory.shift();
speakingHistory.push(0 + (currentVolume > threshold));
looper();
}, interval);
};
looper();
const skipSilence = () => {
if (options.onlySkipBeginning && hasAudioStarted) {
return;
}
if (isSilent && !video.paused) {
video.currentTime += 0.2; // in s
}
};
video.addEventListener("play", function () {
hasAudioStarted = false;
skipSilence();
}
});
});
video.addEventListener("play", function () {
hasAudioStarted = false;
skipSilence();
});
video.addEventListener("seeked", function () {
hasAudioStarted = false;
skipSilence();
});
});
video.addEventListener("seeked", function () {
hasAudioStarted = false;
skipSilence();
});
},
{
passive: true,
}
);
};
function getMaxVolume(analyser, fftBins) {
var maxVolume = -Infinity;
analyser.getFloatFrequencyData(fftBins);
for (var i = 4, ii = fftBins.length; i < ii; i++) {
if (fftBins[i] > maxVolume && fftBins[i] < 0) {
maxVolume = fftBins[i];
}
}
return maxVolume;
}