audiobookshelf/client/cypress/tests/players/SmartSpeedE2E.cy.js
2026-05-07 20:43:30 +01:00

92 lines
3.3 KiB
JavaScript

import LocalAudioPlayer from '../../../players/LocalAudioPlayer'
function createToneSilenceToneBuffer(audioContext) {
const sampleRate = audioContext.sampleRate
const durationSeconds = 1.2
const buffer = audioContext.createBuffer(1, sampleRate * durationSeconds, sampleRate)
const channel = buffer.getChannelData(0)
for (let i = 0; i < channel.length; i++) {
const seconds = i / sampleRate
const isTone = seconds < 0.3 || seconds >= 0.9
channel[i] = isTone ? Math.sin(2 * Math.PI * 440 * seconds) * 0.25 : 0
}
return buffer
}
describe('Smart Speed E2E with real Web Audio', () => {
it('detects silence from real generated audio with the real AudioWorklet', () => {
const AudioContextCtor = window.AudioContext || window.webkitAudioContext
expect(AudioContextCtor).to.exist
const audioContext = new AudioContextCtor()
const messages = []
cy.wrap(audioContext.audioWorklet.addModule('/smart-speed/SilenceDetectorProcessor.js')).then(() => {
const detectorNode = new AudioWorkletNode(audioContext, 'silence-detector')
detectorNode.port.onmessage = (event) => messages.push(event.data)
const source = audioContext.createBufferSource()
source.buffer = createToneSilenceToneBuffer(audioContext)
source.connect(detectorNode)
detectorNode.connect(audioContext.destination)
return audioContext.resume().then(() => {
source.start()
return new Promise((resolve) => {
source.onended = resolve
})
}).then(() => {
detectorNode.disconnect()
return audioContext.close()
})
}).then(() => {
const silenceStart = messages.find((message) => message.type === 'silence-start')
const silenceEnd = messages.find((message) => message.type === 'silence-end')
expect(silenceStart).to.exist
expect(silenceEnd).to.exist
expect(silenceStart.time).to.be.within(250, 450)
expect(silenceEnd.time).to.be.within(850, 1050)
})
})
it('compresses silence in LocalAudioPlayer through the real worklet node', () => {
const localPlayer = new LocalAudioPlayer({})
localPlayer.smartSpeedRatio = 2.5
localPlayer.enableSmartSpeed = true
cy.wrap(localPlayer.setSmartSpeed(true)).then(() => {
expect(localPlayer.usingWebAudio).to.equal(true)
expect(localPlayer.audioContext).to.not.be.null
expect(localPlayer.audioSourceNode).to.not.be.null
expect(localPlayer.silenceDetectorNode).to.not.be.null
expect(localPlayer.silenceDetectorNode.constructor.name).to.equal('AudioWorkletNode')
localPlayer.player.currentTime = 1.0
localPlayer.silenceDetectorNode.port.onmessage({
data: {
type: 'silence-start',
time: localPlayer.audioContext.currentTime * 1000
}
})
expect(localPlayer.player.playbackRate).to.equal(2.5)
localPlayer.player.currentTime = 3.0
localPlayer.silenceDetectorNode.port.onmessage({
data: {
type: 'silence-end',
time: localPlayer.audioContext.currentTime * 1000
}
})
expect(localPlayer.player.playbackRate).to.equal(1.0)
const regions = localPlayer.silenceMap.getRegions()
expect(regions).to.have.lengthOf(1)
expect(localPlayer.timeMapper.totalTimeSaved()).to.be.greaterThan(0)
localPlayer.destroy()
})
})
})