I'm new to both Laravel and vue.js. I'm trying to use getNavigatorMedia and MediaRecorder. In testing it's capturing the mediastream but it seems that the stream is not getting passed into the properties I created in the data object, as they remain null. I've tried to create variables in the actual methods but this isn't working.
Attached please find my code and below is the reported error. If anyone could point me in the right direction it would be much appreciated.
Uncaught TypeError: Cannot set property 'ondataavailable' of null
at VueComponent.toggleRecording (record:104)
at Proxy.boundFn (vue.js:167)
at click (eval at makeFunction (vue.js:9252), <anonymous>:2:152)
at HTMLButtonElement.invoker (vue.js:1732)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.3.4/vue-resource.js" type="text/javascript"> </script>
<script src ="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<script>
Vue.component('record', {
template: '#record-template',
data: function () {
return {
isRecording: false,
audioRecorder: null,
recordingData: [],
dataUrl: ''
};
},
methods:
{
//method to start and stop the recording process
toggleRecording: function() {
var that = this;
this.isRecording = !this.isRecording;
if (this.isRecording) {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia({
audio: true,
video: false
}, function(stream) {
that.stream = stream;
that.audioRecorder = new MediaRecorder(stream, {
mimeType: 'audio/webm;codecs=opus',
audioBitsPerSecond : 96000
});
that.audioRecorder.start();
console.log('Media recorder started');
}, function(error) {
alert(JSON.stringify( error));
});
}
else {
this.audioRecorder.stop();
}
this.audioRecorder.ondataavailable = function(event) {
that.recordingData.push(event.data);
}
this.audioRecorder.onstop = function(event) {
console.log('Data available after MediaRecorder.stop() called');
// var audio = document.createElement('audio');
// audio.controls = true;
var blob = new Blob(that.recordingData, { type: 'audio/ogg'});
that.dataUrl = window.URL.createObjectURL(blob);
// audio.src = dataUrl;
console.log("recorder stopped");
}
},
//method to remove a recording that was saved previously
removeRecording: function() {
this.isRecording = false;
this.recordingData = [];
this.dataUrl = '';
},
//method to start and stop the playback process
togglePlay: function() {
var audioElement = document.getElementById("audio");
if (audioElement.paused === false) {
audioElement.pause();
} else {
audioElement.play();
}
// var handleSuccess = function(stream) {
// if (window.URL) {
// audioElement.src = window.URL.createObjectURL(stream);
// } else {
// audioElement.src = stream;
// }
},
//method to submit the recording to the API using vue-resource
submitRecording: function() {
}
},
});
new Vue({
el: '#app'
});
</script>
<div id="app">
<h1>Test</h1>
<record>
</record>
</div>
<template id="record-template">
<div>
<button class="button red-button" v-on:click.stop.prevent="toggleRecording">
<i class="stop icon" v-show="isRecording"></i>
<span v-show="isRecording">Stop recording</span>
<i class="record icon" v-show="!isRecording"></i>
<span v-show="!isRecording">Start recording</span>
</button>
<button id="remove-recording" class="remove-recording" v-if="dataUrl.length > 0" v-on:click.stop.prevent="removeRecording">
<i class="remove icon"></i> Delete recording
</button>
<button id="send-recording" class="button green-button" v-if="dataUrl.length > 0">
<i class="send icon"></i> Send recording
</button>
<button class="button green-button" v-if="dataUrl.length > 0" v-on:click.stop.prevent="togglePlay">
<i class="play icon"></i> Play recording
</button>
</div>
<audio id="audio" preload="auto" v-model="dataUrl"></audio>
</template>
Javascript, by nature, is asynchronous, meaning the logic later on in the script does not wait for the previous logic to finish. What is happening is you are trying to bind to the MediaRecorder before the Vue property audioRecorder is even a MediaRecorder object.
Try moving the event bindings inside the stream callback. This also requires you to change the property scope from this to that for those bindings
function(stream) {
that.stream = stream;
that.audioRecorder = new MediaRecorder(stream, {
mimeType: 'audio/webm;codecs=opus',
audioBitsPerSecond : 96000
});
// event bindings
that.audioRecorder.ondataavailable = function(event) {
that.recordingData.push(event.data);
}
that.audioRecorder.onstop = function(event) {
console.log('Data available after MediaRecorder.stop() called');
// var audio = document.createElement('audio');
// audio.controls = true;
var blob = new Blob(that.recordingData, { type: 'audio/ogg'});
that.dataUrl = window.URL.createObjectURL(blob);
// audio.src = dataUrl;
console.log("recorder stopped");
}
that.audioRecorder.start();
console.log('Media recorder started');
}