Create an mp3 file using the arrayBuffer functionality

Struggling with StackOverflow, I attempted to record audio from a Raspberry Pi using Node.js (1). The audio stream is then sent through a WebSocket server (code omitted for simplicity), where a Vue.js WebSocket listens to the stream. My goal is to save this stream as an mp3 file (2), but I encounter noise or receive no output.

  1. Raspberry Pi:

    ai = new audio.AudioIO({
            inOptions: {
              channelCount: 1,
              sampleFormat: audio.SampleFormat16Bit,
              sampleRate: 44100,
              deviceId: 6, 
              closeOnError: true
            }
          });
    
          ai.on('data', buf => {
          
          clientAudioWebsocket.send(buf)
          }
          );
         
          ai.start();  
    
  2. Vue.js Portion

    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) {
    
    
      }
    
  3. Converting 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)); 
    
              mp3Data.push(mp3Tmp);
              mp3Tmp = mp3encoder.flush();
              mp3Data.push(mp3Tmp);
    

Confused by the arraybuffer size of 16384, I am seeking solutions without involving server-side processing. Thank you.

Answer №1

After some searching, I finally found the solution to my problem. It turns out that I forgot to create an Int16Array - a simple mistake with a big impact! (Note to self: sometimes stepping away for an hour can help clear your mind and lead you to the answer).

Here is the solution I discovered:

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

Answer №2

If you're looking to explore more, check out this link -> https://github.com/johndoe/audio-recording-tool. It's worth checking out. I have plans to develop a user-friendly web application for this purpose instead of relying on cronjob. Instructions

To get started, simply run the command below in your terminal or set it up as a recurring cronjob:

$ node record.js -s "http://musicstreaming.com" -d 15000 -o "./musiclibrary"

Please make sure that when setting this up as a cronjob, you provide absolute paths for both node and record.js files. Parameters

-s The URL of the audio stream to be recorded (default http://musicstreaming.com)
-d Recording duration in milliseconds (default 10000)
-o Output directory for saving the file (default ./musiclibrary)

Integration with IFTTT

In addition, you can include these parameters to integrate with an IFTTT Webhook applet that triggers upon completion of each recording.

--ifttt_event Specify the Event Name used in the Webhook applet
--ifttt_key User's unique IFTTT Webhooks key

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating the value of a $scope variable located within an included template in AngularJS

My setup is quite simple as outlined below. The issue I'm facing is that out of the two variables I define within the $http success callback, only one is reflected in the UI. In this scenario, I am attempting to display progress when the controller l ...

Tips for positioning text on the left and right sides of a div in HTML styling

I am struggling with positioning two pieces of text within a div. Despite having some styling already in place, the text is currently displaying one after the other on the left-hand side. I want to position one piece of text to the left and another to the ...

Create a unique functionality by assigning multiple event handlers to a single event

I am looking to add a JavaScript function to an event that already has a handler function. The new function should complement the existing one rather than replace it. For instance: There is a function named exFunction() that is currently linked to docume ...

Error encountered with NG6 Angular sass files

Lately, I've been experimenting with NG6 Angular and it's growing on me. However, I hit a roadblock when attempting to switch from its default stylus to SASS, which is my preferred style in other projects. I have all the necessary dependencies in ...

Coming back from retrieving data from an API

I'm having trouble with a function that performs a POST request to retrieve access tokens from an API. Although the function successfully prints the token to the console, I haven't been able to figure out how to properly parse and save the access ...

Here is a unique rewrite:"Adjusting the prop of a Material UI Button component depending on screen size breakpoints can be achieved by utilizing

While using the Material UI Button component, I encountered an issue with conditionally determining the variant of the button based on screen size. Specifically, I want the variant to be 'outlined' on medium and larger screens, and no variant at ...

Is NodeJS significantly slower compared to PHP?

Currently running a small-scale web server under Apache + PHP + MySQL, I am considering the possibility of switching to NodeJS. The server's primary functions are serving static files and querying the database for select and insert operations only. I ...

Trouble with Firebase Setup in Ionic 4+ Web Application

I'm currently trying to establish a connection between my ionic application and Firebase for data storage, retrieval, and authentication. Despite using the npm package with npm install firebase, I encountered an error message that reads: > [email& ...

Is it possible to utilize NodeMailer within strongloop for sending emails?

I'm attempting to send emails from my StrongLoop application. I am currently working within the CloudNine platform online. Despite trying a simple code to send the email, I am encountering issues and nothing seems to be working as expected. ...

What is the best way to append a JavaScript object to a JSON file on a new line

What changes should be made to this function in order to append each object in the file on a new line? exports.addWaypoint = function(id, type, param){ var dataIn = fs.readFileSync('./markers.json'); var obj = JSON.parse(dataI ...

What is the best way to retrieve an array that was created using the useEffect hook in React?

Utilizing the power of useEffect, I am fetching data from two different APIs to build an array. My goal is to access this array outside of useEffect and utilize it in the return statement below to render points on a map. However, when trying to access it ...

Parsing error: Unforeseen token encountered. Consider adding a supplementary loader to manage the output of these loaders

Could someone please break down this syntax message?.length === 1 and show me how to convert it into standard JavaScript? https://i.stack.imgur.com/20Ui6.png I am encountering an error when trying to use a Vue.js component that I downloaded from another ...

What sets apart a class from a service in NativeScript?

I am embarking on the journey of learning Nativescript + Angular2, and while reading through the tutorial, I came across this interesting snippet: We’ll build this functionality as an Angular service, which is Angular’s mechanism for reusable classes ...

The mobile navigation in HTML has a slight issue with the ::after pseudo-element, specifically within the

As I prepare to launch my website, I have made adjustments to the mobile layout by moving the navigation links to a navigation drawer. The template I am using included JavaScript scripts to handle this navigation change. However, I encountered an issue whe ...

Angular Testing - issue with promise returning unexpected results

I'm having trouble with populating vm.chartData in my HomeCtrl. Even though I've mocked data to it in the beforeEach() function, when I console.log(scope.vm.chartData), it returns undefined. However, other scope variables like graphLoading are pr ...

Unlocking location data in React Router-DOM 6: A step-by-step guide

I am currently working on implementing a 'forgot password' feature, where I am attempting to transfer the email data from the 'login page' to the 'forgot password' page using a Link element. However, I am encountering an issu ...

PHP Ajax not updating variable as expected

Apologies for the repetitive questions, but I have tried numerous solutions and cannot seem to figure out why this particular one is not working. I am invoking ajax through a click function, but I am unable to retrieve the jList value and update the variab ...

Can you explain the purpose of using 'created' and 'activated' with keep-alive components in Vue.js?

At first, I am retrieving data from the api within the created hook and it is functioning perfectly. created() { this.fetchInformation() } While exploring best practices for lifecycle hooks, I stumbled upon this advice: You need to fetch some data f ...

Using Cookies with Next.js and Vercel

I am facing an issue with my NextJs app deployed on Vercel where the cookie is not being set. Upon checking the console in Network, I can see that the request returns a 200 status and the set-cookie value is present without any warning. However, when I loo ...

Tips and tricks for personalizing an npm package in vue.js

I've been working on customizing a multiselect package to incorporate tab events in vuejs, but so far I haven't seen any changes reflected. I'm looking for guidance on how to modify a library within Vue. My approach was to navigate to the n ...