@vivix-ai/ivi-frontend-sdk 0.3.3 → 0.3.4
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/dist/index.cjs +91 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +91 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -198,6 +198,7 @@ declare class TrtcSourceManager {
|
|
|
198
198
|
private readonly onTrtcEvent?;
|
|
199
199
|
private readonly aiDenoiser?;
|
|
200
200
|
private readonly sessions;
|
|
201
|
+
private readonly sourceSessionKeys;
|
|
201
202
|
private readonly listeners;
|
|
202
203
|
constructor(onLog?: IviRuntimeLogCallback | undefined, onTrtcEvent?: IviRuntimeTrtcEventListener | undefined, aiDenoiser?: (boolean | IviRuntimeTrtcAIDenoiserOptions) | undefined);
|
|
203
204
|
/**
|
|
@@ -238,6 +239,11 @@ declare class TrtcSourceManager {
|
|
|
238
239
|
attachView(sourceId: string, viewId: string, container: HTMLElement, muted: boolean): Promise<void>;
|
|
239
240
|
detachView(sourceId: string, viewId: string): void;
|
|
240
241
|
updateViewMuted(sourceId: string, viewId: string, muted: boolean): void;
|
|
242
|
+
private unlinkSourceFromSession;
|
|
243
|
+
private getSession;
|
|
244
|
+
private snapshotFromSession;
|
|
245
|
+
private emitSessionSnapshot;
|
|
246
|
+
private emitSessionTrtcEvent;
|
|
241
247
|
private createSession;
|
|
242
248
|
/**
|
|
243
249
|
* 懒连接入口:同一会话只允许一次并发 connectPromise。
|
package/dist/index.d.ts
CHANGED
|
@@ -198,6 +198,7 @@ declare class TrtcSourceManager {
|
|
|
198
198
|
private readonly onTrtcEvent?;
|
|
199
199
|
private readonly aiDenoiser?;
|
|
200
200
|
private readonly sessions;
|
|
201
|
+
private readonly sourceSessionKeys;
|
|
201
202
|
private readonly listeners;
|
|
202
203
|
constructor(onLog?: IviRuntimeLogCallback | undefined, onTrtcEvent?: IviRuntimeTrtcEventListener | undefined, aiDenoiser?: (boolean | IviRuntimeTrtcAIDenoiserOptions) | undefined);
|
|
203
204
|
/**
|
|
@@ -238,6 +239,11 @@ declare class TrtcSourceManager {
|
|
|
238
239
|
attachView(sourceId: string, viewId: string, container: HTMLElement, muted: boolean): Promise<void>;
|
|
239
240
|
detachView(sourceId: string, viewId: string): void;
|
|
240
241
|
updateViewMuted(sourceId: string, viewId: string, muted: boolean): void;
|
|
242
|
+
private unlinkSourceFromSession;
|
|
243
|
+
private getSession;
|
|
244
|
+
private snapshotFromSession;
|
|
245
|
+
private emitSessionSnapshot;
|
|
246
|
+
private emitSessionTrtcEvent;
|
|
241
247
|
private createSession;
|
|
242
248
|
/**
|
|
243
249
|
* 懒连接入口:同一会话只允许一次并发 connectPromise。
|
package/dist/index.js
CHANGED
|
@@ -1115,6 +1115,7 @@ var TrtcSourceManager = class {
|
|
|
1115
1115
|
this.onTrtcEvent = onTrtcEvent;
|
|
1116
1116
|
this.aiDenoiser = aiDenoiser;
|
|
1117
1117
|
this.sessions = /* @__PURE__ */ new Map();
|
|
1118
|
+
this.sourceSessionKeys = /* @__PURE__ */ new Map();
|
|
1118
1119
|
this.listeners = /* @__PURE__ */ new Map();
|
|
1119
1120
|
}
|
|
1120
1121
|
/**
|
|
@@ -1123,15 +1124,16 @@ var TrtcSourceManager = class {
|
|
|
1123
1124
|
* - 清理已不在 runtime 中的会话(释放资源)
|
|
1124
1125
|
*/
|
|
1125
1126
|
syncRuntimeSources(sources) {
|
|
1126
|
-
const
|
|
1127
|
+
const trtcSourceIds = /* @__PURE__ */ new Set();
|
|
1127
1128
|
sources.forEach((source, sourceId) => {
|
|
1128
1129
|
if (!isRuntimeTrtcSource(source)) {
|
|
1129
1130
|
return;
|
|
1130
1131
|
}
|
|
1132
|
+
trtcSourceIds.add(sourceId);
|
|
1131
1133
|
this.upsertSource(sourceId, source.playback.trtc);
|
|
1132
1134
|
});
|
|
1133
|
-
this.
|
|
1134
|
-
if (!
|
|
1135
|
+
Array.from(this.sourceSessionKeys.keys()).forEach((sourceId) => {
|
|
1136
|
+
if (!trtcSourceIds.has(sourceId)) {
|
|
1135
1137
|
this.removeSource(sourceId);
|
|
1136
1138
|
}
|
|
1137
1139
|
});
|
|
@@ -1141,21 +1143,28 @@ var TrtcSourceManager = class {
|
|
|
1141
1143
|
* 若配置发生变化,会先销毁旧会话再按新参数重建连接。
|
|
1142
1144
|
*/
|
|
1143
1145
|
upsertSource(sourceId, trtc, aiDenoiser) {
|
|
1144
|
-
const existing = this.
|
|
1145
|
-
if (
|
|
1146
|
-
this.log("info", `\u65B0\u5EFA\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")} user=${getTrtcString(trtc, "user_id")}`);
|
|
1147
|
-
const session2 = this.createSession(sourceId, trtc, aiDenoiser);
|
|
1148
|
-
this.sessions.set(sourceId, session2);
|
|
1149
|
-
void this.ensureConnected(session2);
|
|
1146
|
+
const existing = this.getSession(sourceId);
|
|
1147
|
+
if (existing && isSameTrtcConfig(existing.trtc, trtc) && isSameAIDenoiserOptions(existing.aiDenoiser, aiDenoiser)) {
|
|
1150
1148
|
return;
|
|
1151
1149
|
}
|
|
1152
|
-
if (
|
|
1150
|
+
if (existing) {
|
|
1151
|
+
this.log("info", `\u914D\u7F6E\u53D8\u66F4\uFF0C\u91CD\u5EFA\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")}`);
|
|
1152
|
+
this.unlinkSourceFromSession(sourceId, existing);
|
|
1153
|
+
}
|
|
1154
|
+
const sessionKey = buildTrtcSessionKey(trtc, aiDenoiser);
|
|
1155
|
+
const reusable = this.sessions.get(sessionKey);
|
|
1156
|
+
if (reusable) {
|
|
1157
|
+
this.log("info", `\u590D\u7528\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")} user=${getTrtcString(trtc, "user_id")}`);
|
|
1158
|
+
reusable.sourceIds.add(sourceId);
|
|
1159
|
+
this.sourceSessionKeys.set(sourceId, sessionKey);
|
|
1160
|
+
this.emitSnapshot(sourceId, this.snapshotFromSession(reusable));
|
|
1161
|
+
void this.ensureConnected(reusable);
|
|
1153
1162
|
return;
|
|
1154
1163
|
}
|
|
1155
|
-
this.log("info", `\
|
|
1156
|
-
void this.disposeSession(existing);
|
|
1164
|
+
this.log("info", `\u65B0\u5EFA\u4F1A\u8BDD source=${sourceId} room=${getTrtcString(trtc, "room_id")} user=${getTrtcString(trtc, "user_id")}`);
|
|
1157
1165
|
const session = this.createSession(sourceId, trtc, aiDenoiser);
|
|
1158
|
-
this.sessions.set(
|
|
1166
|
+
this.sessions.set(session.sessionKey, session);
|
|
1167
|
+
this.sourceSessionKeys.set(sourceId, session.sessionKey);
|
|
1159
1168
|
void this.ensureConnected(session);
|
|
1160
1169
|
}
|
|
1161
1170
|
/**
|
|
@@ -1163,13 +1172,12 @@ var TrtcSourceManager = class {
|
|
|
1163
1172
|
* 该操作通常由 source.deleted 或会话重置触发。
|
|
1164
1173
|
*/
|
|
1165
1174
|
removeSource(sourceId) {
|
|
1166
|
-
const session = this.
|
|
1175
|
+
const session = this.getSession(sourceId);
|
|
1167
1176
|
if (!session) {
|
|
1168
1177
|
return;
|
|
1169
1178
|
}
|
|
1170
1179
|
this.log("info", `\u79FB\u9664\u4F1A\u8BDD source=${sourceId}`);
|
|
1171
|
-
this.
|
|
1172
|
-
void this.disposeSession(session);
|
|
1180
|
+
this.unlinkSourceFromSession(sourceId, session);
|
|
1173
1181
|
this.emitSnapshot(sourceId, {
|
|
1174
1182
|
status: "idle"
|
|
1175
1183
|
});
|
|
@@ -1179,6 +1187,7 @@ var TrtcSourceManager = class {
|
|
|
1179
1187
|
this.log("info", `\u91CD\u7F6E\u5168\u90E8\u4F1A\u8BDD count=${this.sessions.size}`);
|
|
1180
1188
|
const sessions = Array.from(this.sessions.values());
|
|
1181
1189
|
this.sessions.clear();
|
|
1190
|
+
this.sourceSessionKeys.clear();
|
|
1182
1191
|
sessions.forEach((session) => {
|
|
1183
1192
|
void this.disposeSession(session);
|
|
1184
1193
|
});
|
|
@@ -1201,7 +1210,7 @@ var TrtcSourceManager = class {
|
|
|
1201
1210
|
};
|
|
1202
1211
|
}
|
|
1203
1212
|
getSnapshot(sourceId) {
|
|
1204
|
-
const session = this.
|
|
1213
|
+
const session = this.getSession(sourceId);
|
|
1205
1214
|
if (!session) {
|
|
1206
1215
|
return {
|
|
1207
1216
|
status: "idle"
|
|
@@ -1216,7 +1225,7 @@ var TrtcSourceManager = class {
|
|
|
1216
1225
|
* 检查指定 source 的 TRTC 会话是否曾收到过 REMOTE_VIDEO_AVAILABLE 事件。
|
|
1217
1226
|
*/
|
|
1218
1227
|
hasRemoteVideoAvailable(sourceId) {
|
|
1219
|
-
const session = this.
|
|
1228
|
+
const session = this.getSession(sourceId);
|
|
1220
1229
|
return session?.hasEverReceivedRemoteVideo ?? false;
|
|
1221
1230
|
}
|
|
1222
1231
|
/**
|
|
@@ -1225,7 +1234,7 @@ var TrtcSourceManager = class {
|
|
|
1225
1234
|
* - 若会话被销毁或超时,返回 false。
|
|
1226
1235
|
*/
|
|
1227
1236
|
waitForRemoteVideoAvailable(sourceId, timeoutMs = 3e4) {
|
|
1228
|
-
const session = this.
|
|
1237
|
+
const session = this.getSession(sourceId);
|
|
1229
1238
|
if (!session) return Promise.resolve(false);
|
|
1230
1239
|
if (session.hasEverReceivedRemoteVideo) return Promise.resolve(true);
|
|
1231
1240
|
return new Promise((resolve) => {
|
|
@@ -1253,11 +1262,12 @@ var TrtcSourceManager = class {
|
|
|
1253
1262
|
* - 应用全局音频策略(根据所有 view 的 muted 汇总)
|
|
1254
1263
|
*/
|
|
1255
1264
|
async attachView(sourceId, viewId, container, muted) {
|
|
1256
|
-
const session = this.
|
|
1265
|
+
const session = this.getSession(sourceId);
|
|
1257
1266
|
if (!session) {
|
|
1258
1267
|
throw new Error(`TRTC source session not found: ${sourceId}`);
|
|
1259
1268
|
}
|
|
1260
1269
|
session.views.set(viewId, {
|
|
1270
|
+
sourceId,
|
|
1261
1271
|
container,
|
|
1262
1272
|
muted,
|
|
1263
1273
|
startedVideoKeys: /* @__PURE__ */ new Set(),
|
|
@@ -1272,15 +1282,18 @@ var TrtcSourceManager = class {
|
|
|
1272
1282
|
await this.applyAudioPolicy(session);
|
|
1273
1283
|
}
|
|
1274
1284
|
detachView(sourceId, viewId) {
|
|
1275
|
-
const session = this.
|
|
1285
|
+
const session = this.getSession(sourceId);
|
|
1276
1286
|
if (!session) {
|
|
1277
1287
|
return;
|
|
1278
1288
|
}
|
|
1279
|
-
session.views.
|
|
1289
|
+
const binding = session.views.get(viewId);
|
|
1290
|
+
if (binding?.sourceId === sourceId) {
|
|
1291
|
+
session.views.delete(viewId);
|
|
1292
|
+
}
|
|
1280
1293
|
void this.applyAudioPolicy(session);
|
|
1281
1294
|
}
|
|
1282
1295
|
updateViewMuted(sourceId, viewId, muted) {
|
|
1283
|
-
const session = this.
|
|
1296
|
+
const session = this.getSession(sourceId);
|
|
1284
1297
|
if (!session) {
|
|
1285
1298
|
return;
|
|
1286
1299
|
}
|
|
@@ -1291,9 +1304,43 @@ var TrtcSourceManager = class {
|
|
|
1291
1304
|
binding.muted = muted;
|
|
1292
1305
|
void this.applyAudioPolicy(session);
|
|
1293
1306
|
}
|
|
1307
|
+
unlinkSourceFromSession(sourceId, session) {
|
|
1308
|
+
session.sourceIds.delete(sourceId);
|
|
1309
|
+
this.sourceSessionKeys.delete(sourceId);
|
|
1310
|
+
session.views.forEach((binding, viewId) => {
|
|
1311
|
+
if (binding.sourceId === sourceId) {
|
|
1312
|
+
session.views.delete(viewId);
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
if (session.sourceIds.size > 0) {
|
|
1316
|
+
session.sourceId = session.sourceIds.values().next().value ?? session.sourceId;
|
|
1317
|
+
void this.applyAudioPolicy(session);
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
this.sessions.delete(session.sessionKey);
|
|
1321
|
+
void this.disposeSession(session);
|
|
1322
|
+
}
|
|
1323
|
+
getSession(sourceId) {
|
|
1324
|
+
const sessionKey = this.sourceSessionKeys.get(sourceId);
|
|
1325
|
+
return sessionKey ? this.sessions.get(sessionKey) : void 0;
|
|
1326
|
+
}
|
|
1327
|
+
snapshotFromSession(session) {
|
|
1328
|
+
return {
|
|
1329
|
+
status: session.status,
|
|
1330
|
+
error: session.error
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
emitSessionSnapshot(session, snapshot) {
|
|
1334
|
+
session.sourceIds.forEach((sourceId) => this.emitSnapshot(sourceId, snapshot));
|
|
1335
|
+
}
|
|
1336
|
+
emitSessionTrtcEvent(session, type, rawType, payload) {
|
|
1337
|
+
session.sourceIds.forEach((sourceId) => this.emitTrtcEvent(sourceId, type, rawType, payload));
|
|
1338
|
+
}
|
|
1294
1339
|
createSession(sourceId, trtc, aiDenoiser) {
|
|
1295
1340
|
return {
|
|
1341
|
+
sessionKey: buildTrtcSessionKey(trtc, aiDenoiser),
|
|
1296
1342
|
sourceId,
|
|
1343
|
+
sourceIds: /* @__PURE__ */ new Set([sourceId]),
|
|
1297
1344
|
trtc,
|
|
1298
1345
|
aiDenoiser,
|
|
1299
1346
|
TRTC: null,
|
|
@@ -1321,7 +1368,7 @@ var TrtcSourceManager = class {
|
|
|
1321
1368
|
}
|
|
1322
1369
|
session.status = "connecting";
|
|
1323
1370
|
session.error = void 0;
|
|
1324
|
-
this.
|
|
1371
|
+
this.emitSessionSnapshot(session, {
|
|
1325
1372
|
status: session.status
|
|
1326
1373
|
});
|
|
1327
1374
|
session.connectPromise = (async () => {
|
|
@@ -1350,7 +1397,7 @@ var TrtcSourceManager = class {
|
|
|
1350
1397
|
session.views.forEach((binding) => {
|
|
1351
1398
|
void this.startRemoteVideoForBinding(client, event.userId, event.streamType, binding, remoteVideoKey);
|
|
1352
1399
|
});
|
|
1353
|
-
this.
|
|
1400
|
+
this.emitSessionTrtcEvent(session, "remote_video_available", TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, event);
|
|
1354
1401
|
};
|
|
1355
1402
|
const onRemoteVideoUnavailable = (event) => {
|
|
1356
1403
|
this.log("info", `\u8FDC\u7AEF\u89C6\u9891\u4E0D\u53EF\u7528 source=${session.sourceId} userId=${event.userId} streamType=${event.streamType}`);
|
|
@@ -1364,19 +1411,19 @@ var TrtcSourceManager = class {
|
|
|
1364
1411
|
userId: event.userId,
|
|
1365
1412
|
streamType: event.streamType
|
|
1366
1413
|
}).catch(() => void 0);
|
|
1367
|
-
this.
|
|
1414
|
+
this.emitSessionTrtcEvent(session, "remote_video_unavailable", TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, event);
|
|
1368
1415
|
};
|
|
1369
1416
|
const onRemoteAudioAvailable = (event) => {
|
|
1370
1417
|
this.log("info", `\u8FDC\u7AEF\u97F3\u9891\u53EF\u7528 source=${session.sourceId} userId=${event.userId}`);
|
|
1371
1418
|
session.remoteAudioUsers.add(event.userId);
|
|
1372
1419
|
void this.applyAudioPolicy(session);
|
|
1373
|
-
this.
|
|
1420
|
+
this.emitSessionTrtcEvent(session, "remote_audio_available", TRTC.EVENT.REMOTE_AUDIO_AVAILABLE, event);
|
|
1374
1421
|
};
|
|
1375
1422
|
const onRemoteAudioUnavailable = (event) => {
|
|
1376
1423
|
this.log("info", `\u8FDC\u7AEF\u97F3\u9891\u4E0D\u53EF\u7528 source=${session.sourceId} userId=${event.userId}`);
|
|
1377
1424
|
session.remoteAudioUsers.delete(event.userId);
|
|
1378
1425
|
void this.applyAudioPolicy(session);
|
|
1379
|
-
this.
|
|
1426
|
+
this.emitSessionTrtcEvent(session, "remote_audio_unavailable", TRTC.EVENT.REMOTE_AUDIO_UNAVAILABLE, event);
|
|
1380
1427
|
};
|
|
1381
1428
|
session.onRemoteVideoAvailable = onRemoteVideoAvailable;
|
|
1382
1429
|
session.onRemoteVideoUnavailable = onRemoteVideoUnavailable;
|
|
@@ -1402,7 +1449,7 @@ var TrtcSourceManager = class {
|
|
|
1402
1449
|
session.error = void 0;
|
|
1403
1450
|
this.log("info", `\u8FDB\u623F\u6210\u529F source=${session.sourceId} room=${roomId}`);
|
|
1404
1451
|
await this.applyAIDenoiserPolicy(session, client, sdkAppId, userId, userSig);
|
|
1405
|
-
this.
|
|
1452
|
+
this.emitSessionSnapshot(session, {
|
|
1406
1453
|
status: session.status
|
|
1407
1454
|
});
|
|
1408
1455
|
await this.applyAudioPolicy(session);
|
|
@@ -1410,7 +1457,7 @@ var TrtcSourceManager = class {
|
|
|
1410
1457
|
session.status = "error";
|
|
1411
1458
|
session.error = error instanceof Error ? error.message : String(error);
|
|
1412
1459
|
this.log("error", `\u8FDE\u63A5\u5931\u8D25 source=${session.sourceId} error=${session.error}`);
|
|
1413
|
-
this.
|
|
1460
|
+
this.emitSessionSnapshot(session, {
|
|
1414
1461
|
status: session.status,
|
|
1415
1462
|
error: session.error
|
|
1416
1463
|
});
|
|
@@ -1587,6 +1634,20 @@ function isRuntimeTrtcSource(source) {
|
|
|
1587
1634
|
function isSameTrtcConfig(a, b) {
|
|
1588
1635
|
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;
|
|
1589
1636
|
}
|
|
1637
|
+
function buildTrtcSessionKey(trtc, aiDenoiser) {
|
|
1638
|
+
const denoiser = resolveAIDenoiserOptions(aiDenoiser);
|
|
1639
|
+
return JSON.stringify({
|
|
1640
|
+
appId: trtc.app_id,
|
|
1641
|
+
roomId: trtc.room_id,
|
|
1642
|
+
userId: trtc.user_id,
|
|
1643
|
+
userSig: trtc.user_sig,
|
|
1644
|
+
aiDenoiser: {
|
|
1645
|
+
enabled: denoiser.enabled,
|
|
1646
|
+
mode: denoiser.mode,
|
|
1647
|
+
assetsPath: denoiser.assetsPath
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1590
1651
|
function isSameAIDenoiserOptions(a, b) {
|
|
1591
1652
|
const left = resolveAIDenoiserOptions(a);
|
|
1592
1653
|
const right = resolveAIDenoiserOptions(b);
|