@bdky/aaas-pilot-kit 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/index.cjs.js +255 -23
  2. package/dist/index.cjs.js.LICENSE.txt +9 -0
  3. package/dist/index.esm.js +254 -22
  4. package/dist/index.esm.js.LICENSE.txt +9 -0
  5. package/dist/index.umd.js +254 -22
  6. package/dist/index.umd.js.LICENSE.txt +9 -0
  7. package/dist/ky-aaas-pilot-kit.umd.js +254 -22
  8. package/dist/ky-aaas-pilot-kit.umd.js.LICENSE.txt +9 -0
  9. package/dist/libs/aaas-pilot-kit/src/index.d.ts +2 -0
  10. package/dist/libs/aaas-pilot-kit/src/lib/DI/types.d.ts +1 -0
  11. package/dist/libs/aaas-pilot-kit/src/lib/constants/azure.d.ts +423 -0
  12. package/dist/libs/aaas-pilot-kit/src/lib/service/conversation/conversationService.d.ts +24 -0
  13. package/dist/libs/aaas-pilot-kit/src/lib/service/conversation/types.d.ts +37 -0
  14. package/dist/libs/aaas-pilot-kit/src/lib/service/rtc-asr/asr/azureAsrService.d.ts +108 -0
  15. package/dist/libs/aaas-pilot-kit/src/lib/service/rtc-asr/asr/baseAsrService.d.ts +38 -3
  16. package/dist/libs/aaas-pilot-kit/src/lib/service/rtc-asr/signal/noop.d.ts +54 -0
  17. package/dist/libs/aaas-pilot-kit/src/lib/utils/AudioDeviceDetector.d.ts +3 -1
  18. package/dist/libs/aaas-pilot-kit/src/lib/utils/EnergyBasedGate.d.ts +240 -0
  19. package/dist/libs/aaas-pilot-kit/src/lib/utils/MediaStreamManager.d.ts +209 -0
  20. package/dist/libs/aaas-pilot-kit/src/lib/utils/audio-processing/AudioContextLifecycle.d.ts +110 -0
  21. package/dist/libs/aaas-pilot-kit/src/lib/utils/audio-processing/AudioWorkletCapability.d.ts +95 -0
  22. package/dist/libs/aaas-pilot-kit/src/lib/utils/audio-processing/FloatAPICompat.d.ts +103 -0
  23. package/dist/libs/aaas-pilot-kit/src/types/config.d.ts +358 -4
  24. package/package.json +23 -1
@@ -1,6 +1,7 @@
1
1
  import Emittery from 'emittery';
2
2
  import type { IResolvedOptions } from '../../../../types/config';
3
3
  import type { BaseSignalingService } from '../signal/base';
4
+ import type { MediaStreamManager } from '../../../utils/MediaStreamManager';
4
5
  import { ErrorManager } from '../../../error';
5
6
  import { type AudioDeviceCheckResult, type AudioDetectorOptions } from '../../../utils/AudioDeviceDetector';
6
7
  export declare namespace NBaseAsrService {
@@ -37,6 +38,7 @@ export declare namespace NBaseAsrService {
37
38
  interface IMessageEventPayload extends IMessageProtocol, IEventWithSessionIdPayload {
38
39
  }
39
40
  type IDeviceCheckCompletedPayload = AudioDeviceCheckResult;
41
+ type IDeviceCheckResult = AudioDeviceCheckResult;
40
42
  interface IEmitter {
41
43
  start: IStartEventPayload;
42
44
  stop: IStopEventPayload;
@@ -58,11 +60,25 @@ export declare abstract class BaseAsrService<E extends NBaseAsrService.IEmitter
58
60
  muted: boolean;
59
61
  readonly emitter: Emittery<E, E & import("emittery").OmnipresentEventData, import("emittery").DatalessEventNames<E>>;
60
62
  protected started: boolean;
63
+ protected customSessionId: string | null;
64
+ /**
65
+ * MediaStream 管理器(通过 DI 注入)
66
+ */
67
+ protected readonly streamManager: MediaStreamManager;
61
68
  private lastCheckResult;
62
69
  private lastCheckTime;
63
70
  private readonly CHECK_CACHE_TTL;
64
- constructor(opts: IResolvedOptions, signalingService: BaseSignalingService, errorManager: ErrorManager);
71
+ constructor(opts: IResolvedOptions, signalingService: BaseSignalingService, errorManager: ErrorManager, streamManager: MediaStreamManager);
65
72
  get sessionId(): string | null;
73
+ /**
74
+ * 静音控制
75
+ *
76
+ * 实现说明:
77
+ * - BRTC: 调用 signalingService.Mute(),由 BRTC SDK 控制
78
+ * - Azure: 设置 MediaStreamTrack.enabled = false,生成空帧(软静音)
79
+ *
80
+ * @param muted - 是否静音
81
+ */
66
82
  mute: (muted: boolean) => void;
67
83
  setMutedByUser: (muted: boolean) => void;
68
84
  /**
@@ -75,6 +91,18 @@ export declare abstract class BaseAsrService<E extends NBaseAsrService.IEmitter
75
91
  tryUnmuteAsr: () => boolean;
76
92
  disable: () => void;
77
93
  enable: () => void;
94
+ /**
95
+ * 设置外部播放抑制启用状态
96
+ *
97
+ * 该方法用于控制 ASR 输入的外部播放抑制策略(例如 TTS 外放期间抬阈门控)。
98
+ *
99
+ * @param enabled - 是否启用抑制
100
+ *
101
+ * @remarks
102
+ * - 默认实现为空操作,需要子类根据具体实现来重写
103
+ * - 例如 Azure ASR 使用能量门控(EnergyBasedGate)进行抬阈抑制
104
+ */
105
+ setPlaybackSuppressionEnabled: (enabled: boolean) => void;
78
106
  /**
79
107
  * 检查音频设备可用性
80
108
  *
@@ -102,6 +130,15 @@ export declare abstract class BaseAsrService<E extends NBaseAsrService.IEmitter
102
130
  checkAudioDevice: (options?: AudioDetectorOptions & {
103
131
  forceCheck?: boolean;
104
132
  }) => Promise<AudioDeviceCheckResult>;
133
+ /**
134
+ * 处理麦克风检测失败的策略
135
+ *
136
+ * @param strategy - 处理策略
137
+ * @param result - 检测结果
138
+ * @param callback - 用户自定义回调(仅 prompt 策略使用)
139
+ * @returns Promise<boolean> - true: 继续启动,false: 终止启动
140
+ */
141
+ protected readonly handleMicrophoneCheckFailure: (strategy: "error" | "warn" | "silent" | "prompt", result: AudioDeviceCheckResult, callback?: (result: AudioDeviceCheckResult) => Promise<boolean>) => Promise<boolean>;
105
142
  protected readonly _stop: () => Promise<void>;
106
143
  protected readonly _dispose: () => void;
107
144
  /**
@@ -112,6 +149,4 @@ export declare abstract class BaseAsrService<E extends NBaseAsrService.IEmitter
112
149
  abstract start(): Promise<void>;
113
150
  abstract stop(): Promise<void>;
114
151
  abstract dispose(): void;
115
- protected abstract makeStartOptions(extra: any): unknown;
116
- protected abstract parseMessage(raw: string): NBaseAsrService.IMessageProtocol;
117
152
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @file 空信令服务实现(用于不需要 Signaling 的 ASR,如 Azure)
3
+ * @description 用于满足 DI 容器的依赖注入要求,但实际不执行任何信令操作
4
+ */
5
+ import { BaseSignalingService } from './base';
6
+ /**
7
+ * 空信令服务(No-op Signaling Service)
8
+ *
9
+ * 用于不需要独立信令层的 ASR 实现(如 Azure Speech SDK)
10
+ * 提供最小化的方法实现以满足 BaseSignalingService 接口要求
11
+ *
12
+ * 特点:
13
+ * - 不执行任何实际的信令操作
14
+ * - 自动生成简单的 sessionId
15
+ * - 所有方法都是空操作(no-op)
16
+ *
17
+ * 使用场景:
18
+ * - Azure ASR 不需要独立的信令服务
19
+ * - 其他自管理连接的 ASR 实现
20
+ */
21
+ export declare class NoopSignalingService extends BaseSignalingService {
22
+ /**
23
+ * 启动信令服务(空操作)
24
+ *
25
+ * 仅生成一个简单的 sessionId 以满足接口要求
26
+ *
27
+ * @param _opts - 启动选项(未使用)
28
+ */
29
+ Start<P extends Record<string, any>>(_opts: P): Promise<void>;
30
+ /**
31
+ * 停止信令服务(空操作)
32
+ *
33
+ * 清空 sessionId
34
+ */
35
+ Stop(): Promise<void>;
36
+ /**
37
+ * 销毁信令服务(空操作)
38
+ *
39
+ * 调用基类的 _dispose 方法进行清理
40
+ */
41
+ Dispose(): void;
42
+ /**
43
+ * 静音控制(空操作)
44
+ *
45
+ * @param _muted - 是否静音(未使用)
46
+ */
47
+ Mute(_muted: boolean): void;
48
+ /**
49
+ * 获取会话 ID
50
+ *
51
+ * @returns 自动生成的会话 ID
52
+ */
53
+ GetSessionID(): string;
54
+ }
@@ -46,8 +46,10 @@ export interface AudioDeviceCheckResult {
46
46
  available: boolean;
47
47
  /** 错误类型 (仅在 available = false 时存在) */
48
48
  error?: AudioDeviceError;
49
- /** 错误详细信息 */
49
+ /** 错误详细信息(技术性) */
50
50
  message?: string;
51
+ /** 用户友好的错误提示文案 */
52
+ userMessage?: string;
51
53
  /** 检测通过的层级 (1-4) */
52
54
  passedLevel?: number;
53
55
  /** 找到的音频设备列表 */
@@ -0,0 +1,240 @@
1
+ /**
2
+ * @file 基于能量检测的智能门控 (Energy-based Gate)
3
+ * @description 通过实时监测音频能量差异,智能过滤外部音频干扰(如 TTS 回声),减少移动端 ASR 误识别
4
+ *
5
+ * 原理:
6
+ * 1. 实时计算麦克风音频的能量(RMS)
7
+ * 2. 在降噪启用期间,提高 ASR 激活阈值
8
+ * 3. 只有当麦克风能量显著高于基准能量时,才允许 ASR 识别
9
+ * 4. 使用自适应阈值算法,适应不同环境噪音
10
+ *
11
+ * 重构版本 (v2):
12
+ * - ✅ 修复历史窗口计算错误 (100帧 ≠ 1秒)
13
+ * - ✅ 直接从 inputBuffer 计算 RMS (绕过 analyser 分支不更新问题)
14
+ * - ✅ Float API 兼容层 (防止 iOS 崩溃)
15
+ * - ✅ 渐进增强: AudioWorklet → ScriptProcessorNode
16
+ * - ✅ AudioContext 生命周期管理
17
+ */
18
+ /**
19
+ * 能量门控配置选项
20
+ */
21
+ export interface IEnergyGateOptions {
22
+ /**
23
+ * 外部播放抑制启用时的能量倍数阈值
24
+ * 麦克风能量必须显著高于基准能量才能通过
25
+ * @default 3.0
26
+ */
27
+ suppressionEnergyMultiplier?: number;
28
+ /**
29
+ * 空闲期间的基准能量阈值(dBFS)
30
+ * 低于此值的信号被视为静音或微弱回声
31
+ * @default -45
32
+ */
33
+ idleThreshold?: number;
34
+ /**
35
+ * 能量平滑系数(0-1)
36
+ * 值越大,能量变化越平滑(降低噪声干扰)
37
+ * @default 0.7
38
+ */
39
+ smoothingFactor?: number;
40
+ /**
41
+ * 外部播放抑制启用延迟(毫秒)
42
+ * 启用抑制后,延迟多久才启用高阈值
43
+ * @default 100
44
+ */
45
+ suppressionActivationDelay?: number;
46
+ /**
47
+ * 外部播放抑制关闭恢复延迟(毫秒)
48
+ * 停止抑制后,延迟多久恢复正常阈值
49
+ * @default 500
50
+ */
51
+ suppressionRecoveryDelay?: number;
52
+ /**
53
+ * 是否启用调试日志
54
+ * @default false
55
+ */
56
+ debug?: boolean;
57
+ }
58
+ /**
59
+ * 能量统计数据
60
+ */
61
+ export interface IEnergyStats {
62
+ /**
63
+ * 当前麦克风能量(dBFS)
64
+ */
65
+ microphoneEnergy: number;
66
+ /**
67
+ * 外部播放抑制是否启用(考虑延迟后的状态)
68
+ */
69
+ isSuppressionEnabled: boolean;
70
+ /**
71
+ * 当前激活阈值(dBFS)
72
+ */
73
+ currentThreshold: number;
74
+ /**
75
+ * 信号是否允许通过
76
+ */
77
+ isGateOpen: boolean;
78
+ /**
79
+ * 最近 1 秒内通过的帧数占比
80
+ */
81
+ passRate: number;
82
+ }
83
+ /**
84
+ * 基于能量检测的智能门控
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const gate = new EnergyBasedGate(audioContext, {
89
+ * suppressionEnergyMultiplier: 3.0,
90
+ * idleThreshold: -45
91
+ * });
92
+ *
93
+ * // 连接麦克风
94
+ * microphoneNode.connect(gate.input);
95
+ *
96
+ * // 获取过滤后的输出流
97
+ * const cleanStream = gate.getOutputStream();
98
+ *
99
+ * // 外部音频播放时启用回声消除(如 TTS 播报)
100
+ * tts.on('start', () => gate.setSuppressionEnabled(true));
101
+ * tts.on('end', () => gate.setSuppressionEnabled(false));
102
+ *
103
+ * // 传给 Azure ASR
104
+ * const audioConfig = SpeechSDK.AudioConfig.fromStreamInput(cleanStream);
105
+ * ```
106
+ */
107
+ export declare class EnergyBasedGate {
108
+ /**
109
+ * 音频输入节点
110
+ */
111
+ readonly input: GainNode;
112
+ private readonly context;
113
+ private readonly options;
114
+ /**
115
+ * 输出目标节点
116
+ */
117
+ private readonly destination;
118
+ /**
119
+ * 门控增益节点(用于静音)
120
+ */
121
+ private readonly gate;
122
+ /**
123
+ * 音频处理器 (AudioWorkletNode 或 ScriptProcessorNode)
124
+ */
125
+ private processor;
126
+ /**
127
+ * 处理器类型
128
+ */
129
+ private processorType;
130
+ /**
131
+ * 门控状态历史(用于计算通过率)
132
+ */
133
+ private readonly gateHistory;
134
+ /**
135
+ * ScriptProcessor 门控历史最大长度(动态计算,约 1 秒)
136
+ */
137
+ private readonly scriptProcessorMaxHistoryLength;
138
+ /**
139
+ * AudioWorklet 门控历史最大长度(动态计算,约 1 秒)
140
+ *
141
+ * @remarks
142
+ * AudioWorklet 的 render quantum 固定为 128 samples/callback,
143
+ * 与 ScriptProcessor(这里使用 2048) 不同,因此需要分别计算。
144
+ */
145
+ private readonly audioWorkletMaxHistoryLength;
146
+ /**
147
+ * 回声消除是否启用
148
+ */
149
+ private isSuppressionEnabled;
150
+ /**
151
+ * 回声消除状态切换定时器
152
+ */
153
+ private suppressionStateTimer;
154
+ /**
155
+ * 实际回声消除状态(考虑延迟后的状态)
156
+ */
157
+ private effectiveSuppressionState;
158
+ /**
159
+ * 当前麦克风能量(RMS,dBFS)
160
+ */
161
+ private currentEnergy;
162
+ /**
163
+ * 平滑后的能量值
164
+ */
165
+ private smoothedEnergy;
166
+ /**
167
+ * AudioWorklet 上报的最近一次统计(用于 getStats)
168
+ */
169
+ private workletPassRate;
170
+ private workletIsGateOpen;
171
+ /**
172
+ * 是否已启动
173
+ */
174
+ private started;
175
+ /**
176
+ * 创建配置的promise
177
+ */
178
+ private readonly setupAudioGraphPromise;
179
+ constructor(context: AudioContext, options?: IEnergyGateOptions);
180
+ /**
181
+ * 设置外部播放抑制启用状态(例如 TTS 播放期间抬阈)
182
+ *
183
+ * @param enabled - 是否启用抑制
184
+ */
185
+ setSuppressionEnabled: (enabled: boolean) => void;
186
+ /**
187
+ * 启动门控
188
+ */
189
+ start: () => void;
190
+ /**
191
+ * 停止门控
192
+ */
193
+ stop: () => void;
194
+ /**
195
+ * 获取处理后的音频流
196
+ */
197
+ getOutputStream: () => MediaStream;
198
+ /**
199
+ * 获取当前能量统计
200
+ */
201
+ getStats: () => IEnergyStats;
202
+ /**
203
+ * 动态调整阈值倍数
204
+ */
205
+ setEnergyMultiplier: (multiplier: number) => void;
206
+ /**
207
+ * 清理资源
208
+ */
209
+ dispose: () => void;
210
+ /**
211
+ * 搭建音频处理图(异步,支持 AudioWorklet 检测)
212
+ */
213
+ private setupAudioGraph;
214
+ /**
215
+ * 使用 AudioWorklet 设置音频图
216
+ */
217
+ private setupWithAudioWorklet;
218
+ /**
219
+ * 使用 ScriptProcessorNode 设置音频图(降级方案)
220
+ */
221
+ private setupWithScriptProcessor;
222
+ /**
223
+ * ScriptProcessor 音频处理回调
224
+ * 修复: 直接从 inputBuffer 计算 RMS,绕过 analyser 问题
225
+ */
226
+ private readonly processAudioScriptProcessor;
227
+ /**
228
+ * 判断门控是否应该打开
229
+ */
230
+ private readonly shouldGateOpen;
231
+ /**
232
+ * 获取当前激活阈值
233
+ */
234
+ private readonly getCurrentThreshold;
235
+ /**
236
+ * 获取 AudioWorklet 处理器代码
237
+ * (内联版本,生产环境可改为加载外部文件)
238
+ */
239
+ private getEnergyGateWorkletCode;
240
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * @file MediaStream 管理器
3
+ * @description 负责获取和管理 MediaStream,支持浏览器特性检测、动态约束构建、降级策略
4
+ */
5
+ /**
6
+ * 音频处理特性配置
7
+ *
8
+ * 直接使用 Web 标准的 MediaTrackConstraints 类型,支持所有标准音频约束参数
9
+ *
10
+ * 常用特性:
11
+ * - echoCancellation: 回声消除
12
+ * - noiseSuppression: 降噪处理
13
+ * - autoGainControl: 自动增益控制
14
+ * - sampleRate: 采样率(Hz)
15
+ * - sampleSize: 采样大小(位)
16
+ * - channelCount: 通道数(1=单声道, 2=立体声)
17
+ * - deviceId: 设备 ID
18
+ *
19
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
20
+ */
21
+ export type IAudioFeatureConfig = MediaTrackConstraints;
22
+ /**
23
+ * 浏览器特性支持检测结果
24
+ */
25
+ export interface IFeatureSupportResult {
26
+ /**
27
+ * 支持的特性列表
28
+ */
29
+ supported: string[];
30
+ /**
31
+ * 不支持的特性列表
32
+ */
33
+ unsupported: string[];
34
+ /**
35
+ * 是否有不支持的特性
36
+ */
37
+ hasUnsupportedFeatures: boolean;
38
+ }
39
+ /**
40
+ * MediaStream 获取结果
41
+ */
42
+ export interface IMediaStreamResult {
43
+ /**
44
+ * 获取到的 MediaStream 实例
45
+ */
46
+ stream: MediaStream;
47
+ /**
48
+ * 实际应用的约束配置
49
+ */
50
+ appliedConstraints: MediaTrackConstraints;
51
+ /**
52
+ * 启用的特性列表(用于调试)
53
+ */
54
+ enabledFeatures: string[];
55
+ /**
56
+ * 浏览器不支持的特性列表
57
+ */
58
+ unsupportedFeatures: string[];
59
+ }
60
+ /**
61
+ * MediaStreamManager 配置选项
62
+ */
63
+ export interface IMediaStreamManagerOptions {
64
+ /**
65
+ * 音频特性配置
66
+ * @default { echoCancellation: true, noiseSuppression: true, autoGainControl: true }
67
+ */
68
+ audioFeatures?: IAudioFeatureConfig;
69
+ /**
70
+ * 是否在检测到不支持的特性时输出警告
71
+ * @default true
72
+ */
73
+ warnOnUnsupportedFeatures?: boolean;
74
+ /**
75
+ * 是否在成功获取流后输出调试信息
76
+ * @default true
77
+ */
78
+ logEnabledFeatures?: boolean;
79
+ /**
80
+ * 是否在完全不支持任何特性时回退到基础约束 {audio: true}
81
+ * @default true
82
+ */
83
+ enableFallback?: boolean;
84
+ }
85
+ /**
86
+ * MediaStream 管理器
87
+ *
88
+ * 负责获取和管理 MediaStream,支持:
89
+ * - 浏览器特性检测(echoCancellation、noiseSuppression、autoGainControl)
90
+ * - 动态约束构建(仅使用支持的特性)
91
+ * - 降级策略(不支持时使用基础约束)
92
+ * - 资源清理
93
+ *
94
+ * @example 默认配置
95
+ * ```typescript
96
+ * const manager = new MediaStreamManager();
97
+ * const result = await manager.getUserMedia();
98
+ * console.log('启用的特性:', result.enabledFeatures);
99
+ *
100
+ * // 使用完毕后清理
101
+ * manager.cleanup();
102
+ * ```
103
+ *
104
+ * @example 自定义配置
105
+ * ```typescript
106
+ * const manager = new MediaStreamManager({
107
+ * audioFeatures: {
108
+ * echoCancellation: true,
109
+ * noiseSuppression: true,
110
+ * autoGainControl: false, // 禁用自动增益
111
+ * sampleRate: 48000, // 高采样率
112
+ * channelCount: 1 // 单声道
113
+ * },
114
+ * warnOnUnsupportedFeatures: true
115
+ * });
116
+ *
117
+ * const result = await manager.getUserMedia();
118
+ * ```
119
+ */
120
+ export declare class MediaStreamManager {
121
+ /**
122
+ * 默认音频特性配置(三大核心特性)
123
+ */
124
+ private static readonly DEFAULT_AUDIO_FEATURES;
125
+ /**
126
+ * 当前持有的 MediaStream 实例
127
+ */
128
+ private mediaStream;
129
+ /**
130
+ * 管理器配置选项
131
+ */
132
+ private readonly options;
133
+ /**
134
+ * 构造函数
135
+ *
136
+ * @param options - 配置选项
137
+ */
138
+ constructor(options?: IMediaStreamManagerOptions);
139
+ /**
140
+ * 检测浏览器支持的音频约束特性
141
+ *
142
+ * @returns 特性支持检测结果
143
+ */
144
+ checkFeatureSupport: () => IFeatureSupportResult;
145
+ /**
146
+ * 获取 MediaStream
147
+ *
148
+ * 核心方法,执行以下流程:
149
+ * 1. 检测浏览器特性支持
150
+ * 2. 构建动态约束对象
151
+ * 3. 降级处理(如需要)
152
+ * 4. 调用 getUserMedia 获取流
153
+ * 5. 记录日志
154
+ *
155
+ * @returns MediaStream 获取结果
156
+ * @throws Error - 获取失败时抛出原始错误(包含权限、设备等)
157
+ */
158
+ getUserMedia: () => Promise<IMediaStreamResult>;
159
+ /**
160
+ * 获取当前持有的 MediaStream
161
+ *
162
+ * @returns 当前的 MediaStream 实例,如果未获取则返回 null
163
+ */
164
+ getStream: () => MediaStream | null;
165
+ /**
166
+ * 控制音频轨道静音
167
+ *
168
+ * 通过设置 MediaStreamTrack.enabled 实现软静音
169
+ * enabled = false 时,track 生成空帧
170
+ *
171
+ * @param muted - 是否静音
172
+ * @returns this(支持链式调用)
173
+ */
174
+ mute: (muted: boolean) => MediaStreamManager;
175
+ /**
176
+ * 清理资源
177
+ *
178
+ * 停止所有音频轨道并释放 MediaStream
179
+ * 调用后可以再次调用 getUserMedia 获取新流
180
+ */
181
+ cleanup: () => void;
182
+ /**
183
+ * 检查当前是否持有有效的 MediaStream
184
+ *
185
+ * @returns 是否持有有效流
186
+ */
187
+ hasActiveStream: () => boolean;
188
+ /**
189
+ * 构建动态音频约束对象
190
+ *
191
+ * 仅包含浏览器支持的特性
192
+ *
193
+ * @param supportResult - 特性支持检测结果
194
+ * @returns 动态构建的约束对象
195
+ */
196
+ private readonly buildAudioConstraints;
197
+ /**
198
+ * 记录不支持的特性警告
199
+ *
200
+ * @param unsupportedFeatures - 不支持的特性列表
201
+ */
202
+ private readonly logUnsupportedFeaturesWarning;
203
+ /**
204
+ * 记录启用的特性
205
+ *
206
+ * @param enabledFeatures - 启用的特性列表
207
+ */
208
+ private readonly logEnabledFeatures;
209
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @file AudioContext 生命周期管理
3
+ * @description 管理 AudioContext 在移动端的生命周期,处理页面后台/前台切换
4
+ *
5
+ * 移动端问题:
6
+ * - iOS: 页面后台运行或锁屏后,AudioContext 自动 suspend
7
+ * - Android: 部分设备在后台会暂停音频处理
8
+ * - 用户需要手动恢复(需要用户手势)
9
+ *
10
+ * 解决方案:
11
+ * - 监听 visibilitychange 事件
12
+ * - 监听 AudioContext.statechange 事件
13
+ * - 页面前台时自动尝试 resume
14
+ * - 提供回调通知上层应用
15
+ */
16
+ /**
17
+ * AudioContext 生命周期选项
18
+ */
19
+ export interface IAudioContextLifecycleOptions {
20
+ /**
21
+ * Context 被挂起时的回调
22
+ */
23
+ onSuspended?: () => void;
24
+ /**
25
+ * Context 恢复运行时的回调
26
+ */
27
+ onResumed?: () => void;
28
+ /**
29
+ * Context 被中断时的回调 (如来电)
30
+ */
31
+ onInterrupted?: () => void;
32
+ /**
33
+ * 是否自动恢复 (页面前台时)
34
+ * @default true
35
+ */
36
+ autoResume?: boolean;
37
+ }
38
+ /**
39
+ * AudioContext 生命周期管理器
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const context = new AudioContext();
44
+ * const lifecycle = new AudioContextLifecycle(
45
+ * context,
46
+ * {
47
+ * onSuspended: () => console.log('Audio suspended'),
48
+ * onResumed: () => console.log('Audio resumed'),
49
+ * autoResume: true
50
+ * }
51
+ * );
52
+ *
53
+ * lifecycle.startMonitoring();
54
+ *
55
+ * // 手动确保运行 (需要用户手势上下文)
56
+ * await lifecycle.ensureRunning();
57
+ *
58
+ * // 停止监控
59
+ * lifecycle.stopMonitoring();
60
+ * lifecycle.dispose();
61
+ * ```
62
+ */
63
+ export declare class AudioContextLifecycle {
64
+ private readonly context;
65
+ private readonly options;
66
+ private isMonitoring;
67
+ private readonly boundHandleVisibilityChange;
68
+ private readonly boundHandleStateChange;
69
+ constructor(context: AudioContext, options?: IAudioContextLifecycleOptions);
70
+ /**
71
+ * 开始监控 AudioContext 生命周期
72
+ *
73
+ * @remarks
74
+ * 监听:
75
+ * - document.visibilitychange (页面前后台切换)
76
+ * - AudioContext.statechange (Context 状态变化)
77
+ * - window.pagehide/pageshow (iOS 特定)
78
+ */
79
+ startMonitoring: () => void;
80
+ /**
81
+ * 停止监控
82
+ */
83
+ stopMonitoring: () => void;
84
+ /**
85
+ * 确保 AudioContext 处于运行状态
86
+ *
87
+ * @returns 是否成功恢复到运行状态
88
+ *
89
+ * @remarks
90
+ * - 必须在用户手势上下文中调用 (如 click/touch 事件)
91
+ * - 如果 Context 已关闭,无法恢复,返回 false
92
+ */
93
+ ensureRunning: () => Promise<boolean>;
94
+ /**
95
+ * 获取当前 AudioContext 状态
96
+ */
97
+ getState: () => AudioContextState;
98
+ /**
99
+ * 清理资源
100
+ */
101
+ dispose: () => void;
102
+ /**
103
+ * 处理页面可见性变化
104
+ */
105
+ private readonly handleVisibilityChange;
106
+ /**
107
+ * 处理 AudioContext 状态变化
108
+ */
109
+ private readonly handleStateChange;
110
+ }