JavaScript 实现页面中录音功能

Posted wayou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript 实现页面中录音功能相关的知识,希望对你有一定的参考价值。

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

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

准备页面

首先准备一个页面,其中内容很简单,两个按钮,一个用于录音,一个用于播放。

<!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("授权成功!");

      const mediaRecorder = new MediaRecorder(stream);

      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);
      ;

      mediaRecorder.ondataavailable = function(e) 
        chunks.push(e.data);
      ;
    ,
    () => 
      console.error("授权失败!");
    
  );
 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("授权成功!");

      const mediaRecorder = new MediaRecorder(stream);

      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);
      ;

      mediaRecorder.ondataavailable = e => 
        chunks.push(e.data);
      ;

      mediaRecorder.onstop = e => 
        var blob = new Blob(chunks,  type: "audio/ogg; codecs=opus" );
        chunks = [];
        var audioURL = window.URL.createObjectURL(blob);
        player.src = audioURL;
      ;
    ,
    () => 
      console.error("授权失败!");
    
  );
 else 
  console.error("浏览器不支持 getUserMedia");

运行

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

相关资源

以上是关于JavaScript 实现页面中录音功能的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript实用功能代码片段

javascript是干嘛用的

微信小程序录音界面以及功能实现

从零开始实现基于微信JS-SDK的录音与语音评价功能

javascript对象

是否可以使用 Javascript 在音频文件中找到一段无声的片段?