Reputation: 191
I currently have a MediaStream which is being recorded using MediaRecorder. At the end of the recording after recorder.stop(), it produce a Blob and I am able to play that video back. My goal is to play not the entire video at the end, but play a chunk while recording. For the moment, a chunk is not playable while recording is not ended.
How can i do that using javascript? The final objective is to send a chunk by websocket that is playable even if recording is in action.
I am not able to bring new solutions. Can anyone help or at least explain me the things ?
What I've tried was
navigator.mediaDevices.getUserMedia().then(function(media_stream) {
var recorder = new MediaRecorder(media_stream);
recorder.ondataavailable = event => {
//How to play each chunk without waiting for recorder.stop() ???
//event.data represent the data of a chunk (i.e. a blob)
};
recorder.start(1000);
});
Upvotes: 12
Views: 3246
Reputation: 860
I recently worked has a company project that requires me to process chunks of audio files while recording. Likewise, it would not work because the chunk is not playable without ending the recording.
Reason: Because the header that specify the file is on the first chunk only. To test it out, you can actually play the first chunk without any problem.
A hacky solution: We could just find a way to get the header and merge it with every other requested chunk that is not the first chunk.
Steps:
I could not post the entire source code, but here are the structure of the function just for a simple reference.
I am using VueJs, Typescript. Same concept could be applied to any JS framework
let mediaRecorder: MediaRecorder | null = null;
let audioChunkInterval: any = null;
let headerBlob: any = null
const startRecord = async() => {
let mediaHeaderRequested: boolean = false;
// Request microphone access
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
if(audioChunkInterval) clearInterval(audioChunkInterval)
// Create a MediaRecorder
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
mediaRecorder.onstart = async() => {
if(!mediaRecorder) return;
mediaRecorder.requestData();
}
// Process chunks
mediaRecorder.ondataavailable = async(event: any) => {
if (event.data.size > 0) {
if(!mediaHeaderRequested){
// Set header blob
headerBlob = event.data;
mediaHeaderRequested = true;
return;
}
// merge event.data with header blob here
}
};
//Process chunk every X seconds
audioChunkInterval = setInterval(() => {
if(!mediaRecorder) return;
mediaRecorder.requestData();
}, 10000)
mediaRecorder.onstop = () => {
console.log('Recording stopped');
};
}
In my case, I send all the chunks to my NodeJS backend and dd the merging on the backend, because i am running the audio analyzing logic on the backend. I just applied the same concept and instead on the backend, did the merging on the front. After you have bunch of playable chunks, it's up to you on how would you like to play those chunks.
Upvotes: 0
Reputation: 2960
This is the simplest example I could come up with.
You need a video element for playing the video as you stream it, and a record button to kick off the recording.
The script does the following
HTML
<video id="player"></video>
<button class="record">Record</button>
JS
<script>
const video = document.querySelector('#player');
const record = document.querySelector('.record');
(function start() {
// 1. check for support
if (! navigator.mediaDevices.getUserMedia) {
return console.log('getUserMedia not supported on your browser!');
}
// 2. create onSuccess handler
// 4. called if permitted
const onSuccess = function (stream) {
// 5. create the recorder
const mediaRecorder = new MediaRecorder(stream);
// 6. create onclick handler for record button
// 7. called if record is clicked
record.onclick = function() {
// 8. starts recording
mediaRecorder.start();
// 9. sets video element to use the stream
video.srcObject = stream;
// 10. sets the video element to autoplay, otherwise user would have to click play
video.autoplay = true;
};
};
// 2. create onError handler
const onError = function (error) {
console.error('The following error occured: ' + error);
};
// 3. ask permission to record audio and video
const constraints = {video: true, audio: true};
navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
})();
</script>
Upvotes: 0