@vivix-ai/ivi-frontend-sdk 0.3.9 → 0.3.11
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 +44 -0
- package/dist/index.cjs +501 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +501 -63
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReceiveConversationItemAddedEvent, ReceiveConversationItemDoneEvent, ReceiveResponseCreatedEvent, IviClient, ReceiveSessionCreatedEvent, ReceiveSessionEndedEvent, ReceiveSessionStageGetResponseEvent, ReceiveSessionStageUpdatedEvent, ReceiveSessionTrackCreatedEvent, ReceiveSessionTrackDeletedEvent, ReceiveSessionTrackTookEvent, ReceiveSessionTrackCuedEvent, ReceiveSessionTrackNextSetEvent, ReceiveSessionTracksListResponseEvent, ReceiveSessionSourceCreatedEvent, ReceiveSessionSourceReadyEvent, ReceiveSessionSourceFailedEvent, ReceiveSessionSourceDeletedEvent, ReceiveSessionSourcePreloadEvent, ReceiveSessionSourceClearPreloadEvent, ReceiveSessionSourcesListResponseEvent, ReceiveSessionSourcePlaybackCompletedEvent, ReceiveSessionStreamCreatedEvent, ReceiveSessionStreamStartedEvent, ReceiveSessionStreamEndedEvent, ReceiveSessionStreamFailedEvent, ReceiveSessionStreamDeletedEvent, ReceiveSessionStreamsListResponseEvent, ReceiveConversationListResponseEvent, ReceiveResponseOutputTextDeltaEvent, ReceiveResponseOutputTextDoneEvent, ReceiveResponseOutputAudioTranscriptDeltaEvent, ReceiveResponseOutputAudioTranscriptDoneEvent, ReceiveResponseDoneEvent } from '@vivix-ai/ivi-sdk-ts';
|
|
2
|
+
import { propagation, SpanKind, trace, SpanStatusCode, context } from '@opentelemetry/api';
|
|
2
3
|
import { WebSocketTransport } from '@vivix-ai/ivi-sdk-ts/transports/websocket';
|
|
3
4
|
import { createContext, useState, useEffect, useMemo, useRef, useContext, useCallback, useId } from 'react';
|
|
4
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -1139,6 +1140,94 @@ var ConversationManager = class {
|
|
|
1139
1140
|
];
|
|
1140
1141
|
}
|
|
1141
1142
|
};
|
|
1143
|
+
var DEFAULT_TRACER_NAME = "@vivix-ai/ivi-frontend-sdk";
|
|
1144
|
+
function getIviTelemetryTracer(options) {
|
|
1145
|
+
return options?.tracer ?? trace.getTracer(DEFAULT_TRACER_NAME);
|
|
1146
|
+
}
|
|
1147
|
+
function getIviTelemetryContext(options) {
|
|
1148
|
+
return options?.context ?? context.active();
|
|
1149
|
+
}
|
|
1150
|
+
function startIviTelemetrySpan(name, options, attributes) {
|
|
1151
|
+
const tracer = getIviTelemetryTracer(options);
|
|
1152
|
+
const parentContext = getIviTelemetryContext(options);
|
|
1153
|
+
const span = tracer.startSpan(
|
|
1154
|
+
name,
|
|
1155
|
+
{
|
|
1156
|
+
kind: SpanKind.INTERNAL,
|
|
1157
|
+
attributes: mergeIviTelemetryAttributes(options?.attributes, attributes)
|
|
1158
|
+
},
|
|
1159
|
+
parentContext
|
|
1160
|
+
);
|
|
1161
|
+
return {
|
|
1162
|
+
span,
|
|
1163
|
+
context: trace.setSpan(parentContext, span)
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
function endIviTelemetrySpan(span, attributes) {
|
|
1167
|
+
const cleaned = cleanIviTelemetryAttributes(attributes);
|
|
1168
|
+
if (cleaned) {
|
|
1169
|
+
span.setAttributes(cleaned);
|
|
1170
|
+
}
|
|
1171
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1172
|
+
span.end();
|
|
1173
|
+
}
|
|
1174
|
+
function failIviTelemetrySpan(span, error, attributes) {
|
|
1175
|
+
const cleaned = cleanIviTelemetryAttributes(attributes);
|
|
1176
|
+
if (cleaned) {
|
|
1177
|
+
span.setAttributes(cleaned);
|
|
1178
|
+
}
|
|
1179
|
+
recordIviTelemetryError(span, error);
|
|
1180
|
+
span.end();
|
|
1181
|
+
}
|
|
1182
|
+
function recordIviTelemetrySpan(name, options, attributes, error) {
|
|
1183
|
+
const { span } = startIviTelemetrySpan(name, options, attributes);
|
|
1184
|
+
if (error === void 0) {
|
|
1185
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1186
|
+
} else {
|
|
1187
|
+
recordIviTelemetryError(span, error);
|
|
1188
|
+
}
|
|
1189
|
+
span.end();
|
|
1190
|
+
}
|
|
1191
|
+
function withIviTelemetryContext(options, context, attributes) {
|
|
1192
|
+
return {
|
|
1193
|
+
...options,
|
|
1194
|
+
context,
|
|
1195
|
+
attributes: mergeIviTelemetryAttributes(options?.attributes, attributes)
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
function mergeIviTelemetryAttributes(base, next) {
|
|
1199
|
+
return cleanIviTelemetryAttributes({
|
|
1200
|
+
...base ?? {},
|
|
1201
|
+
...next ?? {}
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
function cleanIviTelemetryAttributes(attributes) {
|
|
1205
|
+
const cleaned = {};
|
|
1206
|
+
Object.entries(attributes ?? {}).forEach(([key, value]) => {
|
|
1207
|
+
if (isIviTelemetryAttributeValue(value)) {
|
|
1208
|
+
cleaned[key] = value;
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
return Object.keys(cleaned).length > 0 ? cleaned : void 0;
|
|
1212
|
+
}
|
|
1213
|
+
function recordIviTelemetryError(span, error) {
|
|
1214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1215
|
+
span.recordException(error instanceof Error ? error : message);
|
|
1216
|
+
span.setStatus({
|
|
1217
|
+
code: SpanStatusCode.ERROR,
|
|
1218
|
+
message
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
function isIviTelemetryAttributeValue(value) {
|
|
1222
|
+
if (typeof value === "string" || typeof value === "boolean") return true;
|
|
1223
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
1224
|
+
if (!Array.isArray(value)) return false;
|
|
1225
|
+
const nonNullValues = value.filter((item) => item !== null && item !== void 0);
|
|
1226
|
+
if (nonNullValues.length === 0) return true;
|
|
1227
|
+
const firstType = typeof nonNullValues[0];
|
|
1228
|
+
if (firstType !== "string" && firstType !== "number" && firstType !== "boolean") return false;
|
|
1229
|
+
return nonNullValues.every((item) => typeof item === firstType && (typeof item !== "number" || Number.isFinite(item)));
|
|
1230
|
+
}
|
|
1142
1231
|
|
|
1143
1232
|
// src/runtime/managers/trtc-source-manager.ts
|
|
1144
1233
|
var TAG = "[IVI-TRTC]";
|
|
@@ -1149,10 +1238,11 @@ var DEFAULT_DENOISER_OPTIONS = {
|
|
|
1149
1238
|
mode: "normal"
|
|
1150
1239
|
};
|
|
1151
1240
|
var TrtcSourceManager = class {
|
|
1152
|
-
constructor(onLog, onTrtcEvent, aiDenoiser) {
|
|
1241
|
+
constructor(onLog, onTrtcEvent, aiDenoiser, telemetry) {
|
|
1153
1242
|
this.onLog = onLog;
|
|
1154
1243
|
this.onTrtcEvent = onTrtcEvent;
|
|
1155
1244
|
this.aiDenoiser = aiDenoiser;
|
|
1245
|
+
this.telemetry = telemetry;
|
|
1156
1246
|
this.sessions = /* @__PURE__ */ new Map();
|
|
1157
1247
|
this.sourceSessionKeys = /* @__PURE__ */ new Map();
|
|
1158
1248
|
this.listeners = /* @__PURE__ */ new Map();
|
|
@@ -1448,9 +1538,14 @@ var TrtcSourceManager = class {
|
|
|
1448
1538
|
const client = TRTC.create();
|
|
1449
1539
|
const onRemoteVideoAvailable = (event) => {
|
|
1450
1540
|
this.log("info", `\u8FDC\u7AEF\u89C6\u9891\u53EF\u7528 source=${session.sourceId} userId=${event.userId} streamType=${event.streamType}`);
|
|
1541
|
+
const telemetryAttributes = buildTrtcMediaTelemetryAttributes(session.sourceId, event.userId, event.streamType);
|
|
1451
1542
|
const remoteVideoKey = buildRemoteVideoKey(event.userId, String(event.streamType));
|
|
1452
1543
|
session.remoteVideoStreams.add(remoteVideoKey);
|
|
1453
1544
|
if (!session.hasEverReceivedRemoteVideo) {
|
|
1545
|
+
this.endRemoteVideoAvailableWait(session, {
|
|
1546
|
+
...telemetryAttributes,
|
|
1547
|
+
"ivi.media.trtc.waiting_remote_video_available.result": "available"
|
|
1548
|
+
});
|
|
1454
1549
|
session.hasEverReceivedRemoteVideo = true;
|
|
1455
1550
|
for (const waiter of session.remoteVideoWaiters) {
|
|
1456
1551
|
waiter(true);
|
|
@@ -1497,15 +1592,38 @@ var TrtcSourceManager = class {
|
|
|
1497
1592
|
client.on(TRTC.EVENT.REMOTE_AUDIO_AVAILABLE, onRemoteAudioAvailable);
|
|
1498
1593
|
client.on(TRTC.EVENT.REMOTE_AUDIO_UNAVAILABLE, onRemoteAudioUnavailable);
|
|
1499
1594
|
this.log("info", `\u6B63\u5728\u8FDB\u623F source=${session.sourceId} room=${roomId} sdkAppId=${sdkAppId} userId=${userId}`);
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1595
|
+
session.remoteVideoAvailableSpan = startIviTelemetrySpan(
|
|
1596
|
+
"sdk.media.trtc.waiting_remote_video_available",
|
|
1597
|
+
this.telemetry,
|
|
1598
|
+
buildTrtcWaitingRemoteVideoTelemetryAttributes(session.sourceId, roomId, sdkAppId, isStringRoomId)
|
|
1599
|
+
);
|
|
1600
|
+
const joinRoomSpan = startIviTelemetrySpan(
|
|
1601
|
+
"sdk.media.trtc.join_room",
|
|
1602
|
+
this.telemetry,
|
|
1603
|
+
buildTrtcJoinRoomTelemetryAttributes(session.sourceId, roomId, userId, sdkAppId, isStringRoomId)
|
|
1604
|
+
);
|
|
1605
|
+
try {
|
|
1606
|
+
await client.enterRoom({
|
|
1607
|
+
sdkAppId,
|
|
1608
|
+
userId,
|
|
1609
|
+
userSig,
|
|
1610
|
+
scene: TRTC.TYPE.SCENE_LIVE,
|
|
1611
|
+
role: TRTC.TYPE.ROLE_AUDIENCE,
|
|
1612
|
+
autoReceiveAudio: true,
|
|
1613
|
+
...isStringRoomId ? { strRoomId: roomId } : { roomId: Number(roomId) }
|
|
1614
|
+
});
|
|
1615
|
+
endIviTelemetrySpan(joinRoomSpan.span, {
|
|
1616
|
+
"ivi.media.trtc.join_room.result": "connected"
|
|
1617
|
+
});
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
this.failRemoteVideoAvailableWait(session, error, {
|
|
1620
|
+
"ivi.media.trtc.waiting_remote_video_available.result": "join_failed"
|
|
1621
|
+
});
|
|
1622
|
+
failIviTelemetrySpan(joinRoomSpan.span, error, {
|
|
1623
|
+
"ivi.media.trtc.join_room.result": "failed"
|
|
1624
|
+
});
|
|
1625
|
+
throw error;
|
|
1626
|
+
}
|
|
1509
1627
|
session.TRTC = TRTC;
|
|
1510
1628
|
session.client = client;
|
|
1511
1629
|
session.status = "connected";
|
|
@@ -1517,6 +1635,9 @@ var TrtcSourceManager = class {
|
|
|
1517
1635
|
});
|
|
1518
1636
|
await this.applyAudioPolicy(session);
|
|
1519
1637
|
})().catch((error) => {
|
|
1638
|
+
this.failRemoteVideoAvailableWait(session, error, {
|
|
1639
|
+
"ivi.media.trtc.waiting_remote_video_available.result": "connect_failed"
|
|
1640
|
+
});
|
|
1520
1641
|
session.status = "error";
|
|
1521
1642
|
session.error = error instanceof Error ? error.message : String(error);
|
|
1522
1643
|
this.log("error", `\u8FDE\u63A5\u5931\u8D25 source=${session.sourceId} error=${session.error}`);
|
|
@@ -1555,6 +1676,16 @@ var TrtcSourceManager = class {
|
|
|
1555
1676
|
return;
|
|
1556
1677
|
}
|
|
1557
1678
|
binding.startingVideoKeys.add(remoteVideoKey);
|
|
1679
|
+
const telemetryAttributes = buildTrtcMediaTelemetryAttributes(
|
|
1680
|
+
binding.sourceId,
|
|
1681
|
+
userId,
|
|
1682
|
+
streamType
|
|
1683
|
+
);
|
|
1684
|
+
const telemetrySpan = startIviTelemetrySpan(
|
|
1685
|
+
"sdk.media.trtc.start_remote_video",
|
|
1686
|
+
this.telemetry,
|
|
1687
|
+
telemetryAttributes
|
|
1688
|
+
);
|
|
1558
1689
|
try {
|
|
1559
1690
|
this.log("info", `\u5F00\u59CB\u6E32\u67D3\u8FDC\u7AEF\u89C6\u9891 source=${binding.sourceId} view=${remoteVideoKey} userId=${userId} streamType=${streamType}`);
|
|
1560
1691
|
await client.startRemoteVideo({
|
|
@@ -1563,14 +1694,24 @@ var TrtcSourceManager = class {
|
|
|
1563
1694
|
view: binding.container,
|
|
1564
1695
|
option: { fillMode: "contain" }
|
|
1565
1696
|
});
|
|
1697
|
+
endIviTelemetrySpan(telemetrySpan.span);
|
|
1698
|
+
recordIviTelemetrySpan(
|
|
1699
|
+
"sdk.media.trtc.remote_video_rendered",
|
|
1700
|
+
this.telemetry,
|
|
1701
|
+
telemetryAttributes
|
|
1702
|
+
);
|
|
1566
1703
|
this.log("info", `\u8FDC\u7AEF\u89C6\u9891\u6E32\u67D3\u5B8C\u6210 source=${binding.sourceId} userId=${userId} streamType=${streamType}`);
|
|
1567
1704
|
binding.startedVideoKeys.add(remoteVideoKey);
|
|
1568
1705
|
enforceContainMedia(binding.container);
|
|
1569
1706
|
} catch (error) {
|
|
1570
1707
|
if (error instanceof Error && /already started|OPERATION_ABORT/i.test(error.message)) {
|
|
1571
1708
|
binding.startedVideoKeys.add(remoteVideoKey);
|
|
1709
|
+
endIviTelemetrySpan(telemetrySpan.span, {
|
|
1710
|
+
"ivi.media.trtc.start_remote_video.result": "already_started"
|
|
1711
|
+
});
|
|
1572
1712
|
return;
|
|
1573
1713
|
}
|
|
1714
|
+
failIviTelemetrySpan(telemetrySpan.span, error);
|
|
1574
1715
|
this.log("warn", `\u8FDC\u7AEF\u89C6\u9891\u6E32\u67D3\u5931\u8D25 userId=${userId} streamType=${streamType}`, error);
|
|
1575
1716
|
} finally {
|
|
1576
1717
|
binding.startingVideoKeys.delete(remoteVideoKey);
|
|
@@ -1619,6 +1760,22 @@ var TrtcSourceManager = class {
|
|
|
1619
1760
|
this.log("warn", `TRTC AIDenoiser \u5F00\u542F\u5931\u8D25 source=${session.sourceId}`, error);
|
|
1620
1761
|
}
|
|
1621
1762
|
}
|
|
1763
|
+
endRemoteVideoAvailableWait(session, attributes) {
|
|
1764
|
+
const waitingSpan = session.remoteVideoAvailableSpan;
|
|
1765
|
+
if (!waitingSpan) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
session.remoteVideoAvailableSpan = void 0;
|
|
1769
|
+
endIviTelemetrySpan(waitingSpan.span, attributes);
|
|
1770
|
+
}
|
|
1771
|
+
failRemoteVideoAvailableWait(session, error, attributes) {
|
|
1772
|
+
const waitingSpan = session.remoteVideoAvailableSpan;
|
|
1773
|
+
if (!waitingSpan) {
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
session.remoteVideoAvailableSpan = void 0;
|
|
1777
|
+
failIviTelemetrySpan(waitingSpan.span, error, attributes);
|
|
1778
|
+
}
|
|
1622
1779
|
/**
|
|
1623
1780
|
* 销毁单个 source 会话:
|
|
1624
1781
|
* 解绑事件、停止远端视频、退出房间并销毁客户端。
|
|
@@ -1632,6 +1789,9 @@ var TrtcSourceManager = class {
|
|
|
1632
1789
|
session.remoteVideoStreams.clear();
|
|
1633
1790
|
session.status = "idle";
|
|
1634
1791
|
session.error = void 0;
|
|
1792
|
+
this.endRemoteVideoAvailableWait(session, {
|
|
1793
|
+
"ivi.media.trtc.waiting_remote_video_available.result": "cancelled"
|
|
1794
|
+
});
|
|
1635
1795
|
for (const waiter of session.remoteVideoWaiters) {
|
|
1636
1796
|
waiter(false);
|
|
1637
1797
|
}
|
|
@@ -1784,6 +1944,30 @@ function getAIDenoiserModeValue(mode) {
|
|
|
1784
1944
|
function buildRemoteVideoKey(userId, streamType) {
|
|
1785
1945
|
return `${userId}::${streamType}`;
|
|
1786
1946
|
}
|
|
1947
|
+
function buildTrtcMediaTelemetryAttributes(sourceId, userId, streamType) {
|
|
1948
|
+
return {
|
|
1949
|
+
"ivi.source.id": sourceId,
|
|
1950
|
+
"ivi.trtc.user_id": userId,
|
|
1951
|
+
"ivi.trtc.stream_type": String(streamType)
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
function buildTrtcJoinRoomTelemetryAttributes(sourceId, roomId, userId, sdkAppId, isStringRoomId) {
|
|
1955
|
+
return {
|
|
1956
|
+
"ivi.source.id": sourceId,
|
|
1957
|
+
"ivi.trtc.room_id": roomId,
|
|
1958
|
+
"ivi.trtc.user_id": userId,
|
|
1959
|
+
"ivi.trtc.sdk_app_id": sdkAppId,
|
|
1960
|
+
"ivi.trtc.room_id.is_string": isStringRoomId
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
function buildTrtcWaitingRemoteVideoTelemetryAttributes(sourceId, roomId, sdkAppId, isStringRoomId) {
|
|
1964
|
+
return {
|
|
1965
|
+
"ivi.source.id": sourceId,
|
|
1966
|
+
"ivi.trtc.room_id": roomId,
|
|
1967
|
+
"ivi.trtc.sdk_app_id": sdkAppId,
|
|
1968
|
+
"ivi.trtc.room_id.is_string": isStringRoomId
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1787
1971
|
function parseRemoteVideoKey(key) {
|
|
1788
1972
|
const separatorIndex = key.indexOf("::");
|
|
1789
1973
|
if (separatorIndex < 0) {
|
|
@@ -1846,9 +2030,10 @@ function describeLivekitRoom(livekit) {
|
|
|
1846
2030
|
// src/runtime/managers/livekit-source-manager.ts
|
|
1847
2031
|
var TAG2 = "[IVI-LIVEKIT]";
|
|
1848
2032
|
var LivekitSourceManager = class {
|
|
1849
|
-
constructor(onLog, onRemoteVideoAvailable) {
|
|
2033
|
+
constructor(onLog, onRemoteVideoAvailable, telemetry) {
|
|
1850
2034
|
this.onLog = onLog;
|
|
1851
2035
|
this.onRemoteVideoAvailable = onRemoteVideoAvailable;
|
|
2036
|
+
this.telemetry = telemetry;
|
|
1852
2037
|
this.sessions = /* @__PURE__ */ new Map();
|
|
1853
2038
|
this.listeners = /* @__PURE__ */ new Map();
|
|
1854
2039
|
}
|
|
@@ -2070,6 +2255,15 @@ var LivekitSourceManager = class {
|
|
|
2070
2255
|
kind
|
|
2071
2256
|
});
|
|
2072
2257
|
if (kind === "video" && !session.hasEverReceivedRemoteVideo) {
|
|
2258
|
+
recordIviTelemetrySpan(
|
|
2259
|
+
"sdk.media.livekit.remote_video_available",
|
|
2260
|
+
this.telemetry,
|
|
2261
|
+
{
|
|
2262
|
+
"ivi.source.id": session.sourceId,
|
|
2263
|
+
"ivi.livekit.participant_identity": participant.identity,
|
|
2264
|
+
"ivi.livekit.track_sid": track.sid
|
|
2265
|
+
}
|
|
2266
|
+
);
|
|
2073
2267
|
session.hasEverReceivedRemoteVideo = true;
|
|
2074
2268
|
for (const waiter of session.remoteVideoWaiters) {
|
|
2075
2269
|
waiter(true);
|
|
@@ -2107,7 +2301,22 @@ var LivekitSourceManager = class {
|
|
|
2107
2301
|
"info",
|
|
2108
2302
|
`\u6B63\u5728\u8FDB\u623F source=${session.sourceId} room=${describeLivekitRoom(session.livekit)} ws=${session.livekit.ws_url}`
|
|
2109
2303
|
);
|
|
2110
|
-
|
|
2304
|
+
const joinRoomSpan = startIviTelemetrySpan(
|
|
2305
|
+
"sdk.media.livekit.join_room",
|
|
2306
|
+
this.telemetry,
|
|
2307
|
+
buildLivekitJoinRoomTelemetryAttributes(session)
|
|
2308
|
+
);
|
|
2309
|
+
try {
|
|
2310
|
+
await room.connect(session.livekit.ws_url, session.livekit.token);
|
|
2311
|
+
endIviTelemetrySpan(joinRoomSpan.span, {
|
|
2312
|
+
"ivi.media.livekit.join_room.result": "connected"
|
|
2313
|
+
});
|
|
2314
|
+
} catch (error) {
|
|
2315
|
+
failIviTelemetrySpan(joinRoomSpan.span, error, {
|
|
2316
|
+
"ivi.media.livekit.join_room.result": "failed"
|
|
2317
|
+
});
|
|
2318
|
+
throw error;
|
|
2319
|
+
}
|
|
2111
2320
|
session.room = room;
|
|
2112
2321
|
session.livekitModule = livekitModule;
|
|
2113
2322
|
session.status = "connected";
|
|
@@ -2242,6 +2451,13 @@ var LivekitSourceManager = class {
|
|
|
2242
2451
|
function buildRemoteTrackKey(identity, trackId) {
|
|
2243
2452
|
return `${identity}::${trackId}`;
|
|
2244
2453
|
}
|
|
2454
|
+
function buildLivekitJoinRoomTelemetryAttributes(session) {
|
|
2455
|
+
return {
|
|
2456
|
+
"ivi.source.id": session.sourceId,
|
|
2457
|
+
"ivi.livekit.room": session.livekit.room,
|
|
2458
|
+
"ivi.livekit.identity": session.livekit.identity
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2245
2461
|
function enforceContainMedia2(element) {
|
|
2246
2462
|
element.style.setProperty("width", "100%", "important");
|
|
2247
2463
|
element.style.setProperty("height", "100%", "important");
|
|
@@ -2291,11 +2507,16 @@ var IviRuntimeCoordinator = class {
|
|
|
2291
2507
|
this.trtcSourceManager = new TrtcSourceManager(
|
|
2292
2508
|
this.config.onLog,
|
|
2293
2509
|
(event) => this.onTrtcManagerEvent(event),
|
|
2294
|
-
this.config.trtcAIDenoiser
|
|
2510
|
+
this.config.trtcAIDenoiser,
|
|
2511
|
+
this.config.telemetry
|
|
2512
|
+
);
|
|
2513
|
+
this.livekitSourceManager = new LivekitSourceManager(
|
|
2514
|
+
this.config.onLog,
|
|
2515
|
+
() => {
|
|
2516
|
+
this.recomposeBootstrapState();
|
|
2517
|
+
},
|
|
2518
|
+
this.config.telemetry
|
|
2295
2519
|
);
|
|
2296
|
-
this.livekitSourceManager = new LivekitSourceManager(this.config.onLog, () => {
|
|
2297
|
-
this.recomposeBootstrapState();
|
|
2298
|
-
});
|
|
2299
2520
|
this.sessionHandler = new SessionEventHandler(this.sessionManager, {
|
|
2300
2521
|
onSessionCreated: (event) => this.onSessionCreated(event),
|
|
2301
2522
|
onSessionEnded: (event) => this.onSessionEnded(event)
|
|
@@ -2332,15 +2553,27 @@ var IviRuntimeCoordinator = class {
|
|
|
2332
2553
|
* 启动后状态会从 idle/stopped 进入 connecting,连接成功后由事件驱动进入后续状态。
|
|
2333
2554
|
*/
|
|
2334
2555
|
async start() {
|
|
2335
|
-
this.
|
|
2336
|
-
|
|
2337
|
-
|
|
2556
|
+
const telemetrySpan = startIviTelemetrySpan("sdk.runtime.start", this.config.telemetry, {
|
|
2557
|
+
"ivi.runtime.status": this.state.status,
|
|
2558
|
+
"ivi.session.id": this.state.session?.id
|
|
2338
2559
|
});
|
|
2339
|
-
this.dispatcher.start();
|
|
2340
2560
|
try {
|
|
2561
|
+
this.setState({
|
|
2562
|
+
...this.state,
|
|
2563
|
+
status: "connecting"
|
|
2564
|
+
});
|
|
2565
|
+
this.dispatcher.start();
|
|
2341
2566
|
await this.client.connect();
|
|
2567
|
+
endIviTelemetrySpan(telemetrySpan.span, {
|
|
2568
|
+
"ivi.runtime.status": this.state.status,
|
|
2569
|
+
"ivi.session.id": this.state.session?.id
|
|
2570
|
+
});
|
|
2342
2571
|
} catch (error) {
|
|
2343
2572
|
this.stop();
|
|
2573
|
+
failIviTelemetrySpan(telemetrySpan.span, error, {
|
|
2574
|
+
"ivi.runtime.status": this.state.status,
|
|
2575
|
+
"ivi.session.id": this.state.session?.id
|
|
2576
|
+
});
|
|
2344
2577
|
throw error;
|
|
2345
2578
|
}
|
|
2346
2579
|
}
|
|
@@ -2348,13 +2581,31 @@ var IviRuntimeCoordinator = class {
|
|
|
2348
2581
|
* 停止协调器并断开实时连接,同时重置运行态数据为 stopped。
|
|
2349
2582
|
*/
|
|
2350
2583
|
stop() {
|
|
2351
|
-
this.
|
|
2352
|
-
|
|
2353
|
-
|
|
2584
|
+
const telemetrySpan = startIviTelemetrySpan("sdk.runtime.stop", this.config.telemetry, {
|
|
2585
|
+
"ivi.runtime.status": this.state.status,
|
|
2586
|
+
"ivi.session.id": this.state.session?.id
|
|
2587
|
+
});
|
|
2588
|
+
try {
|
|
2589
|
+
this.dispatcher.stop();
|
|
2590
|
+
this.client.disconnect();
|
|
2591
|
+
this.resetStoppedState();
|
|
2592
|
+
endIviTelemetrySpan(telemetrySpan.span, {
|
|
2593
|
+
"ivi.runtime.status": this.state.status
|
|
2594
|
+
});
|
|
2595
|
+
} catch (error) {
|
|
2596
|
+
failIviTelemetrySpan(telemetrySpan.span, error, {
|
|
2597
|
+
"ivi.runtime.status": this.state.status,
|
|
2598
|
+
"ivi.session.id": this.state.session?.id
|
|
2599
|
+
});
|
|
2600
|
+
throw error;
|
|
2601
|
+
}
|
|
2354
2602
|
}
|
|
2355
2603
|
getState() {
|
|
2356
2604
|
return this.state;
|
|
2357
2605
|
}
|
|
2606
|
+
getTelemetryOptions() {
|
|
2607
|
+
return this.config.telemetry;
|
|
2608
|
+
}
|
|
2358
2609
|
onStateChange(listener) {
|
|
2359
2610
|
this.stateListeners.add(listener);
|
|
2360
2611
|
return () => {
|
|
@@ -2928,44 +3179,101 @@ async function createIVISession(request, options) {
|
|
|
2928
3179
|
if (!fetchImpl) {
|
|
2929
3180
|
throw new Error("fetch is not available. Pass options.fetch to createIVISession.");
|
|
2930
3181
|
}
|
|
2931
|
-
const
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3182
|
+
const telemetrySpan = startIviTelemetrySpan(
|
|
3183
|
+
"sdk.session.create",
|
|
3184
|
+
options.telemetry,
|
|
3185
|
+
buildCreateSessionTelemetryAttributes(request)
|
|
3186
|
+
);
|
|
3187
|
+
try {
|
|
3188
|
+
const requestBody = toCpCreateIVISessionRequestBody(request);
|
|
3189
|
+
const headers = await buildHeaders(options.headers);
|
|
3190
|
+
injectIviTelemetryHeaders(headers, telemetrySpan.context);
|
|
3191
|
+
const response = await fetchImpl(resolveCreateIVISessionUrl(options), {
|
|
3192
|
+
method: "POST",
|
|
3193
|
+
headers,
|
|
3194
|
+
body: JSON.stringify(requestBody),
|
|
3195
|
+
credentials: options.credentials,
|
|
3196
|
+
signal: options.signal
|
|
3197
|
+
});
|
|
3198
|
+
const responseBody = await readJsonResponse(response);
|
|
3199
|
+
if (!response.ok) {
|
|
3200
|
+
const error = new IviCreateIVISessionError(response, responseBody);
|
|
3201
|
+
failIviTelemetrySpan(telemetrySpan.span, error, {
|
|
3202
|
+
"http.response.status_code": response.status,
|
|
3203
|
+
"http.response.status_text": response.statusText
|
|
3204
|
+
});
|
|
3205
|
+
throw error;
|
|
3206
|
+
}
|
|
3207
|
+
const result = normalizeCreateIVISessionResponse(responseBody, request, requestBody);
|
|
3208
|
+
endIviTelemetrySpan(telemetrySpan.span, {
|
|
3209
|
+
"http.response.status_code": response.status,
|
|
3210
|
+
"ivi.session.id": result.iviSessionId,
|
|
3211
|
+
"ivi.prebuild.playback.kind": result.prebuiltPlayback?.kind
|
|
3212
|
+
});
|
|
3213
|
+
return result;
|
|
3214
|
+
} catch (error) {
|
|
3215
|
+
if (!(error instanceof IviCreateIVISessionError)) {
|
|
3216
|
+
failIviTelemetrySpan(telemetrySpan.span, error);
|
|
3217
|
+
}
|
|
3218
|
+
throw error;
|
|
2942
3219
|
}
|
|
2943
|
-
return normalizeCreateIVISessionResponse(responseBody, request, requestBody);
|
|
2944
3220
|
}
|
|
2945
3221
|
function createRuntimeFromSession(session, options = {}) {
|
|
2946
|
-
const
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
transport: new WebSocketTransport({
|
|
2950
|
-
url: websocketUrl,
|
|
2951
|
-
sessionId: session.iviSessionId,
|
|
2952
|
-
protocols: options.websocket?.protocols,
|
|
2953
|
-
socketFactory: options.websocket?.socketFactory
|
|
2954
|
-
})
|
|
3222
|
+
const telemetrySpan = startIviTelemetrySpan("sdk.runtime.create", options.telemetry, {
|
|
3223
|
+
"ivi.session.id": session.iviSessionId,
|
|
3224
|
+
"ivi.prebuild.playback.kind": session.prebuiltPlayback?.kind
|
|
2955
3225
|
});
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
3226
|
+
try {
|
|
3227
|
+
const websocketUrl = buildWebSocketUrl(session.endpoint, options.websocket);
|
|
3228
|
+
const childTelemetry = withIviTelemetryContext(options.telemetry, telemetrySpan.context, {
|
|
3229
|
+
"ivi.session.id": session.iviSessionId
|
|
3230
|
+
});
|
|
3231
|
+
const clientTelemetry = mergeIviTelemetryOptions(
|
|
3232
|
+
options.clientConfig?.telemetry,
|
|
3233
|
+
childTelemetry
|
|
3234
|
+
);
|
|
3235
|
+
const runtimeTelemetry = mergeIviTelemetryOptions(
|
|
3236
|
+
options.runtimeConfig?.telemetry,
|
|
3237
|
+
childTelemetry
|
|
3238
|
+
);
|
|
3239
|
+
const client = new IviClient({
|
|
3240
|
+
...options.clientConfig ?? {},
|
|
3241
|
+
telemetry: clientTelemetry,
|
|
3242
|
+
transport: new WebSocketTransport({
|
|
3243
|
+
url: websocketUrl,
|
|
3244
|
+
sessionId: session.iviSessionId,
|
|
3245
|
+
protocols: options.websocket?.protocols,
|
|
3246
|
+
socketFactory: options.websocket?.socketFactory
|
|
3247
|
+
})
|
|
3248
|
+
});
|
|
3249
|
+
const runtime = new IviRuntimeCoordinator(client, {
|
|
3250
|
+
...options.runtimeConfig ?? {},
|
|
3251
|
+
telemetry: runtimeTelemetry
|
|
3252
|
+
});
|
|
3253
|
+
if (options.fastStart !== false && session.prebuiltPlayback) {
|
|
3254
|
+
runtime.setBootstrapSource(toBootstrapSource(session.prebuiltPlayback, options));
|
|
3255
|
+
}
|
|
3256
|
+
endIviTelemetrySpan(telemetrySpan.span);
|
|
3257
|
+
return {
|
|
3258
|
+
session,
|
|
3259
|
+
client,
|
|
3260
|
+
runtime
|
|
3261
|
+
};
|
|
3262
|
+
} catch (error) {
|
|
3263
|
+
failIviTelemetrySpan(telemetrySpan.span, error);
|
|
3264
|
+
throw error;
|
|
2959
3265
|
}
|
|
2960
|
-
return {
|
|
2961
|
-
session,
|
|
2962
|
-
client,
|
|
2963
|
-
runtime
|
|
2964
|
-
};
|
|
2965
3266
|
}
|
|
2966
3267
|
async function createIVISessionRuntime(request, options) {
|
|
2967
|
-
const
|
|
2968
|
-
|
|
3268
|
+
const telemetry = mergeIviTelemetryOptions(options.telemetry, options.http.telemetry);
|
|
3269
|
+
const session = await createIVISession(request, {
|
|
3270
|
+
...options.http,
|
|
3271
|
+
telemetry
|
|
3272
|
+
});
|
|
3273
|
+
return createRuntimeFromSession(session, {
|
|
3274
|
+
...options,
|
|
3275
|
+
telemetry
|
|
3276
|
+
});
|
|
2969
3277
|
}
|
|
2970
3278
|
function toCpCreateIVISessionRequestBody(request) {
|
|
2971
3279
|
const body = { ...request };
|
|
@@ -3051,6 +3359,25 @@ function resolveCreateIVISessionUrl(options) {
|
|
|
3051
3359
|
const path = options.path ?? "/v1/ivi/sessions";
|
|
3052
3360
|
return new URL(path, ensureTrailingSlash(options.baseUrl)).toString();
|
|
3053
3361
|
}
|
|
3362
|
+
function buildCreateSessionTelemetryAttributes(request) {
|
|
3363
|
+
return {
|
|
3364
|
+
"ivi.version": request.iviVersion,
|
|
3365
|
+
"ivi.stream.type": request.streamType,
|
|
3366
|
+
"ivi.prebuild.enabled": Boolean(
|
|
3367
|
+
request.prebuiltStream || request.prebuiltCharacters && request.prebuiltCharacters.length > 0
|
|
3368
|
+
)
|
|
3369
|
+
};
|
|
3370
|
+
}
|
|
3371
|
+
function mergeIviTelemetryOptions(explicit, inherited) {
|
|
3372
|
+
if (!explicit && !inherited) {
|
|
3373
|
+
return void 0;
|
|
3374
|
+
}
|
|
3375
|
+
return {
|
|
3376
|
+
tracer: explicit?.tracer ?? inherited?.tracer,
|
|
3377
|
+
context: explicit?.context ?? inherited?.context,
|
|
3378
|
+
attributes: mergeIviTelemetryAttributes(inherited?.attributes, explicit?.attributes)
|
|
3379
|
+
};
|
|
3380
|
+
}
|
|
3054
3381
|
async function buildHeaders(headers) {
|
|
3055
3382
|
const resolvedHeaders = typeof headers === "function" ? await headers() : headers;
|
|
3056
3383
|
const next = new Headers(resolvedHeaders);
|
|
@@ -3059,6 +3386,14 @@ async function buildHeaders(headers) {
|
|
|
3059
3386
|
}
|
|
3060
3387
|
return next;
|
|
3061
3388
|
}
|
|
3389
|
+
var headersTextMapSetter = {
|
|
3390
|
+
set(carrier, key, value) {
|
|
3391
|
+
carrier.set(key, value);
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3394
|
+
function injectIviTelemetryHeaders(headers, context) {
|
|
3395
|
+
propagation.inject(context, headers, headersTextMapSetter);
|
|
3396
|
+
}
|
|
3062
3397
|
async function readJsonResponse(response) {
|
|
3063
3398
|
const text = await response.text();
|
|
3064
3399
|
if (!text) {
|
|
@@ -3232,32 +3567,71 @@ var IviFrontendSdk = class {
|
|
|
3232
3567
|
this.config = config;
|
|
3233
3568
|
}
|
|
3234
3569
|
createClient(config) {
|
|
3235
|
-
return new IviClient(
|
|
3570
|
+
return new IviClient({
|
|
3571
|
+
...config,
|
|
3572
|
+
telemetry: mergeSdkTelemetryOptions(config.telemetry, this.config.telemetry)
|
|
3573
|
+
});
|
|
3236
3574
|
}
|
|
3237
3575
|
createRuntimeCoordinator(clientConfig, runtimeConfig) {
|
|
3238
3576
|
const client = this.createClient(clientConfig);
|
|
3239
|
-
return new IviRuntimeCoordinator(client,
|
|
3577
|
+
return new IviRuntimeCoordinator(client, {
|
|
3578
|
+
...runtimeConfig ?? {},
|
|
3579
|
+
telemetry: mergeSdkTelemetryOptions(runtimeConfig?.telemetry, this.config.telemetry)
|
|
3580
|
+
});
|
|
3240
3581
|
}
|
|
3241
3582
|
createIVISession(request, options) {
|
|
3583
|
+
const telemetry = mergeSdkTelemetryChain(
|
|
3584
|
+
this.config.telemetry,
|
|
3585
|
+
this.config.http?.telemetry,
|
|
3586
|
+
options?.telemetry
|
|
3587
|
+
);
|
|
3242
3588
|
return createIVISession(request, {
|
|
3243
3589
|
...this.config.http ?? {},
|
|
3244
|
-
...options ?? {}
|
|
3590
|
+
...options ?? {},
|
|
3591
|
+
telemetry
|
|
3245
3592
|
});
|
|
3246
3593
|
}
|
|
3247
3594
|
createRuntimeFromSession(session, options) {
|
|
3248
|
-
return createRuntimeFromSession(session,
|
|
3595
|
+
return createRuntimeFromSession(session, {
|
|
3596
|
+
...options ?? {},
|
|
3597
|
+
telemetry: mergeSdkTelemetryChain(this.config.telemetry, options?.telemetry)
|
|
3598
|
+
});
|
|
3249
3599
|
}
|
|
3250
3600
|
createIVISessionRuntime(request, options) {
|
|
3601
|
+
const telemetry = mergeSdkTelemetryChain(
|
|
3602
|
+
this.config.telemetry,
|
|
3603
|
+
this.config.http?.telemetry,
|
|
3604
|
+
options?.http?.telemetry,
|
|
3605
|
+
options?.telemetry
|
|
3606
|
+
);
|
|
3251
3607
|
const http = {
|
|
3252
3608
|
...this.config.http ?? {},
|
|
3253
|
-
...options?.http ?? {}
|
|
3609
|
+
...options?.http ?? {},
|
|
3610
|
+
telemetry
|
|
3254
3611
|
};
|
|
3255
3612
|
return createIVISessionRuntime(request, {
|
|
3256
3613
|
...options ?? {},
|
|
3614
|
+
telemetry,
|
|
3257
3615
|
http
|
|
3258
3616
|
});
|
|
3259
3617
|
}
|
|
3260
3618
|
};
|
|
3619
|
+
function mergeSdkTelemetryChain(...items) {
|
|
3620
|
+
return items.reduce(
|
|
3621
|
+
(merged, item) => mergeSdkTelemetryOptions(item, merged),
|
|
3622
|
+
void 0
|
|
3623
|
+
);
|
|
3624
|
+
}
|
|
3625
|
+
function mergeSdkTelemetryOptions(explicit, inherited) {
|
|
3626
|
+
if (!explicit && !inherited) {
|
|
3627
|
+
return void 0;
|
|
3628
|
+
}
|
|
3629
|
+
return {
|
|
3630
|
+
tracer: explicit?.tracer ?? inherited?.tracer,
|
|
3631
|
+
context: explicit?.context ?? inherited?.context,
|
|
3632
|
+
attributes: mergeIviTelemetryAttributes(inherited?.attributes, explicit?.attributes)
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3261
3635
|
var IviStageViewContext = createContext(null);
|
|
3262
3636
|
var EMPTY_RUNTIME_STATE = {
|
|
3263
3637
|
status: "idle",
|
|
@@ -4458,7 +4832,16 @@ function makeLoadPolicy(label, onLog) {
|
|
|
4458
4832
|
};
|
|
4459
4833
|
}
|
|
4460
4834
|
function IVIHlsVideo(props) {
|
|
4461
|
-
const {
|
|
4835
|
+
const {
|
|
4836
|
+
url,
|
|
4837
|
+
sourceId,
|
|
4838
|
+
videoProps,
|
|
4839
|
+
style,
|
|
4840
|
+
aggressivePreload = false,
|
|
4841
|
+
paused = false,
|
|
4842
|
+
onLog,
|
|
4843
|
+
telemetry
|
|
4844
|
+
} = props;
|
|
4462
4845
|
const videoRef = useRef(null);
|
|
4463
4846
|
const pausedRef = useRef(paused);
|
|
4464
4847
|
useEffect(() => {
|
|
@@ -4495,6 +4878,7 @@ function IVIHlsVideo(props) {
|
|
|
4495
4878
|
const onVideoError = () => {
|
|
4496
4879
|
const el = videoRef.current;
|
|
4497
4880
|
const mediaErr = el?.error;
|
|
4881
|
+
recordVideoTelemetry("sdk.media.video.error", telemetry, sourceId, "hls", mediaErr);
|
|
4498
4882
|
emitHlsLog(onLog, "warn", "<video> \u5143\u7D20\u62A5\u9519", {
|
|
4499
4883
|
code: mediaErr?.code,
|
|
4500
4884
|
message: mediaErr?.message,
|
|
@@ -4504,6 +4888,13 @@ function IVIHlsVideo(props) {
|
|
|
4504
4888
|
});
|
|
4505
4889
|
};
|
|
4506
4890
|
const onVideoStalled = () => {
|
|
4891
|
+
recordVideoTelemetry(
|
|
4892
|
+
"sdk.media.video.stalled",
|
|
4893
|
+
telemetry,
|
|
4894
|
+
sourceId,
|
|
4895
|
+
"hls",
|
|
4896
|
+
new Error("<video> stalled")
|
|
4897
|
+
);
|
|
4507
4898
|
emitHlsLog(onLog, "warn", "<video> stalled\uFF08\u7F13\u51B2\u505C\u6EDE\uFF09", {
|
|
4508
4899
|
currentTime: videoRef.current?.currentTime,
|
|
4509
4900
|
readyState: videoRef.current?.readyState
|
|
@@ -4646,7 +5037,7 @@ function IVIHlsVideo(props) {
|
|
|
4646
5037
|
hlsInstance?.destroy();
|
|
4647
5038
|
hlsInstance = null;
|
|
4648
5039
|
};
|
|
4649
|
-
}, [url, aggressivePreload, onLog]);
|
|
5040
|
+
}, [url, sourceId, aggressivePreload, onLog, telemetry]);
|
|
4650
5041
|
return /* @__PURE__ */ jsx(
|
|
4651
5042
|
"video",
|
|
4652
5043
|
{
|
|
@@ -4659,6 +5050,17 @@ function IVIHlsVideo(props) {
|
|
|
4659
5050
|
}
|
|
4660
5051
|
);
|
|
4661
5052
|
}
|
|
5053
|
+
function recordVideoTelemetry(name, telemetry, sourceId, kind, error) {
|
|
5054
|
+
recordIviTelemetrySpan(
|
|
5055
|
+
name,
|
|
5056
|
+
telemetry,
|
|
5057
|
+
{
|
|
5058
|
+
"ivi.source.id": sourceId,
|
|
5059
|
+
"ivi.media.kind": kind
|
|
5060
|
+
},
|
|
5061
|
+
error
|
|
5062
|
+
);
|
|
5063
|
+
}
|
|
4662
5064
|
function isM3u8Url(url) {
|
|
4663
5065
|
return /\.m3u8(?:$|[?#])/i.test(url);
|
|
4664
5066
|
}
|
|
@@ -4724,6 +5126,7 @@ function TrackSlotMediaContent(props) {
|
|
|
4724
5126
|
source,
|
|
4725
5127
|
isPreloading: !isActive
|
|
4726
5128
|
};
|
|
5129
|
+
const telemetry = runtime?.getTelemetryOptions();
|
|
4727
5130
|
const mediaStyle = buildAdaptiveMediaStyle(adaptToSourceSize, fitStrategy);
|
|
4728
5131
|
const shouldMute = !isActive;
|
|
4729
5132
|
if (renderMedia) return renderMedia(renderContext);
|
|
@@ -4795,9 +5198,11 @@ function TrackSlotMediaContent(props) {
|
|
|
4795
5198
|
IVIHlsVideo,
|
|
4796
5199
|
{
|
|
4797
5200
|
url: playbackUrl,
|
|
5201
|
+
sourceId: slotSourceId,
|
|
4798
5202
|
videoProps: mergedVideoProps,
|
|
4799
5203
|
style: videoStyle,
|
|
4800
|
-
paused: shouldPause
|
|
5204
|
+
paused: shouldPause,
|
|
5205
|
+
telemetry
|
|
4801
5206
|
}
|
|
4802
5207
|
);
|
|
4803
5208
|
}
|
|
@@ -4819,6 +5224,7 @@ function TrackSlotMediaContent(props) {
|
|
|
4819
5224
|
SlotVideo,
|
|
4820
5225
|
{
|
|
4821
5226
|
src: playbackUrl,
|
|
5227
|
+
sourceId: slotSourceId,
|
|
4822
5228
|
paused: shouldPause,
|
|
4823
5229
|
videoProps: {
|
|
4824
5230
|
...mergedVideoProps,
|
|
@@ -4826,7 +5232,8 @@ function TrackSlotMediaContent(props) {
|
|
|
4826
5232
|
playsInline: videoProps?.playsInline ?? true,
|
|
4827
5233
|
controls: isActive ? videoProps?.controls ?? true : false
|
|
4828
5234
|
},
|
|
4829
|
-
style: videoStyle
|
|
5235
|
+
style: videoStyle,
|
|
5236
|
+
telemetry
|
|
4830
5237
|
}
|
|
4831
5238
|
);
|
|
4832
5239
|
}
|
|
@@ -4876,17 +5283,48 @@ function SlotVideo(props) {
|
|
|
4876
5283
|
video.play().catch(() => void 0);
|
|
4877
5284
|
}
|
|
4878
5285
|
}, [props.paused]);
|
|
5286
|
+
const onError = (event) => {
|
|
5287
|
+
recordPlainVideoTelemetry(
|
|
5288
|
+
"sdk.media.video.error",
|
|
5289
|
+
props.telemetry,
|
|
5290
|
+
props.sourceId,
|
|
5291
|
+
event.currentTarget.error
|
|
5292
|
+
);
|
|
5293
|
+
props.videoProps.onError?.(event);
|
|
5294
|
+
};
|
|
5295
|
+
const onStalled = (event) => {
|
|
5296
|
+
recordPlainVideoTelemetry(
|
|
5297
|
+
"sdk.media.video.stalled",
|
|
5298
|
+
props.telemetry,
|
|
5299
|
+
props.sourceId,
|
|
5300
|
+
new Error("<video> stalled")
|
|
5301
|
+
);
|
|
5302
|
+
props.videoProps.onStalled?.(event);
|
|
5303
|
+
};
|
|
4879
5304
|
return /* @__PURE__ */ jsx(
|
|
4880
5305
|
"video",
|
|
4881
5306
|
{
|
|
4882
5307
|
ref: videoRef,
|
|
4883
5308
|
src: props.src,
|
|
4884
5309
|
...props.videoProps,
|
|
5310
|
+
onError,
|
|
5311
|
+
onStalled,
|
|
4885
5312
|
autoPlay: props.paused ? false : props.videoProps.autoPlay ?? true,
|
|
4886
5313
|
style: props.style
|
|
4887
5314
|
}
|
|
4888
5315
|
);
|
|
4889
5316
|
}
|
|
5317
|
+
function recordPlainVideoTelemetry(name, telemetry, sourceId, error) {
|
|
5318
|
+
recordIviTelemetrySpan(
|
|
5319
|
+
name,
|
|
5320
|
+
telemetry,
|
|
5321
|
+
{
|
|
5322
|
+
"ivi.source.id": sourceId,
|
|
5323
|
+
"ivi.media.kind": "video"
|
|
5324
|
+
},
|
|
5325
|
+
error
|
|
5326
|
+
);
|
|
5327
|
+
}
|
|
4890
5328
|
|
|
4891
5329
|
// src/react/internal/use-multi-preload-sources.ts
|
|
4892
5330
|
function useMultiPreloadSources(sources, activeSourceId) {
|