浏览器通过原生JS实现录音功能

浏览器通过原生JS实现录音功能

    • 一. AudioContext介绍
    • 二. getUserMedia介绍
    • 三. MediaRecorder介绍
    • 四. 录音执行流程
    • 五. 主要代码简述
    • 六. Vue样式
    • 七. Vue完整代码
    • 八. 常见问题

一. AudioContext介绍

  • AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。在做任何其他操作之前,您需要创建一个AudioContext对象,因为所有事情都是在上下文中发生的。建议创建一个AudioContext对象并复用它,而不是每次初始化一个新的AudioContext对象,并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。详情
  • AudioContext 兼容写法
if (!window.AudioContext) {
     
   window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
}

二. getUserMedia介绍

  • Navigator.getUserMedia()方法提醒用户需要使用音频(0或者1)和(0或者1)视频输入设备,比如相机,屏幕共享,或者麦克风。如果用户给予许可,successCallback回调就会被调用,MediaStream对象作为回调函数的参数。如果用户拒绝许可或者没有媒体可用,errorCallback就会被调用,类似的,PermissionDeniedError 或者NotFoundError对象作为它的参数。注意,有可能以上两个回调函数都不被调用,因为不要求用户一定作出选择(允许或者拒绝)。详情
  • Navigator.getUserMedia 兼容写法
// 老版浏览器可能根本没有实现mediaDevices, 为其设置一个空对象
if (!navigator.mediaDevices) {
     
  navigator.mediaDevices = {
     };
}
if (!navigator.mediaDevices.getUserMedia) {
     
  navigator.mediaDevices.getUserMedia = function (constraints) {
     
    let getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
    // 浏览器不支持
    if (!getUserMedia) {
     
      return Promise.reject(new Error('您的浏览器暂不支持 getUserMedia !'));
    }
    // 包装老版 getUserMedia
    return new Promise((resolve, reject) => getUserMedia.call(navigator, constraints, resolve, reject));
  }
}

三. MediaRecorder介绍

  • MediaDevices 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。详情

四. 录音执行流程

打开
打开失败
打开成功
创建一个新的音视频对象
创建音视频源
将音视频源 链接 到新音视频对象 中
创建媒体录制接口对象
录制
录制结束
getUserMedia获取音频输入设备
打开设备
打印日志
AudioContext获取实例
audioContext.createMediaStreamDestination
audioContext.createMediaStreamSource_stream_
new MediaRecorder_destination.stream_
开始录制
创建本地音视频文件URL.createObjectURL_blob_

五. 主要代码简述

methods: {
     
  start() {
     
    // 停止之前的录制内容
    this.$mediaRecorder && this.$mediaRecorder.stop();

    if (!window.AudioContext) {
     
      window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
    }

    // 参考 https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia

    // 老版浏览器可能根本没有实现mediaDevices, 为其设置一个空对象
    if (!navigator.mediaDevices) {
     
      navigator.mediaDevices = {
     };
    }
    if (!navigator.mediaDevices.getUserMedia) {
     
      navigator.mediaDevices.getUserMedia = function (constraints) {
     
        let getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
        // 浏览器不支持
        if (!getUserMedia) {
     
          return Promise.reject(new Error('您的浏览器暂不支持 getUserMedia !'));
        }
        // 包装老版 getUserMedia
        return new Promise((resolve, reject) => getUserMedia.call(navigator, constraints, resolve, reject));
      }
    }
    // 参数
    // let constraints = {audio: true, video: true}; // 请求不带任何参数的音频和视频
    let constraints = {
     audio: true};  // 请求音频

    let mediaStream = navigator.mediaDevices.getUserMedia(constraints);

    mediaStream.then((stream) => {
     
      console.info("打开成功!")

      let audioContext = new AudioContext();

      // 创建一个新的音视频对象
      let destination = audioContext.createMediaStreamDestination();
      // 创建音视频源
      let mediaStreamSource = audioContext.createMediaStreamSource(stream);
      // 将音视频源 链接 到新音视频对象 中
      mediaStreamSource.connect(destination);

      // 参考 https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder
      // 媒体录制接口
      let mediaRecorder = new MediaRecorder(destination.stream, {
     audioBitsPerSecond: 16000});

      let chunks = [];
      // 有可用数据流时触发,e.data即需要的音视频数据
      mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
      // 间视频录制结束时触发
      mediaRecorder.onstop = () => {
     
        // 通过Blob数据块, 合成完整的Blob块数据
        let blob = new Blob(chunks, {
     'type': 'audio/mpeg'});
        // 通过Blob合建对象URL本地地址
        let url = URL.createObjectURL(blob);
        // 绑定到 audio 元素上
        this.$refs.recordPlayer.src = url;
      };
      // 將 mediaRecorder 对象扔到全局this中, 用于其他方法调用
      this.$mediaRecorder = mediaRecorder;
      // 录制开始
      mediaRecorder.start();
    }, () => {
     
      console.log("打开失败!");
    });
  },
  stop() {
     
    // 返回录制的二进制数据, 调用这个方法后会生成一个新的Blob对象
    this.$mediaRecorder.requestData();
    // 停止录制
    this.$mediaRecorder.stop();
  },
},

六. Vue样式

浏览器通过原生JS实现录音功能_第1张图片

七. Vue完整代码

<template>
  <div style="height: 100%; width: 100%;">
    <div>
      <audio ref="recordPlayer" controls src=""/>
      <div></div>
      <ButtonGroup>
        <Button size="small" @click="start">开始</Button>
        <Button size="small" @click="stop">结束</Button>
      </ButtonGroup>
    </div>
  </div>
</template>

<script>
  export default {
     
    name: "home",
    mounted() {
     
    },
    methods: {
     
      start() {
     
        // 停止之前的录制内容
        this.$mediaRecorder && this.$mediaRecorder.stop();

        if (!window.AudioContext) {
     
          window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
        }

        // 参考 https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia

        // 老版浏览器可能根本没有实现mediaDevices, 为其设置一个空对象
        if (!navigator.mediaDevices) {
     
          navigator.mediaDevices = {
     };
        }
        if (!navigator.mediaDevices.getUserMedia) {
     
          navigator.mediaDevices.getUserMedia = function (constraints) {
     
            let getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
            // 浏览器不支持
            if (!getUserMedia) {
     
              return Promise.reject(new Error('您的浏览器暂不支持 getUserMedia !'));
            }
            // 包装老版 getUserMedia
            return new Promise((resolve, reject) => getUserMedia.call(navigator, constraints, resolve, reject));
          }
        }
        // 参数
        // let constraints = {audio: true, video: true}; // 请求不带任何参数的音频和视频
        let constraints = {
     audio: true};  // 请求音频

        let mediaStream = navigator.mediaDevices.getUserMedia(constraints);

        mediaStream.then((stream) => {
     
          console.info("打开成功!")

          let audioContext = new AudioContext();

          // 创建一个新的音视频对象
          let destination = audioContext.createMediaStreamDestination();
          // 创建音视频源
          let mediaStreamSource = audioContext.createMediaStreamSource(stream);
          // 将音视频源 链接 到新音视频对象 中
          mediaStreamSource.connect(destination);

          // 参考 https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder
          // 媒体录制接口
          let mediaRecorder = new MediaRecorder(destination.stream, {
     audioBitsPerSecond: 16000});

          let chunks = [];
          // 有可用数据流时触发,e.data即需要的音视频数据
          mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
          // 间视频录制结束时触发
          mediaRecorder.onstop = () => {
     
            // 通过Blob数据块, 合成完整的Blob块数据
            let blob = new Blob(chunks, {
     'type': 'audio/mpeg'});
            // 通过Blob合建对象URL本地地址
            let url = URL.createObjectURL(blob);
            // 绑定到 audio 元素上
            this.$refs.recordPlayer.src = url;
          };
          // 將 mediaRecorder 对象扔到全局this中, 用于其他方法调用
          this.$mediaRecorder = mediaRecorder;
          // 录制开始
          mediaRecorder.start();
        }, () => {
     
          console.log("打开失败!");
        });
      },
      stop() {
     
        // 返回录制的二进制数据, 调用这个方法后会生成一个新的Blob对象
        this.$mediaRecorder.requestData();
        // 停止录制
        this.$mediaRecorder.stop();
      },
    },
  }
</script>

<style scoped>
</style>

八. 常见问题

页面开始录音时, Console提示 Cannot read property ‘getUserMedia’ of undefined .
该问题可以通过以下几个方式解决:

  1. 访问localhost, 或127.0.0.1地址解决.
  2. Vue或其他引擎启用Https访问.
  3. 修改浏览器Insecure origins treated as secure配置, 谷歌浏览器地址栏打开chrome://flags/#unsafely-treat-insecure-origin-as-secure, 找到Insecure origins treated as secure, 启用该配置, 然后填写自己的IP地址, 包括Port, 最后Relaunch.
    浏览器通过原生JS实现录音功能_第2张图片

你可能感兴趣的:(JS,web,js,javascript,html5)