text: Q:
  
  El grabador de audio no funciona
  
  Me interesa un grabador de audio, buscando en internet encontré este grabador pero no funciona... se activa el microfono pero no graba y el botón de parar y escuchar tampoco, cómo puedo hacer para que funcione en cualquier navegador y de manera local en mi pc?
  ¿O necesito un servidor? el codigo lo probé en w3schools
  En casi todas las páginas de internet solo aparece este ejemplo.
  me interesa saber que problemas tiene este codigo o si hay otra manera más simple de hacerlo ya que entiendo muy poco de javascript.
  
     //Función en caso de error
     var error = function(e) {
      console.log('¡No pude grabarte!', e);
     };
     //Función cuando todo tenga exito
     var exito = function(s) {
      var context = new webkitAudioContext(); //Conectamos con nuestra entrada de audio
      var flujo = context.createMediaStreamSource(s); //Obtenemos el flujo de datos desde la fuente
      recorder = new Recorder(flujo); //Todo el flujo de datos lo pasamos a nuestra libreria para procesarlo en esta instancia
      recorder.record(); //Ejecutamos la función para procesarlo
     }
     //Convertirmos el objeto en URL
     window.URL = window.URL || window.webkitURL;
     navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
     var recorder; //Es nuestra variable para usar la libreria Recorder.js
     var audio = document.querySelector('audio'); //Seleccionamos la etiqueta audio para enviarte el audio y escucharla
     //Funcion para iniciar el grabado
     function grabar() {
      if (navigator.getUserMedia) { //Preguntamos si nuestro navegador es compatible con esta función que permite usar microfono o camara web
       navigator.getUserMedia({audio: true}, exito, error); //En caso de que si, habilitamos audio y se ejecutan las funciones, en caso de exito o error.
       document.querySelector('p').innerHTML = "Estamos grabando...";
      } else {
       console.log('¡Tu navegador no es compatible!, ¿No lo vas a acutalizar?'); //Si no es compatible, enviamos este mensaje.
      }
     }
     //Funcion para parar la grabación y escucharla
     function parar() {
      recorder.stop(); //Paramos la grabación
      recorder.exportWAV(function(s) { //Exportamos en formato WAV el audio 
       audio.src = window.URL.createObjectURL(s); //Y convertimos el valor devuelto en URL para pasarlo a nuestro reproductor.
      });
      document.querySelector('p').innerHTML = "Paramos la grabación y ahora escuchala...";
     }
    </script>
  
  <script>
  (function(window){
  
    var WORKER_PATH = 'recorderWorker.js';
  
    var Recorder = function(source, cfg){
      var config = cfg || {};
      var bufferLen = config.bufferLen || 4096;
      this.context = source.context;
      this.node = this.context.createJavaScriptNode(bufferLen, 2, 2);
      var worker = new Worker(config.workerPath || WORKER_PATH);
      worker.postMessage({
        command: 'init',
        config: {
          sampleRate: this.context.sampleRate
        }
      });
      var recording = false,
        currCallback;
  
      this.node.onaudioprocess = function(e){
        if (!recording) return;
        worker.postMessage({
          command: 'record',
          buffer: [
            e.inputBuffer.getChannelData(0),
            e.inputBuffer.getChannelData(1)
          ]
        });
      }
  
      this.configure = function(cfg){
        for (var prop in cfg){
          if (cfg.hasOwnProperty(prop)){
            config[prop] = cfg[prop];
          }
        }
      }
  
      this.record = function(){
        recording = true;
      }
  
      this.stop = function(){
        recording = false;
      }
  
      this.clear = function(){
        worker.postMessage({ command: 'clear' });
      }
  
      this.getBuffer = function(cb) {
        currCallback = cb || config.callback;
        worker.postMessage({ command: 'getBuffer' })
      }
  
      this.exportWAV = function(cb, type){
        currCallback = cb || config.callback;
        type = type || config.type || 'audio/wav';
        if (!currCallback) throw new Error('Callback not set');
        worker.postMessage({
          command: 'exportWAV',
          type: type
        });
      }
  
      worker.onmessage = function(e){
        var blob = e.data;
        currCallback(blob);
      }
  
      source.connect(this.node);
      this.node.connect(this.context.destination);    //this should not be necessary
    };
  
    Recorder.forceDownload = function(blob, filename){
      var url = (window.URL || window.webkitURL).createObjectURL(blob);
      var link = window.document.createElement('a');
      link.href = url;
      link.download = filename || 'output.wav';
      var click = document.createEvent("Event");
      click.initEvent("click", true, true);
      link.dispatchEvent(click);
    }
  
    window.Recorder = Recorder;
  
  })(window);
  var recLength = 0,
    recBuffersL = [],
    recBuffersR = [],
    sampleRate;
  
  this.onmessage = function(e){
    switch(e.data.command){
      case 'init':
        init(e.data.config);
        break;
      case 'record':
        record(e.data.buffer);
        break;
      case 'exportWAV':
        exportWAV(e.data.type);
        break;
      case 'getBuffer':
        getBuffer();
        break;
      case 'clear':
        clear();
        break;
    }
  };
  
  function init(config){
    sampleRate = config.sampleRate;
  }
  
  function record(inputBuffer){
    recBuffersL.push(inputBuffer[0]);
    recBuffersR.push(inputBuffer[1]);
    recLength += inputBuffer[0].length;
  }
  
  function exportWAV(type){
    var bufferL = mergeBuffers(recBuffersL, recLength);
    var bufferR = mergeBuffers(recBuffersR, recLength);
    var interleaved = interleave(bufferL, bufferR);
    var dataview = encodeWAV(interleaved);
    var audioBlob = new Blob([dataview], { type: type });
  
    this.postMessage(audioBlob);
  }
  
  function getBuffer() {
    var buffers = [];
    buffers.push( mergeBuffers(recBuffersL, recLength) );
    buffers.push( mergeBuffers(recBuffersR, recLength) );
    this.postMessage(buffers);
  }
  
  function clear(){
    recLength = 0;
    recBuffersL = [];
    recBuffersR = [];
  }
  
  function mergeBuffers(recBuffers, recLength){
    var result = new Float32Array(recLength);
    var offset = 0;
    for (var i = 0; i < recBuffers.length; i++){
      result.set(recBuffers[i], offset);
      offset += recBuffers[i].length;
    }
    return result;
  }
  
  function interleave(inputL, inputR){
    var length = inputL.length + inputR.length;
    var result = new Float32Array(length);
  
    var index = 0,
      inputIndex = 0;
  
    while (index < length){
      result[index++] = inputL[inputIndex];
      result[index++] = inputR[inputIndex];
      inputIndex++;
    }
    return result;
  }
  
  function floatTo16BitPCM(output, offset, input){
    for (var i = 0; i < input.length; i++, offset+=2){
      var s = Math.max(-1, Math.min(1, input[i]));
      output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
    }
  }
  
  function writeString(view, offset, string){
    for (var i = 0; i < string.length; i++){
      view.setUint8(offset + i, string.charCodeAt(i));
    }
  }
  
  function encodeWAV(samples){
    var buffer = new ArrayBuffer(44 + samples.length * 2);
    var view = new DataView(buffer);
  
    /* RIFF identifier */
    writeString(view, 0, 'RIFF');
    /* file length */
    view.setUint32(4, 32 + samples.length * 2, true);
    /* RIFF type */
    writeString(view, 8, 'WAVE');
    /* format chunk identifier */
    writeString(view, 12, 'fmt ');
    /* format chunk length */
    view.setUint32(16, 16, true);
    /* sample format (raw) */
    view.setUint16(20, 1, true);
    /* channel count */
    view.setUint16(22, 2, true);
    /* sample rate */
    view.setUint32(24, sampleRate, true);
    /* byte rate (sample rate * block align) */
    view.setUint32(28, sampleRate * 4, true);
    /* block align (channel count * bytes per sample) */
    view.setUint16(32, 4, true);
    /* bits per sample */
    view.setUint16(34, 16, true);
    /* data chunk identifier */
    writeString(view, 36, 'data');
    /* data chunk length */
    view.setUint32(40, samples.length * 2, true);
  
    floatTo16BitPCM(view, 44, samples);
  
    return view;
  }
    audio{
     margin:20px;
    }
    p{
     margin:10px;
    }
    input[type="button"]{
     background:#CCC;
     border:none;
     border-radius:5px;
     cursor:pointer;
     font-size:1em;
     padding:5px;
    }
    input[type="button"]:hover{
     background:#666;
    }
   <audio controls autoplay></audio>
    <script type="text/javascript" src="recorder.js"> </script>
    <p></p>
    <input onclick="grabar()" type="button" value="Grabar ahora" />
    <input onclick="parar()" type="button" value="Parar y escuchar" />
  
  A:
  
  Mi solución se basa en utilizar la Media​Stream Recording API.
  En base a esta condición voy a tratar de responder a todas las preguntas por separado y en un orden que permita realizar una respuesta entendible.
  
  [...]cómo puedo hacer para que funcione en cualquier navegador[...]
  
  Esto no es posible, ya que esta API no esta disponible en todos los navegadores. 
  
  [...] necesito un servidor [...]
  
  No, ya que es una herramienta provista por el navegador y no le importa si la página esta online o en la PC.
  
  [...] hay otra manera más simple de hacerlo [...]
  
  La solución que planteo debajo, desde mi punto de vista es simple (dudo que sea la más simple).
  Atención: El snippet no funciona por las políticas de sandbox establecidas para el mismo. Acá dejo un enlace donde se lo puede ver en funcionamiento.
  
  <audio id="audio" controls></audio>
  <p></p>
  <input id="record" type="button" value="Grabar" />
  <input id="pause" type="button" value="Pausar" disabled />
  <input id="resume" type="button" value="Continuar" disabled />
  <input id="stop" type="button" value="Parar" disabled />
  <script>
  
  if (navigator.mediaDevices) {
  
    var chunks = [];
    var audio = document.getElementById('audio');
    var record = document.getElementById('record');
    var pause = document.getElementById('pause');
    var resume = document.getElementById('resume');
    var stop = document.getElementById('stop');
  
  
    navigator.mediaDevices.getUserMedia({
      audio: true
    })
      .then(function(stream) {
  
      var mediaRecorder = new MediaRecorder(stream);
  
      record.onclick = function() {
       if (mediaRecorder.state != 'inactive') {
         return;
        }
       record.disabled = true;
        pause.disabled = false;
        stop.disabled = false;
        mediaRecorder.start();
      }
      pause.onclick = function() {
       if (mediaRecorder.state != 'recording') {
         return;
        }
       pause.disabled = true;
        resume.disabled = false;
        mediaRecorder.pause();
      }
      resume.onclick = function() {
       if (mediaRecorder.state != 'paused') {
         return;
        }
       pause.disabled = false;
        resume.disabled = true;
        mediaRecorder.resume();
      }
      stop.onclick = function() {
       if (mediaRecorder.state == 'inactive') {
         return;
        }
       record.disabled = false;
        pause.disabled = true;
        resume.disabled = true;
        stop.disabled = true;
        mediaRecorder.stop();
      }
  
      mediaRecorder.onstop = function(e) {
        audio.controls = true;
        var blob = new Blob(chunks, {
          'type': 'audio/ogg; codecs=opus'
        });
        
        chunks = [];
        audio.src = URL.createObjectURL(blob);
      }
  
      mediaRecorder.ondataavailable = function(e) {
        chunks.push(e.data);
      }
    })
      .catch(function(err) {
      console.log('The following error occurred: ' + err);
    })
  }
  </script>
  
  [...] y de manera local en mi pc? [...]
  
  Pasos: 
  
  Crear un archivo HTML, por ejemplo grabador.html 
  Copiar el contenido del snippet dentro y guardar
  Hacer doble clik sobre el archivo y abrirlo con un navegador
  Permitir el uso de micrófono y listo!
  
  