zoukankan      html  css  js  c++  java
  • JavaScript 实现页面中录音功能

    页面中实现录音需要使用浏览器提供的 Media​Recorder API,所以前提是需要浏览器支持 MediaStream Recording 相关的功能。

    以下代码默认工作在 Chrome 环境中。

    准备页面

    首先准备一个页面,其中内容很简单,一个录音按钮,一个用于播放的 <audio> 标签。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>audio record</title>
    </head>
    <body>
        <div class="app">
            <button class="record-btn">record</button>
            <audio controls class="audio-player"></audio>
        </div>
        <script src="./recorder.js"></script>
    </body>
    </html>

    获取录音权限

    因为录音需要使用设备的话筒,所以第一步应该是向用户索要录音的权限。这是通过 Media​Devices​.get​User​Media()
    来完成的,其用法为:

    var promise = navigator.mediaDevices.getUserMedia(constraints);

    其中 constraints 为需要获取的权限列表,这里只需要指定音频 audio 即可。

    其返回是个 Promise,因为用户何时进行授权是不确定的。通过在 Promise 的回调中进行授权成功或失败的处理。

    在使用前需要判断浏览器是否已经支持相应的 API,此时得到如下的代码:

    if (navigator.mediaDevices.getUserMedia) {
      const constraints = { audio: true };
      navigator.mediaDevices.getUserMedia(constraints).then(
        stream => {
          console.log("授权成功!");
        },
        () => {
          console.error("授权失败!");
        }
      );
    } else {
      console.error("浏览器不支持 getUserMedia");
    }

    其中成功回调里得到的入参 streamMediaStream 对象。

    此时运行后可看到浏览器展示出了让用户授权使用麦克风的提示。

    向用户索要麦克风使用权限

    向用户索要麦克风使用权限

    创建录音实例

    将上一步获取到的 MediaStream 传入 Media​Recorder 的构造器创建一个录音器的实例。

    var mediaRecorder = new MediaRecorder(stream);

    启动录音

    通过监听页面中录音按钮的点击来启动录音。

    const recordBtn = document.querySelector(".record-btn");
    const mediaRecorder = new MediaRecorder(stream);
    recordBtn.onclick = () => {
      mediaRecorder.start();
      console.log("录音中...");
    };

    MediaRecorder 实例上有个 state 状态,可用来判断录音器当前的活动状态,总共有三种值:

    • inactive:处于休息状态,要么是没开始,要么是开始后已经停止。
    • recording:录音中
    • paused:已经开始,但被暂停了,不是停止也没有被恢复。

    所以通过这个状态,我们可以实现再次点击按钮时,结束录音。

    recordBtn.onclick = () => {
      if (mediaRecorder.state === "recording") {
        mediaRecorder.stop();
        recordBtn.textContent = "record";
        console.log("录音结束");
      } else {
        mediaRecorder.start();
        console.log("录音中...");
        recordBtn.textContent = "stop";
      }
      console.log("录音器状态:", mediaRecorder.state);
    };

    音频数据的获取

    上面按钮处理来自用户的交互,只负责启动或停止录音。音频的数据还是从 Media​Recorder 实例上通过监听其相应的事件来完成的。

    当录音开始时,会触发其 MediaRecorder.ondataavailable 事件,从该事件回调的入参为 BlobEvent,从它身上取到 event.data 便是我们需要的音频数据。因为数据是一段一段产生的,所以需要暂存到一个数组中。

    const chunks = [];
    mediaRecorder.ondataavailable = function(e) {
      chunks.push(e.data);
    };

    目前为止完成的代码应该是这样的:

    recorder.js
    const recordBtn = document.querySelector(".record-btn");
    const playBtn = document.querySelector(".play-btn");
    

    if (navigator.mediaDevices.getUserMedia) {
    var chunks = [];
    const constraints = { audio: true };
    navigator.mediaDevices.getUserMedia(constraints).then(
    stream => {
    console.log("授权成功!");

      <span class="pl-k">const</span> <span class="pl-c1">mediaRecorder</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">MediaRecorder</span>(stream);
    
      <span class="pl-smi">recordBtn</span>.<span class="pl-en">onclick</span> <span class="pl-k">=</span> () <span class="pl-k">=&gt;</span> {
        <span class="pl-k">if</span> (<span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>recording<span class="pl-pds">"</span></span>) {
          <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">stop</span>();
          <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>record<span class="pl-pds">"</span></span>;
          <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音结束<span class="pl-pds">"</span></span>);
        } <span class="pl-k">else</span> {
          <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">start</span>();
          <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音中...<span class="pl-pds">"</span></span>);
          <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>stop<span class="pl-pds">"</span></span>;
        }
        <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音器状态:<span class="pl-pds">"</span></span>, <span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span>);
      };
    
      <span class="pl-smi">mediaRecorder</span>.<span class="pl-en">ondataavailable</span> <span class="pl-k">=</span> <span class="pl-k">function</span>(<span class="pl-smi">e</span>) {
        <span class="pl-smi">chunks</span>.<span class="pl-c1">push</span>(<span class="pl-smi">e</span>.<span class="pl-c1">data</span>);
      };
    },
    () <span class="pl-k">=&gt;</span> {
      <span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>授权失败!<span class="pl-pds">"</span></span>);
    }
    

    );
    } else {
    console.error("浏览器不支持 getUserMedia");
    }

    录音状态的查看

    录音状态的查看

    录音结束及音频的播放

    通过监听 MediaRecorder.onstop 事件,将收集好的音频数据创建成 Blob 对象,然后 通过 URL.createObjectURL 创建成 HTML 中 <audio> 标签可使用的资源链接。

    mediaRecorder.onstop = e => {
      var blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
      chunks = [];
      var audioURL = window.URL.createObjectURL(blob);
      audio.src = audioURL;
    };

    其中,在使用完收到到的音频数据后,将 chunks 置空方便下次录音时使用。

    目前为止完成的代码应该是这样的:

    recorder.js
    const recordBtn = document.querySelector(".record-btn");
    const player = document.querySelector(".audio-player");
    

    if (navigator.mediaDevices.getUserMedia) {
    var chunks = [];
    const constraints = { audio: true };
    navigator.mediaDevices.getUserMedia(constraints).then(
    stream => {
    console.log("授权成功!");

      <span class="pl-k">const</span> <span class="pl-c1">mediaRecorder</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">MediaRecorder</span>(stream);
    
      <span class="pl-smi">recordBtn</span>.<span class="pl-en">onclick</span> <span class="pl-k">=</span> () <span class="pl-k">=&gt;</span> {
        <span class="pl-k">if</span> (<span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>recording<span class="pl-pds">"</span></span>) {
          <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">stop</span>();
          <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>record<span class="pl-pds">"</span></span>;
          <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音结束<span class="pl-pds">"</span></span>);
        } <span class="pl-k">else</span> {
          <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">start</span>();
          <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音中...<span class="pl-pds">"</span></span>);
          <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>stop<span class="pl-pds">"</span></span>;
        }
        <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音器状态:<span class="pl-pds">"</span></span>, <span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span>);
      };
    
      <span class="pl-smi">mediaRecorder</span>.<span class="pl-en">ondataavailable</span> <span class="pl-k">=</span> <span class="pl-smi">e</span> <span class="pl-k">=&gt;</span> {
        <span class="pl-smi">chunks</span>.<span class="pl-c1">push</span>(<span class="pl-smi">e</span>.<span class="pl-c1">data</span>);
      };
    
      <span class="pl-smi">mediaRecorder</span>.<span class="pl-en">onstop</span> <span class="pl-k">=</span> <span class="pl-smi">e</span> <span class="pl-k">=&gt;</span> {
        <span class="pl-k">var</span> blob <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">Blob</span>(chunks, { type<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>audio/ogg; codecs=opus<span class="pl-pds">"</span></span> });
        chunks <span class="pl-k">=</span> [];
        <span class="pl-k">var</span> audioURL <span class="pl-k">=</span> <span class="pl-c1">window</span>.<span class="pl-c1">URL</span>.<span class="pl-en">createObjectURL</span>(blob);
        <span class="pl-smi">player</span>.<span class="pl-smi">src</span> <span class="pl-k">=</span> audioURL;
      };
    },
    () <span class="pl-k">=&gt;</span> {
      <span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>授权失败!<span class="pl-pds">"</span></span>);
    }
    

    );
    } else {
    console.error("浏览器不支持 getUserMedia");
    }

    运行

    完成上面步骤后,实现了一个简单的录音功能,可通过此地址在线体验。完整的代码可在仓库 wayou/audio-recorder 中获取到。

    相关资源

  • 相关阅读:
    easy ui 表单ajax和from两种提交数据方法
    easy ui 下拉级联效果 ,下拉框绑定数据select控件
    easy ui 下拉框绑定数据select控件
    easy ui 异步上传文件,跨域
    easy ui 菜单和按钮(Menu and Button)
    HTTP 错误 404.3
    EXTJS4.2 后台管理菜单栏
    HTML 背景图片自适应
    easy ui 表单元素input控件后面加说明(红色)
    EXTJS 4.2 添加滚动条
  • 原文地址:https://www.cnblogs.com/Wayou/p/js_audio_recorder.html
Copyright © 2011-2022 走看看