Utilizing Audio Record Feature with a pair of buttons - one for initiating recording and the other for concluding recording

I'm new to Vue.js and trying to create a simple audio recorder that starts recording on click of a button and stops when another button is clicked. The goal is to display the audio file in the template and save it locally as a blob.

Here is the template I have implemented:

<template>
    <div class="form-group row">
        <label for="Audio" class="col-2 col-form-label labelTop">Audio</label>
        <div class="col-1">
            <button @click="recordAudio()" type="button" id="button_record" class="btn btn-danger">
            </button>
            <button type="button" id="button_stop" class="btn btn-success">
            </button>
            <div id="audio" class="audio" controls>
            </div>
        </div>
    </div>
</template>

And here is the script with the code:

export default {
    methods: {
        recordAudio() {
            var device = navigator.mediaDevices.getUserMedia({ audio: true });
            var items = [];
            device.then((stream) => {
                var recorder = new MediaRecorder(stream);
                recorder.ondataavailable = (e) => {
                    items.push(e.data);
                    if (recorder.state == "inactive") {
                        var blob = new Blob(items, { type: "audio/*" });
                        var audio = document.getElementById("audio");
                        var mainaudio = document.createElement("audio");
                        mainaudio.setAttribute("controls", "controls");
                        audio.appendChild(mainaudio);
                        mainaudio.innerHTML =
                            '<source src="' +
                            URL.createObjectURL(blob) +
                            '" type="audio/*" />';
                    }
                };
                recorder.start();
                document.getElementById("button_stop").addEventListener("click", () => {
                    recorder.stop();
                });
            });
        },
    }
};

I have tried several ways to stop the recording upon clicking the stop button, but nothing seems to work. Any help would be greatly appreciated as I am new to Vue and Javascript.

Answer №1

If you want to make sure you can achieve this functionality successfully, consider storing the recorder in a variable within your component rather than just within your function. This way, you will have the ability to easily call this.recorder.stop() when a button is clicked.

Here's how you can implement it:

data() {
  return {
    recorder: null
  }
},
methods: {
    recordAudio() {
      var device = navigator.mediaDevices.getUserMedia({ audio: true });
      device.then((stream) => {
        // utilize this approach!
        this.recorder = new MediaRecorder(stream);
        this.recorder.ondataavailable = (e) => {
           // ....
        };
      });
    },
    // triggered when button is clicked
    stop() {
      this.recorder.stop()
    }
}

Template:

<button type="button" id="button_stop" class="btn btn-success" @click="stop">

Answer №2

In this section, my parent component initiates the recordAudio and stop methods. Once the recording is complete, the data is sent back to the parent component and then forwarded to another child component for transmission to a server. This process is similar to sending a voice message on WhatsApp, with the result being displayed in a chat above.

<template>
  <!-- Voice Record -->
  <div>
    <v-btn @click="recordAudio()">
      <v-icon> mdi-microphone </v-icon>
    </v-btn>
    <v-btn @click="stop()">
      <v-icon> mdi-stop-circle-outline </v-icon>
    </v-btn>
  </div>
</template>
<script>
export default {
  data() {
    return {
      recorder: null,
      chunks: [],
      device: null,
      blobObj: null,
    };
  },

  created() {
    this.device = navigator.mediaDevices.getUserMedia({ audio: true });
  },
  methods: {
    
    recordAudio() {
      this.device.then((stream) => {
        this.recorder = new MediaRecorder(stream);
        this.recorder.ondataavailable = (e) => {
          this.chunks.push(e.data);
          if (this.recorder.state === "inactive") {
            let blob = new Blob(this.chunks, { type: "audio/wav" });
            // save to blobObj
            this.blobObj = blob;
            this.chunks = [];
            // emit to parent
            this.$emit("send-audio", this.blobObj);
            this.blobObj = null;
          }
        };
        // start
        this.recorder.start();
      });
    },
    stop() {
      // stop
      this.recorder.stop();
    },
  },
};
</script>

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

The Google timezone API is displaying an inaccurate daylight saving offset

London now has an additional +1 hour of daylight saving time. I made a request to the Google timezone API for the London timezone, but unfortunately, it is not displaying the correct time. https://maps.googleapis.com/maps/api/timezone/json?location=51.507 ...

Creating a list of font sizes for each <p> tag in my HTML document

I am looking to create an array containing the font sizes of all the p tags in my HTML document. How can I specifically target only the p elements and not their parent elements? ...

Discover the method for selecting an element within a table that includes a style attribute with padding using Jquery

Looking for a way to identify a td element with the padding style in a table I've attempted to locate a td element with the padding style attribute in a table $(Table).find('td[style="padding:"]') or $(Table).find('td[style] ...

Struggling to create a SVG Line with DOM Manipulation in Typescript

I'm having trouble adding an SVG element to my div using the appendChild function in TypeScript. I want to add a line inside the SVG, but for some reason, I can't see the line output on my browser. There are no errors showing up either. Please he ...

Why does the shadow in Three.js only appear in a limited region?

I brought in a model and noticed that the shadow is only visible in a small area (highlighted in green in the image). How can I make all objects display their shadows? https://i.sstatic.net/hmzp2.png Below is my code snippet. light = new THREE.Direction ...

What exactly is HTML cloud storage all about?

As I work on developing an app through phonegap, one question that comes to mind is the possibility of storing information online. For instance, if there's a number variable that increases when a button is pressed, can this value be saved somewhere an ...

Is it possible to make the info box centered and adjust everything to seamlessly fit on all screen sizes?

Is there a way to create a centered info box that stretches to fit any screen size? ...

Tips for creating a reusable function in React.js?

I have a script that executes on input focus and passes certain values based on a specific logic. I would like to reuse this script for multiple input fields that trigger the focus event. How can I accomplish this? This is my current script: <input ...

Include additional data in the FormData object before sending it over AJAX requests

Currently, I am utilizing AJAX to store some data. The primary concern I have is figuring out how to incorporate additional information into the FormData object along with what I already have. Below is the function that I'm using. Could you assist me ...

Jquery Plugin fails to generate dynamic elements effectively

I developed a masking jQuery script that dynamically adds elements to an existing input element. var link = $('<a title="show" role="link" href="#" class="masker-value">show</a>'); wrapper: function() { container = $(container) ...

"Exploring the Keyboard Shortcuts and Navigation Features of Vuetify 2.x's v-data

Why is it not possible to navigate v-data-tables in Vuetify 2.x when it was a feature in earlier versions like 1.5.x? Is there a straightforward solution for this or an explanation behind the removal of these keyboard commands? ...

Altering the backdrop upon hovering over an element

As a beginner in Javascript and Jquery, I am working on creating an interactive feature where hovering over one element changes the background image in another column. I have managed to write the function, but now I want to add an animation to the image tr ...

Utilizing Next.js to create dynamic routes and static builds incorporating unique ID values within the URL paths

Is there a way to create a page in Next.js where I can extract the ID from the URL in a dynamic route and use it for a static build without having to predefine all possible values of the ID in getStaticProps()? For example, the URL is as follows: localhost ...

What is the reason for needing a page reload in Javascript or JQuery?

I'm curious why Javascript or jQuery require a page reload before applying certain effects. CSS updates in real-time, as demonstrated by the following example: This changes dynamically without needing to refresh the page @media all and (max-width:7 ...

Concealing the pathway to a background image

Currently, I have a large grid made up of divs that display different sections of an image. By using background-image and background-position, I am able to showcase parts of the image. However, one issue is that users can easily view the complete image by ...

Using props in the v-bind:src directive with Vue - a comprehensive guide!

I have a Vue application with a Block component that needs to display an image. The Block component is used multiple times in the App component, each time passing a value to determine which image src to choose from an array. When I try to print {{ this.Im ...

Clones are made sortable instead of arranging them in a specific order

I have a list that can be sorted with some customizations. However, I am facing an issue where the items in the list get duplicated every time I try to sort them. When I pull one item to sort it, another copy gets added automatically. I am struggling to u ...

Iterating through data in Vue.js does not depend on the number of fields present in the results

v-for appears to be iterating over my fields instead of the selected data. For example, if I have 3 fields in my database (name, email, username), it will loop 3 times. See Result Profile.vue <template> <div> <h3>Profile< ...

Vue.js: When Props Become Undefined

After running this code, the output shows "undefined". Child component export default { porps: [ 'idx' ], mounted () { console.log(this.idx) }, } //BambooPage.vue Parent component <template> <div class="bamboo"& ...

How can I use AngularJS to initiate code to run after the view and controller have successfully synchronized a specific change?

I am currently using AJAX to load date ranges into a pair of SELECTs (managed with AngularJS ng-repeat), which are then transformed into a slider using jQuery UI's selectToUISlider. My concern is that selectToUISlider may behave unexpectedly if the SE ...