【问题标题】:Use getusermedia media devices in reactJS to record audio在 reactJS 中使用 getusermedia 媒体设备录制音频
【发布时间】:2018-10-30 01:41:51
【问题描述】:

大家好,我尝试在我的 reactJS 应用程序中实现 getUserMedia 来录制音频。

我很难将我的 mediaRecorder this.state 对象链接到状态更改,并使媒体设备 API 获得我需要提供我的应用程序的功能。

当我点击视图上的“开始记录”时,我的控制台会返回:

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

这里是我的 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;

【问题讨论】:

  • 据此 (developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/start) mediaRecorder.start() 函数不返回任何内容。为什么要通过 this.setState 更新 mediaRecorder 对象并返回 mediaRecorder.start() 的值?另外,您确定要在 componentDidMount 回调中设置 mediaRecorder 对象吗?
  • 嗨,Ricardo,我的目标是直接在构造函数中设置我的 mediaDevices API,以使我的 API 线路与组件的不同方法保持一致。
  • 理想的应该是在我的 componentDidMount() 函数中创建 onClick 函数,以便在单击元素时调用它们。我目前正在尝试,希望它能在 ReactJS 上运行。如果你查看原始代码,就会有很多 onClick 回调。 github.com/mdn/web-dictaphone/edit/gh-pages/scripts/app.js

标签: reactjs api audio recording


【解决方案1】:

试试这个?

import React, { useEffect } from 'react';

const Chat = (props) => {
    useEffect(() => {
        var constraints = {
            video: true,
            audio: true
        };
        async function getMedia(constraints) {
            let stream = null;
            try {
                stream = await navigator.mediaDevices.getUserMedia(constraints);
                // console.log(stream.getAudioTracks()[0].getCapabilities()) ;
                localVideoref.current.srcObject = stream;
                localVideoref.current.muted = true;
            } catch (err) {
                /* handle the error */
                console.log(err);
            }
        }

        getMedia(constraints);
    }, []);
    var localVideoref = React.createRef();

    return (
        <div>
            peer component
            <video ref={localVideoref} autoPlay ></video>
        </div>);
}

export default Chat;

非常不言自明。

【讨论】:

    【解决方案2】:

    这里是我的问题的解决方案:

    /* 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
    

    【讨论】:

    • this.mediaRecorder=new MediaRecorder(stream); 之后没有任何工作没有控制台没有任何东西,如果执行 stop 方法然后我得到 TypeError: Cannot read property 'stop' of undefined
    • 发生了什么事?从那以后你克服了这个错误吗?
    • 是的,它正在工作,但我猜我下载时音频坏了,它只在 mpc(经典媒体播放器)播放器中播放,后来我切换到 github.com/mattdiamond/Recorderjs,但我无法对缓冲区进行下采样并使其成为单声道
    • 你能告诉我吗,这个 getUserMedia() 在 React v15 中是支持的。请给我建议。
    • @kaviya.PI 这么认为,因为 getUserMedia() 是一个 javascript 规范,因此应该不受 React 规范的任何影响,也就是说,getUserMedia 可以发展,例如,navigator.mediaDevices.getUserMedia 已经已弃用,我们现在邀请使用MediaDevices.getUserMedia()developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMediadeveloper.mozilla.org/en-US/docs/Web/API/MediaDevices/…,您是否遇到过navigator.mediaDevices.getUserMedia 的问题?
    猜你喜欢
    • 1970-01-01
    • 2016-03-26
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    相关资源
    最近更新 更多