I'm trying to record video in a React + TS component. I want to conditionally render the video player: if the user is recording, the video player source should be the live stream (MediaStream
), but if the recording is finished, the video player source should change from the live stream to the newly created recordingURL
(created with URL.createObjectURL(blob)
.
As you can see, I'm replacing the one <video/>
tag with another, because I cannot just use HTMLMediaElement.srcObject
to set a source different from a MediaStream
.
<div className="VideoRecorder flex flex-col mx-2">
{recordingURL.current! ? (
<video
src={recordingURL.current}
playsInline
controls
className="RECORDED"
/>
) : (
<video
ref={(ref) => {
if (ref)
ref.srcObject = recordingStream.current;
}}
autoPlay
className="LIVE"
/>
)}
</div>
When the recording starts, the video player successfully displays the live MediaStream
. When the recording stops the video player does change (I checked the render HTML and the video player with the className="RECORDED"
comes in replacement for the one with the className="LIVE"
), the recordingURL.current
also changes from null
to the object URL string
but the problem is that, somehow, this new video player is still showing a live stream
The code below shows the relevant state
and ref
managing for the MediaRecorder
.
const recordingURL = useRef<null | string>(null);
const stopRecording = () => {
const blob = new Blob(recordedChunks.current, {
type: mediaConstraints.audio ? 'audio/mpeg' : 'video/mp4'
});
setIsRecording(false);
recordingURL.current = URL.createObjectURL(blob);
setBlob(blob);
};
const initializeDevice = async () => {
try {
recordingStream.current = await navigator.mediaDevices.getUserMedia(
mediaConstraints
);
setPermissionGranted(true);
mediaRecorder.current = new MediaRecorder(recordingStream.current);
mediaRecorder.current!.ondataavailable = saveRecordingChunks;
mediaRecorder.current!.onstop = stopRecording;
} catch (error: any) {
// Exception handling...
}
};
And this HTML fragment shows the <video>
element that replaced the recording one. As you can see, its src
is set to a url, yet this component actually shows the data stream:
<video class="RECORDED" src="blob:http://localhost:3000/af437ac7-e77e-4d5b-a2f5-2645507448ed" playsinline="" controls=""></video>
What could be causing this problem?
Adding a key
parameter to each <video>
element solved the problem.