@ai-coustics/aic-sdk

中文文档
0.26.0发布于 2026/11/06Apache-2.0TypeScriptCommonJS零依赖构建来源已验证近 30 天下载 13.1万

Node.js package of ai-coustics SDK

原始使用文档
文档目录14 节
  1. Installation
  2. Quick start
  3. Models
  4. Enhancement
  5. Async processing
  6. Running several streams
  7. Voice activity detection
  8. Run the VAD on the original audio
  9. Energy-based voice activity detection
  10. Analysis
  11. Telemetry
  12. Memory management
  13. Development
  14. License

@ai-coustics/aic-sdk

Node.js bindings for the ai-coustics SDK: speech enhancement, voice activity detection and audio analysis.

For product documentation see docs.ai-coustics.com.

[!NOTE] This SDK requires a license key. Generate one at developers.ai-coustics.com.

Installation

npm install @ai-coustics/aic-sdk

Prebuilt binaries are published for macOS (x64, arm64), Linux (x64, arm64, glibc and musl) and Windows (x64, arm64, MSVC). The native SDK is linked statically, so there is no separate library to install or put on a search path.

Quick start

const { Model, Processor } = require('@ai-coustics/aic-sdk')

async function main() {
  // Download a model once, or fetch one manually from https://artifacts.ai-coustics.io
  const modelPath = await Model.download('quail-vf-2.3-s-16khz', './models')
  const model = Model.fromFile(modelPath)

  // Use the model's optimal configuration for the lowest delay
  const sampleRate = model.getOptimalSampleRate()
  const blockSize = model.getOptimalBlockSize(sampleRate)

  const processor = new Processor(model, process.env.AIC_SDK_LICENSE)
  processor.initialize(sampleRate, blockSize)

  // Enhance a mono block in place
  const audio = new Float32Array(blockSize)
  processor.process(audio)
}

main()

Processing is mono. For multichannel audio, mix down to mono or use one processor per channel. Initialize each instance before passing audio. Blocks must contain exactly blockSize samples. Set the third initialize argument, variableBlockSize, to true to allow shorter blocks; longer blocks are always rejected. This also applies to VAD processing and analyzer buffering.

The following snippets assume an enclosing async function. CommonJS files do not support top-level await.

Runnable scripts for enhancement, VAD, analysis and whole-file processing, synchronous and async, are in examples/.

Models

Available models and their IDs are listed at artifacts.ai-coustics.io. Each class accepts the model types listed below and rejects other types:

ClassAccepted models
Processor, ProcessorAsyncenhancement, bypass
Vad, VadAsyncdedicated VAD
Analyzeranalysis

Model.download runs on Node's libuv thread pool and returns a promise for the model's path. Model.fromFile memory-maps the file. Do not modify or delete it while the model or any instance created from it is still alive.

Enhancement

Parameters can be changed while audio is being processed, through a context handle:

const { ProcessorParameter } = require('@ai-coustics/aic-sdk')

const context = processor.getContext()

context.setParameter(ProcessorParameter.EnhancementLevel, 0.8)
context.setParameter(ProcessorParameter.Bypass, 0)

console.log(context.getParameter(ProcessorParameter.EnhancementLevel))

// Get the audio delay in samples to align the output with other streams
console.log(context.getAudioDelay())

// Clear internal state on a stream discontinuity or seek
context.reset()

Async processing

ProcessorAsync and VadAsync run initialization and processing on Node's libuv thread pool. Await these calls to keep the event loop available for other work, such as network requests. Construction and disposal remain synchronous.

Use Processor or Vad on a dedicated worker thread, or in a batch script that can block the calling thread. These classes process each block without a promise or input copy.

const { Model, ProcessorAsync } = require('@ai-coustics/aic-sdk')

const processor = await new ProcessorAsync(model, process.env.AIC_SDK_LICENSE).withConfig(sampleRate, blockSize)

// The input remains unmodified; the promise resolves to the enhanced samples.
const audio = new Float32Array(blockSize)
const enhanced = await processor.process(audio)

Both async classes copy the input before queuing work and return a new Float32Array. ProcessorAsync.process returns enhanced samples; VadAsync.process returns the original samples. The caller's input remains unmodified.

Context creation is asynchronous. The returned context's methods are synchronous and can be used while processing runs:

const context = await processor.getContext()
context.setParameter(ProcessorParameter.EnhancementLevel, 0.8)

Running several streams

Use one instance per stream and await each operation before submitting the next. Concurrent calls on one instance are not guaranteed to execute in submission order. Separate instances can process streams concurrently.

const processors = await Promise.all(
  streams.map(() => new ProcessorAsync(model, licenseKey).withConfig(sampleRate, blockSize)),
)

const enhanced = await Promise.all(processors.map((processor, i) => processor.process(blocks[i])))

Work runs on Node's libuv thread pool, which is four threads by default and shared with fs, dns and crypto. To run more streams in parallel, raise UV_THREADPOOL_SIZE before Node starts:

UV_THREADPOOL_SIZE=16 node server.js

AIC_NUM_THREADS does not apply to these bindings; async audio work uses libuv.

Voice activity detection

VAD runs a dedicated VAD model and is driven independently of any processor.

const { Model, Vad, VadParameter } = require('@ai-coustics/aic-sdk')

const vadModel = Model.fromFile(await Model.download('vad-ms-2.1-xxs-16khz', './models'))
const vad = new Vad(vadModel, process.env.AIC_SDK_LICENSE)

const sampleRate = vadModel.getOptimalSampleRate()
vad.initialize(sampleRate, vadModel.getOptimalBlockSize(sampleRate))

const context = vad.getContext()
context.setParameter(VadParameter.Sensitivity, 0.8)

vad.process(block) // reads the block, does not modify it

if (context.isSpeechDetected()) {
  console.log('speech')
}

// Raw model output, before speech-hold and thresholding
console.log(context.getRawVadProbability())

Run the VAD on the original audio

When enhancement and detection run together, feed the VAD the original input, not the processor's output. Enhancement is designed to change the signal, so detecting on its output means running the VAD on audio that no longer matches what its model expects, and it stacks the processor's delay on top of the prediction delay. Because vad.process leaves its input untouched, run it before enhancement. Configure both instances with the same sample rate and block size:

vad.process(block) // reads the block
processor.process(block) // enhances it in place

The two delays describe different things and are independent:

context.getAudioDelay() // enhanced audio lags the input by this many samples
vadContext.getPredictionDelay() // the VAD decision lags the same input by this many

The prediction delay is not applied to the audio. Use it to align speech decisions with the input audio.

Energy-based voice activity detection

An enhancement processor can detect speech in its enhanced signal before output mixing, without loading a separate VAD model. Create a context before processing and read it after each block:

const { VadParameter } = require('@ai-coustics/aic-sdk')

const vadContext = processor.getEnergyVadContext()

// The energy VAD uses 1.0 to 15.0; higher values detect quieter speech.
vadContext.setParameter(VadParameter.Sensitivity, 6.0)

processor.process(block)
console.log(vadContext.isSpeechDetected())

// Equal to the processor's audio delay
console.log(vadContext.getPredictionDelay())

// Clear the prediction on a stream discontinuity or seek
vadContext.reset()

Contexts from one processor share a detector, and their methods can be called while audio is being processed. A context stays valid after its processor is disposed, but receives no more audio. Creating a context keeps inference active even when processing is bypassed or the enhancement level is zero. processor.getContext().reset() also resets the energy VAD. On ProcessorAsync, getEnergyVadContext() returns a promise.

Use Vad with a dedicated VAD model for a speech probability (getRawVadProbability()) or detection that does not depend on an enhancement model.

Analysis

Analysis models score audio quality. Collect audio with buffer, then run the model with analyzeAsync or analyze.

const { Model, Analyzer } = require('@ai-coustics/aic-sdk')

const analysisModel = Model.fromFile(await Model.download('tyto-1.2-l-16khz', './models'))
const analyzer = new Analyzer(analysisModel, process.env.AIC_SDK_LICENSE)

const sampleRate = analysisModel.getOptimalSampleRate()
analyzer.initialize(sampleRate, analysisModel.getOptimalBlockSize(sampleRate))

analyzer.buffer(block)

// Runs the model on a worker thread. `analyze()` does the same on the calling thread.
const result = await analyzer.analyzeAsync()
console.log(result.riskScore, result.noise, result.speakerReverb)

buffer is synchronous and does not acquire the analyzer lock. Audio collection can continue while analyzeAsync runs on a worker thread. Use analyze when blocking the calling thread is acceptable, such as in a CLI or dedicated worker.

Analysis uses a fixed duration of audio determined by the model. Older samples are discarded as new audio arrives. If insufficient audio has been collected, analysis pads the remaining input with silence.

Calls to analyze, reset, updateBearerToken, terminateSession and dispose acquire the analyzer lock and may block while async analysis is running. initialize only configures the collector.

All scores range from 0.0 to 1.0. For every field except speakerLoudness, lower values indicate less problematic audio. riskScore predicts the likelihood of failure in downstream models such as speech-to-text, VAD or turn-taking.

Telemetry

Telemetry follows the runtime environment (e.g. AIC_SDK_OTEL_ENABLE). To override it for a single instance:

const processor = new Processor(model, licenseKey, {
  enable: true,
  sessionId: 'my-session',
  exportIntervalMs: 60000,
})

A telemetry session ends when its native object is destroyed. Use terminateSession() to request termination at a specific lifecycle event. Once termination is handled, processors and VADs can no longer process audio, and analyzers can no longer analyze buffered audio. On ProcessorAsync and VadAsync, termination runs on a libuv worker thread and returns a promise because it may block.

If your license key is a JWT, refresh it in place instead of rebuilding the object:

context.updateBearerToken(renewedJwt)

Memory management

Model, Processor, ProcessorAsync, Vad, VadAsync and Analyzer hold large native allocations behind small JavaScript objects. The binding reports estimated native memory usage to V8 so the garbage collector can account for these allocations. This influences collection frequency but does not guarantee when an object will be released.

Use dispose() to release native resources at a specific point instead of waiting for garbage collection:

const processor = new Processor(model, licenseKey)
try {
  processor.initialize(sampleRate, blockSize)
  processor.process(block)
} finally {
  processor.dispose()
}

After dispose(), all methods except dispose() fail; repeated disposal has no effect. Async methods reject their promises. Disposal blocks the calling thread if a worker holds the native object's lock. Queued work that acquires the lock after disposal fails.

Disposing a model releases its reference to the model data. Processors, VADs and analyzers created from it retain their own references and remain usable.

Cleanup timing also affects native memory usage:

  • Native cleanup runs on the event loop when the object is finalized, not synchronously at garbage collection. Finalizers run on event-loop turns, so batches that create many of these objects back to back hold native memory until the loop turns. An await on an already-resolved promise (a microtask) is not enough; real async boundaries such as I/O, setTimeout or setImmediate are. A tight synchronous loop that creates thousands of objects accumulates their native memory for the duration of the loop; create these objects per unit of work behind real async boundaries, or reuse a single instance.
  • RSS may remain elevated after disposal because the allocator can retain freed memory for reuse. Peak memory use depends on the number of concurrently live instances, including objects awaiting finalization.

Development

Building, testing, benchmarking and releasing this package are covered in DEVELOPMENT.md.

License

This Node wrapper is distributed under the Apache 2.0 license (LICENSE). The core SDK it links against is distributed under the proprietary AIC-SDK license (LICENSE.AIC_SDK).

版本与发布记录

@ai-coustics/aic-sdk 共发布 20 个版本,首次发布于 2025/10/06;过去 12 个月发布了 19 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.26.0latest2026/11/062 天前
0.25.22026/10/2612 天前
0.25.12026/10/1424 天前
0.25.02026/09/301 个月前
0.24.02026/09/081 个月前
0.23.12026/09/072 个月前

关于 @ai-coustics/aic-sdk 的常见问题

@ai-coustics/aic-sdk 是什么?

Node.js package of ai-coustics SDK

如何安装 @ai-coustics/aic-sdk?

在项目目录运行 npm install @ai-coustics/aic-sdk,或使用 pnpm add / yarn add / bun add。

@ai-coustics/aic-sdk 支持 TypeScript 吗?

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

@ai-coustics/aic-sdk 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@ai-coustics/aic-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >= 18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ai-coustics/aic-sdk 可以商用吗?

@ai-coustics/aic-sdk 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@ai-coustics/aic-sdk 的下载量有多少?

根据 npm 官方下载统计,@ai-coustics/aic-sdk 在 2026/10/05 – 2026/11/03 这 30 天内被下载 130,574 次,日均约 4,352 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ai-coustics/aic-sdk 还在维护吗?

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