Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

229
Vistas
Live-recorded base64-encoded audio from MediaRecorder is broken

I wrote a simple page on js and php to live record audio from microphone. Logic is simple:

JS

  1. Get chunk of data from mic;
  2. Base64 encode it and urlencode it;
  3. Send it via POST request;

PHP

  1. Base64 decode data;
  2. (re)Write to .ogg file;
  3. Repeat 1 after delay.

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>
about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

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.

about 4 years ago · Juan Pablo Isaza Denunciar

0

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>
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda