@vivix-ai/ivi-frontend-sdk 0.3.1 → 0.3.3
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 +24 -0
- package/dist/index.cjs +94 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -3
- package/dist/index.d.ts +48 -3
- package/dist/index.js +94 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -155,12 +155,35 @@ const unlistenEvent = runtime.onEvent((event, state) => {
|
|
|
155
155
|
console.log("event:", event.type, "runtime:", state.status);
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
+
const unlistenTrtcEvent = runtime.onTrtcEvent((event) => {
|
|
159
|
+
console.log("trtc event:", event.sourceId, event.type, event.payload);
|
|
160
|
+
});
|
|
161
|
+
|
|
158
162
|
// 业务结束时
|
|
159
163
|
unlistenState();
|
|
160
164
|
unlistenEvent();
|
|
165
|
+
unlistenTrtcEvent();
|
|
161
166
|
runtime.stop();
|
|
162
167
|
```
|
|
163
168
|
|
|
169
|
+
也可以在创建 runtime 时通过 `onTrtcEvent` 配置项统一接收 TRTC SDK 原始事件:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const runtime = new IviRuntimeCoordinator(client, {
|
|
173
|
+
trtcAIDenoiser: {
|
|
174
|
+
enabled: true,
|
|
175
|
+
mode: "normal" // 也可使用 "far_field_reduction"
|
|
176
|
+
},
|
|
177
|
+
onTrtcEvent: (event) => {
|
|
178
|
+
// event.type: "remote_video_available" | "remote_video_unavailable" | "remote_audio_available" | "remote_audio_unavailable"
|
|
179
|
+
// event.rawType: TRTC SDK 原始事件名
|
|
180
|
+
// event.payload: TRTC SDK 原始事件 payload
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`trtcAIDenoiser` 默认开启,传 `false` 可关闭;也可以传 `{ enabled, mode, assetsPath }` 调整 TRTC SDK 的 AIDenoiser 插件参数。
|
|
186
|
+
|
|
164
187
|
### 3)发送用户文本并触发模型回复
|
|
165
188
|
|
|
166
189
|
```ts
|
|
@@ -472,6 +495,7 @@ TRTC 远端流播放器,自动以 audience 身份入会并订阅远端流。
|
|
|
472
495
|
| `loadingFallback` | `ReactNode` | 加载中兜底 |
|
|
473
496
|
| `errorFallback` | `ReactNode` | 错误兜底 |
|
|
474
497
|
| `muted` | `boolean` | 是否静音 |
|
|
498
|
+
| `trtcAIDenoiser` | `boolean \| IviRuntimeTrtcAIDenoiserOptions` | 独立使用 `IVITrtcPlayer` 时的 TRTC AIDenoiser 配置,默认开启 |
|
|
475
499
|
| `className` / `style` | — | 容器样式 |
|
|
476
500
|
|
|
477
501
|
### `IVILivekitPlayer`
|
package/dist/index.cjs
CHANGED
|
@@ -1107,9 +1107,15 @@ var ConversationManager = class {
|
|
|
1107
1107
|
|
|
1108
1108
|
// src/runtime/managers/trtc-source-manager.ts
|
|
1109
1109
|
var TAG = "[IVI-TRTC]";
|
|
1110
|
+
var DEFAULT_DENOISER_OPTIONS = {
|
|
1111
|
+
enabled: true,
|
|
1112
|
+
mode: "normal"
|
|
1113
|
+
};
|
|
1110
1114
|
var TrtcSourceManager = class {
|
|
1111
|
-
constructor(onLog) {
|
|
1115
|
+
constructor(onLog, onTrtcEvent, aiDenoiser) {
|
|
1112
1116
|
this.onLog = onLog;
|
|
1117
|
+
this.onTrtcEvent = onTrtcEvent;
|
|
1118
|
+
this.aiDenoiser = aiDenoiser;
|
|
1113
1119
|
this.sessions = /* @__PURE__ */ new Map();
|
|
1114
1120
|
this.listeners = /* @__PURE__ */ new Map();
|
|
1115
1121
|
}
|
|
@@ -1136,21 +1142,21 @@ var TrtcSourceManager = class {
|
|
|
1136
1142
|
* 按 sourceId 注册/更新 TRTC 配置。
|
|
1137
1143
|
* 若配置发生变化,会先销毁旧会话再按新参数重建连接。
|
|
1138
1144
|
*/
|
|
1139
|
-
upsertSource(sourceId, trtc) {
|
|
1145
|
+
upsertSource(sourceId, trtc, aiDenoiser) {
|
|
1140
1146
|
const existing = this.sessions.get(sourceId);
|
|
1141
1147
|
if (!existing) {
|
|
1142
1148
|
this.log("info", `\u65B0\u5EFA\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")} user=${getTrtcString(trtc, "user_id")}`);
|
|
1143
|
-
const session2 = this.createSession(sourceId, trtc);
|
|
1149
|
+
const session2 = this.createSession(sourceId, trtc, aiDenoiser);
|
|
1144
1150
|
this.sessions.set(sourceId, session2);
|
|
1145
1151
|
void this.ensureConnected(session2);
|
|
1146
1152
|
return;
|
|
1147
1153
|
}
|
|
1148
|
-
if (isSameTrtcConfig(existing.trtc, trtc)) {
|
|
1154
|
+
if (isSameTrtcConfig(existing.trtc, trtc) && isSameAIDenoiserOptions(existing.aiDenoiser, aiDenoiser)) {
|
|
1149
1155
|
return;
|
|
1150
1156
|
}
|
|
1151
1157
|
this.log("info", `\u914D\u7F6E\u53D8\u66F4\uFF0C\u91CD\u5EFA\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")}`);
|
|
1152
1158
|
void this.disposeSession(existing);
|
|
1153
|
-
const session = this.createSession(sourceId, trtc);
|
|
1159
|
+
const session = this.createSession(sourceId, trtc, aiDenoiser);
|
|
1154
1160
|
this.sessions.set(sourceId, session);
|
|
1155
1161
|
void this.ensureConnected(session);
|
|
1156
1162
|
}
|
|
@@ -1287,10 +1293,11 @@ var TrtcSourceManager = class {
|
|
|
1287
1293
|
binding.muted = muted;
|
|
1288
1294
|
void this.applyAudioPolicy(session);
|
|
1289
1295
|
}
|
|
1290
|
-
createSession(sourceId, trtc) {
|
|
1296
|
+
createSession(sourceId, trtc, aiDenoiser) {
|
|
1291
1297
|
return {
|
|
1292
1298
|
sourceId,
|
|
1293
1299
|
trtc,
|
|
1300
|
+
aiDenoiser,
|
|
1294
1301
|
TRTC: null,
|
|
1295
1302
|
client: null,
|
|
1296
1303
|
connectPromise: null,
|
|
@@ -1345,6 +1352,7 @@ var TrtcSourceManager = class {
|
|
|
1345
1352
|
session.views.forEach((binding) => {
|
|
1346
1353
|
void this.startRemoteVideoForBinding(client, event.userId, event.streamType, binding, remoteVideoKey);
|
|
1347
1354
|
});
|
|
1355
|
+
this.emitTrtcEvent(session.sourceId, "remote_video_available", TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, event);
|
|
1348
1356
|
};
|
|
1349
1357
|
const onRemoteVideoUnavailable = (event) => {
|
|
1350
1358
|
this.log("info", `\u8FDC\u7AEF\u89C6\u9891\u4E0D\u53EF\u7528 source=${session.sourceId} userId=${event.userId} streamType=${event.streamType}`);
|
|
@@ -1358,16 +1366,19 @@ var TrtcSourceManager = class {
|
|
|
1358
1366
|
userId: event.userId,
|
|
1359
1367
|
streamType: event.streamType
|
|
1360
1368
|
}).catch(() => void 0);
|
|
1369
|
+
this.emitTrtcEvent(session.sourceId, "remote_video_unavailable", TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, event);
|
|
1361
1370
|
};
|
|
1362
1371
|
const onRemoteAudioAvailable = (event) => {
|
|
1363
1372
|
this.log("info", `\u8FDC\u7AEF\u97F3\u9891\u53EF\u7528 source=${session.sourceId} userId=${event.userId}`);
|
|
1364
1373
|
session.remoteAudioUsers.add(event.userId);
|
|
1365
1374
|
void this.applyAudioPolicy(session);
|
|
1375
|
+
this.emitTrtcEvent(session.sourceId, "remote_audio_available", TRTC.EVENT.REMOTE_AUDIO_AVAILABLE, event);
|
|
1366
1376
|
};
|
|
1367
1377
|
const onRemoteAudioUnavailable = (event) => {
|
|
1368
1378
|
this.log("info", `\u8FDC\u7AEF\u97F3\u9891\u4E0D\u53EF\u7528 source=${session.sourceId} userId=${event.userId}`);
|
|
1369
1379
|
session.remoteAudioUsers.delete(event.userId);
|
|
1370
1380
|
void this.applyAudioPolicy(session);
|
|
1381
|
+
this.emitTrtcEvent(session.sourceId, "remote_audio_unavailable", TRTC.EVENT.REMOTE_AUDIO_UNAVAILABLE, event);
|
|
1371
1382
|
};
|
|
1372
1383
|
session.onRemoteVideoAvailable = onRemoteVideoAvailable;
|
|
1373
1384
|
session.onRemoteVideoUnavailable = onRemoteVideoUnavailable;
|
|
@@ -1392,6 +1403,7 @@ var TrtcSourceManager = class {
|
|
|
1392
1403
|
session.status = "connected";
|
|
1393
1404
|
session.error = void 0;
|
|
1394
1405
|
this.log("info", `\u8FDB\u623F\u6210\u529F source=${session.sourceId} room=${roomId}`);
|
|
1406
|
+
await this.applyAIDenoiserPolicy(session, client, sdkAppId, userId, userSig);
|
|
1395
1407
|
this.emitSnapshot(session.sourceId, {
|
|
1396
1408
|
status: session.status
|
|
1397
1409
|
});
|
|
@@ -1477,6 +1489,25 @@ var TrtcSourceManager = class {
|
|
|
1477
1489
|
await client.muteRemoteAudio(userId, false);
|
|
1478
1490
|
}
|
|
1479
1491
|
}
|
|
1492
|
+
async applyAIDenoiserPolicy(session, client, sdkAppId, userId, userSig) {
|
|
1493
|
+
const options = resolveAIDenoiserOptions(session.aiDenoiser ?? this.aiDenoiser);
|
|
1494
|
+
if (!options.enabled) {
|
|
1495
|
+
this.log("info", `TRTC AIDenoiser \u5DF2\u5173\u95ED source=${session.sourceId}`);
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
try {
|
|
1499
|
+
await client.startPlugin("AIDenoiser", {
|
|
1500
|
+
sdkAppId,
|
|
1501
|
+
userId,
|
|
1502
|
+
userSig,
|
|
1503
|
+
mode: getAIDenoiserModeValue(options.mode),
|
|
1504
|
+
...options.assetsPath ? { assetsPath: options.assetsPath } : {}
|
|
1505
|
+
});
|
|
1506
|
+
this.log("info", `TRTC AIDenoiser \u5DF2\u5F00\u542F source=${session.sourceId} mode=${options.mode}`);
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
this.log("warn", `TRTC AIDenoiser \u5F00\u542F\u5931\u8D25 source=${session.sourceId}`, error);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1480
1511
|
/**
|
|
1481
1512
|
* 销毁单个 source 会话:
|
|
1482
1513
|
* 解绑事件、停止远端视频、退出房间并销毁客户端。
|
|
@@ -1540,6 +1571,17 @@ var TrtcSourceManager = class {
|
|
|
1540
1571
|
data: extra.length > 0 ? { message, extra } : { message }
|
|
1541
1572
|
});
|
|
1542
1573
|
}
|
|
1574
|
+
emitTrtcEvent(sourceId, type, rawType, payload) {
|
|
1575
|
+
const event = {
|
|
1576
|
+
sourceId,
|
|
1577
|
+
type,
|
|
1578
|
+
rawType: String(rawType),
|
|
1579
|
+
payload,
|
|
1580
|
+
userId: payload.userId,
|
|
1581
|
+
streamType: payload.streamType
|
|
1582
|
+
};
|
|
1583
|
+
this.onTrtcEvent?.(event);
|
|
1584
|
+
}
|
|
1543
1585
|
};
|
|
1544
1586
|
function isRuntimeTrtcSource(source) {
|
|
1545
1587
|
return source.status === "ready" && source.playback?.type === "trtc" && typeof source.playback.trtc === "object" && source.playback.trtc !== null;
|
|
@@ -1547,6 +1589,11 @@ function isRuntimeTrtcSource(source) {
|
|
|
1547
1589
|
function isSameTrtcConfig(a, b) {
|
|
1548
1590
|
return a.app_id === b.app_id && a.user_id === b.user_id && a.user_sig === b.user_sig && a.room_id === b.room_id;
|
|
1549
1591
|
}
|
|
1592
|
+
function isSameAIDenoiserOptions(a, b) {
|
|
1593
|
+
const left = resolveAIDenoiserOptions(a);
|
|
1594
|
+
const right = resolveAIDenoiserOptions(b);
|
|
1595
|
+
return left.enabled === right.enabled && left.mode === right.mode && left.assetsPath === right.assetsPath;
|
|
1596
|
+
}
|
|
1550
1597
|
function shouldUseStringRoomId(roomId) {
|
|
1551
1598
|
if (!/^\d+$/.test(roomId)) {
|
|
1552
1599
|
return true;
|
|
@@ -1558,6 +1605,26 @@ function getTrtcString(trtc, key) {
|
|
|
1558
1605
|
const value = trtc[key];
|
|
1559
1606
|
return typeof value === "string" ? value : "";
|
|
1560
1607
|
}
|
|
1608
|
+
function resolveAIDenoiserOptions(options) {
|
|
1609
|
+
if (options === false) {
|
|
1610
|
+
return {
|
|
1611
|
+
...DEFAULT_DENOISER_OPTIONS,
|
|
1612
|
+
enabled: false
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
if (options === true || options === void 0) {
|
|
1616
|
+
return DEFAULT_DENOISER_OPTIONS;
|
|
1617
|
+
}
|
|
1618
|
+
return {
|
|
1619
|
+
...DEFAULT_DENOISER_OPTIONS,
|
|
1620
|
+
...options,
|
|
1621
|
+
enabled: options.enabled ?? DEFAULT_DENOISER_OPTIONS.enabled,
|
|
1622
|
+
mode: options.mode ?? DEFAULT_DENOISER_OPTIONS.mode
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
function getAIDenoiserModeValue(mode) {
|
|
1626
|
+
return mode === "far_field_reduction" ? 1 : 0;
|
|
1627
|
+
}
|
|
1561
1628
|
function buildRemoteVideoKey(userId, streamType) {
|
|
1562
1629
|
return `${userId}::${streamType}`;
|
|
1563
1630
|
}
|
|
@@ -2038,6 +2105,7 @@ var IviRuntimeCoordinator = class {
|
|
|
2038
2105
|
this.conversationManager = new ConversationManager();
|
|
2039
2106
|
this.stateListeners = /* @__PURE__ */ new Set();
|
|
2040
2107
|
this.eventListeners = /* @__PURE__ */ new Set();
|
|
2108
|
+
this.trtcEventListeners = /* @__PURE__ */ new Set();
|
|
2041
2109
|
this.pendingUserTextToResponseFlows = /* @__PURE__ */ new Map();
|
|
2042
2110
|
this.userTextFlowCounter = 0;
|
|
2043
2111
|
this.waitingTracksListValidation = false;
|
|
@@ -2057,7 +2125,11 @@ var IviRuntimeCoordinator = class {
|
|
|
2057
2125
|
syncStageOnSessionCreated: true,
|
|
2058
2126
|
...config
|
|
2059
2127
|
};
|
|
2060
|
-
this.trtcSourceManager = new TrtcSourceManager(
|
|
2128
|
+
this.trtcSourceManager = new TrtcSourceManager(
|
|
2129
|
+
this.config.onLog,
|
|
2130
|
+
(event) => this.emitTrtcEvent(event),
|
|
2131
|
+
this.config.trtcAIDenoiser
|
|
2132
|
+
);
|
|
2061
2133
|
this.livekitSourceManager = new LivekitSourceManager(this.config.onLog);
|
|
2062
2134
|
this.sessionHandler = new SessionEventHandler(this.sessionManager, {
|
|
2063
2135
|
onSessionCreated: (event) => this.onSessionCreated(event),
|
|
@@ -2130,6 +2202,12 @@ var IviRuntimeCoordinator = class {
|
|
|
2130
2202
|
this.eventListeners.delete(listener);
|
|
2131
2203
|
};
|
|
2132
2204
|
}
|
|
2205
|
+
onTrtcEvent(listener) {
|
|
2206
|
+
this.trtcEventListeners.add(listener);
|
|
2207
|
+
return () => {
|
|
2208
|
+
this.trtcEventListeners.delete(listener);
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2133
2211
|
emitLog(entry) {
|
|
2134
2212
|
this.config.onLog?.(entry);
|
|
2135
2213
|
}
|
|
@@ -2384,6 +2462,10 @@ var IviRuntimeCoordinator = class {
|
|
|
2384
2462
|
this.progressUserTextToResponseFlows(event);
|
|
2385
2463
|
this.eventListeners.forEach((listener) => listener(event, this.state));
|
|
2386
2464
|
}
|
|
2465
|
+
emitTrtcEvent(event) {
|
|
2466
|
+
this.config.onTrtcEvent?.(event);
|
|
2467
|
+
this.trtcEventListeners.forEach((listener) => listener(event));
|
|
2468
|
+
}
|
|
2387
2469
|
resetStoppedState() {
|
|
2388
2470
|
this.rejectPendingUserTextToResponseFlows(
|
|
2389
2471
|
new Error("Runtime stopped before user text to response flow completed.")
|
|
@@ -3126,7 +3208,8 @@ function IVITrtcPlayer(props) {
|
|
|
3126
3208
|
style,
|
|
3127
3209
|
loadingFallback = null,
|
|
3128
3210
|
errorFallback = null,
|
|
3129
|
-
muted = false
|
|
3211
|
+
muted = false,
|
|
3212
|
+
trtcAIDenoiser
|
|
3130
3213
|
} = props;
|
|
3131
3214
|
const containerRef = react.useRef(null);
|
|
3132
3215
|
const viewIdRef = react.useRef(`trtc-view-${Math.random().toString(36).slice(2, 10)}`);
|
|
@@ -3147,7 +3230,7 @@ function IVITrtcPlayer(props) {
|
|
|
3147
3230
|
}
|
|
3148
3231
|
let disposed = false;
|
|
3149
3232
|
if (shouldManageSourceLifecycle) {
|
|
3150
|
-
manager.upsertSource(resolvedSourceId, trtc);
|
|
3233
|
+
manager.upsertSource(resolvedSourceId, trtc, trtcAIDenoiser);
|
|
3151
3234
|
}
|
|
3152
3235
|
const unsubscribe = manager.subscribe(resolvedSourceId, (snapshot) => {
|
|
3153
3236
|
if (disposed) {
|
|
@@ -3178,7 +3261,8 @@ function IVITrtcPlayer(props) {
|
|
|
3178
3261
|
trtc.app_id,
|
|
3179
3262
|
trtc.room_id,
|
|
3180
3263
|
trtc.user_id,
|
|
3181
|
-
trtc.user_sig
|
|
3264
|
+
trtc.user_sig,
|
|
3265
|
+
trtcAIDenoiser
|
|
3182
3266
|
]);
|
|
3183
3267
|
react.useEffect(() => {
|
|
3184
3268
|
manager.updateViewMuted(resolvedSourceId, viewIdRef.current, muted);
|