I am trying to record a video and then save it to the server. My issue is the file is not being saved to the server and I am not sure why. The issue seems to be that it is not creating the blob or maybe not able to get the file as a blob?
I say that because in the Console I see this error
stopRecording failure TypeError: Failed to execute 'createObjectURL' on 'URL': Overload resolution failed.
Here is my file
<html>
<head>
<script src="https://cdn.webrtc-experiment.com/RecordRTC.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
</head>
<body>
<button id="btn-start-recording">Start Recording</button>
<button id="btn-stop-recording" disabled="disabled">Stop Recording</button>
<button id="btn-save-recording" disabled="disabled">Stop& Save Recording</button>
<!--
2. Include a video element that will display the current video stream
and as well to show the recorded video at the end.
-->
<hr>
<video id="my-preview" controls autoplay></video>
<!-- 4. Initialize and prepare the video recorder logic -->
<script>
// Store a reference of the preview video element and a global reference to the recorder instance
var video = document.getElementById('my-preview');
var recorder;
// When the user clicks on start video recording
document.getElementById('btn-start-recording').addEventListener("click", function(){
// Disable start recording button
this.disabled = true;
// Request access to the media devices
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(function(stream) {
// Display a live preview on the video element of the page
setSrcObject(stream, video);
// Start to display the preview on the video element
// and mute the video to disable the echo issue !
video.play();
video.muted = true;
// Initialize the recorder
recorder = new RecordRTCPromisesHandler(stream, {
mimeType: 'video/webm',
bitsPerSecond: 128000
});
// Start recording the video
recorder.startRecording().then(function() {
console.info('Recording video ...');
}).catch(function(error) {
console.error('Cannot start video recording: ', error);
});
// release stream on stopRecording
recorder.stream = stream;
// Enable stop recording button
document.getElementById('btn-stop-recording').disabled = false;
document.getElementById('btn-save-recording').disabled = false;
}).catch(function(error) {
console.error("Cannot access media devices: ", error);
});
}, false);
// When the user clicks on Stop video recording
document.getElementById('btn-stop-recording').addEventListener("click", function(){
this.disabled = true;
recorder.stopRecording().then(function() {
console.info('stopRecording success');
// Retrieve recorded video as blob and display in the preview element
var videoBlob = recorder.getBlob();
video.src = URL.createObjectURL(videoBlob);
video.play();
// Unmute video on preview
video.muted = false;
// Stop the device streaming
recorder.stream.stop();
// Enable record button again !
document.getElementById('btn-start-recording').disabled = false;
}).catch(function(error) {
console.error('stopRecording failure', error);
});
}, false);
//lets save the video
document.getElementById('btn-save-recording').addEventListener("click", function(){
// Retrieve recorded video as blob and display in the preview element
var videoBlob = recorder.getBlob();
video.src = URL.createObjectURL(videoBlob);
video.play();
// Unmute video on preview
video.muted = false;
// Stop the device streaming
recorder.stream.stop();
var formData = new FormData();
formData.append('video', player.recordedData.video);
// Execute the ajax request, in this case we have a very simple PHP script
// that accepts and save the uploaded "video" file
xhr('upload-videoclaim.php', formData, function (fName) {
console.log("Video succesfully uploaded !");
})
// Helper function to send
function xhr(url, data, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4 && request.status == 200) {
callback(location.href + request.responseText);
}
};
request.open('POST', url);
request.send(data);
}
});
</script>
</body>
</html>
See the MDN docs on parameters for URL.createObjectURL
:
A
File
,Blob
, orMediaSource
object to create an object URL for.
Just try passing something else to URL.createObjectURL
that it doesn't expect like a number. You'll get a similar / same error message.
Now see the implementation of RecordRTCPromisesHandler.getBlob()
. It returns a Promise
:
/**
* This method returns the recorded blob.
* @method
* @memberof RecordRTCPromisesHandler
* @example
* recorder.stopRecording().then(function() {
* recorder.getBlob().then(function(blob) {})
* }).catch(errorCB);
*/
this.getBlob = function() {
return new Promise(function(resolve, reject) {
try {
resolve(self.recordRTC.getBlob());
} catch (e) {
reject(e);
}
});
};
Look at the @example
given in the JSDoc comment. It does recorder.getBlob().then(<callback>)
. Follow the example.
Option 1 (nested Promise.then()
):
recorder.stopRecording().then(function() {
console.info('stopRecording success');
// do whatever else you want here.
recorder.getBlob().then(videoBlob => {
video.src = URL.createObjectURL(videoBlob);
video.play();
video.muted = false;
// ...
});
}).catch(function(error) {
// ...
Option 2 (chained Promise.then()
):
recorder.stopRecording().then(() => recorder.getBlob()).then(videoBlob => {
video.src = URL.createObjectURL(videoBlob);
video.play();
video.muted = false;
// ...
}).catch(function(error) {
// ...
Option 3 (async-await):
try {
await recorder.stopRecording();
const videoBlob = await recorder.getBlob();
video.src = URL.createObjectURL(videoBlob);
video.play();
video.muted = false;
// ...
} catch(error) {
// ...
I'm not sure, but part of why you didn't understand the problem might have been due to limitations of intellisense when writing JS in HTML, and particularly when using a library without downloading the source locally so that it's visible to the intellisense facilities. I wouldn't really fault you for that. If you think it's appropriate, you could consider politely asking the maintainer of the library to add to their library's website's docuentation to also document the Promise-based interfaces of the library, or even writing up PRs to do that.