npm.io
0.0.9 • Published 4 months ago

audio-recorder-worklet-processor

Licence
ISC
Version
0.0.9
Deps
20
Size
2.3 MB
Vulns
0
Weekly
0

audio-recorder-worklet-processor

基于 AudioWorklet 的浏览器端实时录音库,提供音频采集、降噪、格式转换等原子能力。

不做音频数据存储,仅提供原子能力。业务层可自行缓存数据,再调用 encodePCM / encodeWAV 转换格式。 内置多种降噪算法,可根据业务需求选择。

浏览器支持

Chrome Firefox Edge Opera Safari
66+ 76+ 79+ 53+ 14.1+

音频处理流程

┌──────────┐    ┌──────────────┐    ┌────────────┐    ┌───────────────┐    ┌────────────┐
│ 麦克风   │───▶│ RNNoise?     │───▶│ Biquad?    │───▶│ MainWorklet   │───▶│ Destination│
│          │    │ (AI降噪-A)   │    │ (带通滤波) │    │ (采集+音量)   │    │ (扬声器)   │
└──────────┘    └──────────────┘    └────────────┘    └───────┬───────┘    └────────────┘
                                                           │ postMessage
                                                           ▼
                                                     ┌──────────────┐
                                                     │ 主线程回调    │
                                                     │ DeepFilter?  │── 48kHz降噪 → 重采样回目标采样率
                                                     │              │
                                                     │ onDataProcess│── { vol, buffer }
                                                     └──────────────┘
降噪方案(互斥,三选一)
方案 原理 延迟 效果 备注
RNNoise AudioWorklet 线程内 RNN 推理 极低 中 需引入 WASM + Worklet 文件
DeepFilter 主线程 DeepFilterNet3 WASM 推理 ~10-20ms 高 需联网加载模型,内部 48kHz 自动重采样
Vonage 替换麦克风流轨道 低 中 第三方 SDK

另有 Biquad 带通滤波器(传统 DSP),可与上述方案叠加使用。


安装

npm install audio-recorder-worklet-processor

引入

ES Module:

import Recorder from "audio-recorder-worklet-processor";

const recorder = new Recorder();

CDN / Script 标签:

<script src="../dist/index.js"></script>
<script>
  const recorder = new Recorder();
</script>

API

init(config?)

初始化录音环境,创建 AudioContext 和各音频节点(不获取麦克风、不连接链路)。

await recorder.init(config);
IConfig 完整定义
interface IConfig {
  /** 实时音频回调,返回音量(0-1)和 Float32 原始数据 */
  onDataProcess?: (data: { vol: number; buffer: Float32Array }) => void;

  /** 音频采集参数 */
  processOptions?: IProcessOptions;

  /** 频谱分析参数(可用于可视化) */
  analyserOptions?: IAnalyserOptions;

  /** Biquad 带通滤波器参数 */
  noiseReductionOptions?: INoiseReductionOptions;

  /** 是否使用 Vonage AI 降噪,默认 false */
  useVonage?: boolean;

  /** RNNoise 降噪参数 */
  rnnoiseOptions?: IRnnoiseOptions;

  /** DeepFilter 降噪参数(内部 48kHz 处理后自动重采样回 sampleRate) */
  deepFilterOptions?: IDeepFilterOptions;
}
IProcessOptions 采集参数
参数 类型 默认值 说明
processSize number 4096 每次回调的采样数
numChannels 1 | 2 1 声道数
sampleBits 16 | 8 16 采样位深
sampleRate number 16000 采样率,常用 16000 / 48000
IAnalyserOptions 频谱分析参数
参数 类型 默认值 说明
open boolean false 是否开启 AnalyserNode
fftSize number 512 FFT 精度,范围 32-32768,越大越精确
INoiseReductionOptions 带通滤波器参数
参数 类型 默认值 说明
open boolean false 是否启用
frequency number 1300 中心频率 Hz(人声 300-3400Hz)
Q number 1 品质因数,决定带宽 = frequency/Q
IRnnoiseOptions RNNoise 参数
参数 类型 说明
useRnnoise boolean 是否启用
rnnoiseWasmPath string rnnoise.wasm 文件路径
rnnoiseSimdWasmPath string rnnoise_simd.wasm 文件路径(SIMD 加速)
rnnoiseWorkletPath string rnnoise.worklet.js 文件路径
IDeepFilterOptions DeepFilter 参数
参数 类型 默认值 说明
useDeepFilter boolean false 是否启用
cdnUrl string https://cdn.laptrinhai.id.vn/deepfilternet3 WASM/模型资源 CDN 地址
attenuationLimit number 50 降噪强度 dB,0-100,越大越强
postFilterBeta number 0.02 后滤波强度,0-0.05,0=禁用

注意: 首次 init() 需联网加载 WASM + 模型(约 2-4MB),耗时数秒,建议应用启动时预初始化。启用后自动关闭浏览器原生降噪/回声消除/自动增益。内部 48kHz 处理后自动重采样回你配置的 sampleRate。


start()

开始录音,获取麦克风并建立音频链路。

await recorder.start();
stop()

停止录音。会将缓冲区中不足 processSize 的剩余数据再回调一次 onDataProcess,不丢数据。

await recorder.stop();
destroy()

销毁录音器,彻底释放所有资源。调用后需重新 init() 才能使用。

await recorder.destroy();
getAnalyserData()

获取实时频谱数据(需在 init 时开启 analyserOptions.open)。

const data: Uint8Array = recorder.getAnalyserData();
encodePCM(bytes, sampleBits?, littleEdian?)

Float32 原始数据 → PCM DataView。

参数 类型 默认值 说明
bytes Float32Array — onDataProcess 返回的原始数据
sampleBits 16 | 8 init 配置 采样位深
littleEdian boolean 自动检测 字节序
const pcmData = recorder.encodePCM(bufferArr);
encodeWAV(buffer, sampleRate?, numChannels?, sampleBits?, littleEdian?)

PCM DataView → WAV DataView。

参数 类型 默认值 说明
buffer DataView — encodePCM 返回的数据
sampleRate number init 配置 采样率
numChannels 1 | 2 init 配置 声道数
sampleBits 16 | 8 init 配置 采样位深
littleEdian boolean 自动检测 字节序
const wavData = recorder.encodeWAV(pcmData);
dataViewToBase64(dataView)

DataView → base64 字符串。

const base64 = recorder.dataViewToBase64(wavData);

示例

基础录音 + 频谱
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Recorder Demo</title>
    <script src="../dist/index.js"></script>
  </head>
  <body>
    <button onclick="init()">init</button>
    <button onclick="start()">start</button>
    <button onclick="stop()">stop</button>
  </body>
  <script>
    const recorder = new Recorder();
    const bufferArr = [];

    const init = () => {
      recorder.init({
        analyserOptions: { open: true },
        onDataProcess: (data) => {
          bufferArr.push(...data.buffer);
        },
      });
    };

    const start = async () => {
      await recorder.start();
    };

    const stop = async () => {
      await recorder.stop();
      const pcmData = recorder.encodePCM(bufferArr);
      const wavData = recorder.encodeWAV(pcmData);
      const wavBlob = new Blob([wavData], { type: "audio/wav" });
      const oA = document.createElement("a");
      oA.href = URL.createObjectURL(wavBlob);
      oA.download = "recorder.wav";
      oA.click();
    };
  </script>
</html>
</html>
DeepFilter AI 降噪
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>DeepFilter Demo</title>
    <script src="../dist/index.js"></script>
  </head>
  <body>
    <button onclick="init()">init</button>
    <button onclick="start()">start</button>
    <button onclick="stop()">stop</button>
  </body>
  <script>
    const recorder = new Recorder();
    const bufferArr = [];

    const init = async () => {
      await recorder.init({
        deepFilterOptions: {
          useDeepFilter: true,
          attenuationLimit: 50,  // 降噪强度 0-100
          postFilterBeta: 0.02,  // 后滤波 0-0.05
        },
        processOptions: {
          numChannels: 1,
          sampleBits: 16,
          sampleRate: 16000,  // 可自由配置,DeepFilter 内部 48kHz 处理后自动重采样回来
        },
        onDataProcess: (data) => {
          bufferArr.push(...data.buffer);
        },
      });
      console.log("DeepFilter ready");
    };

    const start = async () => {
      await recorder.start();
    };

    const stop = async () => {
      await recorder.stop();
      const pcmData = recorder.encodePCM(bufferArr);
      const wavData = recorder.encodeWAV(pcmData);
      const wavBlob = new Blob([wavData], { type: "audio/wav" });
      const oA = document.createElement("a");
      oA.href = URL.createObjectURL(wavBlob);
      oA.download = "denoised.wav";
      oA.click();
    };
  </script>
</html>
</html>

生命周期

init()  ──▶  start()  ──▶  stop()  ──▶  start()  ──▶  ...
  │              │            │
  │              └─ onDataProcess 循环回调
  │
  └──────────────────────────▶  destroy()  ──彻底释放
  • init() 可重复调用(会关闭旧 context),但录音中不允许
  • stop() 后状态回到 ready,可再次 start()
  • destroy() 后需重新 init() 才能使用