在前端网页中,录音功能一般常用于语音输入,例如 Google翻译的语音输入,YouTube 的语音搜索。相比桌面客户端和手机 App 来说网页的录音用的要少一些,但现在越来越多的桌面应用程序都使用 Electron 开发,手机 App 也会用到 Webview,浏览器的录音 API 在这些地方也是可以用的。

我这里使用的是比较简单的 MediaRecorder API,MediaRecorder 不支持 IE 系列浏览器。

点击 录音demo 可以查看最终实现效果。

录音和播放

下面实现录音和播放录音,放几个 HTML 按钮:

<button type="button" id="start-btn">开始录音</button>
<button type="button" id="stop-btn">停止录音</button>
<button type="button" id="play-btn">播放录音</button>
<a href="https://www.misterma.com">Mr. Ma's Blog misterma.com</a>

上面的 Mr. Ma's Blog 链接可以忽略。

JavaScript:

const startBtn = document.querySelector('#start-btn');  // 开始录音按钮
const stopBtn = document.querySelector('#stop-btn');  // 停止录音按钮
const playBtn = document.querySelector('#play-btn');  // 播放录音按钮
let mediaRecorder = null;  // 存放 MediaRecorder
let audioData = [];  // 存储录音数据块

// 开始录音按钮点击
startBtn.addEventListener('click', () => {
  // 请求麦克风权限
  navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
    // 创建媒体记录
    mediaRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
    // 开始录制
    mediaRecorder.start();

    // 处理音频数据
    mediaRecorder.addEventListener('dataavailable', ev => {
      // 把数据块添加到数组
      audioData.push(ev.data);
    });

    // 录音停止
    mediaRecorder.addEventListener('stop', () => {
      // 把音频数据块转换为 Blob
      audioData = new Blob(audioData);
    });
  }).catch(info => {
    alert('无法获取麦克风权限!错误信息:' + info);
  });
});

// 停止录音按钮点击
stopBtn.addEventListener('click', () => {
  mediaRecorder.stop();
});

// 播放录音按钮点击
playBtn.addEventListener('click', () => {
  if (audioData === null) return false;
  // 创建一个 URL 资源对象给 Audio 读取
  const audio = new Audio(URL.createObjectURL(audioData));
  // 播放音频
  audio.play();
});

上面只是简单演示,没有做按钮重复点击判断之类的。

点击 开始录音 按钮后浏览器会弹出麦克风授权的对话框,点击 允许 就会开始录音,点击 拒绝 或点击取消就会弹出 无法获取麦克风权限! 的提示。

点击 停止录音 按钮就会停止录音,点击 播放录音 按钮就能播放刚才的录音。

详细说明

上面的录音和播放录音可分为几个步骤:

  1. 申请麦克风权限
  2. 录音
  3. 获取音频数据
  4. 转换和播放音频

申请麦克风权限

navigator.mediaDevices.getUserMedia 可以请求媒体输入许可,需要传入一个对象来设置请求媒体类型,支持的类型包括 audiovideoaudio 是音频输入设备,例如麦克风,video 是视频输入设备,例如摄像头,如果需要拍照就需要申请 video,如果要拍视频就可以同时申请 videoaudio

用户选择完成后会返回一个 Promise,成功 then 会返回一个媒体流对象,失败 catch 会返回错误信息。

录制音频

有了麦克风权限就可以创建 MediaRecorder 音频录制接口,在实例化时需要传入一个媒体流对象,可以直接使用申请权限时返回的 stream 。第二个参数是配置选项,如果省略会使用浏览器的默认配置。配置选项是一个对象,包括 mimeType MIME 类型和 audioBitsPerSecond 音频比特率,我设置的 mimeTypeaudio/webm ,也就是使用 webm 格式来录制音频,webm 是 Google 的音视频格式 Firefox 不一定支持,使用 MediaRecorderisTypeSupported() 方法可以查看浏览器是否支持该 mimeType

调用 MediaRecorderstart() 方法可以开始录制,start() 方法可以传入一个 timeslice 参数,timeslice 参数可以设置一个毫秒值,录音数据可以根据设置的时长分割为多个数据区块,省略 timeslice 会生成一个完整的 Blob 数据。

处理音频数据

dataavailable 事件会在录音停止时触发,如果在 start 中传入了时长的话,时间到了也会触发,eventdata 属性就是音频数据。

播放录音

播放录音就比较简单了,直接使用 audio 元素就可以,音频数据需要使用 URL.createObjectURL() 转换为 URL 对象传给 audio 使用,调用 Audioplay 方法可以播放音频。

MediaRecorder 相关

下面是我这里没有用到的一些 MediaRecorder 的事件和方法:

MediaRecorder.pause() 方法

暂停媒体录制。

MediaRecorder.resume() 方法

继续录制。

MediaRecorder.requestData() 方法

调用这个方法时,录制数据会被截断,同时也会触发 dataavailable 事件,但录制不会停止。

pause 事件

录制暂停时触发。

resume 事件

从暂停状态恢复录制时触发。

start 事件

录制开始时触发。

stop 事件

录制停止时触发。

导出录音

这里在上面的代码基础上再增加一个导出录音文件的功能,HTML 增加一个按钮:

<button type="button" id="export-btn">导出录音</button>

这里的 JS 代码需要和上面的 JS 代码结合:

const exportBtn = document.querySelector('#export-btn');  // 导出录音按钮

// 导出录音按钮点击
exportBtn.addEventListener('click', () => {
  // 创建一个链接
  const link = document.createElement('a');
  // 把音频数据转换为 URL 资源对象传给链接的 href
  link.href = URL.createObjectURL(audioData);
  // 设置下载时的文件名,后缀是 webm
  link.download = 'audio.webm';
  // 点击链接
  link.click();
});

点击导出按钮会弹出文件下载,导出的是一个 webm 格式的文件,常见的播放器可能无法正常播放,把文件拖到 Chrome 浏览器或使用 audio 元素可以正常播放。

以上就是前端浏览器录音功能的简单实现,如果要上传录音文件的话,可以把 Blob 数据添加到 FormData 上传。

类似文章: