I tried to download the recorded audio file using javascript, which is
recordedBlobs
seems fine by checking the log (size !=0),
but var blob = new Blob(recordedBlobs, {type: "audio/webm; codecs=opus"});
would return a empty blob.
Also something weird: I found that console.log(recordedBlobs.length)
is 0 ?! I'm kinda new to javascript, is this normal?
I feel really confused :( Any suggestions would be appreciated, thanks in advance.
Below is my code.
<script>
let mediaRecorder;
let recordedBlobs;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
console.log("getUserMedia supported.");
navigator.mediaDevices
.getUserMedia(
{audio: true, video: false}
)
// Success callback
.then(function (stream) {
mediaRecorder = new MediaRecorder(stream);
})
// Error callback
.catch(function (err) {
console.log("The following getUserMedia error occurred: " + err);
});
} else {
console.log("getUserMedia not supported on your browser!");
}
function handleDataAvailable(event) {
console.log('handleDataAvailable', event);
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
function Play() {
console.log("play");
recordedBlobs = [];
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
console.log(mediaRecorder.state);
}
function Stop() {
console.log("stop");
mediaRecorder.stop();
downloadVideo();
}
function downloadVideo() {
console.log('recorded blob:', recordedBlobs);
var blob = new Blob(recordedBlobs, {type: "audio/webm; codecs=opus"});
console.log('new blob:', blob);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
}
</script>
I guess it has something to do with Javascript's asynchronous properties. So when stop()
is called, the data is not ready yet.
Therefore, I added a onstop
listener, and it works!
function Play() {
recordedBlobs = [];
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.onstop = downloadVideo; // download when onstop is triggered
mediaRecorder.start();
}
Then, in function downloadVideo
, I implemented two versions:
(1) download locally
(2) post to server
function downloadVideo() {
// 1. download locally
/*const blob = new Blob(recordedBlobs, { 'type': 'audio/webm; codecs=opus' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 1000);*/
// 2. post audio blob to server
const blob = new Blob(recordedBlobs, { 'type': 'audio/webm; codecs=opus' });
var data = new FormData();
var youtube_ID = document.getElementById("youtube_ID").innerHTML;
data.append('file', blob, youtube_ID);
data.append('youtube_ID', youtube_ID);
fetch(`/api/get_recording`, {
method: "POST",
body: data,
});
Reference: