UNPKG

process-audio-capture

Version:

Native process-level audio capture for Node.js and Electron applications

202 lines (164 loc) 4.33 kB
import bindings from "bindings"; import type {AudioData, PermissionStatus, ProcessInfo} from "./types"; import {EventEmitter} from "events"; /** * 原生插件接口 */ interface AudioCaptureAddon { /** 检查音频捕获权限状态 */ checkPermission(): PermissionStatus; /** 请求音频捕获权限 */ requestPermission(callback: (result: PermissionStatus) => void): void; /** 获取可捕获音频的进程列表 */ getProcessList(): ProcessInfo[]; /** 开始捕获指定进程的音频 */ startCapture(pid: number, callback: (audioData: AudioData) => void): boolean; /** 停止捕获 */ stopCapture(): boolean; } interface NativeModule { AudioCaptureAddon: { new (): AudioCaptureAddon; }; } // 加载原生插件 const native: NativeModule = bindings("audio_capture"); /** * 音频捕获事件映射 */ export interface AudioCaptureEvents { /** 是否正在捕获音频状态变化 */ capturing: [capturing: boolean]; /** 音频数据 */ "audio-data": [audioData: AudioData]; } /** * 音频捕获类 */ class AudioCaptureStub extends EventEmitter<AudioCaptureEvents> { constructor() { super(); } /** 是否正在捕获音频 */ public get isCapturing(): boolean { return false; } private set isCapturing(_value: boolean) { // do nothing } /** 当前平台是否支持音频捕获 */ isPlatformSupported(): boolean { return false; } /** 检查音频捕获权限状态 */ checkPermission(): PermissionStatus { return { status: "authorized" }; } /** 请求音频捕获权限 */ requestPermission(): Promise<PermissionStatus> { return Promise.resolve({ status: "authorized" }); } /** 获取可捕获音频的进程列表 */ getProcessList(): ProcessInfo[] { return []; } /** 开始捕获指定进程的音频 */ startCapture( _pid: number, _callback?: (audioData: AudioData) => void ): boolean { return false; } /** 停止捕获 */ stopCapture(): boolean { return false; } } /** * 音频捕获类 */ export class AudioCapture extends AudioCaptureStub { private addon: AudioCaptureAddon; private _capturing: boolean; constructor() { super(); // 创建C++类的实例 this.addon = new native.AudioCaptureAddon(); this._capturing = false; } public get isCapturing(): boolean { return this._capturing; } private set isCapturing(value: boolean) { if (value === this._capturing) { return; } this._capturing = value; this.emit("capturing", value); } isPlatformSupported(): boolean { return true; } checkPermission(): PermissionStatus { return this.addon.checkPermission(); } requestPermission(): Promise<PermissionStatus> { return new Promise<PermissionStatus>((resolve) => { this.addon.requestPermission((result) => { resolve(result); }); }); } getProcessList(): ProcessInfo[] { // 检查权限 const permission = this.checkPermission(); if (permission.status !== "authorized") { throw new Error("没有音频捕获权限"); } return this.addon.getProcessList(); } startCapture( pid: number, callback?: (audioData: AudioData) => void ): boolean { // 检查权限 const permission = this.checkPermission(); if (permission.status !== "authorized") { throw new Error("没有音频捕获权限"); } if (this.isCapturing) { throw new Error("已经在捕获音频,请先停止"); } try { const result = this.addon.startCapture(pid, (audioData) => { callback?.(audioData); this.emit("audio-data", audioData); }); if (result) { this.isCapturing = true; } return result; } catch (error) { throw error; } } stopCapture(): boolean { if (!this.isCapturing) { return false; } const result = this.addon.stopCapture(); if (result) { this.isCapturing = false; } return result; } } /** 音频捕获实例 */ let audioCapture: AudioCaptureStub; if (process.platform === "darwin" || process.platform === "win32") { audioCapture = new AudioCapture(); } else { // 为不支持的平台提供回退方案 audioCapture = new AudioCaptureStub(); } export { audioCapture };