7

I've seen many partial answers to this here and elsewhere, but I am very much a novice coder and am hoping for a thorough solution. I have been able to set up recording audio from a laptop mic in Chrome Canary (v. 29.x) and can, using recorder.js, relatively easily set up recording a .wav file and saving that locally, a la:

http://webaudiodemos.appspot.com/AudioRecorder/index.html

But I need to be able to save the file onto a Linux server I have running. It's the actual sending of the blob recorded data to the server and saving it out as a .wav file that's catching me up. I don't have the requisite PHP and/or AJAX knowledge about how to save the blob to a URL and to deal, as I have been given to understand, with binaries on Linux that make saving that .wav file challenging indeed. I'd greatly welcome any pointers in the right direction.

jimiayler
  • 674
  • 2
  • 11
  • 27
  • Duplicate of http://stackoverflow.com/questions/13658888/save-blob-audio-file-on-server-with-xmlhttprequest?rq=1, but it hasn't been answered yet. – Forest Katsch May 17 '13 at 19:29
  • http://stackoverflow.com/questions/18951197/null-parameter-when-trying-to-pass-a-blob-to-c-sharp-controller/18996423#18996423 Rely to this if you are working with ASP MVC – Minh Triet Sep 25 '13 at 04:48

2 Answers2

16

Client side JavaScript function to upload the WAV blob:

function upload(blob) {
  var xhr=new XMLHttpRequest();
  xhr.onload=function(e) {
      if(this.readyState === 4) {
          console.log("Server returned: ",e.target.responseText);
      }
  };
  var fd=new FormData();
  fd.append("that_random_filename.wav",blob);
  xhr.open("POST","<url>",true);
  xhr.send(fd);
}

PHP file upload_wav.php:

<?php
// get the temporary name that PHP gave to the uploaded file
$tmp_filename=$_FILES["that_random_filename.wav"]["tmp_name"];
// rename the temporary file (because PHP deletes the file as soon as it's done with it)
rename($tmp_filename,"/tmp/uploaded_audio.wav");
?>

after which you can play the file /tmp/uploaded_audio.wav.

But remember! /tmp/uploaded_audio.wav was created by the user www-data, and (by PHP default) is not readable by the user. To automate adding the appropriate permissions, append the line

chmod("/tmp/uploaded_audio.wav",0755);

to the end of the PHP (before the PHP end tag ?>).

Hope this helps.

Forest Katsch
  • 1,485
  • 2
  • 15
  • 26
  • Any idea how to apply the above to http://webaudiodemos.appspot.com/AudioRecorder/index.html ? The way they wrote their code is so confusing to me. – Ael Oct 09 '17 at 22:32
  • Argh. Too long, will save as separate answer. – cwilso Oct 09 '17 at 23:02
  • I get PHP error Undefined index: that_random_filename.wav Does this work where blob is an AudioBuffer? – Curtis Jul 08 '18 at 21:20
  • Ok this doesn't work because the PHP should be $_FILES["that_random_filename_wav"] because a period isn't allowed in a name for a form input. – Curtis Jul 09 '18 at 01:33
  • I happen to be stuck with an issue appearently similar to yours and can't make it work: https://stackoverflow.com/questions/52196802/cant-upload-audio-data-with-xmlhttprequest. Any idea? – Michel Sep 08 '18 at 02:40
3

Easiest way, if you just want to hack that code, is go in to recorderWorker.js, and hack the exportWAV() function to something like this:

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 });

    var xhr=new XMLHttpRequest();
    xhr.onload=function(e) {
        if(this.readyState === 4) {
            console.log("Server returned: ",e.target.responseText);
        }
    };
    var fd=new FormData();
    fd.append("that_random_filename.wav",audioBlob);
    xhr.open("POST","<url>",true);
    xhr.send(fd);
}

Then that method will save to server from inside the worker thread, rather than pushing it back to the main thread. (The complex Worker-based mechanism in RecorderJS is because a large encode should be done off-thread.)

Really, ideally, you'd just use a MediaRecorder today, and let it do the encoding, but that's a whole 'nother ball of wax.

cwilso
  • 13,610
  • 1
  • 30
  • 35