record mp3 with arrayBuffer

Viewed 650

I try a lot of things with Stackoverflow and I can't get it . So I try to record audio from raspberry pi with nodejs (1). After this stream goes through a websocket server(I don't put this code because it's just a redirection). And last a websocket in vuejs listen the stream. And after I want to record this stream in mp3 (2). But I have noise or nothing. 1 - Raspberry pi :

ai = new audio.AudioIO({
        inOptions: {
          channelCount: 1,
          sampleFormat: audio.SampleFormat16Bit,
          sampleRate: 44100,
          deviceId: 6, // Use -1 or omit the deviceId to select the default device
          closeOnError: true // Close the stream if an audio error is detected, if set false then just log the error
        }
      });

      ai.on('data', buf => {
      
      clientAudioWebsocket.send(buf)
      }
      );
      
     
      ai.start();  

2- Part vuejs

  • Socket :

     this.dataBuffer = []
    
       var self = this
    
       var connectionToLocalServer = new WebSocket("ws://"+ip  +":4444")
       connectionToLocalServer.binaryType = "arraybuffer"
    
        connectionToLocalServer.onmessage = function(event) {
            self.dataBuffer.push(event.data);
    
        }
        connectionToLocalServer.onopen = function(event) {
    
    
      }
    
  • part arraybuffer to mp3

      concatArrayBuffers (bufs) {
                              var offset = 0;
                              var bytes = 0;
                              var bufs2=bufs.map(function(buf,total){
                                  bytes += buf.byteLength;
                                  return buf;
                              });
                              var buffer = new ArrayBuffer(bytes);
                              var store = new Uint8Array(buffer);
                              bufs2.forEach(function(buf){
                                  store.set(new Uint8Array(buf.buffer||buf,buf.byteOffset),offset);
                                  offset += buf.byteLength;
                              });
                              return buffer }
    
    
    
              this.tmpResult = this.concatArrayBuffers(this.dataBuffer);
    
              var mp3Data = [];
    
              var mp3encoder = new lamejs.Mp3Encoder(1, 44100, 128);
    
              var mp3Tmp = mp3encoder.encodeBuffer(this.tmpResult, 0, Math.floor(this.tmpResult.byteLength / 2)); 
            //Push encode buffer to mp3Data variable
              mp3Data.push(mp3Tmp);
    
              // Get end part of mp3
              mp3Tmp = mp3encoder.flush();
    
              // Write last data to the output data, too
              // mp3Data contains now the complete mp3Data
              mp3Data.push(mp3Tmp);
    

And I don't understand why I have arraybuffer with 16384 size buffer. I'm really open to any solution, but I don't want to do it on server side. Thanks

2 Answers

So I found solution and it's because I didn't create an Int16Array :-( (sometimes it'll be better to go outside 1 hour and after you'll find the solution )

The solution is :

let tmpResult = this.concatArrayBuffers(this.dataBuffer)
     
var samples = new Int16Array(tmpResult);
var buffer = [];
var mp3enc = new lamejs.Mp3Encoder(1, 44100, 128);
var remaining = samples.length;
var maxSamples = 1152;
for (var i = 0; remaining >= maxSamples; i += maxSamples) {
     var mono = samples.subarray(i, i + maxSamples);
     var mp3buf = mp3enc.encodeBuffer(mono);
     if (mp3buf.length > 0) {
         buffer.push(new Int8Array(mp3buf));
        }
        remaining -= maxSamples;
}
var d = mp3enc.flush();
if(d.length > 0){
 buffer.push(new Int8Array(d));
}

console.log('done encoding, size=', buffer.length);
var blob = new Blob(buffer, {type: 'audio/mp3'});

You can navigate here -> https://github.com/charlielee/mp3-stream-recorder I recommend this. At some point I'll make a nice GUI web app to do this rather than relying on cronjob. Usage

Run the following in a terminal window or as a cronjob:

$ node index.js -s "http://firewall.pulsradio.com" -d 20000 -o "./shows"

Note: if running this as a cronjob, node and index.js need to be absolute paths to their respective locations. Arguments

-s The URL of the stream to record (default http://firewall.pulsradio.com)
-d The duration in milliseconds to record for (default 5000)
-o The output directory of the file (default ./shows)

IFTTT Support

The following arguments can also be supplied, in order to trigger an IFTTT Webhook applet each time a recording finishes.

--ifttt_event The Event Name entered on the Webhook applet
--ifttt_key The user's IFTTT Webhooks key
Related