I am developing a JavaScript application where the user listens to a pre-recorded sound and simultaneously repeats the text. During this process, the app will record the user’s voice as well.
The issue I’m facing is that when I start recording while playing the sound, the first second of the user’s voice is missed. For example, if the user clicks to start listening and says “one two three four,” the recording captures only “two three four,” and the sound quality is lower, with a slightly metallic tone.
If I record only the user’s voice without playing any sound, everything works perfectly.
Here is the code I am using:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Record and Play Sound</title>
</head>
<body>
<button id="start">Start Recording and Play Sound</button>
<button id="stop">Stop Recording and Sound</button>
<audio id="audioPlayback" controls></audio>
<script>
let mediaRecorder;
let audioChunks = [];
let playAudioContext;
let source;
document.getElementById('start').addEventListener('click', async () => {
// recording
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = event => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(audioBlob);
document.getElementById('audioPlayback').src = audioUrl;
};
mediaRecorder.start(100);
// Play a sound in a separate audio context
playAudioContext = new (window.AudioContext || window.webkitAudioContext)();
const response = await fetch('/mp3');
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await playAudioContext.decodeAudioData(arrayBuffer);
source = playAudioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(playAudioContext.destination);
source.start();
});
document.getElementById('stop').addEventListener('click', () => {
mediaRecorder.stop();
if (source) {
source.stop();
}
if (playAudioContext) {
playAudioContext.close();
}
});
</script>
</body>
</html>
I already tried using AudioWorklet to play the sound, but the result did not improve.