fix: web audio playback quality — gapless scheduling + sample rate debug
- Schedule each playback buffer to start exactly where the last ended (was causing gaps/overlaps with fixed 60ms offset) - Log AudioContext sample rate to console for debugging - Reset playback timeline when falling behind Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,8 @@ function stopCall() {
|
|||||||
|
|
||||||
function startAudioCapture() {
|
function startAudioCapture() {
|
||||||
audioCtx = new AudioContext({ sampleRate: SAMPLE_RATE });
|
audioCtx = new AudioContext({ sampleRate: SAMPLE_RATE });
|
||||||
|
console.log('AudioContext sampleRate:', audioCtx.sampleRate);
|
||||||
|
setStatus('Connected — mic active (sample rate: ' + audioCtx.sampleRate + 'Hz)');
|
||||||
const source = audioCtx.createMediaStreamSource(mediaStream);
|
const source = audioCtx.createMediaStreamSource(mediaStream);
|
||||||
|
|
||||||
// ScriptProcessorNode requires power-of-2 buffer. We use 1024 and
|
// ScriptProcessorNode requires power-of-2 buffer. We use 1024 and
|
||||||
@@ -171,10 +173,11 @@ function startAudioCapture() {
|
|||||||
scriptNode.connect(audioCtx.destination);
|
scriptNode.connect(audioCtx.destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nextPlayTime = 0;
|
||||||
|
|
||||||
function playAudio(pcmInt16) {
|
function playAudio(pcmInt16) {
|
||||||
if (!audioCtx) return;
|
if (!audioCtx) return;
|
||||||
|
|
||||||
// Convert int16 to float32
|
|
||||||
const floatData = new Float32Array(pcmInt16.length);
|
const floatData = new Float32Array(pcmInt16.length);
|
||||||
for (let i = 0; i < pcmInt16.length; i++) {
|
for (let i = 0; i < pcmInt16.length; i++) {
|
||||||
floatData[i] = pcmInt16[i] / 32768.0;
|
floatData[i] = pcmInt16[i] / 32768.0;
|
||||||
@@ -187,9 +190,14 @@ function playAudio(pcmInt16) {
|
|||||||
source.buffer = buffer;
|
source.buffer = buffer;
|
||||||
source.connect(audioCtx.destination);
|
source.connect(audioCtx.destination);
|
||||||
|
|
||||||
// Schedule playback with small buffer to reduce latency
|
// Schedule seamlessly: each buffer starts exactly where the last one ended
|
||||||
const playTime = audioCtx.currentTime + 0.06; // 60ms buffer
|
const now = audioCtx.currentTime;
|
||||||
source.start(playTime);
|
if (nextPlayTime < now) {
|
||||||
|
// Fell behind — reset with small lookahead
|
||||||
|
nextPlayTime = now + 0.04; // 40ms initial buffer
|
||||||
|
}
|
||||||
|
source.start(nextPlayTime);
|
||||||
|
nextPlayTime += buffer.duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startStatsUpdate() {
|
function startStatsUpdate() {
|
||||||
|
|||||||
Reference in New Issue
Block a user