npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aoq-electron-sdk

v1.3.0-58586345

Published

AoqClientSdk for Electron (NAPI addon + TypeScript API)

Readme

aoq-electron-sdk

AoqClientSdk 的 Electron / Node.js SDK,提供实时音视频采集、编解码、传输与数据消息能力。

安装

npm install aoq-electron-sdk

安装后 postinstall 会自动解压当前平台的原生库(macOS 的 AoqClientSdk.framework),无需额外操作。

包内同时包含各平台的原生产物,运行时按 process.platform-process.arch 自动选择:

node_modules/aoq-electron-sdk/prebuilds/
  darwin-arm64/   aoq_node_ext.node + AoqClientSdk.framework + PluginOpus.framework
  darwin-x64/     同上
  win32-x64/      aoq_node_ext.node + AoqClientSdk.dll + PluginOpus.dll + alivcffmpeg.dll

环境要求

| 项 | 要求 | |---|---| | 操作系统 | macOS(Intel x64 / Apple Silicon arm64)、Windows x64 | | Node.js | >= 16 | | Electron | 任意版本(基于 Node-API,ABI 稳定,无需按 Electron 版本重编) |

Electron 集成配置(必读)

SDK 含原生 addon,需要两处配置,否则运行时无法加载:

1. 允许 renderer 使用 Node 模块,并把 SDK 声明为 external

vue.config.js(vue-cli-plugin-electron-builder)示例:

module.exports = {
  pluginOptions: {
    electronBuilder: {
      nodeIntegration: true,
      // 原生 addon 不能被 webpack 打包,须走运行时 require
      externals: ['aoq-electron-sdk'],
      builderOptions: {
        // 打包时把 SDK 解包到 app.asar.unpacked,
        // 否则 .node / .framework 无法从 asar 内加载
        asarUnpack: ['node_modules/aoq-electron-sdk/**']
      }
    }
  }
}

裸 webpack 配置等价写法:

externals: { 'aoq-electron-sdk': 'commonjs2 aoq-electron-sdk' }

2. 首次采集会触发系统麦克风/摄像头授权弹窗,请在应用 Info.plist 中声明 NSMicrophoneUsageDescription / NSCameraUsageDescription

快速开始

import createAoqClientEngine, { AoqTrackType } from 'aoq-electron-sdk'

const engine = createAoqClientEngine()

// 1. 监听事件
engine.on('onConnectionStatusChange', (status) => console.log('status:', status))
engine.on('onDataMsg', (data) => console.log('recv:', Buffer.from(data).toString()))
engine.on('onError', (code, message) => console.error('error:', code, message))

// 2. 创建引擎
engine.createEngine({
  workDir: '/tmp/aoq',        // 日志与临时文件目录
  enableDumpAudio: false,
  extras: ''
})

// 3. 编解码配置(可选,不设则用默认值)
engine.setAudioEncoderConfig({
  trackType: AoqTrackType.AoqTrackTypeAudio,
  codecType: 2,               // Opus
  sampleRate: 16000, channel: 1, bitrate: 24000
})

// 4. 连接(token / sid / relayEndpoints 由业务服务端下发)
engine.connect({
  token, sid, certFingerprint,
  relayEndpoints: [{ routeIndex: 0, endpoint, port }],
  publishTracks:   [{ trackType: AoqTrackType.AoqTrackTypeAudio }],
  subscribeTracks: [{ trackType: AoqTrackType.AoqTrackTypeAudio }]
})

// 5. 开启音频采集与播放
engine.startAudioCapture({ channel: 1 })
engine.startAudioPlayer({ channel: 1 })

// 6. 收发数据消息
engine.sendDataMsg('hello')

// 7. 收尾
engine.disconnect()
engine.destroy()

所有接口返回 number0 表示成功,非 0 为错误码。

API 概览

生命周期与连接

| 接口 | 说明 | |---|---| | createEngine(config) | 创建引擎(单例,重复调用返回同一实例) | | destroy() | 销毁引擎;销毁后接口短路返回 -1 | | getVersion() | 返回 SDK 版本号字符串 | | connect(config) | 连接;状态变化由 onConnectionStatusChange 通知 | | disconnect() | 断开连接 | | enableSendMediaStream(trackType, enable) | 控制某路流是否发送 |

音频

| 分类 | 接口 | |---|---| | 采集 | startAudioCapture / stopAudioCapture / muteAudioCapture | | 播放 | startAudioPlayer / stopAudioPlayer / pauseAudioPlayer / resumeAudioPlayer / interruptAudioPlayer | | 编解码 | setAudioEncoderConfig / setAudioDecoderConfig | | 文件混音 | startAudioFile / stopAudioFile / pauseAudioFile / resumeAudioFile / getAudioFileDuration / getAudioFileCurrentPosition / setAudioFilePositionMillis / setAudioFileVolume / getAudioFileVolume | | 外部音频流 | addAudioExternalStream / pushAudioExternalStreamData / setAudioExternalStreamVolume / getAudioExternalStreamVolume / clearAudioExternalStreamBuffer / removeAudioExternalStream |

视频

| 分类 | 接口 | |---|---| | 采集 | startVideoCapture / stopVideoCapture | | 编解码 | setVideoEncoderConfig / setVideoDecoderConfig | | 外部推帧 | pushExternalVideoCapturedFrame(BGRA / I420)、pushExternalVideoEncodedFrame(JPEG) |

数据消息

sendDataMsg(data) —— data 支持 stringBuffer;对端消息通过 onDataMsg 事件回调。

帧观察者

engine.setAudioFrameObserver(true)
engine.enableAudioFrameObserver({ enabled: true, audioSource: 0, sampleRate: 48000, channels: 1 })
engine.on('onCapturedAudioFrame', (frame) => { /* frame.buffer 为 PCM 数据 */ })

视频侧对应 setVideoFrameObserver / enableVideoFrameObserver + onCapturedVideoFrame / onPreEncodeVideoFrame / onRemoteVideoFrame

帧观察者为只读模式,回调中不支持回写帧数据。

事件列表

engine.on(event, handler) 支持:

onError / onWarning / onConnectionStatusChange / onStats
onAudioDeviceStateChanged / onAudioDeviceRouteChanged / onAudioFileState
onVideoDeviceStateChanged / onDataMsg
onCapturedAudioFrame / onProcessCapturedAudioFrame / onPublishAudioFrame / onPlaybackAudioFrame
onCapturedVideoFrame / onPreEncodeVideoFrame / onRemoteVideoFrame

完整的参数与枚举定义见包内 types/ 目录下的 TypeScript 类型声明(IDE 可自动提示)。

视频预览与渲染

Electron renderer 是 Chromium 环境,无法嵌入原生视图,因此 SDK 不提供 setLocalView / setRemoteView。视频预览通过「帧观察者 + Canvas」实现,SDK 已内置渲染器:

import { YUVCanvasRenderer } from 'aoq-electron-sdk'

const renderer = new YUVCanvasRenderer()
renderer.bind(document.getElementById('preview'))   // 传入 <canvas> 元素

engine.setVideoFrameObserver(true)
engine.enableVideoFrameObserver({
  enabled: true,
  videoSource: 0,
  trackType: 1, // Video;Screen 为 3
  format: 1     // I420
})
engine.on('onCapturedVideoFrame', (frame) => {
  // frame.trackType 可区分 Video / Screen
  renderer.drawFrame(frame)
})

渲染填充模式(拉伸/裁剪等)用 CSS object-fit 控制 canvas 即可。

Windows 摄像头采集与消息泵

Windows 的摄像头采集依赖一个 message-only window 收开/关摄像头的消息,派发靠 加载 AoqClientSdk.dll 那个线程(即 require('aoq-electron-sdk') 所在的 JS 线程) 的 Win32 消息循环。Electron renderer 进程不派发这类窗口消息,因此 SDK 在 createEngine() 时会在该线程的 libuv 循环上挂一个 16ms 的消息泵,destroy() 时停掉。

由此带来两点约定:

  • 不要在 createEngine() 之后长时间阻塞 JS 线程(同步大计算、execSync 等), 否则消息泵停摆,摄像头会卡在「启动中」
  • 别的线程/进程里裸调 native 层(绕过本 SDK)不会有这个消息泵,摄像头不会出帧

使用建议

  • 事件回调中避免重计算:native 回调经异步线程投递,高频帧事件中做耗时操作会造成堆积
  • 生产应用建议走 main 进程 + IPC:本文档示例为 renderer 直接加载(便于快速接入), 生产环境把 SDK 放在 main 进程、通过 IPC 与界面通信更稳妥
  • destroy() 后需重新 createEngine() 才能继续使用

常见问题

Q: 运行时报 Cannot find module '.../aoq_node_ext.node' 检查是否配置了 nodeIntegration: trueexternals(见上文集成配置)。

Q: 打包后的应用启动即崩溃 / 找不到 framework 检查 asarUnpack 是否包含 node_modules/aoq-electron-sdk/**。原生库不能放在 asar 内。

Q: npm install 报平台不支持 / 运行时报“找不到当前平台的原生模块” 报错会列出它查找过的目录。对照 prebuilds/ 下是否有你平台对应的目录; 如果没有,说明这个版本的包未包含该平台产物(当前发布矩阵:macOS x64/arm64、Windows x64)。

Q: 采集无声音 确认已授予麦克风权限,且 Info.plist 声明了 NSMicrophoneUsageDescription