Use getusermedia media devices in reactJS to record audio

Webwoman picture Webwoman · May 20, 2018 · Viewed 8.2k times · Source

Hi all I try to implement getUserMedia in my reactJS application to record audio.

I struggle to link my mediaRecorder this.state object to the state changement, and make the media devices API get the function I need to provide my application.

When I click on "start the record" on my view, my console return me :

TypeError: this.state.mediaRecorder.start is not a function

48 | startRecord() { 49 | 50 |

51 | this.setState({mediaRecorder: this.state.mediaRecorder.start()}); 52 | alert("start record function started =, mediaRecorder state : " + this.state.mediaRecorder.state) 53 | console.log( this.state.mediaRecorder.state); // > recording 54 |
console.log("recorder started"); View compiled

Here my app.js :

  import React from "react";
// import "./install.js" ;
import "./mediaDevices-getUserMedia-polyfill.js";
class RecorderAPI extends React.Component {
  constructor(props) {
    super(props);
    this.handleDelete = this.handleDelete.bind(this);
    this.startRecord = this.startRecord.bind(this);
    this.stopRecord = this.stopRecord.bind(this);
    this.recordOnStop = this.recordOnStop.bind(this);

      this.state = {
      mediaRecorder : [],
      audioURL : []
      }
  }

  componentDidMount() {
  if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    console.log('getUserMedia supported');
                                          // target
    navigator.mediaDevices.getUserMedia( {audio: true })

      /***** success callback ******/
      // create a media stream
      .then(function (stream) {
        //if callback succeed, the following code will run :

        // create a new Media Recorder instance
        // with MediaRecorder() constructor
        // this instance is the entry point
        // into using the MediaRecorder API
        stream = new MediaRecorder(stream);
        this.setState({ mediaRecorder: stream });
      })/***** error callback *****/
      .catch(function (err) {
        console.log("error : " + err)
      });
  }
  else {
    console.log("getUserMedia : missing")
  }
}


  // launch mediaRecorder.start methods the stream
  // when the record button is pressed:
  startRecord() {


          this.setState({mediaRecorder: this.state.mediaRecorder.start()});
          alert("start record function started =, mediaRecorder state : " + this.state.mediaRecorder.state)
          console.log( this.state.mediaRecorder.state); // > recording
          console.log("recorder started");

          // As recording progresses we
          // collect the audio data via an event handler
          var chunks = []; // we set a container
          this.setState({mediaRecorder: this.state.mediaRecorder.ondataavailable = function (e) {
            chunks.push(e.data);
          }
        });

  }

  // e MediaRecorder.stop() method
  // to stop the recording when the stop button is pressed
  stopRecord() {
    // callback for onStop function
    this.recordOnStop();
    console.log( this.state.mediaRecorder.state);
    console.log("recorder stopped");

  }

  /***** Grabbing and using the blob *****/

  // stop event finalize our blob there
  // from all the chunks we have received:
  recordOnStop() { //  event handler stop of recording
    console.log("recorder stopped");

    var blob = new Blob(this.chunks, { 'type': "audio/ogg ; codecs=opus" })
    this.chunks = [];
    // creates a DOMString containing a URL representing
    // the object given in the parameter
    this.setState({ audioURL: window.URL.createObjectURL(blob)})
  }

  handleDelete(e) {
    var evtTgt = e.target;
    evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
  }



  render() {
    return (

      <div>
        <button className="dashboard">
          Dashboard</button>

        <span className="controlsBar">

          <button onClick={this.startRecord} className="start">
            Start recording
      </button>
          <button onClick={this.stopRecord} className="stop">
            Stop recording</button>
          <button onClick={this.deleteRecord} className="delete">
            Delete recording
      </button>

        </span>
      </div>
    )
  }
}

export default RecorderAPI;

Answer

Webwoman picture Webwoman · May 21, 2018

HERE MY SOLUTION TO MY QUESTION :

/* eslint-env browser */
import React from 'react';
import Bird from "./sounds/birds.mp3"
const audioType = 'audio/*';

class RecordingAPI extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      recording: false,
      audios: [],
    };
  }

  async componentDidMount() {
    const stream = await navigator.mediaDevices.getUserMedia({audio: true});
    // show it to user
    this.audio.src = window.URL.createObjectURL(stream);
    this.audio.play();
    // init recording
    this.mediaRecorder = new MediaRecorder(stream);
    // init data storage for video chunks
    this.chunks = [];
    // listen for data from media recorder
    this.mediaRecorder.ondataavailable = e => {
      if (e.data && e.data.size > 0) {
        this.chunks.push(e.data);
      }
    };
  }

  startRecording(e) {
    e.preventDefault();
    // wipe old data chunks
    this.chunks = [];
    // start recorder with 10ms buffer
    this.mediaRecorder.start(10);
    // say that we're recording
    this.setState({recording: true});
  }

  stopRecording(e) {
    e.preventDefault();
    // stop the recorder
    this.mediaRecorder.stop();
    // say that we're not recording
    this.setState({recording: false});
    // save the video to memory
    this.saveAudio();
  }

  saveAudio() {
    // convert saved chunks to blob
    const blob = new Blob(this.chunks, {type: audioType});
    // generate video url from blob
    const audioURL = window.URL.createObjectURL(blob);
    // append videoURL to list of saved videos for rendering
    const audios = this.state.audios.concat([audioURL]);
    this.setState({audios});
  }

  deleteAudio(audioURL) {
    // filter out current videoURL from the list of saved videos
    const audios = this.state.audios.filter(a => a !== audioURL);
    this.setState({audios});
  }

  render() {
    const {recording, audios} = this.state;

    return (
      <div className="camera">
        <audio


          style={{width: 400}}
          ref={a => {
            this.audio = a;
          }}>
         <p>Audio stream not available. </p>
        </audio>
        <div>
          {!recording && <button onClick={e => this.startRecording(e)}>Record</button>}
          {recording && <button onClick={e => this.stopRecording(e)}>Stop</button>}
        </div>
        <div>
          <h3>Recorded audios:</h3>
          {audios.map((audioURL, i) => (
            <div key={`audio_${i}`}>
              <audio controls style={{width: 200}} src={audioURL}   />
              <div>
                <button onClick={() => this.deleteAudio(audioURL)}>Delete</button>
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }
}
export default RecordingAPI