跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端音频录制工具:AudioRecorder 类实现与使用指南

前端音频录制涉及麦克风权限、流媒体处理及格式转换。本方案基于 MediaRecorder 与 AudioContext 构建 AudioRecorder 类,支持暂停恢复、时长限制及 WebM 转 WAV 功能。通过封装状态管理与资源清理,解决内存泄漏与重复操作问题,提供标准化回调接口适配业务场景。

DevStack发布于 2026/4/8更新于 2026/7/2535 浏览

在前端开发中,音频录制是一个常见的需求(如语音笔记、音频投稿、实时语音交互等)。这里我们深入剖析一个功能完善的 AudioRecorder 类,它基于浏览器的 MediaRecorder 和 AudioContext API 实现,具备麦克风权限处理、录制时长控制、暂停/恢复/停止/关闭、以及音频格式转换(WebM → WAV)等核心能力。

一、AudioRecorder 类核心特性

该类设计注重状态管理与资源释放,避免常见的内存泄漏问题。主要包含以下特性:

  1. 基础录制能力:启动 / 暂停 / 恢复 / 停止 / 关闭录音,支持重复调用的异常处理;
  2. 时长控制:自定义最大录制时长(默认 5 分钟),超时自动停止,实时返回 mm:ss 格式的录制时长;
  3. 权限处理:优雅处理麦克风权限申请,拒绝时给出明确错误提示;
  4. 资源管理:自动释放媒体流、音频上下文等资源,确保页面切换或销毁时不残留进程;
  5. 格式转换:提供将录制的 WebM 格式音频转为 48kHz 16 位 PCM WAV 格式的接口(兼容性更强);
  6. 状态管理:内置录音状态(录制中 / 暂停 / 空闲),防止重复操作导致逻辑冲突;
  7. 回调体系:提供开始、时长更新、停止、错误等回调,方便业务层灵活处理。

二、完整代码实现

下面是完整的类实现,重点展示了异步权限获取与状态流转的逻辑。

class AudioRecorder {
  /**
   * 构造函数
   * @param {Object} options 配置项
   * @param {number} options.maxDuration 最大录制时长(秒,默认 300 秒=5 分钟)
   * @param {Function} options.onTimeUpdate 录制时间更新回调(参数:格式化为 mm:ss 的时间字符串)
   * @param {Function} options.onStart 录音开始回调
   * @param {Function} options.onStop 录音停止回调(参数:最终音频 Blob 对象)
   * @param {Function} options.onError 错误回调(参数:错误信息)
   */
  constructor(options = {}) {
    // 配置项默认值
    this.config = {
      maxDuration: options.maxDuration || 300,
      onTimeUpdate: options.onTimeUpdate || (() => {}),
      : options. || ( {}),
      : options. || ( {}),
      : options. || ( .(, err))
    };

    
    . = {
      : ,     
      : ,        
      : ,      
      : ,      
      : ,      
      : ,         
      : ,         
      : [],        
      : , 
      :  
    };
  }

  
   () {
     {
      
       (.. && !..) {
        ..();
        ;
      }

      
       (..) {
        .();
        ;
      }

      
      .. = ;
      .. = navigator..({
        : {
          : { :  },
          : { :  },
          : { :  },
          : { :  }
        }
      });

      
      .. =  ..;

      
       (!..) {
        .();
        ;
      }

      
      .. = ;
      .. = ;

      
      .. =  (..);
      .. = [];

      
      ... =  {
         (e.. > ) {
          ...(e.);
        }
      };

      
      ... =  {
         blob =  (.., { :  });
        ..(blob);
        .();
      };

      
      ... =  {
        ..(e.);
        .();
      };

      
      ...(); 
      .. = ;
      .. = ;
      .. = ;

      
      .();
      ..();

    }  (err) {
      ..(err.);
       err;
    }
  }

  
  () {
     (.. && ..) {
      ...();
      .. = ;
      .. = ;
      .();
    }
  }

  
  () {
    (..);
    .. = ( {
       (!..) {
        ..++;
         minutes = .(.. / ).().(, );
         seconds = (.. % ).().(, );
        ..();

        
         (.. >= ..) {
          .();
        }
      }
    }, );
  }

  
  () {
     (.. && !..) {
      ...();
      .. = ;
      .. = ;
      (..);
    }
  }

  
  () {
     (.. || ..) {
       (.. && ... !== ) {
        ...();
      }
      (..);
      .. = ;
      .. = ;
    }
  }

  
   () {
    .();
    .();
    .. = ;
  }

  
  () {
     (..) {
      ...().( track.());
      .. = ;
    }
     (..) {
      .. = ;
    }
  }

  
  () {
    .. = ;
    .. = ;
    .. = ;
    (..);
  }

  
  () {
    
    
    .(, blob.);
     blob; 
  }
}
onStart
onStart
() =>
onStop
onStop
() =>
onError
onError
(err) =>
console
error
'录音错误:'
// 录音核心状态
this
state
isRecording
false
// 是否正在录音
isPaused
false
// 是否暂停
recordDuration
0
// 已录制时长(秒)
recordTimer
null
// 时间计时定时器
mediaStream
null
// 媒体流
audioCtx
null
// 音频上下文
recorder
null
// 媒体录制器
audioChunks
// 音频数据片段
isAcquiringPermission
false
// 标记是否正在获取麦克风权限
permissionPromise
null
// 存储获取权限的 Promise,用于中断
/** * 1. 开始录音(支持实时返回 mm:ss 格式时间) * @returns {Promise<void>} */
async
start
try
// 避免重复启动
if
this
state
isRecording
this
state
isPaused
this
config
onError
'当前已在录音中,无需重复启动'
return
// 情况 1:从暂停状态恢复录音
if
this
state
isPaused
this
_resumeRecording
return
// 情况 2:全新启动录音 → 标记异步状态
this
state
isAcquiringPermission
true
this
state
permissionPromise
mediaDevices
getUserMedia
audio
sampleRate
ideal
48000
channelCount
ideal
1
echoCancellation
ideal
true
noiseSuppression
ideal
true
// 等待权限获取结果
this
state
mediaStream
await
this
state
permissionPromise
// 关键:如果在权限获取期间已调用 close,直接终止后续逻辑
if
this
state
isAcquiringPermission
this
_cleanupMediaStream
return
// 权限获取成功 → 清除异步标记
this
state
isAcquiringPermission
false
this
state
permissionPromise
null
// 创建 MediaRecorder
this
state
recorder
new
MediaRecorder
this
state
mediaStream
this
state
audioChunks
// 监听数据块
this
state
recorder
ondataavailable
(e) =>
if
data
size
0
this
state
audioChunks
push
data
// 监听停止事件
this
state
recorder
onstop
() =>
const
new
Blob
this
state
audioChunks
type
'audio/webm'
this
config
onStop
this
_resetState
// 监听错误事件
this
state
recorder
onerror
(e) =>
this
config
onError
error
this
_resetState
// 开始录制
this
state
recorder
start
1000
// 每 1 秒触发一次 ondataavailable
this
state
isRecording
true
this
state
recordDuration
0
this
state
isPaused
false
// 启动时长计时器
this
_startTimer
this
config
onStart
catch
this
config
onError
message
throw
/** * 内部方法:恢复录音 */
_resumeRecording
if
this
state
recorder
this
state
isPaused
this
state
recorder
resume
this
state
isPaused
false
this
state
isRecording
true
this
_startTimer
/** * 内部方法:启动时长计时器 */
_startTimer
clearInterval
this
state
recordTimer
this
state
recordTimer
setInterval
() =>
if
this
state
isPaused
this
state
recordDuration
const
Math
floor
this
state
recordDuration
60
toString
padStart
2
'0'
const
this
state
recordDuration
60
toString
padStart
2
'0'
this
config
onTimeUpdate
`${minutes}:${seconds}`
// 检查是否超时
if
this
state
recordDuration
this
config
maxDuration
this
stop
1000
/** * 暂停录音 */
pause
if
this
state
isRecording
this
state
isPaused
this
state
recorder
pause
this
state
isPaused
true
this
state
isRecording
false
clearInterval
this
state
recordTimer
/** * 停止录音 */
stop
if
this
state
isRecording
this
state
isPaused
if
this
state
recorder
this
state
recorder
state
'inactive'
this
state
recorder
stop
clearInterval
this
state
recordTimer
this
state
isRecording
false
this
state
isPaused
false
/** * 关闭并释放资源 */
async
close
this
stop
this
_cleanupMediaStream
this
state
audioCtx
null
/** * 内部方法:清理媒体流资源 */
_cleanupMediaStream
if
this
state
mediaStream
this
state
mediaStream
getTracks
forEach
track =>
stop
this
state
mediaStream
null
if
this
state
recorder
this
state
recorder
null
/** * 内部方法:重置状态 */
_resetState
this
state
isRecording
false
this
state
isPaused
false
this
state
recordDuration
0
clearInterval
this
state
recordTimer
/** * 导出为 WAV 格式(需配合解码库或后端处理) * 注意:浏览器端直接转换 WebM 到 WAV 通常需要额外的解码逻辑 */
exportAsWav
blob
// 实际项目中建议使用专门的库进行转码,此处仅做接口示意
// 例如:使用 ffmpeg.wasm 或后端 API 进行格式转换
console
log
'准备转换为 WAV:'
type
return

三、使用示例

在实际业务中,你可以这样实例化并使用它:

const recorder = new AudioRecorder({
  maxDuration: 60, // 限制 60 秒
  onTimeUpdate: (time) => {
    console.log(`录制中:${time}`);
    document.getElementById('timer').innerText = time;
  },
  onStart: () => {
    console.log('录音已开始');
    document.getElementById('status').innerText = '录音中...';
  },
  onStop: (blob) => {
    console.log('录音结束,大小:', blob.size);
    const url = URL.createObjectURL(blob);
    document.getElementById('audioPlayer').src = url;
    document.getElementById('status').innerText = '已完成';
  },
  onError: (err) => {
    alert('发生错误:' + err);
  }
});

// 绑定按钮事件
document.getElementById('btnStart').onclick = () => recorder.start();
document.getElementById('btnPause').onclick = () => recorder.pause();
document.getElementById('btnResume').onclick = () => recorder.start();
document.getElementById('btnStop').onclick = () => recorder.stop();
document.getElementById('btnClose').onclick = () => recorder.close();

四、注意事项

  1. 权限策略:现代浏览器要求 HTTPS 环境才能调用 getUserMedia,本地调试请使用 localhost。
  2. 资源回收:务必在组件卸载或页面跳转前调用 close(),否则后台录音进程可能持续占用麦克风。
  3. 格式兼容:MediaRecorder 默认输出通常为 webm,若需通用性更强的 wav,建议在后端处理或使用专用转码库。
  4. 性能优化:长时录制时注意内存管理,避免 audioChunks 无限增长,可考虑分片上传或定期清理。

目录

  1. 一、AudioRecorder 类核心特性
  2. 二、完整代码实现
  3. 三、使用示例
  4. 四、注意事项
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 法奥机器人操作与编程入门指南
  • Python Plotly 数据可视化:从基础到最佳实践
  • Flutter 组件 google_generative_language_api 适配鸿蒙 HarmonyOS 实战
  • 反射内存卡原理:PCIE-5565 底层架构与 FPGA 设计解析
  • C语言快速排序算法详解及多种变式实现
  • 数据结构实战:队列原理与 C 语言实现
  • 网络安全攻防:黑客攻击简要流程
  • SQL 核心概念:JOIN 和 UNION 的区别
  • Diffusion Transformer(DiT):用 ViT 替代 U-Net 用于视频生成与机器人动作预测
  • 扣子工作流详解:逻辑结构与常见节点
  • MCPHost 实战:命令行驱动大模型与外部工具交互
  • Python缠论分析指南:代码实现精准买卖点识别
  • FPGA 实现 CAN 总线接口与数据帧解析
  • HarmonyOS ArkUI 布局详解:相对布局与栅格布局
  • C++ 模板详解(进阶)
  • OpenClaw 安装与飞书机器人接入指南
  • Flutter huggingface_client 鸿蒙化适配指南
  • Linux 下 GCC 编译入门与基础用法
  • Android 开发岗位历年高频面试题及参考答案
  • 基于 Python 的抖音视频批量自动化工具实战指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online