ajbeaven ajbeaven - 1 month ago 43
Node.js Question

Upload a binary encoded audio file via ajax and save

I have an audio file saved locally that I want to read, upload to a server via ajax and then store on the server. Somewhere along this process the file gets corrupted such that the file that's saved on the server cannot be played.

I'll list simplified bits of code that show the process I'm going through so hopefully it'll be evident where I'm going wrong.

1) After audio is recorded (using getUserMedia and MediaRecorder), a local file is saved:

var audioData = new Blob(chunks, { type: 'audio/webm' });
var fileReader = new FileReader();
fileReader.onloadend = function() {
var buffer = this.result,
uint8Array = new Uint8Array(buffer);

fs.writeFile('path/to/file.webm', uint8Array, { flags: 'w' });
}
fileReader.readAsArrayBuffer(audioData);


2) Later this local file is read and sent to a server (using the library axios to send the ajax request)

fs.readFile('path/to/file.webm', 'binary', (err, data) => {
var formData = new FormData();
formData.append('file', new Blob([data], {type: 'audio/webm'}), 'file.webm');
axios.put('/upload', formData);
});


3) The server then handles this request and saves the file

[HttpPut]
public IActionResult Upload(IFormFile file)
{
using (var fileStream = new FileStream("path/to/file.webm", FileMode.Create))
{
file.CopyTo(fileStream);
}
}


The local audio file can be played successfully however the audio file on the server does not play.

I'm not sure if this is helpful information, but here are the first few lines of text I see when I open the local file in a text editor (notepad++):

enter image description here

And the same when I open the one on the server:

enter image description here

So kinda the same... but different. I've tried encoding a myriad of different ways but everything seems to fail. Fingers crossed someone can point me in the right direction here.

Answer

The problem was with how I was passing through the file contents from fs.readFile. If I passed a base64 encoded raw buffer from fs.readFile via json, converted that to a byte array on the server and saved that, then I can successfully play it on the server.


fs.readFile('path/to/file.webm', (err, data) => {
    axios.put('/upload', { audioData: data.toString('base64') });
});

[HttpPut]
public IActionResult Upload([FromBody]UploadViewModel upload)
{
    var audioDataBytes = Convert.FromBase64String(upload.AudioData);

    using (var memoryStream = new MemoryStream(audioDataBytes))
    using (var fileStream = new FileStream("path/to/file.webm", FileMode.Create))
    {
        await memoryStream.CopyToAsync(fileStream);
    }
}