@cantoo/capacitor-audio-capture

中文文档
0.3.4发布于 2026/06/05MITTypeScriptESM + CJS零依赖近 30 天下载 8121

Capacitor v7 plugin that captures microphone audio and streams raw PCM (base64 Float32) chunks to the consumer (web/Android/iOS).

原始使用文档
文档目录14 节
  1. Platforms
  2. Installation
  3. Permissions
  4. Usage
  5. Examples
  6. API
  7. startCapture(options?)
  8. stopCapture()
  9. release()
  10. Exported types
  11. Error handling
  12. Why base64 on the wire, Float32Array in the API?
  13. Web and Content-Security-Policy
  14. License

@cantoo/capacitor-audio-capture

Capacitor v7 plugin that captures microphone audio on web / Android / iOS and streams raw PCM as Float32Array (mono) chunks to the consumer. No format conversion, no compression — your app decides what to do with the samples.

npm license


Platforms

PlatformImplementationMinimum
WebgetUserMedia + AudioWorklet (DSP off the main thread)modern browser
AndroidAudioRecord (44.1 kHz PCM16) on a dedicated threadAPI 23 (Android 6)
iOSAVAudioEngine.installTap on a dedicated queueiOS 14

Native captures mono audio, resamples it to targetSampleRate via linear interpolation, applies optional RMS silence filtering, and ships each chunk over the bridge as base64 little-endian Float32 PCM. The JS wrapper decodes that base64 once and hands the consumer a Float32Array — no further encoding/decoding inside the plugin.

Installation

pnpm add @cantoo/capacitor-audio-capture
# or: npm i @cantoo/capacitor-audio-capture
# or: yarn add @cantoo/capacitor-audio-capture

npx cap sync

Permissions

  • iOS — add to Info.plist:
    <key>NSMicrophoneUsageDescription</key>
    <string>Used to record audio while you use the app.</string>
    
  • Android — RECORD_AUDIO is already declared by the plugin; permission is requested at runtime on the first call to startCapture.
  • Web — requires a secure context (HTTPS or localhost) and the user must grant microphone access.

Usage

import { AudioCapture } from '@cantoo/capacitor-audio-capture';

await AudioCapture.startCapture({
  chunkDurationMs: 250,
  targetSampleRate: 16000,
  silenceThreshold: 0.01,
  listener: (sequence, chunk) => {
    // chunk: Float32Array, mono, at targetSampleRate (samples in -1..1)
    console.log(sequence, chunk.length);
  },
});

// later
await AudioCapture.stopCapture();
await AudioCapture.release();

Examples

Send to a backend (base64-encode just before the request):

listener: (_seq, chunk) => {
  const bytes = new Uint8Array(chunk.buffer);
  let bin = '';
  for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
  const base64 = btoa(bin);
  fetch('/api/audio', {
    method: 'POST',
    headers: { 'Content-Type': 'application/octet-stream' },
    body: chunk.buffer,
  });
}

Buffer for a client-side WAV:

await AudioCapture.startCapture({
  chunkDurationMs: 250,
  targetSampleRate: 16000,
  silenceThreshold: 0,
  accumulate: true,
});
// ... user stops ...
const { audio } = await AudioCapture.stopCapture();
// `audio` is a Float32Array of the full session — convert to Int16,
// prepend a 44-byte WAV header, and you have a playable file.

API

startCapture(options?)

FieldTypeDefaultDescription
chunkDurationMsnumber1000Duration of each emitted chunk.
targetSampleRatenumber16000Target sample rate. Audio is resampled to this value.
silenceThresholdnumber (RMS 0..1)0Chunks with RMS below this value are dropped (0 disables).
voiceProcessingbooleantrueToggle the platform voice pre-processing bundle (echo cancellation, noise suppression, auto gain) on all platforms. Set false for the rawest signal.
listener(sequence: number, chunk: Float32Array) => void—Stream consumer. Without it, capture runs but emits nothing.
accumulatebooleanfalseBuffer every emitted chunk and return the concatenated PCM from stopCapture. Silent chunks are skipped.

sequence is monotonically increasing per session and resets on every startCapture. It is incremented even for chunks dropped by silence detection, so consumers can detect temporal gaps.

stopCapture()

Stops capture and releases the active capture session. Returns { audio: Float32Array }. When the session was started with accumulate: true, audio is the concatenated PCM (mono Float32 at targetSampleRate); otherwise it is an empty Float32Array.

release()

Stops capture, removes listeners, and frees every open resource.

Exported types

import type {
  AudioCapturePlugin,
  AudioChunkListener,  // (sequence, chunk: Float32Array) => void
  AudioCaptureError,
  AudioCaptureErrorCode,
  StartCaptureOptions,
} from '@cantoo/capacitor-audio-capture';

Error handling

Every rejected Promise from the plugin carries a .code from a closed set, identical across iOS, Android, and Web. Branch on .code rather than parsing messages — the messages are short and stable, but only the code is part of the public contract.

CodeWhen it's raised
PERMISSION_DENIEDUser denied microphone access (or never granted it).
MICROPHONE_UNAVAILABLEMicrophone missing, busy, or fails to initialize (no input device, hardware/OS-level issue).
ALREADY_CAPTURINGstartCapture was called while a session is already running.
UNAVAILABLEWeb only: getUserMedia or AudioWorklet is missing in this environment.
INTERNAL_ERRORFallback for anything not matching the categories above.
import { AudioCapture, type AudioCaptureError } from '@cantoo/capacitor-audio-capture';

try {
  await AudioCapture.startCapture({ /* ... */ });
} catch (e) {
  const code = (e as AudioCaptureError).code;
  if (code === 'PERMISSION_DENIED') {
    // prompt user to enable mic access in OS settings
  } else if (code === 'MICROPHONE_UNAVAILABLE') {
    // surface a "no microphone" state in UI
  } else if (code === 'ALREADY_CAPTURING') {
    // ignore or call stopCapture() first
  }
}

Why base64 on the wire, Float32Array in the API?

Capacitor's native↔JS bridge can only carry JSON-serializable values. Encoding the PCM samples as base64 is ~33% smaller than a JSON number array and significantly faster to serialize/deserialize on both sides. The plugin's wrapper does the one decode (base64 → Float32Array) so the consumer always receives the natural representation for audio: a typed array of mono samples in [-1, 1].

Web and Content-Security-Policy

On web, the AudioWorkletProcessor is inlined as a string and loaded via URL.createObjectURL(new Blob([...])). If the host app has a strict CSP that doesn't allow blob: in script-src / worker-src, the worklet won't load — simply allow blob: in the appropriate directive.

License

MIT © Cantoo

版本与发布记录

@cantoo/capacitor-audio-capture 共发布 8 个版本,首次发布于 2026/05/11;过去 12 个月发布了 8 个版本。

版本发布日期距今
0.3.4latest2026/06/055 个月前
0.3.32026/05/265 个月前
0.3.22026/05/135 个月前
0.3.12026/05/115 个月前
0.3.02026/05/115 个月前
0.1.32026/05/115 个月前

关于 @cantoo/capacitor-audio-capture 的常见问题

@cantoo/capacitor-audio-capture 是什么?

Capacitor v7 plugin that captures microphone audio and streams raw PCM (base64 Float32) chunks to the consumer (web/Android/iOS).

如何安装 @cantoo/capacitor-audio-capture?

在项目目录运行 npm install @cantoo/capacitor-audio-capture,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@capacitor/core(^7.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cantoo/capacitor-audio-capture 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cantoo/capacitor-audio-capture 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cantoo/capacitor-audio-capture 可以商用吗?

@cantoo/capacitor-audio-capture 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cantoo/capacitor-audio-capture 的下载量有多少?

根据 npm 官方下载统计,@cantoo/capacitor-audio-capture 在 2026/10/09 – 2026/11/07 这 30 天内被下载 8,121 次,日均约 271 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cantoo/capacitor-audio-capture 还在维护吗?

最新版本 0.3.4 发布于 2026/06/05(5 个月前);至今共发布 8 个版本,其中过去 12 个月发布了 8 个;首次发布于 2026/05/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。