Closed abhijeet-toptal closed 1 month ago
Unfortunately this kind of error is difficult to reproduce. It indicates that somehow two encodings where started where there should only be one. Could you please provide a minimal example which reproduces the error?
It may also depend on the browser. It's therefore interesting to know if this is happening in all browsers or only in a certain one.
I encountered similar error when I was trying to start a recorder on an inactive stream - this was an issue with React hooks on my part. This also may be cause by strict
mode rendering twice if your hooks are not properly built.
Hi @Rashair, thanks for letting me know.
Did that happen only in one browser or in all browsers? If it was only one which one was it? I'm curious because the code path is different depending on the browser.
I'm sure it happened in Chrome, I don't think I've tested it on other browsers.
Could that be an issue with hot module replacement?
I'm not too familiar with the way it works. But I could imagine the error can occur when the Web Worker which does the actual encoding is kept alive but the main thread code somehow gets refreshed. The result would be that their shared state gets out of sync.
I've had this issue using next 14 with the pages router. Will ssr cause it?
To be honest, I don't know. I'm happy to debug this further with a minimal test case to reproduce the error. But without a way to reproduce it, it's very hard to know what's actually going on.
I face the same issue. and following is my code.
import { IMediaRecorder, MediaRecorder, register } from 'extendable-media-recorder';
import { connect } from 'extendable-media-recorder-wav-encoder';
function init() {
connect().then(async (v) => {
await register(v)
})
}
init()
export class WavRecorder {
private readonly recorder: IMediaRecorder
private readonly blob: Promise<Blob>
private readonly audioContext: AudioContext
private readonly mediaStreamAudioSourceNode: MediaStreamAudioSourceNode
private readonly mediaStreamAudioDestinationNode: MediaStreamAudioDestinationNode
constructor(stream: MediaStream) {
this.audioContext = new AudioContext({ sampleRate: 16000 }); // Force sample rate to 16000.
this.mediaStreamAudioSourceNode = new MediaStreamAudioSourceNode(this.audioContext, { mediaStream: stream });
this.mediaStreamAudioDestinationNode = new MediaStreamAudioDestinationNode(this.audioContext, {
channelCount: 1, // Force channel to 1. If channel count is 2, voice recognize may be error.
channelCountMode: "explicit", // Apply channelCount value.
});
this.mediaStreamAudioSourceNode.connect(this.mediaStreamAudioDestinationNode);
const chunks: Blob[] = []
const mediaRecorder = new MediaRecorder(this.mediaStreamAudioDestinationNode.stream, { mimeType: 'audio/wav' });
this.blob = new Promise<Blob>((resolve) => {
mediaRecorder.onstop = (evt) => {
const blob = new Blob(chunks, { type: mediaRecorder.mimeType })
resolve(blob)
}
})
mediaRecorder.ondataavailable = (evt) => {
chunks.push(evt.data)
}
mediaRecorder.start(1000)
this.recorder = mediaRecorder
}
async stop() {
this.mediaStreamAudioDestinationNode.disconnect()
this.mediaStreamAudioSourceNode.disconnect()
this.audioContext.close()
this.recorder.stop()
return await this.blob
}
}
@seamory How do you run this code? Do you use SSR or hot reloading as mentioned above?
@seamory How do you run this code? Do you use SSR or hot reloading as mentioned above?
I run this code on browser platform with edge latest and chrome latest, not use SSR. Actually it happened during development and hot reloading is working during development. But I confuse why the issue could be also happened when I open the development url address at first time or I refreshed the page.
@seamory Could you add breakpoints or log something when the MediaRecorder
gets created and when you call stop()
. I'm curious if this happens to be out of order for some reason.
@chrisguttandin the hot module replacement is a great suspect - I ran into this a couple of times during development using vue.js but didn't really bother. I'll debug it.
Thanks, @bschelling for taking a stab. Did your debugging reveal anything suspicious?
I'm facing this issue, but it only seems to happen when I call mediaRecorder.stop() just after mediaRecorder.start() is called.
@chrisguttandin From these logs you can see that the error happens consistently when stop is called around 1000ms after start.
Has errors:
start recording
connect took 1.60
stream took 157.60
STOPED. Time since started: 309.40
**Uncaught (in promise) Error: Another request was made to initiate an encoding.**
start recording
connect took 0.50
stream took 126.90
STOPED. Time since started: 686.90
**Uncaught (in promise) Error: Another request was made to initiate an encoding.**
start recording
connect took 1.10
stream took 146.90
STOPED. Time since started: 952.90
**Uncaught (in promise) Error: Another request was made to initiate an encoding.**
No errors:
start recording
connect took 0.40
stream took 129.90
STOPED. Time since started: 2026.10
start recording
connect took 0.70
stream took 140.60
STOPED. Time since started: 1641.30
start recording
connect took 0.50
stream took 141.70
STOPED. Time since started: 1078.30
start recording
connect took 1.30
stream took 162.20
STOPED. Time since started: 1082.70
This is the code (React hook):
type MicListener = (base64Audio: string, sampleRate: number, last: boolean) => void
var startTime: number
export const useMicStream = (
config: () => void,
onData: MicListener
) => {
const [mediaRecorder, setMediaRecorder] = useState<IMediaRecorder>()
const start = (ratio: number) => {
console.log('start recording')
if (mediaRecorder) {
throw new Error('MediaRecorder is already initialized')
}
startTime = performance.now()
Promise.all([
navigator.mediaDevices.getUserMedia({
audio: true, video: false
}),
connect().then((port) => {
if (!MediaRecorder.isTypeSupported('audio/wav')) {
return register(port).then(() => {
console.log('register took', performance.now() - startTime)
})
}
console.log('connect took', performance.now() - startTime)
})
]).then(([stream]) => {
console.log('stream took', performance.now() - startTime)
const mediaRecorder = new MediaRecorder(stream, {
mimeType: 'audio/wav',
})
config()
setMediaRecorder(mediaRecorder)
mediaRecorder.ondataavailable = (event) => {}
startTime = performance.now()
mediaRecorder.start(ratio)
}).catch((error) => {
console.error('userMedia ', error)
})
}
const stop = () => {
console.log('STOPED. Time since started: ', performance.now() - startTime)
mediaRecorder?.stop()
setMediaRecorder(undefined)
}
return {
start,
stop,
isRecording: mediaRecorder?.state === 'recording',
}
}
Thanks @Jrfidellis for providing the example code. I was able to reproduce the problem. As you said it only happened when stopping the MediaRecorder
early on. And it only happened when using the timeslice
parameter which is also the case in the example code provided by @seamory.
The problem was caused by a race condition. It was possible that the MediaRecorder
was stopped already when the first part of the recording was requested. Which in turn triggered the unhandled error.
The problem should be fixed now in v9.2.9. Thank you all for your contributions.
Uncaught (in promise) Error: Another request was made to initiate an encoding. at Worker. (module.ts:49:1)