I wrote a simple page on js and php to live record audio from microphone. Logic is simple:
JS
PHP
The data is successfully written to file, but when I try to play it, player says that file is broken.
The blob solution from Mozilla guide is worked for me, I want exactly PHP solution with saving (rewriting) to file.
The full code below, what am I doing wrong?
<?php
if(isset($_POST["data"]))
{
file_put_contents("r.ogg", base64_decode($_POST["data"]));
exit;
}
?>
<script>
var mediaRecorder = null;
let chunks = [];
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
console.log('getUserMedia supported.');
navigator.mediaDevices.getUserMedia (
{
audio: true
})
.then(function(stream) {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(2000);
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
chunks = [];
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var data = reader.result.split(";base64,")[1];
requestp2("a.php", "data="+encodeURIComponent(data));
}
}
})
.catch(function(err) {
console.log('The following getUserMedia error occurred: ' + err);
}
);
} else {
console.log('getUserMedia not supported on your browser!');
}
function requestp2(path, data)
{
var http = new XMLHttpRequest();
http.open('POST', path, true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.send(data);
}
</script>
You're trying to choose your audio format and codec by specifying a media type in your Blob constructor. You Can't Do That™.
Specify the media type in your MediaRecorder constructor instead. Something like this, not debugged!
...
/* here's the media type definition vvv */
mrOptions = {mimeType: 'audio/ogg; codecs=opus'}
mediaRecorder = new MediaRecorder(stream, mrOptions)
mediaRecorder.start(2000)
mediaRecorder.ondataavailable = function(e) {
...
const blob = new Blob(chunks, { type : mediaRecorder.mimeType })
...
There may also be some trouble with your handling of the consecutive e.data chunks MediaRecorder passes to your ondataavailable handler. To make a valid playable file you must concatenate all those chunks into the file. If you can't get it to work ask another question.
The problem was that seems only first chunk had like signature a label or something else, and hence could be played. So I had to add an interval to stop and play mediaRecorder every time.
Also the format of the file was not ogg but webm.
The full working code:
<?php
if(isset($_POST["data"]))
{
file_put_contents("r.webm", base64_decode($_POST["data"]));
exit;
}
?>
<script>
var mediaRecorder = null;
var delay = 2000;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
console.log('getUserMedia supported.');
navigator.mediaDevices.getUserMedia (
{
audio: true
})
.then(function(stream) {
mediaRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm; codecs=opus'});
mediaRecorder.start();
mediaRecorder.ondataavailable = function(e) {
var blob = e.data;
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var data = reader.result.split(";base64,")[1];
requestp2("a.php", "data="+encodeURIComponent(data));
}
}
setInterval(function(){
mediaRecorder.stop();
mediaRecorder.start();
}, delay);
})
.catch(function(err) {
console.log('The following getUserMedia error occurred: ' + err);
}
);
} else {
console.log('getUserMedia not supported on your browser!');
}
function requestp2(path, data)
{
var http = new XMLHttpRequest();
http.open('POST', path, true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.send(data);
}
</script>