@ayden-fc2/riffle-bridge-web 1.0.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.
- package/README.md +264 -0
- package/dist/index.d.mts +719 -0
- package/dist/index.d.ts +719 -0
- package/dist/index.js +942 -0
- package/dist/index.mjs +899 -0
- package/package.json +47 -0
- package/src/bridge.ts +157 -0
- package/src/controllers/index.ts +527 -0
- package/src/core.ts +236 -0
- package/src/index.ts +94 -0
- package/src/tweaks.ts +383 -0
- package/src/types.ts +295 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Riffle Bridge 控制器模块
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { BridgeCore } from '../core';
|
|
6
|
+
import type {
|
|
7
|
+
HapticFeedbackType,
|
|
8
|
+
SensorType,
|
|
9
|
+
SensorData,
|
|
10
|
+
BarometerData,
|
|
11
|
+
DeviceInfo,
|
|
12
|
+
BatteryInfo,
|
|
13
|
+
NetworkInfo,
|
|
14
|
+
SystemInfo,
|
|
15
|
+
AppInfo,
|
|
16
|
+
ScreenInfo,
|
|
17
|
+
StorageStats,
|
|
18
|
+
FileInfo,
|
|
19
|
+
CachedFileInfo,
|
|
20
|
+
DownloadResult,
|
|
21
|
+
Base64Result,
|
|
22
|
+
PhotoResult,
|
|
23
|
+
AudioStatus,
|
|
24
|
+
CameraFacing,
|
|
25
|
+
CameraFilter,
|
|
26
|
+
RecordingResult,
|
|
27
|
+
PermissionResult,
|
|
28
|
+
VolumeData,
|
|
29
|
+
} from '../types';
|
|
30
|
+
|
|
31
|
+
// ============================================
|
|
32
|
+
// 震动控制器
|
|
33
|
+
// ============================================
|
|
34
|
+
|
|
35
|
+
export class HapticController {
|
|
36
|
+
constructor(private core: BridgeCore) {}
|
|
37
|
+
|
|
38
|
+
async light(): Promise<void> {
|
|
39
|
+
await this.core.send('haptic', 'light');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async medium(): Promise<void> {
|
|
43
|
+
await this.core.send('haptic', 'medium');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async heavy(): Promise<void> {
|
|
47
|
+
await this.core.send('haptic', 'heavy');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async success(): Promise<void> {
|
|
51
|
+
await this.core.send('haptic', 'success');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async warning(): Promise<void> {
|
|
55
|
+
await this.core.send('haptic', 'warning');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async error(): Promise<void> {
|
|
59
|
+
await this.core.send('haptic', 'error');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async selection(): Promise<void> {
|
|
63
|
+
await this.core.send('haptic', 'selection');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 播放震动序列
|
|
68
|
+
*/
|
|
69
|
+
async sequence(types: HapticFeedbackType[], interval = 200): Promise<void> {
|
|
70
|
+
for (let i = 0; i < types.length; i++) {
|
|
71
|
+
const type = types[i];
|
|
72
|
+
const method = this[type as keyof this];
|
|
73
|
+
if (typeof method === 'function') {
|
|
74
|
+
await (method as () => Promise<void>).call(this);
|
|
75
|
+
}
|
|
76
|
+
if (i < types.length - 1) {
|
|
77
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 根据强度震动
|
|
84
|
+
*/
|
|
85
|
+
async intensity(level: number): Promise<void> {
|
|
86
|
+
if (level <= 0.3) return this.light();
|
|
87
|
+
if (level <= 0.7) return this.medium();
|
|
88
|
+
return this.heavy();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================
|
|
93
|
+
// 传感器控制器
|
|
94
|
+
// ============================================
|
|
95
|
+
|
|
96
|
+
export interface SensorStartOptions {
|
|
97
|
+
types?: SensorType[];
|
|
98
|
+
interval?: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export class SensorController {
|
|
102
|
+
private isActive = false;
|
|
103
|
+
private activeTypes: SensorType[] = [];
|
|
104
|
+
|
|
105
|
+
constructor(private core: BridgeCore) {}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 启动传感器
|
|
109
|
+
*/
|
|
110
|
+
async start(options: SensorStartOptions = {}): Promise<{ started: SensorType[]; updateInterval: number }> {
|
|
111
|
+
const {
|
|
112
|
+
types = ['accelerometer', 'gyroscope', 'magnetometer', 'barometer'],
|
|
113
|
+
interval = 100
|
|
114
|
+
} = options;
|
|
115
|
+
|
|
116
|
+
const result = await this.core.send<{ started: SensorType[]; updateInterval: number }>(
|
|
117
|
+
'sensors',
|
|
118
|
+
'start',
|
|
119
|
+
{ types, updateInterval: interval }
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
this.isActive = true;
|
|
123
|
+
this.activeTypes = types;
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 停止传感器
|
|
129
|
+
*/
|
|
130
|
+
async stop(): Promise<{ stopped: boolean }> {
|
|
131
|
+
const result = await this.core.send<{ stopped: boolean }>('sensors', 'stop');
|
|
132
|
+
this.isActive = false;
|
|
133
|
+
this.activeTypes = [];
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 监听加速度计数据
|
|
139
|
+
*/
|
|
140
|
+
onAccelerometer(callback: (data: SensorData[]) => void): () => void {
|
|
141
|
+
return this.core.onSensorData('accelerometer', callback as (data: unknown[]) => void);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 监听陀螺仪数据
|
|
146
|
+
*/
|
|
147
|
+
onGyroscope(callback: (data: SensorData[]) => void): () => void {
|
|
148
|
+
return this.core.onSensorData('gyroscope', callback as (data: unknown[]) => void);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 监听磁力计数据
|
|
153
|
+
*/
|
|
154
|
+
onMagnetometer(callback: (data: SensorData[]) => void): () => void {
|
|
155
|
+
return this.core.onSensorData('magnetometer', callback as (data: unknown[]) => void);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 监听气压计数据
|
|
160
|
+
*/
|
|
161
|
+
onBarometer(callback: (data: BarometerData[]) => void): () => void {
|
|
162
|
+
return this.core.onSensorData('barometer', callback as (data: unknown[]) => void);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 获取当前状态
|
|
167
|
+
*/
|
|
168
|
+
getStatus(): { isActive: boolean; activeTypes: SensorType[] } {
|
|
169
|
+
return { isActive: this.isActive, activeTypes: this.activeTypes };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================
|
|
174
|
+
// 设备信息控制器
|
|
175
|
+
// ============================================
|
|
176
|
+
|
|
177
|
+
export class DeviceController {
|
|
178
|
+
constructor(private core: BridgeCore) {}
|
|
179
|
+
|
|
180
|
+
async getDeviceInfo(): Promise<DeviceInfo> {
|
|
181
|
+
return this.core.send<DeviceInfo>('device', 'getDeviceInfo');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async getBatteryInfo(): Promise<BatteryInfo> {
|
|
185
|
+
return this.core.send<BatteryInfo>('device', 'getBatteryInfo');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async getNetworkInfo(): Promise<NetworkInfo> {
|
|
189
|
+
return this.core.send<NetworkInfo>('device', 'getNetworkInfo');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async getSystemInfo(): Promise<SystemInfo> {
|
|
193
|
+
return this.core.send<SystemInfo>('device', 'getSystemInfo');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getAppInfo(): Promise<AppInfo> {
|
|
197
|
+
return this.core.send<AppInfo>('device', 'getAppInfo');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async getScreenInfo(): Promise<ScreenInfo> {
|
|
201
|
+
return this.core.send<ScreenInfo>('device', 'getScreenInfo');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async getAllInfo(): Promise<{
|
|
205
|
+
device: Partial<DeviceInfo>;
|
|
206
|
+
battery: Partial<BatteryInfo>;
|
|
207
|
+
network: Partial<NetworkInfo>;
|
|
208
|
+
system: Partial<SystemInfo>;
|
|
209
|
+
app: Partial<AppInfo>;
|
|
210
|
+
}> {
|
|
211
|
+
return this.core.send('device', 'getAllInfo');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ============================================
|
|
216
|
+
// 文件存储控制器
|
|
217
|
+
// ============================================
|
|
218
|
+
|
|
219
|
+
export class FileStorageController {
|
|
220
|
+
constructor(private core: BridgeCore) {}
|
|
221
|
+
|
|
222
|
+
async init(): Promise<{ initialized: boolean }> {
|
|
223
|
+
return this.core.send('fileStorage', 'init');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async getStorageStats(): Promise<StorageStats> {
|
|
227
|
+
return this.core.send<StorageStats>('fileStorage', 'getStorageStats');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async takePhoto(): Promise<FileInfo> {
|
|
231
|
+
return this.core.send<FileInfo>('fileStorage', 'takePhoto');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async pickFromGallery(): Promise<FileInfo> {
|
|
235
|
+
return this.core.send<FileInfo>('fileStorage', 'pickFromGallery');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async saveFile(sourceUri: string, filename: string, subfolder?: string): Promise<FileInfo> {
|
|
239
|
+
return this.core.send<FileInfo>('fileStorage', 'saveFile', {
|
|
240
|
+
sourceUri,
|
|
241
|
+
filename,
|
|
242
|
+
subfolder,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async listFiles(subfolder?: string): Promise<FileInfo[]> {
|
|
247
|
+
return this.core.send<FileInfo[]>('fileStorage', 'listFiles', { subfolder });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async downloadAndSave(url: string, filename: string, subfolder?: string): Promise<FileInfo> {
|
|
251
|
+
return this.core.send<FileInfo>('fileStorage', 'downloadAndSave', {
|
|
252
|
+
url,
|
|
253
|
+
downloadFilename: filename,
|
|
254
|
+
downloadSubfolder: subfolder,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async getLocalFileByUrl(url: string): Promise<CachedFileInfo> {
|
|
259
|
+
return this.core.send<CachedFileInfo>('fileStorage', 'getLocalFileByUrl', {
|
|
260
|
+
checkUrl: url,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async clearAppFiles(): Promise<{ cleared: boolean }> {
|
|
265
|
+
return this.core.send('fileStorage', 'clearAppFiles');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async deleteFile(filename: string, subfolder?: string): Promise<{ deleted: boolean }> {
|
|
269
|
+
return this.core.send('fileStorage', 'deleteFile', {
|
|
270
|
+
deleteFilename: filename,
|
|
271
|
+
deleteSubfolder: subfolder,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async loadUrlMappings(): Promise<Array<{ url: string; filename: string; path: string }>> {
|
|
276
|
+
return this.core.send('fileStorage', 'loadUrlMappings');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async downloadWithCache(url: string, checkCache = true): Promise<DownloadResult> {
|
|
280
|
+
return this.core.send<DownloadResult>('fileStorage', 'downloadWithCache', {
|
|
281
|
+
downloadUrl: url,
|
|
282
|
+
checkCache,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async clearUrlMappings(): Promise<{ cleared: boolean }> {
|
|
287
|
+
return this.core.send('fileStorage', 'clearUrlMappings');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async removeUrlMapping(url: string): Promise<{ removed: boolean }> {
|
|
291
|
+
return this.core.send('fileStorage', 'removeUrlMapping', { removeUrl: url });
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async addCustomFileMapping(customKey: string, localUri: string): Promise<{ added: boolean }> {
|
|
295
|
+
return this.core.send('fileStorage', 'addCustomFileMapping', {
|
|
296
|
+
customKey,
|
|
297
|
+
localPath: localUri,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async readAsBase64(uriOrKey: string): Promise<Base64Result> {
|
|
302
|
+
return this.core.send<Base64Result>('fileStorage', 'readAsBase64', { uriOrKey });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ============================================
|
|
307
|
+
// 音频控制器
|
|
308
|
+
// ============================================
|
|
309
|
+
|
|
310
|
+
export interface PlayOptions {
|
|
311
|
+
uri: string;
|
|
312
|
+
volume?: number;
|
|
313
|
+
rate?: number;
|
|
314
|
+
isLooping?: boolean;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export class AudioController {
|
|
318
|
+
constructor(
|
|
319
|
+
private core: BridgeCore,
|
|
320
|
+
private fileStorage: FileStorageController
|
|
321
|
+
) {}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 解析 URI,返回可播放的实际路径
|
|
325
|
+
*/
|
|
326
|
+
private async resolveUri(uri: string): Promise<string> {
|
|
327
|
+
if (!uri) throw new Error('URI is required');
|
|
328
|
+
|
|
329
|
+
// file:// 协议直接使用
|
|
330
|
+
if (uri.startsWith('file://')) {
|
|
331
|
+
return uri;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// 非 http/https 协议,从 MAP 查询
|
|
335
|
+
if (!uri.startsWith('http://') && !uri.startsWith('https://')) {
|
|
336
|
+
const cached = await this.fileStorage.getLocalFileByUrl(uri);
|
|
337
|
+
if (cached?.exists && cached.uri) {
|
|
338
|
+
return cached.uri;
|
|
339
|
+
}
|
|
340
|
+
throw new Error(`File mapping not found: ${uri}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// http/https URL,先查缓存
|
|
344
|
+
try {
|
|
345
|
+
const cached = await this.fileStorage.getLocalFileByUrl(uri);
|
|
346
|
+
if (cached?.exists && cached.uri) {
|
|
347
|
+
return cached.uri;
|
|
348
|
+
}
|
|
349
|
+
} catch {
|
|
350
|
+
// 查询失败,继续使用在线 URL
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return uri;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* 播放音频(智能解析 URI)
|
|
358
|
+
*/
|
|
359
|
+
async playOnline(options: PlayOptions): Promise<{ playing: boolean; uri: string }> {
|
|
360
|
+
const { uri, ...playOptions } = options;
|
|
361
|
+
|
|
362
|
+
let resolvedUri = await this.resolveUri(uri);
|
|
363
|
+
|
|
364
|
+
// 在线 URL 未缓存时,先下载
|
|
365
|
+
if (uri.startsWith('http') && resolvedUri === uri) {
|
|
366
|
+
try {
|
|
367
|
+
const downloadResult = await this.fileStorage.downloadWithCache(uri);
|
|
368
|
+
if (downloadResult?.uri) {
|
|
369
|
+
resolvedUri = downloadResult.uri;
|
|
370
|
+
}
|
|
371
|
+
} catch (e) {
|
|
372
|
+
console.warn('[AudioController] Cache failed, using online URL:', e);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return this.core.send('audio', 'playOnline', {
|
|
377
|
+
...playOptions,
|
|
378
|
+
uri: resolvedUri,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async pause(): Promise<{ paused: boolean }> {
|
|
383
|
+
return this.core.send('audio', 'pause');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async resume(): Promise<{ resumed: boolean }> {
|
|
387
|
+
return this.core.send('audio', 'resume');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async stop(): Promise<{ stopped: boolean }> {
|
|
391
|
+
return this.core.send('audio', 'stop');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async setVolume(volume: number): Promise<{ volume: number }> {
|
|
395
|
+
return this.core.send('audio', 'setVolume', { volume });
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async setRate(rate: number): Promise<{ rate: number }> {
|
|
399
|
+
return this.core.send('audio', 'setRate', { rate });
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async getStatus(): Promise<AudioStatus> {
|
|
403
|
+
return this.core.send<AudioStatus>('audio', 'getStatus');
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ============================================
|
|
408
|
+
// 相机控制器
|
|
409
|
+
// ============================================
|
|
410
|
+
|
|
411
|
+
export class CameraController {
|
|
412
|
+
constructor(private core: BridgeCore) {}
|
|
413
|
+
|
|
414
|
+
async open(options: { facing?: CameraFacing } = {}): Promise<{ isOpen: boolean; facing: CameraFacing }> {
|
|
415
|
+
const { facing = 'back' } = options;
|
|
416
|
+
return this.core.send('camera', 'open', { facing });
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
async close(): Promise<{ isOpen: boolean }> {
|
|
420
|
+
return this.core.send('camera', 'close');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async toggleFacing(): Promise<{ facing: CameraFacing }> {
|
|
424
|
+
return this.core.send('camera', 'toggleFacing');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async takePhoto(): Promise<PhotoResult> {
|
|
428
|
+
return this.core.send<PhotoResult>('camera', 'takePhoto');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async setFilter(filter: CameraFilter): Promise<{ filter: string; customStyles?: Record<string, unknown> }> {
|
|
432
|
+
return this.core.send('camera', 'setFilter', { filter });
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async setFlash(enabled: boolean): Promise<{ flash: boolean }> {
|
|
436
|
+
return this.core.send('camera', 'setFlash', { enabled });
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async toggleFlash(): Promise<{ flash: boolean }> {
|
|
440
|
+
return this.core.send('camera', 'toggleFlash');
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ============================================
|
|
445
|
+
// 麦克风控制器
|
|
446
|
+
// ============================================
|
|
447
|
+
|
|
448
|
+
export class MicrophoneController {
|
|
449
|
+
private isRecording = false;
|
|
450
|
+
|
|
451
|
+
constructor(private core: BridgeCore) {}
|
|
452
|
+
|
|
453
|
+
async requestPermission(): Promise<PermissionResult> {
|
|
454
|
+
return this.core.send<PermissionResult>('microphone', 'requestPermission');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async start(options: { enableMonitoring?: boolean } = {}): Promise<RecordingResult> {
|
|
458
|
+
const { enableMonitoring = true } = options;
|
|
459
|
+
const result = await this.core.send<RecordingResult>('microphone', 'start', {
|
|
460
|
+
enableMonitoring,
|
|
461
|
+
});
|
|
462
|
+
this.isRecording = true;
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
async stop(): Promise<RecordingResult> {
|
|
467
|
+
const result = await this.core.send<RecordingResult>('microphone', 'stop');
|
|
468
|
+
this.isRecording = false;
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async pause(): Promise<{ paused: boolean }> {
|
|
473
|
+
return this.core.send('microphone', 'pause');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async resume(): Promise<{ resumed: boolean }> {
|
|
477
|
+
return this.core.send('microphone', 'resume');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async getStatus(): Promise<{
|
|
481
|
+
isRecording: boolean;
|
|
482
|
+
isDoneRecording?: boolean;
|
|
483
|
+
durationMillis?: number;
|
|
484
|
+
canRecord: boolean;
|
|
485
|
+
}> {
|
|
486
|
+
return this.core.send('microphone', 'getStatus');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* 监听音量数据
|
|
491
|
+
*/
|
|
492
|
+
onVolumeData(callback: (data: VolumeData[]) => void): () => void {
|
|
493
|
+
return this.core.onSensorData('microphone_volume', callback as (data: unknown[]) => void);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
getRecordingState(): boolean {
|
|
497
|
+
return this.isRecording;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// ============================================
|
|
502
|
+
// 配置控制器
|
|
503
|
+
// ============================================
|
|
504
|
+
|
|
505
|
+
export class ConfigController {
|
|
506
|
+
private currentConfig: Record<string, unknown> | null = null;
|
|
507
|
+
|
|
508
|
+
constructor(private core: BridgeCore) {}
|
|
509
|
+
|
|
510
|
+
async updateParams(configData: Record<string, unknown>): Promise<{
|
|
511
|
+
received: boolean;
|
|
512
|
+
configId: number;
|
|
513
|
+
dataKeys: string[];
|
|
514
|
+
message: string;
|
|
515
|
+
}> {
|
|
516
|
+
this.currentConfig = configData;
|
|
517
|
+
return this.core.send('config', 'updateParams', configData);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
getCurrentConfig(): Record<string, unknown> | null {
|
|
521
|
+
return this.currentConfig;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async resetToDefaults(): Promise<{ reset: boolean }> {
|
|
525
|
+
return this.core.send('config', 'resetToDefaults');
|
|
526
|
+
}
|
|
527
|
+
}
|