rvis-aiui-kit 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.
Files changed (44) hide show
  1. package/README.md +22 -0
  2. package/components/image/index.ink +44 -0
  3. package/components/list/index.ink +198 -0
  4. package/components/list/readme.md +71 -0
  5. package/components/markdown/index.ink +109 -0
  6. package/components/markdown/parser.js +149 -0
  7. package/components/markdown/readme.md +50 -0
  8. package/components/model-list/index.ink +181 -0
  9. package/components/model-list/readme.md +111 -0
  10. package/components/paragraph/index.ink +61 -0
  11. package/components/paragraph/readme.md +17 -0
  12. package/components/table/index.ink +272 -0
  13. package/components/table/readme.md +83 -0
  14. package/package.json +35 -0
  15. package/sdk/README.md +1013 -0
  16. package/sdk/api-map.js +25 -0
  17. package/sdk/core/client.js +641 -0
  18. package/sdk/core/constants.js +10 -0
  19. package/sdk/core/transport.js +55 -0
  20. package/sdk/index.js +19 -0
  21. package/sdk/modules/audio/index.js +177 -0
  22. package/sdk/modules/audio/readme.md +136 -0
  23. package/sdk/modules/camera/index.js +380 -0
  24. package/sdk/modules/camera/readme.md +302 -0
  25. package/sdk/modules/device-context/index.js +206 -0
  26. package/sdk/modules/device-context/readme.md +243 -0
  27. package/sdk/modules/face/index.js +108 -0
  28. package/sdk/modules/face/readme.md +196 -0
  29. package/sdk/modules/motion/index.js +116 -0
  30. package/sdk/modules/motion/readme.md +148 -0
  31. package/sdk/modules/notification/index.js +192 -0
  32. package/sdk/modules/notification/readme.md +175 -0
  33. package/sdk/modules/offline-command/index.js +265 -0
  34. package/sdk/modules/offline-command/readme.md +143 -0
  35. package/sdk/modules/screen/index.js +64 -0
  36. package/sdk/modules/screen/readme.md +110 -0
  37. package/sdk/modules/tts/index.js +75 -0
  38. package/sdk/modules/tts/readme.md +162 -0
  39. package/sdk/utils/api-builder.js +16 -0
  40. package/sdk/utils/case.js +19 -0
  41. package/sdk/utils/errors.js +32 -0
  42. package/sdk/utils/events.js +22 -0
  43. package/sdk/utils/message.js +63 -0
  44. package/sdk/utils/request-id.js +18 -0
package/sdk/README.md ADDED
@@ -0,0 +1,1013 @@
1
+ # Glass3 扩展 SDK API 文档
2
+
3
+ 本文档汇总 `sdk/` 目录当前公开的 JavaScript API。公开接口以
4
+ [`api-map.js`](./api-map.js) 为准;各模块的 `readme.md` 提供更完整的 Native
5
+ 协议、事件时序与返回示例。
6
+
7
+ > 适用范围:项目内的 Host RPC 扩展能力。若 `glass3` 已提供对应能力,应优先使用
8
+ > 本 SDK;只有 SDK 未覆盖的能力才使用基础 AIUI 运行时 API。
9
+
10
+ ## 目录
11
+
12
+ - [快速接入](#快速接入)
13
+ - [API 总览](#api-总览)
14
+ - [通用调用约定](#通用调用约定)
15
+ - [Device Context 设备上下文](#device-context-设备上下文)
16
+ - [Screen 屏幕控制](#screen-屏幕控制)
17
+ - [Notification 原生通知](#notification-原生通知)
18
+ - [TTS 语音播报](#tts-语音播报)
19
+ - [Offline Command 离线语音指令](#offline-command-离线语音指令)
20
+ - [Audio 录音与转写](#audio-录音与转写)
21
+ - [Camera 相机](#camera-相机)
22
+ - [Face 人脸识别](#face-人脸识别)
23
+ - [Motion 运动状态检测](#motion-运动状态检测)
24
+ - [错误处理](#错误处理)
25
+ - [页面卸载清理](#页面卸载清理)
26
+ - [Native 映射](#native-映射)
27
+ - [详细文档与 Demo](#详细文档与-demo)
28
+
29
+ ## 快速接入
30
+
31
+ 根据页面所在层级调整导入路径:
32
+
33
+ ```js
34
+ import glass3 from 'rvis-aiui-kit';
35
+
36
+ export default {
37
+ onMessage(messageEvent) {
38
+ // 必须转发。依赖 Host event 的 Promise 和 onEvent 才能正常工作。
39
+ glass3.handleMessage(messageEvent);
40
+ },
41
+
42
+ onUnload() {
43
+ // 先停止仍在运行的长任务,再释放本地监听和未完成调用。
44
+ glass3.dispose();
45
+ }
46
+ };
47
+ ```
48
+
49
+ SDK 还提供命名导出:
50
+
51
+ ```js
52
+ import glass3, {
53
+ glass3 as namedGlass3,
54
+ API_MAP,
55
+ Glass3Error
56
+ } from 'rvis-aiui-kit';
57
+ ```
58
+
59
+ - `glass3`:默认客户端实例及全部公开模块。
60
+ - `API_MAP`:公开 JavaScript API 到 Host RPC 的权威映射。
61
+ - `Glass3Error`:SDK 错误类型。
62
+
63
+ ## API 总览
64
+
65
+ | 模块 | 方法 | 用途 |
66
+ | --- | --- | --- |
67
+ | `deviceContext` | `get(options?)` | 一次性获取设备上下文原子快照。 |
68
+ | `deviceContext` | `observe(options?, callOptions?)` | 订阅设备上下文快照和增量变化。 |
69
+ | `deviceContext` | `stopObserve({ requestId })` | 停止指定的设备上下文订阅。 |
70
+ | `screen` | `turnOff()` | 关闭屏幕并等待 Native 确认。 |
71
+ | `screen` | `turnOn()` | 点亮屏幕并等待 Native 确认。 |
72
+ | `notification` | `show(options)` | 显示 Host 管理的原生通知。 |
73
+ | `notification` | `hide({ requestId })` | 隐藏指定通知。 |
74
+ | `tts` | `speak(options, callOptions?)` | 开始 TTS 播报。 |
75
+ | `tts` | `stop({ requestId })` | 停止指定 TTS。 |
76
+ | `offlineCommand` | `register(options, callOptions?)` | 注册一批离线语音指令。 |
77
+ | `offlineCommand` | `unregister({ requestId })` | 注销指定指令批次。 |
78
+ | `audio` | `startRecord(options?, callOptions?)` | 开始录音,可转写、保存或上传。 |
79
+ | `audio` | `stopRecord({ requestId })` | 停止指定录音并返回结果。 |
80
+ | `camera` | `startPreview(options?)` | 开启相机预览。 |
81
+ | `camera` | `stopPreview({ requestId })` | 关闭指定预览。 |
82
+ | `camera` | `takePhoto(options?)` | 拍照并等待照片结果。 |
83
+ | `camera` | `startTakeVideo(options?, callOptions?)` | 开始分段录像。 |
84
+ | `camera` | `stopTakeVideo({ requestId })` | 停止指定录像。 |
85
+ | `face` | `startRecognize({}, callOptions?)` | 开始持续人脸识别。 |
86
+ | `face` | `stopRecognize({ requestId })` | 停止指定人脸识别。 |
87
+ | `motion` | `startDetect({}, callOptions?)` | 开始持续运动状态检测。 |
88
+ | `motion` | `stopDetect({ requestId })` | 停止指定运动检测。 |
89
+
90
+ 客户端级方法:
91
+
92
+ | 方法 | 返回值 | 说明 |
93
+ | --- | --- | --- |
94
+ | `glass3.handleMessage(messageEvent)` | 匹配结果或 `null` | 将页面收到的 Host 消息交给 SDK。 |
95
+ | `glass3.dispose()` | `undefined` | 清理监听,并以 `CALL_DISPOSED` 结束仍在等待的调用。 |
96
+
97
+ ## 通用调用约定
98
+
99
+ ### Promise 与 `onEvent`
100
+
101
+ - 每个业务方法都返回 Promise。
102
+ - Promise 完成表示该方法定义的“就绪”或“终态”已到达,不一定表示整个长任务结束。
103
+ - `onEvent` 用于接收同一启动请求后续产生的流式事件。
104
+ - Native response 不会进入 `onEvent`;`onEvent` 只接收匹配的 event result。
105
+ - Native 返回的下划线字段通常会递归转换为驼峰字段,具体以各 API 说明为准。
106
+
107
+ ```js
108
+ const task = await glass3.face.startRecognize({}, {
109
+ onEvent(result) {
110
+ console.log('face event:', JSON.stringify(result));
111
+ }
112
+ });
113
+ ```
114
+
115
+ ### `requestId`
116
+
117
+ - 每次调用都有独立的 `requestId`。
118
+ - `start*` 返回的 `requestId` 是后续 `stop*` 的目标 ID,必须保存。
119
+ - `stop*` 自身会创建新的 `requestId`;返回值中的 ID 是 stop 调用的 ID,不是 start ID。
120
+ - 除文档明确允许的字段外,参数均按闭合对象校验,不要添加未记录字段或使用
121
+ `snake_case` 字段。
122
+
123
+ ### Host 消息转发
124
+
125
+ 使用通知、屏幕、拍照,以及任何带事件或等待 Native 终态的 API 时,都必须转发
126
+ `onMessage`:
127
+
128
+ ```js
129
+ onMessage(messageEvent) {
130
+ glass3.handleMessage(messageEvent);
131
+ }
132
+ ```
133
+
134
+ 不转发时,部分请求虽然已被 Native 接收,但 Promise 不会完成,`onEvent` 也不会触发。
135
+
136
+ ## Device Context 设备上下文
137
+
138
+ ### `glass3.deviceContext.get(options?)`
139
+
140
+ 一次性获取所选 domain 的原子快照:
141
+
142
+ ```js
143
+ const result = await glass3.deviceContext.get({
144
+ domains: ['environment', 'power', 'network', 'interaction']
145
+ });
146
+
147
+ console.log(JSON.stringify(result.snapshot));
148
+ ```
149
+
150
+ 可选 domain 为 `identity`、`software`、`account`、`environment`、`power`、
151
+ `network` 和 `interaction`。省略参数或传 `{}` 表示全部;显式传入时必须是非空数组。
152
+
153
+ Promise 等到最终 snapshot 事件后完成:
154
+
155
+ ```js
156
+ {
157
+ requestId: 'get request UUID',
158
+ ok: true,
159
+ eventType: 'snapshot',
160
+ snapshot: {
161
+ schemaVersion: '1.0',
162
+ epoch: 'system-server-process-uuid',
163
+ revision: 12,
164
+ capturedAtElapsedMs: 368219,
165
+ power: { available: true, levelPercent: 76, charging: false },
166
+ network: { effectiveRoute: 'glass_direct', online: true },
167
+ interaction: { screenState: 'on' }
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### `glass3.deviceContext.observe(options?, callOptions?)`
173
+
174
+ ```js
175
+ const observer = await glass3.deviceContext.observe(
176
+ { domains: ['account', 'environment', 'power', 'network'] },
177
+ {
178
+ onEvent(event) {
179
+ if (event.eventType === 'snapshot') {
180
+ initializeContext(event.snapshot);
181
+ } else if (event.eventType === 'changed') {
182
+ applyContextPatch(event);
183
+ } else if (event.eventType === 'invalidated') {
184
+ clearAccountContext();
185
+ reloadScene();
186
+ }
187
+ }
188
+ }
189
+ );
190
+ ```
191
+
192
+ started response 到达后返回:
193
+
194
+ ```js
195
+ { requestId: 'observe request UUID', ok: true, state: 'started' }
196
+ ```
197
+
198
+ 首个业务事件固定为 `snapshot`,之后仅在状态实际变化时产生 `changed`。SDK 不自动
199
+ 合并 patch;调用方应验证事件的 `epoch` 与 `baseRevision` 后再更新当前快照。
200
+
201
+ `invalidated` 表示账号或环境隔离边界已经变化。该事件进入回调后订阅监听会释放;
202
+ 调用方必须清除旧账号上下文并重载 Scene。
203
+
204
+ ### `glass3.deviceContext.stopObserve({ requestId })`
205
+
206
+ ```js
207
+ const result = await glass3.deviceContext.stopObserve({
208
+ requestId: observer.requestId
209
+ });
210
+ // { requestId: 'stop request UUID', ok: true, state: 'stopped' }
211
+ ```
212
+
213
+ 可选字段保持缺省语义。例如 `phone_relay` 路由没有 `online` 时,不能将其解释为
214
+ `false`。枚举值保持 Native 协议原值,不转换 `logged_in`、`glass_direct` 等字符串。
215
+
216
+ 详见 [`modules/device-context/readme.md`](./modules/device-context/readme.md)。
217
+
218
+ ## Screen 屏幕控制
219
+
220
+ ### `glass3.screen.turnOff()`
221
+
222
+ 关闭屏幕,不接收参数。
223
+
224
+ ```js
225
+ const result = await glass3.screen.turnOff();
226
+ ```
227
+
228
+ ### `glass3.screen.turnOn()`
229
+
230
+ 点亮屏幕,不接收参数。
231
+
232
+ ```js
233
+ const result = await glass3.screen.turnOn();
234
+ ```
235
+
236
+ 两个方法的返回结构相同:
237
+
238
+ ```js
239
+ {
240
+ requestId: 'screen request UUID',
241
+ ok: true,
242
+ changed: true,
243
+ screen: 'off' // turnOn 时为 'on'
244
+ }
245
+ ```
246
+
247
+ - `changed: false` 表示调用前已经处于目标状态,仍属于成功。
248
+ - accepted response 仅表示已受理;匹配的成功 `toolResult` 才会完成 Promise。
249
+ - 普通电源键的睡眠/唤醒由 Host 管理时,不要在
250
+ `RokidActionSingleClick` 中调用这些 API,也不要拦截默认行为。
251
+
252
+ ### 系统屏幕状态事件
253
+
254
+ 系统发起的亮屏/息屏通过原始 Host RPC 事件通知页面,不是独立的 `glass3` 订阅 API:
255
+
256
+ ```js
257
+ onMessage(messageEvent) {
258
+ glass3.handleMessage(messageEvent);
259
+
260
+ const message = messageEvent && messageEvent.data;
261
+ if (
262
+ message &&
263
+ message.namespace === 'rokid.device' &&
264
+ message.event === 'screenStateChanged'
265
+ ) {
266
+ const isScreenOn = message.data.state === 'on';
267
+ }
268
+ }
269
+ ```
270
+
271
+ `data.state` 为 `on` 或 `off`。页面可在加载时默认按亮屏处理,此后以该事件作为
272
+ Host 管理的屏幕状态来源。
273
+
274
+ > Native notification 的显示优先级高于息屏状态。若息屏后不应保留通知,应先
275
+ > `notification.hide()`,再 `screen.turnOff()`。
276
+
277
+ 详见 [`modules/screen/readme.md`](./modules/screen/readme.md)。
278
+
279
+ ## Notification 原生通知
280
+
281
+ ### `glass3.notification.show(options)`
282
+
283
+ 显示 Host 管理的原生通知。`title` 与 `text` 至少显式提供一个;允许传空字符串。
284
+
285
+ ```js
286
+ const notification = await glass3.notification.show({
287
+ text: '思考中',
288
+ level: 'active',
289
+ position: 'topCenter',
290
+ durationMs: 8000,
291
+ animation: 'thinking',
292
+ resident: true
293
+ });
294
+ ```
295
+
296
+ | 字段 | 类型 | 必填 | 默认值 | 说明 |
297
+ | --- | --- | --- | --- | --- |
298
+ | `title` | `string` | 条件必填 | 无 | 标题,保留首尾空白。 |
299
+ | `text` | `string` | 条件必填 | 无 | 正文,保留首尾空白。 |
300
+ | `level` | `string` | 否 | `active` | 只允许 `active` 或 `critical`。 |
301
+ | `position` | `string` | 否 | Native 默认值 | 见下方位置枚举。 |
302
+ | `durationMs` | `number` | 否 | Native 默认值 | 大于 0 的整数,单位毫秒。 |
303
+ | `animation` | `string` | 否 | `idle` | 见下方动效枚举。 |
304
+ | `resident` | `boolean` | 否 | Native 默认值 | `true` 时不自动隐藏。 |
305
+
306
+ 位置枚举:
307
+
308
+ ```text
309
+ topLeft, topCenter, topRight,
310
+ bottomLeft, bottomCenter, bottomRight
311
+ ```
312
+
313
+ 动效枚举:
314
+
315
+ ```text
316
+ idle, blink, thinking, calm, nod, bow, salute,
317
+ photo, face, scan, success, listening, speaking, enter, exit
318
+ ```
319
+
320
+ 返回值:
321
+
322
+ ```js
323
+ { requestId: 'notification UUID', ok: true }
324
+ ```
325
+
326
+ ### `glass3.notification.hide({ requestId })`
327
+
328
+ 隐藏 `show()` 创建的通知。
329
+
330
+ ```js
331
+ const result = await glass3.notification.hide({
332
+ requestId: notification.requestId
333
+ });
334
+ // { requestId: 'hide request UUID', ok: true }
335
+ ```
336
+
337
+ 详见 [`modules/notification/readme.md`](./modules/notification/readme.md)。
338
+
339
+ ## TTS 语音播报
340
+
341
+ ### `glass3.tts.speak(options, callOptions?)`
342
+
343
+ ```js
344
+ const playback = await glass3.tts.speak(
345
+ {
346
+ text: '你好,这是一段播报。',
347
+ queueMode: 'flush'
348
+ },
349
+ {
350
+ onEvent(result) {
351
+ // { ok: true, state: 'started' | 'finished' | 'canceled' }
352
+ }
353
+ }
354
+ );
355
+ ```
356
+
357
+ | 字段 | 类型 | 必填 | 说明 |
358
+ | --- | --- | --- | --- |
359
+ | `text` | `string` | 是 | 播报文本;当前 SDK 直接透传,不做本地校验。 |
360
+ | `queueMode` | `string` | 否 | 播放队列策略,例如 `flush`;当前 SDK 直接透传。 |
361
+
362
+ accepted response 到达后 Promise 即完成,不等待播放结束:
363
+
364
+ ```js
365
+ { requestId: 'tts start UUID', ok: true }
366
+ ```
367
+
368
+ `onEvent` 常见状态为 `started`、`finished`、`canceled`。收到 `finished` 或
369
+ `canceled` 后,SDK 会清理该播放的事件监听。
370
+
371
+ ### `glass3.tts.stop({ requestId })`
372
+
373
+ ```js
374
+ const result = await glass3.tts.stop({
375
+ requestId: playback.requestId
376
+ });
377
+ // { requestId: 'tts stop UUID', ok: true, state: 'stopped' }
378
+ ```
379
+
380
+ `stop()` 只等待自己的停止结果;原 `speak()` 仍可能通过其 `onEvent` 收到
381
+ `canceled`。
382
+
383
+ 详见 [`modules/tts/readme.md`](./modules/tts/readme.md)。
384
+
385
+ ## Offline Command 离线语音指令
386
+
387
+ ### `glass3.offlineCommand.register(options, callOptions?)`
388
+
389
+ ```js
390
+ const registration = await glass3.offlineCommand.register(
391
+ {
392
+ language: 'ZH_CN',
393
+ commands: [
394
+ {
395
+ id: 'next_step',
396
+ phrases: [
397
+ { text: '下一步', pinyin: 'xia yi bu' },
398
+ { text: '继续' }
399
+ ]
400
+ }
401
+ ]
402
+ },
403
+ {
404
+ onEvent(result) {
405
+ // 命中:{ ok: true, commandId, phrase, timestamp }
406
+ }
407
+ }
408
+ );
409
+ ```
410
+
411
+ 顶层参数:
412
+
413
+ | 字段 | 类型 | 必填 | 默认值 | 说明 |
414
+ | --- | --- | --- | --- | --- |
415
+ | `language` | `string` | 否 | `ZH_CN` | 非空语言标识,SDK 不限制枚举。 |
416
+ | `commands` | `array` | 是 | 无 | 非空指令数组。 |
417
+
418
+ `commands[]`:
419
+
420
+ | 字段 | 类型 | 必填 | 说明 |
421
+ | --- | --- | --- | --- |
422
+ | `id` | `string` | 是 | 非空业务指令 ID。 |
423
+ | `phrases` | `array` | 是 | 非空触发短语数组。 |
424
+
425
+ `phrases[]`:
426
+
427
+ | 字段 | 类型 | 必填 | 说明 |
428
+ | --- | --- | --- | --- |
429
+ | `text` | `string` | 是 | 非空触发文本。 |
430
+ | `pinyin` | `string` | 否 | 非空拼音;省略时不发送给 Native。 |
431
+
432
+ 注册需要同时观察“请求已受理”和 `started`,两者顺序不固定。返回值:
433
+
434
+ ```js
435
+ {
436
+ requestId: 'offline command start UUID',
437
+ ok: true,
438
+ state: 'started',
439
+ commandCount: 1, // Native 未返回时省略
440
+ phraseCount: 2 // Native 未返回时省略
441
+ }
442
+ ```
443
+
444
+ 同一注册可多次触发 `onEvent`:
445
+
446
+ ```js
447
+ {
448
+ ok: true,
449
+ commandId: 'next_step',
450
+ phrase: '下一步',
451
+ timestamp: 1785403248395
452
+ }
453
+ ```
454
+
455
+ 页面被释放时可能收到终态:
456
+
457
+ ```js
458
+ { ok: true, state: 'canceled', reason: 'owner_release' }
459
+ ```
460
+
461
+ ### `glass3.offlineCommand.unregister({ requestId })`
462
+
463
+ ```js
464
+ const result = await glass3.offlineCommand.unregister({
465
+ requestId: registration.requestId
466
+ });
467
+ // { requestId: 'unregister UUID', ok: true, state: 'stopped' }
468
+ ```
469
+
470
+ 注销成功后 SDK 会释放目标 register 的事件监听。
471
+
472
+ 详见
473
+ [`modules/offline-command/readme.md`](./modules/offline-command/readme.md)。
474
+
475
+ ## Audio 录音与转写
476
+
477
+ ### `glass3.audio.startRecord(options?, callOptions?)`
478
+
479
+ ```js
480
+ const recording = await glass3.audio.startRecord(
481
+ {
482
+ maxMinutes: 10,
483
+ needText: true,
484
+ needMp3: false,
485
+ showCard: true,
486
+ upload: false
487
+ },
488
+ {
489
+ onEvent(result) {
490
+ console.log('audio event:', JSON.stringify(result));
491
+ }
492
+ }
493
+ );
494
+ ```
495
+
496
+ | 字段 | 类型 | 默认值 | 说明 |
497
+ | --- | --- | --- | --- |
498
+ | `maxMinutes` | `number` | `10` | 1~120 的整数。 |
499
+ | `needText` | `boolean` | `true` | 返回整段 ASR 转写 `text`。 |
500
+ | `needMp3` | `boolean` | `false` | 保留并返回音频文件。 |
501
+ | `showCard` | `boolean` | `true` | 显示 Native 录音卡片。 |
502
+ | `upload` | `boolean` | `false` | 上传录音结果;成功时返回 `fileUrl`。 |
503
+
504
+ 只有同一 requestId 的 `response.result.state === 'started'` 才会完成 start Promise;
505
+ started event 本身不会完成 Promise:
506
+
507
+ ```js
508
+ { requestId: 'audio start UUID', ok: true, state: 'started' }
509
+ ```
510
+
511
+ 录音结束结果继续进入 start 的 `onEvent`:
512
+
513
+ ```js
514
+ {
515
+ ok: true,
516
+ finished: true,
517
+ state: 'finished',
518
+ reason: 'max_duration',
519
+ durationMs: 600000,
520
+ text: '整段转写文本',
521
+ filePath: '/path/to/tool_audio.mp3',
522
+ fileUrl: 'https://example.com/tool_audio.mp3',
523
+ sizeBytes: 165164,
524
+ sampleRate: 16000
525
+ }
526
+ ```
527
+
528
+ 用户通过离线指令“结束录音”完成录音时,同样通过原 start 的 `onEvent` 返回正常完成结果:
529
+
530
+ ```js
531
+ {
532
+ ok: true,
533
+ finished: true,
534
+ state: 'finished',
535
+ reason: 'offline_command',
536
+ durationMs: 5140,
537
+ text: '整段转写文本',
538
+ filePath: '/path/to/tool_audio.mp3'
539
+ }
540
+ ```
541
+
542
+ 常见异步失败:
543
+
544
+ ```js
545
+ { ok: false, error: 'mic_busy' }
546
+ { ok: false, error: 'asr_unavailable' }
547
+ ```
548
+
549
+ ### `glass3.audio.stopRecord({ requestId })`
550
+
551
+ ```js
552
+ const result = await glass3.audio.stopRecord({
553
+ requestId: recording.requestId
554
+ });
555
+ ```
556
+
557
+ stop Promise 只等待 stop 自己 requestId 的 `stopped` event,并直接返回录音成果:
558
+
559
+ ```js
560
+ {
561
+ requestId: 'audio stop UUID',
562
+ ok: true,
563
+ state: 'stopped',
564
+ durationMs: 5140,
565
+ text: '整段转写文本',
566
+ filePath: '/path/to/tool_audio.mp3',
567
+ fileUrl: 'https://example.com/tool_audio.mp3',
568
+ sizeBytes: 165164,
569
+ sampleRate: 16000
570
+ }
571
+ ```
572
+
573
+ 详见 [`modules/audio/readme.md`](./modules/audio/readme.md)。
574
+
575
+ ## Camera 相机
576
+
577
+ ### `glass3.camera.startPreview(options?)`
578
+
579
+ 建议不传参数,使用 SDK 默认的顶部预览区域:
580
+
581
+ ```js
582
+ const preview = await glass3.camera.startPreview();
583
+ ```
584
+
585
+ 默认参数:
586
+
587
+ ```js
588
+ {
589
+ left: 0,
590
+ top: 40,
591
+ width: 168,
592
+ height: 103,
593
+ cornerRadius: 2,
594
+ outline: true
595
+ }
596
+ ```
597
+
598
+ 自定义区域:
599
+
600
+ ```js
601
+ const preview = await glass3.camera.startPreview({
602
+ left: 40,
603
+ top: 150,
604
+ width: 240,
605
+ height: 180,
606
+ cornerRadius: 16,
607
+ outline: false
608
+ });
609
+ ```
610
+
611
+ | 字段 | 类型 | 约束 |
612
+ | --- | --- | --- |
613
+ | `left` | `number` | 有限、非负。 |
614
+ | `top` | `number` | 有限、非负。自定义普通预览建议 `top >= 150`。 |
615
+ | `width` | `number` | 有限且大于 0。 |
616
+ | `height` | `number` | 有限且大于 0。 |
617
+ | `cornerRadius` | `number` | 有限、非负。 |
618
+ | `outline` | `boolean` | 是否以线框呈现,默认 `true`。 |
619
+
620
+ 只要提供任意一个区域字段,就必须同时提供 `left`、`top`、`width`、`height`、
621
+ `cornerRadius`。`outline` 可单独设置。
622
+
623
+ Promise 在匹配的 started response 或 event 后完成:
624
+
625
+ ```js
626
+ { requestId: 'preview start UUID', ok: true, state: 'started' }
627
+ ```
628
+
629
+ ### `glass3.camera.stopPreview({ requestId })`
630
+
631
+ ```js
632
+ const result = await glass3.camera.stopPreview({
633
+ requestId: preview.requestId
634
+ });
635
+ // { requestId: 'preview stop UUID', ok: true, state: 'cancel' }
636
+ ```
637
+
638
+ ### `glass3.camera.takePhoto(options?)`
639
+
640
+ ```js
641
+ const photo = await glass3.camera.takePhoto({
642
+ returnBase64: false,
643
+ upload: true,
644
+ timeout: 8000
645
+ });
646
+ ```
647
+
648
+ | 字段 | 类型 | 默认值 | 说明 |
649
+ | --- | --- | --- | --- |
650
+ | `returnBase64` | `boolean` | `true` | 返回 JPEG Base64。 |
651
+ | `upload` | `boolean` | `false` | 上传照片。 |
652
+ | `timeout` | `number` | `5000` | JS 等待超时,正整数毫秒;不发送给 Native。 |
653
+
654
+ accepted response 不会完成 Promise;只有匹配的成功照片 event 才会完成。结果示例:
655
+
656
+ ```js
657
+ {
658
+ requestId: 'photo UUID',
659
+ ok: true,
660
+ photoSize: 41056,
661
+ filePath: '/storage/emulated/0/.../tool_photo_xxx.jpg',
662
+ width: 1080,
663
+ height: 720,
664
+ photoMime: 'image/jpeg',
665
+ photoBase64: '...',
666
+ fileUrl: 'https://...',
667
+ inspectionResultId: 42,
668
+ uploadError: 'no_session'
669
+ }
670
+ ```
671
+
672
+ - `photoMime`、`photoBase64` 仅在 `returnBase64: true` 时出现。
673
+ - `fileUrl`、`inspectionResultId` 仅在上传成功时出现。
674
+ - 上传失败不一定使拍照失败,可能通过 `uploadError` 返回。
675
+ - 超时抛出 `CALL_TIMEOUT`;超时只停止 JS 等待,不保证 Native 拍照已取消。
676
+
677
+ ### `glass3.camera.startTakeVideo(options?, callOptions?)`
678
+
679
+ ```js
680
+ const recording = await glass3.camera.startTakeVideo(
681
+ {
682
+ enableAudio: true,
683
+ segmentMinutes: 20
684
+ },
685
+ {
686
+ onEvent(result) {
687
+ console.log('video event:', JSON.stringify(result));
688
+ }
689
+ }
690
+ );
691
+ ```
692
+
693
+ | 字段 | 类型 | 默认值 | 说明 |
694
+ | --- | --- | --- | --- |
695
+ | `enableAudio` | `boolean` | `true` | 是否录音。 |
696
+ | `segmentMinutes` | `number` | `20` | 正整数,录像分段时长。 |
697
+
698
+ 启动完成返回:
699
+
700
+ ```js
701
+ { requestId: 'video start UUID', ok: true }
702
+ ```
703
+
704
+ 常见事件:
705
+
706
+ ```js
707
+ { ok: true, state: 'started' }
708
+
709
+ {
710
+ ok: true,
711
+ filePath: '/storage/emulated/0/Pictures/example.mp4',
712
+ startTime: 1784543000000,
713
+ endTime: 1784544200000,
714
+ hasMore: true
715
+ }
716
+
717
+ { ok: true, state: 'canceled' }
718
+ { ok: false, errorCode: 500, error: 'recording failed' }
719
+ ```
720
+
721
+ `hasMore: false` 表示最后一段;`canceled` 表示被系统停止。两者都会使 SDK 在
722
+ 事件回调后清理录像流监听。
723
+
724
+ ### `glass3.camera.stopTakeVideo({ requestId })`
725
+
726
+ ```js
727
+ const result = await glass3.camera.stopTakeVideo({
728
+ requestId: recording.requestId
729
+ });
730
+ // { requestId: 'video stop UUID', ok: true, state: 'finished' }
731
+ ```
732
+
733
+ stop 与 start 的监听独立;调用 stop 不会主动清理 start 的监听,start 仍需接收
734
+ 最后一段或终止事件。
735
+
736
+ 详见 [`modules/camera/readme.md`](./modules/camera/readme.md)。
737
+
738
+ ## Face 人脸识别
739
+
740
+ ### `glass3.face.startRecognize({}, callOptions?)`
741
+
742
+ 接口没有业务参数。需要传第二个调用选项时,第一个参数必须是空对象:
743
+
744
+ ```js
745
+ const recognition = await glass3.face.startRecognize({}, {
746
+ onEvent(result) {
747
+ console.log('face event:', JSON.stringify(result));
748
+ }
749
+ });
750
+ ```
751
+
752
+ 也可省略所有参数:
753
+
754
+ ```js
755
+ const recognition = await glass3.face.startRecognize();
756
+ ```
757
+
758
+ started response 或 event 到达后返回:
759
+
760
+ ```js
761
+ { requestId: 'face start UUID', ok: true }
762
+ ```
763
+
764
+ 识别事件示例:
765
+
766
+ ```js
767
+ {
768
+ label: '330…1234|张三|职工',
769
+ labelParts: ['330…1234', '张三', '职工'],
770
+ personId: '330…1234',
771
+ personIdCard: '330…1234',
772
+ personName: '张三',
773
+ personType: '职工',
774
+ similarity: 0.97,
775
+ regScore: 97,
776
+ trackId: 3,
777
+ sdkFrameId: 1024,
778
+ faceModel: {
779
+ frameWidth: 1080,
780
+ frameHeight: 1440,
781
+ frameId: 1024,
782
+ trackId: 3,
783
+ faceScore: 0.99,
784
+ iqaScore: 0.8,
785
+ rect: { left: 100, top: 200, right: 300, bottom: 400 }
786
+ }
787
+ }
788
+ ```
789
+
790
+ ### `glass3.face.stopRecognize({ requestId })`
791
+
792
+ ```js
793
+ const result = await glass3.face.stopRecognize({
794
+ requestId: recognition.requestId
795
+ });
796
+ // { requestId: 'face stop UUID', ok: true, state: 'stopped' }
797
+ ```
798
+
799
+ 原 start request 收到 `state: 'stopped'` 后,其监听会自行清理。
800
+
801
+ 详见 [`modules/face/readme.md`](./modules/face/readme.md)。
802
+
803
+ ## Motion 运动状态检测
804
+
805
+ ### `glass3.motion.startDetect({}, callOptions?)`
806
+
807
+ 接口没有业务参数。需要 `onEvent` 时,第一个参数传空对象:
808
+
809
+ ```js
810
+ const detection = await glass3.motion.startDetect({}, {
811
+ onEvent(result) {
812
+ console.log('motion event:', JSON.stringify(result));
813
+ }
814
+ });
815
+ ```
816
+
817
+ 协议没有单独启动确认事件,fetch 返回 Native 已受理后 Promise 即完成:
818
+
819
+ ```js
820
+ { requestId: 'motion start UUID', ok: true }
821
+ ```
822
+
823
+ Native 仅在状态变化时上报:
824
+
825
+ ```js
826
+ {
827
+ ok: true,
828
+ motionState: 'walk',
829
+ previous: 'still',
830
+ moving: true,
831
+ timestamp: 123456789
832
+ }
833
+ ```
834
+
835
+ 状态枚举:
836
+
837
+ ```text
838
+ still, walk, run, headTurnLeft, headTurnRight
839
+ ```
840
+
841
+ 首个事件的 `previous` 为 `unknown`。SDK 不对事件去重或合并。
842
+
843
+ ### `glass3.motion.stopDetect({ requestId })`
844
+
845
+ ```js
846
+ const result = await glass3.motion.stopDetect({
847
+ requestId: detection.requestId
848
+ });
849
+ // { requestId: 'motion stop UUID', ok: true, state: 'stopped' }
850
+ ```
851
+
852
+ 详见 [`modules/motion/readme.md`](./modules/motion/readme.md)。
853
+
854
+ ## 错误处理
855
+
856
+ 所有 SDK 错误都使用 `Glass3Error`:
857
+
858
+ ```js
859
+ try {
860
+ await glass3.camera.takePhoto({ timeout: 5000 });
861
+ } catch (error) {
862
+ if (error instanceof Glass3Error) {
863
+ console.error(error.code, error.stage, error.requestId);
864
+ }
865
+ }
866
+ ```
867
+
868
+ `Glass3Error` 字段:
869
+
870
+ | 字段 | 说明 |
871
+ | --- | --- |
872
+ | `name` | 固定为 `Glass3Error`。 |
873
+ | `message` | 可读错误信息。 |
874
+ | `code` | 程序判断使用的错误码。 |
875
+ | `stage` | 失败阶段,例如 `params`、`response`、`event`、`timeout`、`dispose`。 |
876
+ | `requestId` | 已生成请求时对应的调用 ID。 |
877
+ | `namespace` / `method` | Host RPC 上下文。 |
878
+ | `details` | Native 响应、事件或补充详情。 |
879
+ | `cause` | 底层原始错误。 |
880
+
881
+ 常见错误码:
882
+
883
+ | 错误码 | 说明 |
884
+ | --- | --- |
885
+ | `INVALID_PARAMS` | 参数缺失、类型错误、枚举无效或出现未支持字段。 |
886
+ | `TRANSPORT_REJECTED` | Host RPC 传输层返回非成功状态。 |
887
+ | `NATIVE_REQUEST_ERROR` | 请求发送或响应阶段异常的统一错误。 |
888
+ | `NATIVE_REQUEST_NOT_ACCEPTED` | Native 响应未通过协议校验或未受理。 |
889
+ | `NATIVE_EVENT_ERROR` | 匹配的 Native event 返回失败。 |
890
+ | `CALL_TIMEOUT` | JS 等待超时;当前用于 `camera.takePhoto()`。 |
891
+ | `CALL_DISPOSED` | 调用尚未完成时执行了 `glass3.dispose()`。 |
892
+ | `GLASS3_ERROR` | 未提供更具体错误码时的默认值。 |
893
+
894
+ Native 也可能直接返回自己的错误码。需要恢复策略时,应按 `error.code` 判断,不要
895
+ 只匹配 `message` 文本。
896
+
897
+ ## 页面卸载清理
898
+
899
+ 页面应保存所有长任务的 start requestId,并在卸载前尽力停止:
900
+
901
+ ```js
902
+ let recognitionRequestId = null;
903
+
904
+ export default {
905
+ onMessage(messageEvent) {
906
+ glass3.handleMessage(messageEvent);
907
+ },
908
+
909
+ async startRecognition() {
910
+ const result = await glass3.face.startRecognize({}, {
911
+ onEvent(eventResult) {
912
+ console.log(JSON.stringify(eventResult));
913
+ }
914
+ });
915
+ recognitionRequestId = result.requestId;
916
+ },
917
+
918
+ onUnload() {
919
+ if (recognitionRequestId) {
920
+ glass3.face.stopRecognize({
921
+ requestId: recognitionRequestId
922
+ }).catch(error => {
923
+ if (error.code !== 'CALL_DISPOSED') {
924
+ console.error(JSON.stringify(error));
925
+ }
926
+ });
927
+ recognitionRequestId = null;
928
+ }
929
+
930
+ glass3.dispose();
931
+ }
932
+ };
933
+ ```
934
+
935
+ 需要主动停止或注销的长任务包括:
936
+
937
+ - `deviceContext.observe()`
938
+ - `tts.speak()`
939
+ - `offlineCommand.register()`
940
+ - `audio.startRecord()`
941
+ - `camera.startPreview()`
942
+ - `camera.startTakeVideo()`
943
+ - `face.startRecognize()`
944
+ - `motion.startDetect()`
945
+
946
+ `dispose()` 只负责 SDK 本地监听和等待中的 Promise,不等价于所有 Native 长任务的
947
+ 业务 stop 操作。
948
+
949
+ ## Native 映射
950
+
951
+ 所有业务调用使用 RPC `version: "2.0.0"`、`namespace: "rokid.tools"`、
952
+ `method: "invoke"`。
953
+
954
+ | JavaScript API | `toolName` | `toolAction` |
955
+ | --- | --- | --- |
956
+ | `deviceContext.get` | `getDeviceContext` | `start` |
957
+ | `deviceContext.observe` | `observeDeviceContext` | `start` |
958
+ | `deviceContext.stopObserve` | `observeDeviceContext` | `stop` |
959
+ | `notification.show` | `showNotification` | `start` |
960
+ | `notification.hide` | `showNotification` | `stop` |
961
+ | `screen.turnOff` | `screenOff` | `start` |
962
+ | `screen.turnOn` | `screenOff` | `start` |
963
+ | `tts.speak` | `tts` | `start` |
964
+ | `tts.stop` | `tts` | `stop` |
965
+ | `offlineCommand.register` | `offlineCommand` | `start` |
966
+ | `offlineCommand.unregister` | `offlineCommand` | `stop` |
967
+ | `audio.startRecord` | `audioRecord` | `start` |
968
+ | `audio.stopRecord` | `audioRecord` | `stop` |
969
+ | `camera.startPreview` | `cameraPreview` | `start` |
970
+ | `camera.stopPreview` | `cameraPreview` | `stop` |
971
+ | `camera.takePhoto` | `takePhoto` | `start` |
972
+ | `camera.startTakeVideo` | `lawEnforcementRecord` | `start` |
973
+ | `camera.stopTakeVideo` | `lawEnforcementRecord` | `stop` |
974
+ | `face.startRecognize` | `faceRecognize` | `start` |
975
+ | `face.stopRecognize` | `faceRecognize` | `stop` |
976
+ | `motion.startDetect` | `motionDetect` | `start` |
977
+ | `motion.stopDetect` | `motionDetect` | `stop` |
978
+
979
+ 业务代码应调用公开 JavaScript API,不要直接依赖这张 Native 映射表发 RPC。
980
+
981
+ ## 详细文档与 Demo
982
+
983
+ ### 模块文档
984
+
985
+ - [Device Context](./modules/device-context/readme.md)
986
+ - [Screen](./modules/screen/readme.md)
987
+ - [Notification](./modules/notification/readme.md)
988
+ - [TTS](./modules/tts/readme.md)
989
+ - [Offline Command](./modules/offline-command/readme.md)
990
+ - [Audio](./modules/audio/readme.md)
991
+ - [Camera](./modules/camera/readme.md)
992
+ - [Face](./modules/face/readme.md)
993
+ - [Motion](./modules/motion/readme.md)
994
+
995
+ ### 示例页面
996
+
997
+ - [Device Context Demo](../pages/sdk-demo/device-context/index.ink)
998
+ - [Screen Demo](../pages/sdk-demo/screen/index.ink)
999
+ - [Notification Demo Suite](../pages/sdk-demo/notification/index.ink)
1000
+ - [文案与默认值](../pages/sdk-demo/notification/content/index.ink)
1001
+ - [通知级别](../pages/sdk-demo/notification/levels/index.ink)
1002
+ - [显示位置](../pages/sdk-demo/notification/positions/index.ink)
1003
+ - [显示时长](../pages/sdk-demo/notification/duration/index.ink)
1004
+ - [通知动效](../pages/sdk-demo/notification/animation/index.ink)
1005
+ - [常驻与隐藏](../pages/sdk-demo/notification/resident/index.ink)
1006
+ - [TTS Demo](../pages/sdk-demo/tts/index.ink)
1007
+ - [Offline Command Demo](../pages/sdk-demo/offline-command/index.ink)
1008
+ - [Audio Record Demo](../pages/sdk-demo/audio-record/index.ink)
1009
+ - [Camera Preview Demo](../pages/sdk-demo/camera/index.ink)
1010
+ - [Camera Photo Demo](../pages/sdk-demo/camera-photo/index.ink)
1011
+ - [Camera Video Demo](../pages/sdk-demo/camera-video/index.ink)
1012
+ - [Face Recognize Demo](../pages/sdk-demo/face-recognize/index.ink)
1013
+ - [Motion Detect Demo](../pages/sdk-demo/motion-detect/index.ink)