@xmaxai/web-sdk 1.0.2 → 1.0.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/dist/{chunk-5NIEZJP5.cjs → chunk-JWAAS6P4.cjs} +324 -276
- package/dist/chunk-JWAAS6P4.cjs.map +1 -0
- package/dist/{chunk-6RIEDVRQ.js → chunk-YMLRUDAO.js} +213 -165
- package/dist/chunk-YMLRUDAO.js.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -8
- package/dist/index.d.ts +17 -8
- package/dist/index.js +1 -1
- package/dist/react/index.cjs +3 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5NIEZJP5.cjs.map +0 -1
- package/dist/chunk-6RIEDVRQ.js.map +0 -1
|
@@ -198,7 +198,7 @@ var XmaxError = class _XmaxError extends Error {
|
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
// src/Foundation/Runtime/RuntimeInfo.ts
|
|
201
|
-
var XMAX_SDK_VERSION = "1.0.
|
|
201
|
+
var XMAX_SDK_VERSION = "1.0.3";
|
|
202
202
|
var _RuntimeInfo = class _RuntimeInfo {
|
|
203
203
|
/**
|
|
204
204
|
* 序列化为接口传输使用的 snake_case 字段。
|
|
@@ -263,10 +263,12 @@ var _ApiService = class _ApiService {
|
|
|
263
263
|
}
|
|
264
264
|
/**
|
|
265
265
|
* 发送请求并返回统一响应中的数据。
|
|
266
|
+
*
|
|
267
|
+
* @param options.keepalive 为 true 时请求可存活于页面卸载之后。
|
|
266
268
|
*/
|
|
267
|
-
async request(method, path, body) {
|
|
269
|
+
async request(method, path, body, options) {
|
|
268
270
|
this.validateConfiguration();
|
|
269
|
-
const request = this.makeRequest(method, path, body);
|
|
271
|
+
const request = this.makeRequest(method, path, body, options);
|
|
270
272
|
const startedAt = Date.now();
|
|
271
273
|
let status;
|
|
272
274
|
let text;
|
|
@@ -313,8 +315,8 @@ var _ApiService = class _ApiService {
|
|
|
313
315
|
/**
|
|
314
316
|
* 发送 DELETE 请求。
|
|
315
317
|
*/
|
|
316
|
-
delete(path) {
|
|
317
|
-
return this.request("DELETE" /* delete */, path);
|
|
318
|
+
delete(path, options) {
|
|
319
|
+
return this.request("DELETE" /* delete */, path, void 0, options);
|
|
318
320
|
}
|
|
319
321
|
/**
|
|
320
322
|
* 校验 API Key 与 Base URL 配置。
|
|
@@ -344,7 +346,7 @@ var _ApiService = class _ApiService {
|
|
|
344
346
|
/**
|
|
345
347
|
* 构造请求地址、请求头与请求体;路径必须相对且与 Base URL 同源。
|
|
346
348
|
*/
|
|
347
|
-
makeRequest(method, path, body) {
|
|
349
|
+
makeRequest(method, path, body, options) {
|
|
348
350
|
const normalizedPath = path.trim();
|
|
349
351
|
if (normalizedPath.length === 0 || normalizedPath.includes("://") || normalizedPath.startsWith("//")) {
|
|
350
352
|
throw new XmaxError(
|
|
@@ -385,7 +387,8 @@ var _ApiService = class _ApiService {
|
|
|
385
387
|
"X-SDK-Version": XMAX_SDK_VERSION
|
|
386
388
|
},
|
|
387
389
|
body: encodedBody,
|
|
388
|
-
signal: AbortSignal.timeout(this.timeoutMs)
|
|
390
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
391
|
+
..._optionalChain([options, 'optionalAccess', _4 => _4.keepalive]) ? { keepalive: true } : {}
|
|
389
392
|
}
|
|
390
393
|
};
|
|
391
394
|
}
|
|
@@ -403,7 +406,7 @@ var _ApiService = class _ApiService {
|
|
|
403
406
|
}
|
|
404
407
|
const ok = status >= 200 && status < 300;
|
|
405
408
|
if (!ok || envelope.success !== true) {
|
|
406
|
-
const message = _optionalChain([envelope, 'access',
|
|
409
|
+
const message = _optionalChain([envelope, 'access', _5 => _5.message, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]);
|
|
407
410
|
throw new XmaxError(
|
|
408
411
|
"API_ERROR" /* apiError */,
|
|
409
412
|
message || "Xmax API request failed",
|
|
@@ -609,7 +612,7 @@ async function frameInterpolationAdapter(size) {
|
|
|
609
612
|
if (size && (!Number.isSafeInteger(size.width) || !Number.isSafeInteger(size.height) || size.width <= 0 || size.height <= 0)) return null;
|
|
610
613
|
try {
|
|
611
614
|
const adapter = await navigator.gpu.requestAdapter();
|
|
612
|
-
if (!_optionalChain([adapter, 'optionalAccess',
|
|
615
|
+
if (!_optionalChain([adapter, 'optionalAccess', _8 => _8.features, 'access', _9 => _9.has, 'call', _10 => _10("shader-f16")])) return null;
|
|
613
616
|
if (size && (Math.ceil(size.width / 16) * 16 > adapter.limits.maxTextureDimension2D || Math.ceil(size.height / 16) * 16 > adapter.limits.maxTextureDimension2D)) return null;
|
|
614
617
|
return adapter;
|
|
615
618
|
} catch (e5) {
|
|
@@ -823,7 +826,7 @@ var StorageService = class _StorageService {
|
|
|
823
826
|
const startedAt = Date.now();
|
|
824
827
|
try {
|
|
825
828
|
const safeName = _StorageService.validateFileName(options.fileName);
|
|
826
|
-
const contentType = _optionalChain([options, 'access',
|
|
829
|
+
const contentType = _optionalChain([options, 'access', _11 => _11.contentType, 'optionalAccess', _12 => _12.trim, 'call', _13 => _13()]) || _StorageService.inferContentType(safeName);
|
|
827
830
|
const body = _StorageService.makeBody(options.data, contentType);
|
|
828
831
|
if (body.size === 0) {
|
|
829
832
|
throw new XmaxError(
|
|
@@ -845,7 +848,7 @@ var StorageService = class _StorageService {
|
|
|
845
848
|
Key: objectKey,
|
|
846
849
|
Body: body,
|
|
847
850
|
ContentType: contentType,
|
|
848
|
-
onProgress: options.onProgress ? (info) => _optionalChain([options, 'access',
|
|
851
|
+
onProgress: options.onProgress ? (info) => _optionalChain([options, 'access', _14 => _14.onProgress, 'optionalCall', _15 => _15(info.loaded, info.total)]) : void 0
|
|
849
852
|
});
|
|
850
853
|
const url = _StorageService.resolveObjectURL(
|
|
851
854
|
uploaded.Location,
|
|
@@ -877,9 +880,9 @@ var StorageService = class _StorageService {
|
|
|
877
880
|
const bucket = _StorageService.nonEmpty(payload.bucket);
|
|
878
881
|
const region = _StorageService.nonEmpty(payload.region);
|
|
879
882
|
const prefix = _StorageService.nonEmpty(payload.prefix);
|
|
880
|
-
const accessKeyID = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
881
|
-
const secretAccessKey = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
882
|
-
const sessionToken = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
883
|
+
const accessKeyID = _StorageService.nonEmpty(_optionalChain([payload, 'access', _16 => _16.credentials, 'optionalAccess', _17 => _17.accessKeyId]));
|
|
884
|
+
const secretAccessKey = _StorageService.nonEmpty(_optionalChain([payload, 'access', _18 => _18.credentials, 'optionalAccess', _19 => _19.secretAccessKey]));
|
|
885
|
+
const sessionToken = _StorageService.nonEmpty(_optionalChain([payload, 'access', _20 => _20.credentials, 'optionalAccess', _21 => _21.sessionToken]));
|
|
883
886
|
if (!bucket || !region || !prefix || !accessKeyID || !secretAccessKey || !sessionToken) {
|
|
884
887
|
throw new XmaxError("API_ERROR" /* apiError */, message);
|
|
885
888
|
}
|
|
@@ -920,7 +923,7 @@ var StorageService = class _StorageService {
|
|
|
920
923
|
reject(
|
|
921
924
|
new XmaxError(
|
|
922
925
|
"UPLOAD_ERROR" /* uploadError */,
|
|
923
|
-
_optionalChain([error, 'access',
|
|
926
|
+
_optionalChain([error, 'access', _22 => _22.message, 'optionalAccess', _23 => _23.trim, 'call', _24 => _24()]) || "Storage upload failed"
|
|
924
927
|
)
|
|
925
928
|
);
|
|
926
929
|
return;
|
|
@@ -934,14 +937,14 @@ var StorageService = class _StorageService {
|
|
|
934
937
|
* 其次拼接自定义 endpoint,最后回退到默认 COS 域名。
|
|
935
938
|
*/
|
|
936
939
|
static resolveObjectURL(location, configuration, objectKey) {
|
|
937
|
-
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess',
|
|
940
|
+
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess', _25 => _25.trim, 'call', _26 => _26()]), () => ( ""));
|
|
938
941
|
if (candidate.startsWith("//")) {
|
|
939
942
|
return `https:${candidate}`;
|
|
940
943
|
}
|
|
941
944
|
if (/^https?:\/\//i.test(candidate)) {
|
|
942
945
|
return candidate;
|
|
943
946
|
}
|
|
944
|
-
const endpoint = _optionalChain([configuration, 'access',
|
|
947
|
+
const endpoint = _optionalChain([configuration, 'access', _27 => _27.endpoint, 'optionalAccess', _28 => _28.trim, 'call', _29 => _29()]);
|
|
945
948
|
if (endpoint) {
|
|
946
949
|
const normalized = /^https?:\/\//i.test(endpoint) ? endpoint : `https://${endpoint}`;
|
|
947
950
|
return `${normalized.replace(/\/+$/, "")}/${objectKey}`;
|
|
@@ -975,7 +978,7 @@ var StorageService = class _StorageService {
|
|
|
975
978
|
* 按文件名后缀推断内容类型。
|
|
976
979
|
*/
|
|
977
980
|
static inferContentType(fileName) {
|
|
978
|
-
const extension = _nullishCoalesce(_optionalChain([fileName, 'access',
|
|
981
|
+
const extension = _nullishCoalesce(_optionalChain([fileName, 'access', _30 => _30.split, 'call', _31 => _31("."), 'access', _32 => _32.pop, 'call', _33 => _33(), 'optionalAccess', _34 => _34.toLowerCase, 'call', _35 => _35()]), () => ( ""));
|
|
979
982
|
return _nullishCoalesce(CONTENT_TYPES[extension], () => ( "application/octet-stream"));
|
|
980
983
|
}
|
|
981
984
|
/**
|
|
@@ -994,7 +997,7 @@ var StorageService = class _StorageService {
|
|
|
994
997
|
* 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
|
|
995
998
|
*/
|
|
996
999
|
static nonEmpty(value) {
|
|
997
|
-
const normalized = _optionalChain([value, 'optionalAccess',
|
|
1000
|
+
const normalized = _optionalChain([value, 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()]);
|
|
998
1001
|
return normalized || void 0;
|
|
999
1002
|
}
|
|
1000
1003
|
};
|
|
@@ -1006,6 +1009,68 @@ var CameraPosition = /* @__PURE__ */ ((CameraPosition3) => {
|
|
|
1006
1009
|
return CameraPosition3;
|
|
1007
1010
|
})(CameraPosition || {});
|
|
1008
1011
|
|
|
1012
|
+
// src/Foundation/Permissions/MediaPermissionWatch.ts
|
|
1013
|
+
var PERMISSION_POLL_INTERVAL_MS = 100;
|
|
1014
|
+
async function watchMediaPermissionPrompt(includeMicrophone) {
|
|
1015
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _38 => _38.permissions, 'optionalAccess', _39 => _39.query])) {
|
|
1016
|
+
return void 0;
|
|
1017
|
+
}
|
|
1018
|
+
const names = ["camera", ...includeMicrophone ? ["microphone"] : []];
|
|
1019
|
+
const queryOnce = () => Promise.all(
|
|
1020
|
+
names.map(async (name) => {
|
|
1021
|
+
const status = await navigator.permissions.query({
|
|
1022
|
+
name
|
|
1023
|
+
});
|
|
1024
|
+
return status.state;
|
|
1025
|
+
})
|
|
1026
|
+
);
|
|
1027
|
+
const queryStates = () => Promise.all(
|
|
1028
|
+
names.map(async (name) => {
|
|
1029
|
+
try {
|
|
1030
|
+
const status = await navigator.permissions.query({
|
|
1031
|
+
name
|
|
1032
|
+
});
|
|
1033
|
+
return status.state;
|
|
1034
|
+
} catch (e6) {
|
|
1035
|
+
return "prompt";
|
|
1036
|
+
}
|
|
1037
|
+
})
|
|
1038
|
+
);
|
|
1039
|
+
let states;
|
|
1040
|
+
try {
|
|
1041
|
+
states = await queryOnce();
|
|
1042
|
+
} catch (e7) {
|
|
1043
|
+
return void 0;
|
|
1044
|
+
}
|
|
1045
|
+
if (states.every((state2) => state2 === "granted")) {
|
|
1046
|
+
return { decided: Promise.resolve(), dispose() {
|
|
1047
|
+
} };
|
|
1048
|
+
}
|
|
1049
|
+
if (!states.includes("prompt")) {
|
|
1050
|
+
return void 0;
|
|
1051
|
+
}
|
|
1052
|
+
let disposed = false;
|
|
1053
|
+
let resolveDecided;
|
|
1054
|
+
const decided = new Promise((resolve) => {
|
|
1055
|
+
resolveDecided = resolve;
|
|
1056
|
+
});
|
|
1057
|
+
const finishIfDecided = (current) => {
|
|
1058
|
+
if (disposed || current.includes("prompt")) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
dispose();
|
|
1062
|
+
resolveDecided();
|
|
1063
|
+
};
|
|
1064
|
+
const poll = setInterval(() => {
|
|
1065
|
+
void queryStates().then(finishIfDecided);
|
|
1066
|
+
}, PERMISSION_POLL_INTERVAL_MS);
|
|
1067
|
+
function dispose() {
|
|
1068
|
+
disposed = true;
|
|
1069
|
+
clearInterval(poll);
|
|
1070
|
+
}
|
|
1071
|
+
return { decided, dispose };
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1009
1074
|
// src/Foundation/RTC/RtcEngineManager.ts
|
|
1010
1075
|
var RtcEngineLease = class {
|
|
1011
1076
|
/**
|
|
@@ -1074,13 +1139,13 @@ var _RtcEngineManager = class _RtcEngineManager {
|
|
|
1074
1139
|
* 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
|
|
1075
1140
|
*/
|
|
1076
1141
|
release(lease) {
|
|
1077
|
-
if (_optionalChain([this, 'access',
|
|
1142
|
+
if (_optionalChain([this, 'access', _40 => _40.activeLease, 'optionalAccess', _41 => _41.id]) !== lease.id) {
|
|
1078
1143
|
return;
|
|
1079
1144
|
}
|
|
1080
1145
|
this.activeLease = void 0;
|
|
1081
1146
|
try {
|
|
1082
1147
|
lease.engine.destroy();
|
|
1083
|
-
} catch (
|
|
1148
|
+
} catch (e8) {
|
|
1084
1149
|
}
|
|
1085
1150
|
void this.fulfillNextRequest();
|
|
1086
1151
|
}
|
|
@@ -1148,10 +1213,10 @@ var RtcStatsLogger = class {
|
|
|
1148
1213
|
`${XmaxLogger.localized("\u7D2F\u8BA1\u63A5\u6536\uFF1A", "Bytes Received: ")}${this.value(stats.bytesReceived, "bytes")}`
|
|
1149
1214
|
])];
|
|
1150
1215
|
const local = stats.localStatistics;
|
|
1151
|
-
if (_optionalChain([local, 'optionalAccess',
|
|
1216
|
+
if (_optionalChain([local, 'optionalAccess', _42 => _42.audio])) {
|
|
1152
1217
|
blocks.push(this.audioBlock("\u672C\u5730\u97F3\u9891\u53D1\u9001 (Local Audio Uplink)", local.audio, false));
|
|
1153
1218
|
}
|
|
1154
|
-
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess',
|
|
1219
|
+
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _43 => _43.video]), () => ( []))) {
|
|
1155
1220
|
blocks.push(this.videoBlock("\u672C\u5730\u89C6\u9891\u53D1\u9001 (Local Video Uplink)", video, false));
|
|
1156
1221
|
}
|
|
1157
1222
|
for (const remote of _nullishCoalesce(stats.remoteStatistics, () => ( []))) {
|
|
@@ -1239,6 +1304,33 @@ var RtcStatsLogger = class {
|
|
|
1239
1304
|
}
|
|
1240
1305
|
};
|
|
1241
1306
|
|
|
1307
|
+
// src/Foundation/RTC/RtcVideoOrientation.ts
|
|
1308
|
+
function shouldTransposeRtcVideoSize(environment) {
|
|
1309
|
+
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _44 => _44.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
|
|
1310
|
+
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _45 => _45.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
|
|
1311
|
+
const mobile = /Android|webOS|iPhone|iPad|iPod|Mobile/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
|
|
1312
|
+
if (!mobile) {
|
|
1313
|
+
return false;
|
|
1314
|
+
}
|
|
1315
|
+
const orientationType = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _46 => _46.orientationType]), () => ( (typeof window === "undefined" ? void 0 : _optionalChain([window, 'access', _47 => _47.screen, 'optionalAccess', _48 => _48.orientation, 'optionalAccess', _49 => _49.type]))));
|
|
1316
|
+
if (orientationType !== void 0) {
|
|
1317
|
+
return orientationType.includes("portrait");
|
|
1318
|
+
}
|
|
1319
|
+
const degrees = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _50 => _50.orientationDegrees]), () => ( (typeof window === "undefined" ? void 0 : window.orientation)));
|
|
1320
|
+
return degrees === 0 || degrees === 180;
|
|
1321
|
+
}
|
|
1322
|
+
function rtcOrientedVideoSize(size, environment) {
|
|
1323
|
+
return shouldTransposeRtcVideoSize(environment) ? { width: size.height, height: size.width } : size;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// src/Foundation/RTC/RemoteAudioVolumeControl.ts
|
|
1327
|
+
function canControlRemoteAudioVolume(environment) {
|
|
1328
|
+
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _51 => _51.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
|
|
1329
|
+
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _52 => _52.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
|
|
1330
|
+
const ios = /iPhone|iPad|iPod/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
|
|
1331
|
+
return !ios;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1242
1334
|
// src/Foundation/RTC/RtcManager.ts
|
|
1243
1335
|
var RTC_EVENT = {
|
|
1244
1336
|
remoteVideoAvailable: "remote-video-available",
|
|
@@ -1313,18 +1405,18 @@ var RtcManager = class {
|
|
|
1313
1405
|
this.isCapturing = false;
|
|
1314
1406
|
this.isAudioCapturing = false;
|
|
1315
1407
|
this.isInRoom = false;
|
|
1316
|
-
_optionalChain([this, 'access',
|
|
1408
|
+
_optionalChain([this, 'access', _53 => _53.removeStatsListeners, 'optionalCall', _54 => _54()]);
|
|
1317
1409
|
this.removeStatsListeners = void 0;
|
|
1318
1410
|
if (!lease) {
|
|
1319
1411
|
return;
|
|
1320
1412
|
}
|
|
1321
1413
|
try {
|
|
1322
1414
|
await lease.engine.stopLocalAudio();
|
|
1323
|
-
} catch (
|
|
1415
|
+
} catch (e9) {
|
|
1324
1416
|
}
|
|
1325
1417
|
try {
|
|
1326
1418
|
await lease.engine.stopLocalVideo();
|
|
1327
|
-
} catch (
|
|
1419
|
+
} catch (e10) {
|
|
1328
1420
|
}
|
|
1329
1421
|
this.engineManager.release(lease);
|
|
1330
1422
|
}
|
|
@@ -1343,13 +1435,17 @@ var RtcManager = class {
|
|
|
1343
1435
|
);
|
|
1344
1436
|
}
|
|
1345
1437
|
try {
|
|
1438
|
+
const captureSize = rtcOrientedVideoSize({
|
|
1439
|
+
width: options.width,
|
|
1440
|
+
height: options.height
|
|
1441
|
+
});
|
|
1346
1442
|
await engine.startLocalVideo({
|
|
1347
1443
|
publish: false,
|
|
1348
1444
|
option: {
|
|
1349
1445
|
useFrontCamera: options.position === "front" /* front */,
|
|
1350
1446
|
profile: {
|
|
1351
|
-
width:
|
|
1352
|
-
height:
|
|
1447
|
+
width: captureSize.width,
|
|
1448
|
+
height: captureSize.height,
|
|
1353
1449
|
frameRate: options.frameRate,
|
|
1354
1450
|
bitrate: CAPTURE_PLACEHOLDER_BITRATE
|
|
1355
1451
|
}
|
|
@@ -1402,7 +1498,7 @@ var RtcManager = class {
|
|
|
1402
1498
|
* 停止摄像头采集;引擎未初始化或采集未启动时不产生效果。
|
|
1403
1499
|
*/
|
|
1404
1500
|
async stopCameraCapture() {
|
|
1405
|
-
const engine = _optionalChain([this, 'access',
|
|
1501
|
+
const engine = _optionalChain([this, 'access', _55 => _55.lease, 'optionalAccess', _56 => _56.engine]);
|
|
1406
1502
|
this.isCapturing = false;
|
|
1407
1503
|
if (!engine) {
|
|
1408
1504
|
return;
|
|
@@ -1452,7 +1548,7 @@ var RtcManager = class {
|
|
|
1452
1548
|
* 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
|
|
1453
1549
|
*/
|
|
1454
1550
|
async leaveRoom() {
|
|
1455
|
-
const engine = _optionalChain([this, 'access',
|
|
1551
|
+
const engine = _optionalChain([this, 'access', _57 => _57.lease, 'optionalAccess', _58 => _58.engine]);
|
|
1456
1552
|
if (!engine || !this.isInRoom) {
|
|
1457
1553
|
return;
|
|
1458
1554
|
}
|
|
@@ -1469,7 +1565,7 @@ var RtcManager = class {
|
|
|
1469
1565
|
/**
|
|
1470
1566
|
* 配置本地视频编码参数。
|
|
1471
1567
|
*
|
|
1472
|
-
* TRTC 只接受单一目标码率,以 `
|
|
1568
|
+
* TRTC 只接受单一目标码率,以 `minimumBitrate`(流畅优先档)作为目标码率;
|
|
1473
1569
|
* 编码策略偏好映射为 TRTC 弱网偏好。
|
|
1474
1570
|
*
|
|
1475
1571
|
* @throws 摄像头采集未启动或编码参数配置失败时抛出错误。
|
|
@@ -1483,13 +1579,17 @@ var RtcManager = class {
|
|
|
1483
1579
|
);
|
|
1484
1580
|
}
|
|
1485
1581
|
try {
|
|
1582
|
+
const encodingSize = rtcOrientedVideoSize({
|
|
1583
|
+
width: configuration.width,
|
|
1584
|
+
height: configuration.height
|
|
1585
|
+
});
|
|
1486
1586
|
await engine.updateLocalVideo({
|
|
1487
1587
|
option: {
|
|
1488
1588
|
profile: {
|
|
1489
|
-
width:
|
|
1490
|
-
height:
|
|
1589
|
+
width: encodingSize.width,
|
|
1590
|
+
height: encodingSize.height,
|
|
1491
1591
|
frameRate: configuration.frameRate,
|
|
1492
|
-
bitrate: configuration.
|
|
1592
|
+
bitrate: configuration.minimumBitrate
|
|
1493
1593
|
},
|
|
1494
1594
|
qosPreference: QOS_PREFERENCE_MAP[configuration.encoderPreference]
|
|
1495
1595
|
}
|
|
@@ -1521,7 +1621,7 @@ var RtcManager = class {
|
|
|
1521
1621
|
* 停止发布本地视频流;采集保持运行,本地预览不受影响。
|
|
1522
1622
|
*/
|
|
1523
1623
|
async unpublishLocalVideo() {
|
|
1524
|
-
const engine = _optionalChain([this, 'access',
|
|
1624
|
+
const engine = _optionalChain([this, 'access', _59 => _59.lease, 'optionalAccess', _60 => _60.engine]);
|
|
1525
1625
|
if (!engine || !this.isCapturing) {
|
|
1526
1626
|
return;
|
|
1527
1627
|
}
|
|
@@ -1553,7 +1653,7 @@ var RtcManager = class {
|
|
|
1553
1653
|
* 停止发布本地音频流;麦克风采集保持运行。
|
|
1554
1654
|
*/
|
|
1555
1655
|
async unpublishLocalAudio() {
|
|
1556
|
-
const engine = _optionalChain([this, 'access',
|
|
1656
|
+
const engine = _optionalChain([this, 'access', _61 => _61.lease, 'optionalAccess', _62 => _62.engine]);
|
|
1557
1657
|
if (!engine || !this.isAudioCapturing) {
|
|
1558
1658
|
return;
|
|
1559
1659
|
}
|
|
@@ -1607,14 +1707,34 @@ var RtcManager = class {
|
|
|
1607
1707
|
throw this.mapError(error);
|
|
1608
1708
|
}
|
|
1609
1709
|
}
|
|
1710
|
+
/**
|
|
1711
|
+
* 当前平台是否支持远端音量控制(iOS Safari/WKWebView 不支持)。
|
|
1712
|
+
*/
|
|
1713
|
+
get supportsRemoteAudioVolumeControl() {
|
|
1714
|
+
return canControlRemoteAudioVolume();
|
|
1715
|
+
}
|
|
1610
1716
|
/**
|
|
1611
1717
|
* 设置指定远端用户的音频播放音量。
|
|
1612
1718
|
*
|
|
1719
|
+
* iOS Safari/WKWebView 不允许 JS 修改媒体元素音量(TRTC 官方标注
|
|
1720
|
+
* `setRemoteAudioVolume` 不支持 iOS Safari),该平台上降级为
|
|
1721
|
+
* 播放/静音二值控制:音量为 0 时停止播放该路音频,非 0 时恢复播放;
|
|
1722
|
+
* 恢复播放需要重新拉流,会有短暂缓冲。
|
|
1723
|
+
*
|
|
1613
1724
|
* @param volume 音量,取值范围为 `0...100`,越界时收敛到边界。
|
|
1614
1725
|
*/
|
|
1615
1726
|
setRemoteAudioVolume(volume, userID) {
|
|
1616
1727
|
const engine = this.requireEngine();
|
|
1617
1728
|
const normalized = Math.min(Math.max(Math.round(volume), 0), 100);
|
|
1729
|
+
if (!canControlRemoteAudioVolume()) {
|
|
1730
|
+
void engine.muteRemoteAudio(userID, normalized === 0).catch((error) => {
|
|
1731
|
+
XmaxLogger.rtc.warning(
|
|
1732
|
+
() => `\u8FDC\u7AEF\u97F3\u9891\u64AD\u653E\u72B6\u6001\u5207\u6362\u5931\u8D25 (Failed to Toggle Remote Audio Playback)
|
|
1733
|
+
\u2514\u2500 ${XmaxLogger.localized("\u539F\u56E0\uFF1A", "Reason: ")}${XmaxError.from(error).message}`
|
|
1734
|
+
);
|
|
1735
|
+
});
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1618
1738
|
engine.setRemoteAudioVolume(userID, normalized);
|
|
1619
1739
|
}
|
|
1620
1740
|
/**
|
|
@@ -1654,19 +1774,19 @@ var RtcManager = class {
|
|
|
1654
1774
|
registerEventBridge(engine) {
|
|
1655
1775
|
const source = engine;
|
|
1656
1776
|
const onStatistics = (stats) => {
|
|
1657
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
1777
|
+
if (this.isInRoom && _optionalChain([this, 'access', _63 => _63.lease, 'optionalAccess', _64 => _64.engine]) === engine) {
|
|
1658
1778
|
RtcStatsLogger.logStatistics(stats);
|
|
1659
|
-
const video = _optionalChain([stats, 'access',
|
|
1779
|
+
const video = _optionalChain([stats, 'access', _65 => _65.localStatistics, 'optionalAccess', _66 => _66.video, 'optionalAccess', _67 => _67.find, 'call', _68 => _68((item) => item.videoType === "big")]);
|
|
1660
1780
|
const valid = (value, minimum) => typeof value === "number" && Number.isFinite(value) && value >= minimum ? value : void 0;
|
|
1661
|
-
_optionalChain([this, 'access',
|
|
1781
|
+
_optionalChain([this, 'access', _69 => _69.eventListener, 'optionalAccess', _70 => _70.onLocalVideoStatistics, 'optionalCall', _71 => _71(video ? Object.freeze({
|
|
1662
1782
|
width: valid(video.width, 1),
|
|
1663
1783
|
height: valid(video.height, 1),
|
|
1664
1784
|
frameRate: valid(video.frameRate, 0),
|
|
1665
1785
|
bitrateKbps: valid(video.bitrate, 0)
|
|
1666
1786
|
}) : void 0)]);
|
|
1667
|
-
_optionalChain([this, 'access',
|
|
1787
|
+
_optionalChain([this, 'access', _72 => _72.eventListener, 'optionalAccess', _73 => _73.onRemoteVideoStatistics, 'optionalCall', _74 => _74(Object.freeze(
|
|
1668
1788
|
(_nullishCoalesce(stats.remoteStatistics, () => ( []))).flatMap((remote) => {
|
|
1669
|
-
const video2 = _optionalChain([remote, 'access',
|
|
1789
|
+
const video2 = _optionalChain([remote, 'access', _75 => _75.video, 'optionalAccess', _76 => _76.find, 'call', _77 => _77((item) => item.videoType === "big")]);
|
|
1670
1790
|
if (!video2) {
|
|
1671
1791
|
return [];
|
|
1672
1792
|
}
|
|
@@ -1688,11 +1808,11 @@ var RtcManager = class {
|
|
|
1688
1808
|
}
|
|
1689
1809
|
};
|
|
1690
1810
|
const onNetworkQuality = (stats) => {
|
|
1691
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
1811
|
+
if (this.isInRoom && _optionalChain([this, 'access', _78 => _78.lease, 'optionalAccess', _79 => _79.engine]) === engine) {
|
|
1692
1812
|
RtcStatsLogger.logNetworkQuality(stats);
|
|
1693
1813
|
const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
|
|
1694
1814
|
const rtt = (value) => Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1695
|
-
_optionalChain([this, 'access',
|
|
1815
|
+
_optionalChain([this, 'access', _80 => _80.eventListener, 'optionalAccess', _81 => _81.onNetworkStatistics, 'optionalCall', _82 => _82(Object.freeze({
|
|
1696
1816
|
uplinkQuality: quality(stats.uplinkNetworkQuality),
|
|
1697
1817
|
downlinkQuality: quality(stats.downlinkNetworkQuality),
|
|
1698
1818
|
uplinkRttMs: rtt(stats.uplinkRTT),
|
|
@@ -1710,13 +1830,13 @@ var RtcManager = class {
|
|
|
1710
1830
|
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
1711
1831
|
return;
|
|
1712
1832
|
}
|
|
1713
|
-
_optionalChain([this, 'access',
|
|
1833
|
+
_optionalChain([this, 'access', _83 => _83.eventListener, 'optionalAccess', _84 => _84.onRemoteVideoPublished, 'call', _85 => _85(event.userId, true)]);
|
|
1714
1834
|
});
|
|
1715
1835
|
source.on(RTC_EVENT.remoteVideoUnavailable, (event) => {
|
|
1716
1836
|
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
1717
1837
|
return;
|
|
1718
1838
|
}
|
|
1719
|
-
_optionalChain([this, 'access',
|
|
1839
|
+
_optionalChain([this, 'access', _86 => _86.eventListener, 'optionalAccess', _87 => _87.onRemoteVideoPublished, 'call', _88 => _88(event.userId, false)]);
|
|
1720
1840
|
});
|
|
1721
1841
|
source.on(RTC_EVENT.customMessage, (event) => {
|
|
1722
1842
|
if (event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
|
|
@@ -1725,18 +1845,18 @@ var RtcManager = class {
|
|
|
1725
1845
|
let message;
|
|
1726
1846
|
try {
|
|
1727
1847
|
message = new TextDecoder().decode(event.data);
|
|
1728
|
-
} catch (
|
|
1848
|
+
} catch (e11) {
|
|
1729
1849
|
XmaxLogger.rtc.warning(() => "\u81EA\u5B9A\u4E49\u6D88\u606F\u89E3\u7801\u5931\u8D25 (Failed to Decode Custom Message)");
|
|
1730
1850
|
return;
|
|
1731
1851
|
}
|
|
1732
|
-
_optionalChain([this, 'access',
|
|
1852
|
+
_optionalChain([this, 'access', _89 => _89.eventListener, 'optionalAccess', _90 => _90.onCustomMessageReceived, 'call', _91 => _91(event.userId, message)]);
|
|
1733
1853
|
});
|
|
1734
1854
|
}
|
|
1735
1855
|
/**
|
|
1736
1856
|
* 返回当前引擎实例;未初始化时抛出错误。
|
|
1737
1857
|
*/
|
|
1738
1858
|
requireEngine() {
|
|
1739
|
-
const engine = _optionalChain([this, 'access',
|
|
1859
|
+
const engine = _optionalChain([this, 'access', _92 => _92.lease, 'optionalAccess', _93 => _93.engine]);
|
|
1740
1860
|
if (!engine) {
|
|
1741
1861
|
throw new XmaxError(
|
|
1742
1862
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -1753,8 +1873,8 @@ var RtcManager = class {
|
|
|
1753
1873
|
return error;
|
|
1754
1874
|
}
|
|
1755
1875
|
const rtcError = error;
|
|
1756
|
-
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess',
|
|
1757
|
-
const message = typeof _optionalChain([rtcError, 'optionalAccess',
|
|
1876
|
+
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess', _94 => _94.originError, 'optionalAccess', _95 => _95.name]), () => ( ""));
|
|
1877
|
+
const message = typeof _optionalChain([rtcError, 'optionalAccess', _96 => _96.message]) === "string" && rtcError.message.trim().length > 0 ? rtcError.message.trim() : String(error);
|
|
1758
1878
|
if (originName === "NotAllowedError" || originName === "SecurityError" || /NotAllowed/i.test(message)) {
|
|
1759
1879
|
return new XmaxError("CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */, message);
|
|
1760
1880
|
}
|
|
@@ -1766,74 +1886,25 @@ var RtcManager = class {
|
|
|
1766
1886
|
};
|
|
1767
1887
|
|
|
1768
1888
|
// src/Foundation/Media/Camera/CameraFrameValidator.ts
|
|
1769
|
-
var
|
|
1770
|
-
var TIMEOUT_MS = 2e3;
|
|
1771
|
-
var CameraFrameValidator = class {
|
|
1772
|
-
/**
|
|
1773
|
-
* 单帧中央区域亮度达标即放行,不等待连续帧或曝光稳定。
|
|
1774
|
-
*/
|
|
1775
|
-
accept(pixels) {
|
|
1776
|
-
const size = pixels.length / 4;
|
|
1777
|
-
if (!size || !Number.isInteger(size)) return false;
|
|
1778
|
-
const histogram = new Uint32Array(256);
|
|
1779
|
-
let total = 0;
|
|
1780
|
-
let dark = 0;
|
|
1781
|
-
for (let i = 0; i < pixels.length; i += 4) {
|
|
1782
|
-
const luminance = Math.round(0.2126 * pixels[i] + 0.7152 * pixels[i + 1] + 0.0722 * pixels[i + 2]);
|
|
1783
|
-
histogram[luminance] = histogram[luminance] + 1;
|
|
1784
|
-
total += luminance;
|
|
1785
|
-
if (luminance < 12) dark++;
|
|
1786
|
-
}
|
|
1787
|
-
let median = 0;
|
|
1788
|
-
let accumulated = 0;
|
|
1789
|
-
for (; median < 255; median++) {
|
|
1790
|
-
accumulated += histogram[median];
|
|
1791
|
-
if (accumulated >= size / 2) break;
|
|
1792
|
-
}
|
|
1793
|
-
const mean = total / size;
|
|
1794
|
-
return mean >= 24 && median >= 18 && dark / size <= 0.75;
|
|
1795
|
-
}
|
|
1796
|
-
};
|
|
1889
|
+
var CAMERA_WARMUP_MS = 200;
|
|
1797
1890
|
function waitForValidCameraFrame(track, signal) {
|
|
1798
1891
|
return new Promise((resolve, reject) => {
|
|
1799
|
-
let
|
|
1800
|
-
let
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
const gate = new CameraFrameValidator();
|
|
1806
|
-
const finish = (result = "valid") => {
|
|
1807
|
-
if (finished) return;
|
|
1808
|
-
finished = true;
|
|
1809
|
-
clearTimeout(timeout);
|
|
1810
|
-
clearTimeout(poll);
|
|
1811
|
-
if (video) {
|
|
1812
|
-
if (frameCallback !== void 0) video.cancelVideoFrameCallback(frameCallback);
|
|
1813
|
-
video.pause();
|
|
1814
|
-
video.srcObject = null;
|
|
1815
|
-
video.remove();
|
|
1816
|
-
}
|
|
1892
|
+
let timer;
|
|
1893
|
+
let settled = false;
|
|
1894
|
+
const finish = (error) => {
|
|
1895
|
+
if (settled) return;
|
|
1896
|
+
settled = true;
|
|
1897
|
+
clearTimeout(timer);
|
|
1817
1898
|
signal.removeEventListener("abort", abort);
|
|
1818
1899
|
track.removeEventListener("ended", ended);
|
|
1819
|
-
if (
|
|
1820
|
-
|
|
1821
|
-
reject(result);
|
|
1900
|
+
if (error) {
|
|
1901
|
+
reject(error);
|
|
1822
1902
|
} else {
|
|
1823
|
-
if (result === "timeout") {
|
|
1824
|
-
XmaxLogger.media.warning(() => XmaxLogger.localized(
|
|
1825
|
-
"\u76F8\u673A\u4EAE\u5EA6\u68C0\u67E5\u8D85\u65F6\uFF0C\u6309\u5F53\u524D\u753B\u9762\u7EE7\u7EED\u751F\u6210 (Camera Frame Validation Timed Out; Continuing)\n\u2514\u2500 \u672A\u83B7\u5F97\u4EAE\u5EA6\u5408\u683C\u5E27\uFF0C\u4E0D\u518D\u7B49\u5F85\u3002",
|
|
1826
|
-
"Camera Frame Validation Timed Out; Continuing\n\u2514\u2500 No sufficiently bright frame received; proceeding without further waiting."
|
|
1827
|
-
));
|
|
1828
|
-
} else {
|
|
1829
|
-
XmaxLogger.media.info(() => `\u76F8\u673A\u66DD\u5149\u68C0\u67E5\u901A\u8FC7 (Camera Exposure Ready)
|
|
1830
|
-
\u2514\u2500 ${Math.round(performance.now() - started)} ms`);
|
|
1831
|
-
}
|
|
1832
1903
|
resolve();
|
|
1833
1904
|
}
|
|
1834
1905
|
};
|
|
1835
|
-
const abort = () => finish(new XmaxError("CANCELLED" /* cancelled */, "Camera
|
|
1836
|
-
const ended = () => finish(new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera track ended before
|
|
1906
|
+
const abort = () => finish(new XmaxError("CANCELLED" /* cancelled */, "Camera warmup cancelled"));
|
|
1907
|
+
const ended = () => finish(new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera track ended before warmup completed"));
|
|
1837
1908
|
signal.addEventListener("abort", abort, { once: true });
|
|
1838
1909
|
track.addEventListener("ended", ended, { once: true });
|
|
1839
1910
|
if (signal.aborted) {
|
|
@@ -1844,70 +1915,7 @@ function waitForValidCameraFrame(track, signal) {
|
|
|
1844
1915
|
ended();
|
|
1845
1916
|
return;
|
|
1846
1917
|
}
|
|
1847
|
-
|
|
1848
|
-
video = document.createElement("video");
|
|
1849
|
-
video.muted = true;
|
|
1850
|
-
video.autoplay = true;
|
|
1851
|
-
video.playsInline = true;
|
|
1852
|
-
video.setAttribute("aria-hidden", "true");
|
|
1853
|
-
video.style.cssText = "position:fixed;left:0;top:0;width:1px;height:1px;opacity:0;pointer-events:none;";
|
|
1854
|
-
const canvas = document.createElement("canvas");
|
|
1855
|
-
canvas.width = 64;
|
|
1856
|
-
canvas.height = 48;
|
|
1857
|
-
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
1858
|
-
if (!context) throw new Error("Camera exposure sampling requires a 2D canvas");
|
|
1859
|
-
video.srcObject = new MediaStream([track]);
|
|
1860
|
-
document.body.appendChild(video);
|
|
1861
|
-
const source = video;
|
|
1862
|
-
let lastFrameTime = -Infinity;
|
|
1863
|
-
const sample = (mediaTime) => {
|
|
1864
|
-
if (source.readyState < 2 || !source.videoWidth || !source.videoHeight || track.muted || !track.enabled) {
|
|
1865
|
-
return;
|
|
1866
|
-
}
|
|
1867
|
-
if (mediaTime === lastFrameTime) return;
|
|
1868
|
-
lastFrameTime = mediaTime;
|
|
1869
|
-
const width = source.videoWidth;
|
|
1870
|
-
const height = source.videoHeight;
|
|
1871
|
-
context.drawImage(source, width * 0.2, height * 0.2, width * 0.6, height * 0.6, 0, 0, 64, 48);
|
|
1872
|
-
if (gate.accept(context.getImageData(0, 0, 64, 48).data)) finish();
|
|
1873
|
-
};
|
|
1874
|
-
const fail = (error) => finish(new XmaxError(
|
|
1875
|
-
"MEDIA_ERROR" /* mediaError */,
|
|
1876
|
-
`Camera exposure check failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1877
|
-
));
|
|
1878
|
-
const schedule = () => {
|
|
1879
|
-
if (finished) return;
|
|
1880
|
-
if (typeof source.requestVideoFrameCallback === "function") {
|
|
1881
|
-
frameCallback = source.requestVideoFrameCallback((_now, metadata) => {
|
|
1882
|
-
frameCallback = void 0;
|
|
1883
|
-
try {
|
|
1884
|
-
sample(metadata.mediaTime);
|
|
1885
|
-
schedule();
|
|
1886
|
-
} catch (error) {
|
|
1887
|
-
fail(error);
|
|
1888
|
-
}
|
|
1889
|
-
});
|
|
1890
|
-
} else {
|
|
1891
|
-
poll = setTimeout(() => {
|
|
1892
|
-
try {
|
|
1893
|
-
const frameTime = typeof source.getVideoPlaybackQuality === "function" ? source.getVideoPlaybackQuality().totalVideoFrames : source.currentTime;
|
|
1894
|
-
sample(frameTime);
|
|
1895
|
-
schedule();
|
|
1896
|
-
} catch (error) {
|
|
1897
|
-
fail(error);
|
|
1898
|
-
}
|
|
1899
|
-
}, FALLBACK_POLL_INTERVAL_MS);
|
|
1900
|
-
}
|
|
1901
|
-
};
|
|
1902
|
-
timeout = setTimeout(() => finish("timeout"), TIMEOUT_MS);
|
|
1903
|
-
XmaxLogger.media.info(() => "\u7B49\u5F85\u9996\u5F20\u4EAE\u5EA6\u5408\u683C\u5E27 (Waiting for the First Sufficiently Bright Frame)");
|
|
1904
|
-
void source.play().then(schedule, fail);
|
|
1905
|
-
} catch (error) {
|
|
1906
|
-
finish(new XmaxError(
|
|
1907
|
-
"MEDIA_ERROR" /* mediaError */,
|
|
1908
|
-
`Camera exposure check failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1909
|
-
));
|
|
1910
|
-
}
|
|
1918
|
+
timer = setTimeout(() => finish(), CAMERA_WARMUP_MS);
|
|
1911
1919
|
});
|
|
1912
1920
|
}
|
|
1913
1921
|
|
|
@@ -1937,7 +1945,7 @@ var PermissionManager = class {
|
|
|
1937
1945
|
* @param deniedCode 权限被拒绝时抛出的错误码。
|
|
1938
1946
|
*/
|
|
1939
1947
|
async ensurePermission(name, deniedCode) {
|
|
1940
|
-
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access',
|
|
1948
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _97 => _97.mediaDevices, 'optionalAccess', _98 => _98.getUserMedia])) {
|
|
1941
1949
|
throw new XmaxError(
|
|
1942
1950
|
deniedCode,
|
|
1943
1951
|
"This browser does not support media capture (getUserMedia)"
|
|
@@ -1945,7 +1953,7 @@ var PermissionManager = class {
|
|
|
1945
1953
|
}
|
|
1946
1954
|
try {
|
|
1947
1955
|
const permissions = navigator.permissions;
|
|
1948
|
-
if (!_optionalChain([permissions, 'optionalAccess',
|
|
1956
|
+
if (!_optionalChain([permissions, 'optionalAccess', _99 => _99.query])) {
|
|
1949
1957
|
return;
|
|
1950
1958
|
}
|
|
1951
1959
|
const status = await permissions.query({
|
|
@@ -2125,10 +2133,10 @@ var _CameraController = class _CameraController {
|
|
|
2125
2133
|
*/
|
|
2126
2134
|
__publicField(this, "storedUseMicrophone", false);
|
|
2127
2135
|
__publicField(this, "storedFrameValidationEnabled", true);
|
|
2128
|
-
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2129
|
-
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2130
|
-
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2131
|
-
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2136
|
+
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _100 => _100.permissionManager]), () => ( new PermissionManager()));
|
|
2137
|
+
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _101 => _101.rtcManager]), () => ( new RtcManager()));
|
|
2138
|
+
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _102 => _102.mediaService]), () => ( new MediaService()));
|
|
2139
|
+
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _103 => _103.errorListener]), () => ( (() => {
|
|
2132
2140
|
})));
|
|
2133
2141
|
}
|
|
2134
2142
|
/**
|
|
@@ -2144,23 +2152,23 @@ var _CameraController = class _CameraController {
|
|
|
2144
2152
|
return this.activeTrack !== void 0 && this.storedUseMicrophone;
|
|
2145
2153
|
}
|
|
2146
2154
|
/**
|
|
2147
|
-
*
|
|
2155
|
+
* 当前活动相机流是否启用发布前预热等待;没有活动流时为 false。
|
|
2148
2156
|
*/
|
|
2149
2157
|
get isFrameValidationEnabled() {
|
|
2150
2158
|
return this.activeTrack !== void 0 && this.storedFrameValidationEnabled;
|
|
2151
2159
|
}
|
|
2152
2160
|
/**
|
|
2153
|
-
*
|
|
2161
|
+
* 等待当前轨道预热完成(固定 200ms);禁用时跳过,取消或轨道被替换时拒绝。
|
|
2154
2162
|
*/
|
|
2155
2163
|
async waitForValidCameraFrame(signal) {
|
|
2156
2164
|
const track = this.activeTrack;
|
|
2157
|
-
const mediaTrack = _optionalChain([track, 'optionalAccess',
|
|
2165
|
+
const mediaTrack = _optionalChain([track, 'optionalAccess', _104 => _104.mediaStreamTrack]);
|
|
2158
2166
|
if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
|
|
2159
2167
|
if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
|
|
2160
2168
|
if (!this.isFrameValidationEnabled) return;
|
|
2161
2169
|
await waitForValidCameraFrame(mediaTrack, signal);
|
|
2162
2170
|
if (this.activeTrack !== track || track.mediaStreamTrack !== mediaTrack) {
|
|
2163
|
-
throw new XmaxError("CANCELLED" /* cancelled */, "Camera track changed during
|
|
2171
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Camera track changed during warmup");
|
|
2164
2172
|
}
|
|
2165
2173
|
}
|
|
2166
2174
|
/**
|
|
@@ -2179,7 +2187,7 @@ var _CameraController = class _CameraController {
|
|
|
2179
2187
|
* @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
|
|
2180
2188
|
* @param options.position 首次启动时使用的摄像头位置。
|
|
2181
2189
|
* @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
|
|
2182
|
-
* @param options.enableFrameValidation
|
|
2190
|
+
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
2183
2191
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
2184
2192
|
* @throws 已有活动相机流、格式无效、权限不足或采集启动失败时抛出错误。
|
|
2185
2193
|
*/
|
|
@@ -2254,7 +2262,7 @@ var _CameraController = class _CameraController {
|
|
|
2254
2262
|
*/
|
|
2255
2263
|
async switchCamera() {
|
|
2256
2264
|
const track = this.activeTrack;
|
|
2257
|
-
const position = _optionalChain([track, 'optionalAccess',
|
|
2265
|
+
const position = _optionalChain([track, 'optionalAccess', _105 => _105.position]);
|
|
2258
2266
|
if (!track || !position) {
|
|
2259
2267
|
throw new XmaxError(
|
|
2260
2268
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -2272,7 +2280,7 @@ var _CameraController = class _CameraController {
|
|
|
2272
2280
|
}
|
|
2273
2281
|
this.previewStream.addTrack(mediaTrack);
|
|
2274
2282
|
}
|
|
2275
|
-
_optionalChain([this, 'access',
|
|
2283
|
+
_optionalChain([this, 'access', _106 => _106.previewMirrorApplier, 'optionalCall', _107 => _107(nextPosition === "front" /* front */)]);
|
|
2276
2284
|
this.observeMediaTrack(track, mediaTrack);
|
|
2277
2285
|
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
2278
2286
|
}
|
|
@@ -2528,12 +2536,13 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2528
2536
|
this.heartbeatVersion += 1;
|
|
2529
2537
|
}
|
|
2530
2538
|
/**
|
|
2531
|
-
*
|
|
2539
|
+
* 关闭指定实时会话;请求带 keepalive,页面卸载后仍能发出。
|
|
2532
2540
|
*/
|
|
2533
2541
|
async closeSession(sessionID) {
|
|
2534
2542
|
try {
|
|
2535
2543
|
await this.apiService.delete(
|
|
2536
|
-
`/session/${sessionID}
|
|
2544
|
+
`/session/${sessionID}`,
|
|
2545
|
+
{ keepalive: true }
|
|
2537
2546
|
);
|
|
2538
2547
|
} catch (error) {
|
|
2539
2548
|
throw XmaxError.from(error);
|
|
@@ -2554,7 +2563,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2554
2563
|
return;
|
|
2555
2564
|
}
|
|
2556
2565
|
_RealtimeSessionService.ensureSessionActive(session);
|
|
2557
|
-
_optionalChain([handlers, 'access',
|
|
2566
|
+
_optionalChain([handlers, 'access', _108 => _108.onRefresh, 'optionalCall', _109 => _109(session)]);
|
|
2558
2567
|
} catch (error) {
|
|
2559
2568
|
if (this.heartbeatVersion !== version) {
|
|
2560
2569
|
return;
|
|
@@ -2647,7 +2656,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2647
2656
|
if (typeof modelExtra === "string") {
|
|
2648
2657
|
try {
|
|
2649
2658
|
return JSON.parse(modelExtra);
|
|
2650
|
-
} catch (
|
|
2659
|
+
} catch (e12) {
|
|
2651
2660
|
return void 0;
|
|
2652
2661
|
}
|
|
2653
2662
|
}
|
|
@@ -2660,7 +2669,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2660
2669
|
* 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
|
|
2661
2670
|
*/
|
|
2662
2671
|
static nonEmpty(value) {
|
|
2663
|
-
const normalized = _optionalChain([value, 'optionalAccess',
|
|
2672
|
+
const normalized = _optionalChain([value, 'optionalAccess', _110 => _110.trim, 'call', _111 => _111()]);
|
|
2664
2673
|
return normalized || void 0;
|
|
2665
2674
|
}
|
|
2666
2675
|
};
|
|
@@ -2732,7 +2741,7 @@ var RealtimeState = class {
|
|
|
2732
2741
|
* @param other 待比较的状态。
|
|
2733
2742
|
*/
|
|
2734
2743
|
equals(other) {
|
|
2735
|
-
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access',
|
|
2744
|
+
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access', _112 => _112.reason, 'optionalAccess', _113 => _113.kind]) === _optionalChain([other, 'access', _114 => _114.reason, 'optionalAccess', _115 => _115.kind]);
|
|
2736
2745
|
}
|
|
2737
2746
|
};
|
|
2738
2747
|
|
|
@@ -2901,7 +2910,7 @@ var RoomEvent = class _RoomEvent {
|
|
|
2901
2910
|
static encode(payload) {
|
|
2902
2911
|
try {
|
|
2903
2912
|
return JSON.stringify({ ...payload, runtime: RuntimeInfo.toJSON() });
|
|
2904
|
-
} catch (
|
|
2913
|
+
} catch (e13) {
|
|
2905
2914
|
throw new XmaxError(
|
|
2906
2915
|
"INTERNAL_ERROR" /* internalError */,
|
|
2907
2916
|
"Failed to encode RTC room event"
|
|
@@ -3023,7 +3032,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
3023
3032
|
let parsed;
|
|
3024
3033
|
try {
|
|
3025
3034
|
parsed = JSON.parse(message);
|
|
3026
|
-
} catch (
|
|
3035
|
+
} catch (e14) {
|
|
3027
3036
|
XmaxLogger.room.warning(() => "\u623F\u95F4\u6D88\u606F\u4E0D\u662F\u5408\u6CD5 JSON (Room Message Is Not Valid JSON)");
|
|
3028
3037
|
return void 0;
|
|
3029
3038
|
}
|
|
@@ -3054,7 +3063,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
3054
3063
|
const joined = parts.join("");
|
|
3055
3064
|
try {
|
|
3056
3065
|
return JSON.parse(joined);
|
|
3057
|
-
} catch (
|
|
3066
|
+
} catch (e15) {
|
|
3058
3067
|
XmaxLogger.room.warning(
|
|
3059
3068
|
() => `\u623F\u95F4\u6D88\u606F\u7EC4\u5305\u540E\u4E0D\u662F\u5408\u6CD5 JSON (Reassembled Message Is Not Valid JSON)
|
|
3060
3069
|
\u2514\u2500 eventId: ${chunk.eventId}`
|
|
@@ -3352,7 +3361,7 @@ var RoomController = class {
|
|
|
3352
3361
|
if (targetUserID && ownUserID && targetUserID !== ownUserID) {
|
|
3353
3362
|
return;
|
|
3354
3363
|
}
|
|
3355
|
-
_optionalChain([this, 'access',
|
|
3364
|
+
_optionalChain([this, 'access', _116 => _116.listener, 'optionalAccess', _117 => _117.onRoomMessage, 'call', _118 => _118(senderUserID, message)]);
|
|
3356
3365
|
}
|
|
3357
3366
|
/**
|
|
3358
3367
|
* 发送房间信令并输出日志。
|
|
@@ -3597,18 +3606,18 @@ var StreamController = class {
|
|
|
3597
3606
|
this.rtcManager.setEventListener({
|
|
3598
3607
|
onNetworkStatistics: (statistics) => {
|
|
3599
3608
|
if (this.state.localVideoPublished) {
|
|
3600
|
-
_optionalChain([this, 'access',
|
|
3609
|
+
_optionalChain([this, 'access', _119 => _119.networkStatisticsListener, 'optionalCall', _120 => _120(statistics)]);
|
|
3601
3610
|
}
|
|
3602
3611
|
},
|
|
3603
3612
|
onRemoteVideoStatistics: (statistics) => {
|
|
3604
|
-
const userID = _optionalChain([this, 'access',
|
|
3605
|
-
_optionalChain([this, 'access',
|
|
3613
|
+
const userID = _optionalChain([this, 'access', _121 => _121.state, 'access', _122 => _122.activeRemoteStream, 'optionalAccess', _123 => _123.userID]);
|
|
3614
|
+
_optionalChain([this, 'access', _124 => _124.remoteVideoStatisticsListener, 'optionalCall', _125 => _125(
|
|
3606
3615
|
userID ? statistics.find((item) => item.userID === userID) : void 0
|
|
3607
3616
|
)]);
|
|
3608
3617
|
},
|
|
3609
3618
|
onLocalVideoStatistics: (statistics) => {
|
|
3610
3619
|
if (this.state.localVideoPublished) {
|
|
3611
|
-
_optionalChain([this, 'access',
|
|
3620
|
+
_optionalChain([this, 'access', _126 => _126.localVideoStatisticsListener, 'optionalCall', _127 => _127(statistics)]);
|
|
3612
3621
|
}
|
|
3613
3622
|
},
|
|
3614
3623
|
onCustomMessageReceived: (senderUserID, message) => {
|
|
@@ -3680,7 +3689,7 @@ var StreamController = class {
|
|
|
3680
3689
|
() => `RTC \u623F\u95F4\u5DF2\u914D\u7F6E (RTC Room Configured)
|
|
3681
3690
|
\u2514\u2500 roomID: ${connection.roomID}, botID: ${_nullishCoalesce(connection.botID, () => ( "(\u672A\u8BBE\u7F6E)"))}`
|
|
3682
3691
|
);
|
|
3683
|
-
await _optionalChain([beforePublish, 'optionalCall',
|
|
3692
|
+
await _optionalChain([beforePublish, 'optionalCall', _128 => _128()]);
|
|
3684
3693
|
ensureActive();
|
|
3685
3694
|
await this.publishLocalStream(includeLocalAudio);
|
|
3686
3695
|
}
|
|
@@ -3751,7 +3760,7 @@ var StreamController = class {
|
|
|
3751
3760
|
this.rejectGenerationStart(taskID, mapped);
|
|
3752
3761
|
try {
|
|
3753
3762
|
this.roomController.stopGeneration(taskID);
|
|
3754
|
-
} catch (
|
|
3763
|
+
} catch (e16) {
|
|
3755
3764
|
}
|
|
3756
3765
|
throw mapped;
|
|
3757
3766
|
}
|
|
@@ -3840,7 +3849,7 @@ var StreamController = class {
|
|
|
3840
3849
|
*/
|
|
3841
3850
|
configureRoom(options) {
|
|
3842
3851
|
const roomID = options.roomID.trim();
|
|
3843
|
-
const botID = _nullishCoalesce(_optionalChain([options, 'access',
|
|
3852
|
+
const botID = _nullishCoalesce(_optionalChain([options, 'access', _129 => _129.botID, 'optionalAccess', _130 => _130.trim, 'call', _131 => _131()]), () => ( ""));
|
|
3844
3853
|
if (!roomID) {
|
|
3845
3854
|
throw new XmaxError(
|
|
3846
3855
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
@@ -3917,7 +3926,7 @@ var StreamController = class {
|
|
|
3917
3926
|
return;
|
|
3918
3927
|
}
|
|
3919
3928
|
this.state.subscribedRemoteUserIDs.delete(trimmedUserID);
|
|
3920
|
-
if (_optionalChain([this, 'access',
|
|
3929
|
+
if (_optionalChain([this, 'access', _132 => _132.state, 'access', _133 => _133.activeRemoteStream, 'optionalAccess', _134 => _134.userID]) === trimmedUserID) {
|
|
3921
3930
|
await this.unsubscribeRemoteAudio(trimmedUserID);
|
|
3922
3931
|
this.state.activeRemoteStream = void 0;
|
|
3923
3932
|
this.clearRemoteStream();
|
|
@@ -3993,14 +4002,23 @@ var StreamController = class {
|
|
|
3993
4002
|
}
|
|
3994
4003
|
}
|
|
3995
4004
|
/**
|
|
3996
|
-
*
|
|
4005
|
+
* 订阅远端音频并按平台能力应用当前音量。
|
|
4006
|
+
*
|
|
4007
|
+
* 支持音量控制的平台先设音量再订阅,避免以默认音量短暂出声;
|
|
4008
|
+
* iOS 上音量降级为播放/静音二值控制,必须先完成订阅(恢复播放)
|
|
4009
|
+
* 再按需静音,否则订阅的恢复播放会覆盖音量 0 的静音状态。
|
|
3997
4010
|
*/
|
|
3998
4011
|
async subscribeRemoteAudio(userID) {
|
|
3999
4012
|
if (this.state.subscribedRemoteAudioUserIDs.has(userID)) {
|
|
4000
4013
|
return;
|
|
4001
4014
|
}
|
|
4002
|
-
this.rtcManager.
|
|
4003
|
-
|
|
4015
|
+
if (this.rtcManager.supportsRemoteAudioVolumeControl) {
|
|
4016
|
+
this.rtcManager.setRemoteAudioVolume(this.remoteAudioVolumePercentage, userID);
|
|
4017
|
+
await this.rtcManager.subscribeRemoteAudio(userID, true);
|
|
4018
|
+
} else {
|
|
4019
|
+
await this.rtcManager.subscribeRemoteAudio(userID, true);
|
|
4020
|
+
this.rtcManager.setRemoteAudioVolume(this.remoteAudioVolumePercentage, userID);
|
|
4021
|
+
}
|
|
4004
4022
|
this.state.subscribedRemoteAudioUserIDs.add(userID);
|
|
4005
4023
|
}
|
|
4006
4024
|
/**
|
|
@@ -4077,7 +4095,7 @@ var StreamController = class {
|
|
|
4077
4095
|
*/
|
|
4078
4096
|
resolveGenerationStart(taskID) {
|
|
4079
4097
|
const waiter = this.state.generationWaiter;
|
|
4080
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
4098
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _135 => _135.taskID]) !== taskID) {
|
|
4081
4099
|
return;
|
|
4082
4100
|
}
|
|
4083
4101
|
this.state.generationWaiter = void 0;
|
|
@@ -4089,7 +4107,7 @@ var StreamController = class {
|
|
|
4089
4107
|
*/
|
|
4090
4108
|
rejectGenerationStart(taskID, error) {
|
|
4091
4109
|
const waiter = this.state.generationWaiter;
|
|
4092
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
4110
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _136 => _136.taskID]) !== taskID) {
|
|
4093
4111
|
return;
|
|
4094
4112
|
}
|
|
4095
4113
|
this.state.generationWaiter = void 0;
|
|
@@ -4100,7 +4118,7 @@ var StreamController = class {
|
|
|
4100
4118
|
* 通知渲染层清理远端生成流;失败仅记录日志。
|
|
4101
4119
|
*/
|
|
4102
4120
|
clearRemoteStream() {
|
|
4103
|
-
_optionalChain([this, 'access',
|
|
4121
|
+
_optionalChain([this, 'access', _137 => _137.remoteVideoStatisticsListener, 'optionalCall', _138 => _138(void 0)]);
|
|
4104
4122
|
try {
|
|
4105
4123
|
this.remoteStreamListener(null);
|
|
4106
4124
|
} catch (error) {
|
|
@@ -4371,7 +4389,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4371
4389
|
}
|
|
4372
4390
|
throw _RealtimeCoordinator.cancelledError();
|
|
4373
4391
|
}
|
|
4374
|
-
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access',
|
|
4392
|
+
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access', _139 => _139.termination, 'optionalAccess', _140 => _140.task]))), async () => ( await this.requestTermination(
|
|
4375
4393
|
_nullishCoalesce(operation.lease.failureScope, () => ( 0)) /* connection */,
|
|
4376
4394
|
void 0,
|
|
4377
4395
|
RealtimeReason.normal,
|
|
@@ -4500,7 +4518,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4500
4518
|
* 结束指定操作,释放操作准入场。
|
|
4501
4519
|
*/
|
|
4502
4520
|
finish(operation) {
|
|
4503
|
-
if (_optionalChain([this, 'access',
|
|
4521
|
+
if (_optionalChain([this, 'access', _141 => _141.activeOperation, 'optionalAccess', _142 => _142.id]) === operation.id) {
|
|
4504
4522
|
this.activeOperation = void 0;
|
|
4505
4523
|
}
|
|
4506
4524
|
}
|
|
@@ -4512,7 +4530,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4512
4530
|
return;
|
|
4513
4531
|
}
|
|
4514
4532
|
this.state = nextState;
|
|
4515
|
-
_optionalChain([this, 'access',
|
|
4533
|
+
_optionalChain([this, 'access', _143 => _143.stateListener, 'optionalCall', _144 => _144(nextState)]);
|
|
4516
4534
|
}
|
|
4517
4535
|
/**
|
|
4518
4536
|
* 构造统一的操作取消错误。
|
|
@@ -4588,17 +4606,25 @@ var RealtimeLaunchTimer = class {
|
|
|
4588
4606
|
this.notify();
|
|
4589
4607
|
return complete;
|
|
4590
4608
|
}
|
|
4609
|
+
/**
|
|
4610
|
+
* 开始等待用户授权系统媒体权限,返回授权决定时调用的记录函数。
|
|
4611
|
+
* 仅在系统弹出授权请求时使用;已授权或未弹窗不记录该阶段。
|
|
4612
|
+
*/
|
|
4613
|
+
startPermission() {
|
|
4614
|
+
return this.measure("permissionMs", performance.now());
|
|
4615
|
+
}
|
|
4591
4616
|
/**
|
|
4592
4617
|
* 开始会话与进房计时,返回连接阶段完成时调用的记录函数。
|
|
4618
|
+
* 相机预热等待计入连接耗时。
|
|
4593
4619
|
*/
|
|
4594
4620
|
startConnection() {
|
|
4595
4621
|
return this.measure("connectionMs", performance.now());
|
|
4596
4622
|
}
|
|
4597
4623
|
/**
|
|
4598
|
-
*
|
|
4624
|
+
* 开始发布本地流计时,返回发布完成时调用的记录函数。
|
|
4599
4625
|
*/
|
|
4600
|
-
|
|
4601
|
-
return this.measure("
|
|
4626
|
+
startPublish() {
|
|
4627
|
+
return this.measure("publishMs", performance.now());
|
|
4602
4628
|
}
|
|
4603
4629
|
/**
|
|
4604
4630
|
* 开始等待远端显示首帧;完成回调同时记录首帧耗时和实际总耗时。
|
|
@@ -4636,9 +4662,9 @@ var RealtimeLaunchTimer = class {
|
|
|
4636
4662
|
*/
|
|
4637
4663
|
notify() {
|
|
4638
4664
|
try {
|
|
4639
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
4665
|
+
void Promise.resolve(_optionalChain([this, 'access', _145 => _145.listener, 'optionalCall', _146 => _146(this.snapshot)])).catch(() => {
|
|
4640
4666
|
});
|
|
4641
|
-
} catch (
|
|
4667
|
+
} catch (e17) {
|
|
4642
4668
|
}
|
|
4643
4669
|
}
|
|
4644
4670
|
};
|
|
@@ -4664,7 +4690,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4664
4690
|
* 当前活动会话标识;尚未连接或清理完成后为空。
|
|
4665
4691
|
*/
|
|
4666
4692
|
get currentSessionID() {
|
|
4667
|
-
return _optionalChain([this, 'access',
|
|
4693
|
+
return _optionalChain([this, 'access', _147 => _147.activeSession, 'optionalAccess', _148 => _148.id]);
|
|
4668
4694
|
}
|
|
4669
4695
|
/**
|
|
4670
4696
|
* 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
|
|
@@ -4674,7 +4700,8 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4674
4700
|
}
|
|
4675
4701
|
/**
|
|
4676
4702
|
* 创建会话、配置编码、进房并发布本地媒体,启动心跳后返回远端占位流。
|
|
4677
|
-
* 进房结束即记录连接耗时;可选 beforePublish
|
|
4703
|
+
* 进房结束即记录连接耗时;可选 beforePublish 检查阻塞发布,计入连接耗时;
|
|
4704
|
+
* 发布本地流单独计时。
|
|
4678
4705
|
* @throws 会话、进房、发布失败或操作租约已失效时抛出错误,由上层统一清理。
|
|
4679
4706
|
*/
|
|
4680
4707
|
async connect(options) {
|
|
@@ -4701,15 +4728,17 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4701
4728
|
}
|
|
4702
4729
|
await streamController.setVideoEncoderConfig(videoFormat);
|
|
4703
4730
|
options.ensureCurrent();
|
|
4731
|
+
let completePublish;
|
|
4704
4732
|
await streamController.connect(connection, options.includeLocalAudio, () => {
|
|
4705
4733
|
options.ensureCurrent();
|
|
4706
4734
|
}, async () => {
|
|
4707
4735
|
options.ensureCurrent();
|
|
4736
|
+
await _optionalChain([options, 'access', _149 => _149.beforePublish, 'optionalCall', _150 => _150()]);
|
|
4708
4737
|
completeConnection();
|
|
4709
|
-
|
|
4710
|
-
await _optionalChain([options, 'access', _137 => _137.beforePublish, 'optionalCall', _138 => _138()]);
|
|
4738
|
+
completePublish = this.dependencies.timing.startPublish();
|
|
4711
4739
|
});
|
|
4712
4740
|
options.ensureCurrent();
|
|
4741
|
+
_optionalChain([completePublish, 'optionalCall', _151 => _151()]);
|
|
4713
4742
|
options.onPublished();
|
|
4714
4743
|
sessionService.startHeartbeat(session.id, {
|
|
4715
4744
|
onFailure: (sessionID, error) => {
|
|
@@ -4732,26 +4761,26 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4732
4761
|
* 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
|
|
4733
4762
|
*/
|
|
4734
4763
|
setFrameInterpolation(options) {
|
|
4735
|
-
_optionalChain([this, 'access',
|
|
4764
|
+
_optionalChain([this, 'access', _152 => _152.remoteTarget, 'optionalAccess', _153 => _153.setFrameInterpolation, 'optionalCall', _154 => _154(options)]);
|
|
4736
4765
|
}
|
|
4737
4766
|
/**
|
|
4738
4767
|
* 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
|
|
4739
4768
|
*/
|
|
4740
4769
|
clearRemoteMedia() {
|
|
4741
|
-
_optionalChain([this, 'access',
|
|
4770
|
+
_optionalChain([this, 'access', _155 => _155.remoteTarget, 'optionalAccess', _156 => _156.setMediaStream, 'call', _157 => _157(null)]);
|
|
4742
4771
|
}
|
|
4743
4772
|
/**
|
|
4744
4773
|
* 停止会话心跳;未配置会话服务时不执行操作。
|
|
4745
4774
|
*/
|
|
4746
4775
|
stopHeartbeat() {
|
|
4747
|
-
_optionalChain([this, 'access',
|
|
4776
|
+
_optionalChain([this, 'access', _158 => _158.dependencies, 'access', _159 => _159.sessionService, 'optionalAccess', _160 => _160.stopHeartbeat, 'call', _161 => _161()]);
|
|
4748
4777
|
}
|
|
4749
4778
|
/**
|
|
4750
4779
|
* 等待接收轨解除静音;超时只警告,取消必须立即退出并移除监听。
|
|
4751
4780
|
*/
|
|
4752
4781
|
async waitUntilRemoteTrackReady(timeoutMs, signal) {
|
|
4753
4782
|
if (signal.aborted) throw RealtimeCoordinator.cancelledError();
|
|
4754
|
-
const mediaTrack = _optionalChain([this, 'access',
|
|
4783
|
+
const mediaTrack = _optionalChain([this, 'access', _162 => _162.activeRemoteTrack, 'optionalAccess', _163 => _163.mediaStreamTrack]);
|
|
4755
4784
|
if (!mediaTrack || !mediaTrack.muted) return;
|
|
4756
4785
|
await new Promise((resolve, reject) => {
|
|
4757
4786
|
const cleanup = () => {
|
|
@@ -4788,7 +4817,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4788
4817
|
if (track) {
|
|
4789
4818
|
track.mediaStreamTrack = void 0;
|
|
4790
4819
|
}
|
|
4791
|
-
_optionalChain([this, 'access',
|
|
4820
|
+
_optionalChain([this, 'access', _164 => _164.remoteTarget, 'optionalAccess', _165 => _165.setMediaStream, 'call', _166 => _166(null)]);
|
|
4792
4821
|
return;
|
|
4793
4822
|
}
|
|
4794
4823
|
if (!track) {
|
|
@@ -4798,7 +4827,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4798
4827
|
);
|
|
4799
4828
|
}
|
|
4800
4829
|
track.mediaStreamTrack = binding.videoTrack;
|
|
4801
|
-
_optionalChain([this, 'access',
|
|
4830
|
+
_optionalChain([this, 'access', _167 => _167.remoteTarget, 'optionalAccess', _168 => _168.setMediaStream, 'call', _169 => _169(new MediaStream([binding.videoTrack]))]);
|
|
4802
4831
|
}
|
|
4803
4832
|
/**
|
|
4804
4833
|
* 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
|
|
@@ -4811,7 +4840,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4811
4840
|
}
|
|
4812
4841
|
},
|
|
4813
4842
|
attachHandler: (view) => {
|
|
4814
|
-
_optionalChain([this, 'access',
|
|
4843
|
+
_optionalChain([this, 'access', _170 => _170.remoteTarget, 'optionalAccess', _171 => _171.setFrameInterpolation, 'optionalCall', _172 => _172(void 0)]);
|
|
4815
4844
|
view.isMirrored = this.dependencies.isMirrored();
|
|
4816
4845
|
this.remoteTarget = view;
|
|
4817
4846
|
this.dependencies.onRenderAttached();
|
|
@@ -4823,7 +4852,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4823
4852
|
this.dependencies.onRenderDetached();
|
|
4824
4853
|
this.remoteTarget = void 0;
|
|
4825
4854
|
}
|
|
4826
|
-
_optionalChain([view, 'access',
|
|
4855
|
+
_optionalChain([view, 'access', _173 => _173.setFrameInterpolation, 'optionalCall', _174 => _174(void 0)]);
|
|
4827
4856
|
view.setMediaStream(null);
|
|
4828
4857
|
}
|
|
4829
4858
|
});
|
|
@@ -4883,7 +4912,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4883
4912
|
* 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
|
|
4884
4913
|
*/
|
|
4885
4914
|
async disconnect() {
|
|
4886
|
-
const sessionID = _optionalChain([this, 'access',
|
|
4915
|
+
const sessionID = _optionalChain([this, 'access', _175 => _175.activeSession, 'optionalAccess', _176 => _176.id]);
|
|
4887
4916
|
this.stopHeartbeat();
|
|
4888
4917
|
this.clearRemoteMedia();
|
|
4889
4918
|
try {
|
|
@@ -5016,7 +5045,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
5016
5045
|
try {
|
|
5017
5046
|
await completion;
|
|
5018
5047
|
} finally {
|
|
5019
|
-
if (_optionalChain([this, 'access',
|
|
5048
|
+
if (_optionalChain([this, 'access', _177 => _177.pendingStop, 'optionalAccess', _178 => _178.completion]) === completion) this.pendingStop = void 0;
|
|
5020
5049
|
}
|
|
5021
5050
|
}
|
|
5022
5051
|
/**
|
|
@@ -5098,6 +5127,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5098
5127
|
*/
|
|
5099
5128
|
__publicField(this, "launchTimer", new RealtimeLaunchTimer());
|
|
5100
5129
|
__publicField(this, "remoteFrameDisplayHandler");
|
|
5130
|
+
/**
|
|
5131
|
+
* 媒体权限弹窗观察
|
|
5132
|
+
*/
|
|
5133
|
+
__publicField(this, "permissionWatchDispose");
|
|
5101
5134
|
/**
|
|
5102
5135
|
* 本地、远端和网络统计快照及观察者
|
|
5103
5136
|
*/
|
|
@@ -5122,18 +5155,18 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5122
5155
|
this.options = options;
|
|
5123
5156
|
this.mediaService = new MediaService(options.model);
|
|
5124
5157
|
this.interpolationRequested = options.isFrameInterpolationEnabled;
|
|
5125
|
-
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5158
|
+
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _179 => _179.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
|
|
5126
5159
|
this.errorHandler = new RealtimeErrorHandler();
|
|
5127
|
-
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5128
|
-
this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5160
|
+
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _180 => _180.rtcManager]), () => ( new RtcManager()));
|
|
5161
|
+
this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _181 => _181.cameraController]), () => ( new CameraController({
|
|
5129
5162
|
rtcManager,
|
|
5130
5163
|
mediaService: this.mediaService,
|
|
5131
5164
|
errorListener: (error) => {
|
|
5132
5165
|
void this.errorHandler.report(error);
|
|
5133
5166
|
}
|
|
5134
5167
|
})));
|
|
5135
|
-
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5136
|
-
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5168
|
+
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _182 => _182.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _183 => _183.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService }) : void 0)));
|
|
5169
|
+
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _184 => _184.streamController]), () => ( new StreamController({
|
|
5137
5170
|
rtcManager,
|
|
5138
5171
|
errorListener: (error) => {
|
|
5139
5172
|
void this.errorHandler.report(error);
|
|
@@ -5147,12 +5180,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5147
5180
|
sessionService,
|
|
5148
5181
|
streamController: this.streamController,
|
|
5149
5182
|
timing: this.launchTimer,
|
|
5150
|
-
isMirrored: () => _optionalChain([this, 'access',
|
|
5183
|
+
isMirrored: () => _optionalChain([this, 'access', _185 => _185.cameraController, 'access', _186 => _186.currentTrack, 'optionalAccess', _187 => _187.position]) === "front" /* front */,
|
|
5151
5184
|
remoteAudioVolume: () => this.storedRemoteAudioVolume,
|
|
5152
5185
|
onHeartbeatFailure: (sessionID, error) => {
|
|
5153
5186
|
void this.handleHeartbeatFailure(sessionID, error);
|
|
5154
5187
|
},
|
|
5155
|
-
onFrameDisplayed: () => _optionalChain([this, 'access',
|
|
5188
|
+
onFrameDisplayed: () => _optionalChain([this, 'access', _188 => _188.remoteFrameDisplayHandler, 'optionalCall', _189 => _189()]),
|
|
5156
5189
|
onRenderAttached: () => this.applyRemoteInterpolation(),
|
|
5157
5190
|
onRenderDetached: () => {
|
|
5158
5191
|
this.interpolationRevision++;
|
|
@@ -5199,7 +5232,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5199
5232
|
*/
|
|
5200
5233
|
async setFrameInterpolationEnabled(enabled) {
|
|
5201
5234
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
5202
|
-
const format = _optionalChain([this, 'access',
|
|
5235
|
+
const format = _optionalChain([this, 'access', _190 => _190.cameraController, 'access', _191 => _191.currentTrack, 'optionalAccess', _192 => _192.videoFormat]);
|
|
5203
5236
|
const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
|
|
5204
5237
|
if (enabled && !await this.checkInterpolationSupport(size, token)) {
|
|
5205
5238
|
token.ensureCurrent();
|
|
@@ -5325,9 +5358,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5325
5358
|
*/
|
|
5326
5359
|
notifyRemoteVideoStatistics() {
|
|
5327
5360
|
try {
|
|
5328
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5361
|
+
void Promise.resolve(_optionalChain([this, 'access', _193 => _193.remoteVideoStatisticsListener, 'optionalCall', _194 => _194(this.remoteVideoStatistics)])).catch(() => {
|
|
5329
5362
|
});
|
|
5330
|
-
} catch (
|
|
5363
|
+
} catch (e18) {
|
|
5331
5364
|
}
|
|
5332
5365
|
}
|
|
5333
5366
|
/**
|
|
@@ -5342,9 +5375,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5342
5375
|
*/
|
|
5343
5376
|
notifyNetworkStatistics() {
|
|
5344
5377
|
try {
|
|
5345
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5378
|
+
void Promise.resolve(_optionalChain([this, 'access', _195 => _195.networkStatisticsListener, 'optionalCall', _196 => _196(this.networkStatistics)])).catch(() => {
|
|
5346
5379
|
});
|
|
5347
|
-
} catch (
|
|
5380
|
+
} catch (e19) {
|
|
5348
5381
|
}
|
|
5349
5382
|
}
|
|
5350
5383
|
/**
|
|
@@ -5362,9 +5395,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5362
5395
|
*/
|
|
5363
5396
|
notifyLocalVideoStatistics() {
|
|
5364
5397
|
try {
|
|
5365
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5398
|
+
void Promise.resolve(_optionalChain([this, 'access', _197 => _197.localVideoStatisticsListener, 'optionalCall', _198 => _198(this.localVideoStatistics)])).catch(() => {
|
|
5366
5399
|
});
|
|
5367
|
-
} catch (
|
|
5400
|
+
} catch (e20) {
|
|
5368
5401
|
}
|
|
5369
5402
|
}
|
|
5370
5403
|
/**
|
|
@@ -5416,7 +5449,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5416
5449
|
*
|
|
5417
5450
|
* 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
|
|
5418
5451
|
*
|
|
5419
|
-
* @param options.enableFrameValidation
|
|
5452
|
+
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
5420
5453
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
5421
5454
|
* @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
|
|
5422
5455
|
*/
|
|
@@ -5434,11 +5467,20 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5434
5467
|
token.ensureCurrent();
|
|
5435
5468
|
const completeCamera = this.launchTimer.startCamera();
|
|
5436
5469
|
this.clearVideoStatistics();
|
|
5470
|
+
this.disposePermissionWatch();
|
|
5471
|
+
const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _199 => _199.useMicrophone]), () => ( false)));
|
|
5472
|
+
if (permissionWatch) {
|
|
5473
|
+
const completePermission = this.launchTimer.startPermission();
|
|
5474
|
+
void permissionWatch.decided.then(() => completePermission()).catch(() => {
|
|
5475
|
+
});
|
|
5476
|
+
this.permissionWatchDispose = permissionWatch.dispose;
|
|
5477
|
+
}
|
|
5437
5478
|
let stream;
|
|
5438
5479
|
try {
|
|
5439
5480
|
token.ensureCurrent();
|
|
5440
5481
|
stream = await this.cameraController.createLocalCameraStream(options);
|
|
5441
5482
|
} catch (error) {
|
|
5483
|
+
this.disposePermissionWatch();
|
|
5442
5484
|
this.launchTimer.cancel();
|
|
5443
5485
|
throw error;
|
|
5444
5486
|
}
|
|
@@ -5451,6 +5493,13 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5451
5493
|
}
|
|
5452
5494
|
);
|
|
5453
5495
|
}
|
|
5496
|
+
/**
|
|
5497
|
+
* 移除媒体权限弹窗观察;授权决定已记录或不再需要观察时调用。
|
|
5498
|
+
*/
|
|
5499
|
+
disposePermissionWatch() {
|
|
5500
|
+
_optionalChain([this, 'access', _200 => _200.permissionWatchDispose, 'optionalCall', _201 => _201()]);
|
|
5501
|
+
this.permissionWatchDispose = void 0;
|
|
5502
|
+
}
|
|
5454
5503
|
/**
|
|
5455
5504
|
* 停止本地相机流并释放本地预览与 RTC 资源。
|
|
5456
5505
|
*/
|
|
@@ -5461,6 +5510,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5461
5510
|
async (token) => {
|
|
5462
5511
|
this.launchTimer.cancel();
|
|
5463
5512
|
this.clearVideoStatistics();
|
|
5513
|
+
this.disposePermissionWatch();
|
|
5464
5514
|
await this.cameraController.stopLocalCameraStream();
|
|
5465
5515
|
token.ensureCurrent();
|
|
5466
5516
|
await this.coordinator.commit(
|
|
@@ -5494,8 +5544,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5494
5544
|
* 使用当前 Manager 创建的本地流建立实时连接。
|
|
5495
5545
|
*
|
|
5496
5546
|
* 创建实时会话、加入 RTC 房间并发布本地流,成功后启动会话心跳。
|
|
5497
|
-
*
|
|
5498
|
-
* 记录警告并按当前画面继续发布,不因环境较暗而阻断连接。
|
|
5547
|
+
* 启用帧检测时,发布前并行等待相机预热(固定 200ms),避免把黑帧推给 RTC。
|
|
5499
5548
|
* 返回的远端媒体流在生成开始后承载远端生成画面。
|
|
5500
5549
|
*
|
|
5501
5550
|
* @param localStream 由 `createLocalCameraStream` 创建的本地媒体流。
|
|
@@ -5604,17 +5653,15 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5604
5653
|
new RealtimeState({ connectionState: "Connecting" /* connecting */ }),
|
|
5605
5654
|
token
|
|
5606
5655
|
);
|
|
5607
|
-
const
|
|
5608
|
-
const
|
|
5609
|
-
token.signal.addEventListener("abort",
|
|
5610
|
-
if (token.signal.aborted)
|
|
5656
|
+
const warmupController = new AbortController();
|
|
5657
|
+
const abortWarmup = () => warmupController.abort();
|
|
5658
|
+
token.signal.addEventListener("abort", abortWarmup, { once: true });
|
|
5659
|
+
if (token.signal.aborted) abortWarmup();
|
|
5611
5660
|
try {
|
|
5612
5661
|
let beforePublish;
|
|
5613
5662
|
if (this.cameraController.isFrameValidationEnabled) {
|
|
5614
|
-
const
|
|
5615
|
-
const cameraReady = this.cameraController.waitForValidCameraFrame(exposureController.signal).then(() => {
|
|
5663
|
+
const cameraReady = this.cameraController.waitForValidCameraFrame(warmupController.signal).then(() => {
|
|
5616
5664
|
token.ensureCurrent();
|
|
5617
|
-
completeFrameValidation();
|
|
5618
5665
|
});
|
|
5619
5666
|
void cameraReady.catch(() => {
|
|
5620
5667
|
});
|
|
@@ -5639,8 +5686,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5639
5686
|
);
|
|
5640
5687
|
return remote;
|
|
5641
5688
|
} finally {
|
|
5642
|
-
token.signal.removeEventListener("abort",
|
|
5643
|
-
|
|
5689
|
+
token.signal.removeEventListener("abort", abortWarmup);
|
|
5690
|
+
abortWarmup();
|
|
5644
5691
|
}
|
|
5645
5692
|
}
|
|
5646
5693
|
/**
|
|
@@ -5697,6 +5744,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5697
5744
|
await this.generationManager.reset(taskID);
|
|
5698
5745
|
const sessionID = await this.connectionManager.disconnect();
|
|
5699
5746
|
if (scope === 1 /* all */) {
|
|
5747
|
+
this.disposePermissionWatch();
|
|
5700
5748
|
try {
|
|
5701
5749
|
await this.cameraController.stopLocalCameraStream();
|
|
5702
5750
|
} catch (error) {
|
|
@@ -5856,11 +5904,11 @@ var RealtimeConfiguration = class {
|
|
|
5856
5904
|
*/
|
|
5857
5905
|
__publicField(this, "frameInterpolation");
|
|
5858
5906
|
this.model = init.model;
|
|
5859
|
-
const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access',
|
|
5907
|
+
const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access', _202 => _202.frameInterpolation, 'optionalAccess', _203 => _203.targetFrameRate]), () => ( 60));
|
|
5860
5908
|
if (!Number.isFinite(targetFrameRate) || targetFrameRate < 1 || targetFrameRate > 60) {
|
|
5861
5909
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Interpolation targetFrameRate must be between 1 and 60");
|
|
5862
5910
|
}
|
|
5863
|
-
this.isFrameInterpolationEnabled = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'access',
|
|
5911
|
+
this.isFrameInterpolationEnabled = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'access', _204 => _204.frameInterpolation, 'optionalAccess', _205 => _205.enabled]), () => ( init.isFrameInterpolationEnabled)), () => ( false));
|
|
5864
5912
|
this.frameInterpolation = Object.freeze({ enabled: this.isFrameInterpolationEnabled, targetFrameRate });
|
|
5865
5913
|
}
|
|
5866
5914
|
};
|
|
@@ -5890,7 +5938,7 @@ var RealtimeContext = class {
|
|
|
5890
5938
|
*/
|
|
5891
5939
|
__publicField(this, "referencePath");
|
|
5892
5940
|
this.prompt = init.prompt.trim();
|
|
5893
|
-
const normalizedReferencePath = _optionalChain([init, 'access',
|
|
5941
|
+
const normalizedReferencePath = _optionalChain([init, 'access', _206 => _206.referencePath, 'optionalAccess', _207 => _207.trim, 'call', _208 => _208()]);
|
|
5894
5942
|
this.referencePath = normalizedReferencePath || void 0;
|
|
5895
5943
|
}
|
|
5896
5944
|
};
|
|
@@ -8017,11 +8065,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
8017
8065
|
if (this.destroyed) return;
|
|
8018
8066
|
this.destroyed = true;
|
|
8019
8067
|
this.device.removeEventListener("uncapturederror", this.onGPUError);
|
|
8020
|
-
_optionalChain([this, 'access',
|
|
8068
|
+
_optionalChain([this, 'access', _209 => _209.runtime, 'optionalAccess', _210 => _210.destroy, 'call', _211 => _211()]);
|
|
8021
8069
|
this.runtime = void 0;
|
|
8022
8070
|
this.textures.forEach((texture) => texture.destroy());
|
|
8023
8071
|
this.textures = [];
|
|
8024
|
-
_optionalChain([this, 'access',
|
|
8072
|
+
_optionalChain([this, 'access', _212 => _212.context, 'optionalAccess', _213 => _213.unconfigure, 'call', _214 => _214()]);
|
|
8025
8073
|
this.device.destroy();
|
|
8026
8074
|
}
|
|
8027
8075
|
};
|
|
@@ -8200,7 +8248,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
8200
8248
|
setActive(active) {
|
|
8201
8249
|
if (active === this.active) return;
|
|
8202
8250
|
this.active = active;
|
|
8203
|
-
_optionalChain([this, 'access',
|
|
8251
|
+
_optionalChain([this, 'access', _215 => _215.options, 'access', _216 => _216.onActiveChange, 'optionalCall', _217 => _217(active)]);
|
|
8204
8252
|
}
|
|
8205
8253
|
resetTimeline() {
|
|
8206
8254
|
this.generation++;
|
|
@@ -8231,7 +8279,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
8231
8279
|
this.callback = void 0;
|
|
8232
8280
|
clearTimeout(this.initializationTimer);
|
|
8233
8281
|
this.resetTimeline();
|
|
8234
|
-
_optionalChain([this, 'access',
|
|
8282
|
+
_optionalChain([this, 'access', _218 => _218.processor, 'optionalAccess', _219 => _219.destroy, 'call', _220 => _220()]);
|
|
8235
8283
|
this.processor = void 0;
|
|
8236
8284
|
}
|
|
8237
8285
|
};
|
|
@@ -8289,7 +8337,7 @@ var XmaxVideoView = class {
|
|
|
8289
8337
|
* DOM 挂载状态
|
|
8290
8338
|
*/
|
|
8291
8339
|
__publicField(this, "detached", false);
|
|
8292
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
8340
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _221 => _221.videoContentMode]), () => ( "fill")) /* fill */;
|
|
8293
8341
|
this.element = document.createElement("div");
|
|
8294
8342
|
this.element.style.position = "relative";
|
|
8295
8343
|
this.element.style.overflow = "hidden";
|
|
@@ -8436,8 +8484,8 @@ var XmaxVideoView = class {
|
|
|
8436
8484
|
stopInterpolation() {
|
|
8437
8485
|
const pipeline = this.interpolationPipeline;
|
|
8438
8486
|
this.interpolationPipeline = void 0;
|
|
8439
|
-
_optionalChain([pipeline, 'optionalAccess',
|
|
8440
|
-
_optionalChain([this, 'access',
|
|
8487
|
+
_optionalChain([pipeline, 'optionalAccess', _222 => _222.stop, 'call', _223 => _223()]);
|
|
8488
|
+
_optionalChain([this, 'access', _224 => _224.interpolationCanvas, 'optionalAccess', _225 => _225.remove, 'call', _226 => _226()]);
|
|
8441
8489
|
this.interpolationCanvas = void 0;
|
|
8442
8490
|
}
|
|
8443
8491
|
/**
|
|
@@ -8463,7 +8511,7 @@ var XmaxVideoView = class {
|
|
|
8463
8511
|
detachCurrentTrack() {
|
|
8464
8512
|
const track = this.currentTrack;
|
|
8465
8513
|
if (track) {
|
|
8466
|
-
_optionalChain([VideoRenderRegistry, 'access',
|
|
8514
|
+
_optionalChain([VideoRenderRegistry, 'access', _227 => _227.binding, 'call', _228 => _228(track), 'optionalAccess', _229 => _229.detachHandler, 'call', _230 => _230(this)]);
|
|
8467
8515
|
}
|
|
8468
8516
|
this.setFrameInterpolation(void 0);
|
|
8469
8517
|
this.cancelFrameDisplayNotification();
|
|
@@ -8483,8 +8531,8 @@ var XmaxVideoView = class {
|
|
|
8483
8531
|
}
|
|
8484
8532
|
this.hasNotifiedFrameDisplay = true;
|
|
8485
8533
|
this.cancelFrameDisplayNotification();
|
|
8486
|
-
_optionalChain([binding, 'optionalAccess',
|
|
8487
|
-
_optionalChain([this, 'access',
|
|
8534
|
+
_optionalChain([binding, 'optionalAccess', _231 => _231.frameDisplayHandler, 'optionalCall', _232 => _232()]);
|
|
8535
|
+
_optionalChain([this, 'access', _233 => _233.frameDisplayHandler, 'optionalCall', _234 => _234()]);
|
|
8488
8536
|
};
|
|
8489
8537
|
if (typeof this.videoElement.requestVideoFrameCallback === "function") {
|
|
8490
8538
|
this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
|
|
@@ -8554,9 +8602,9 @@ var XmaxRealtimeVideoView = class {
|
|
|
8554
8602
|
__publicField(this, "currentLocalTrack");
|
|
8555
8603
|
__publicField(this, "currentRemoteTrack");
|
|
8556
8604
|
__publicField(this, "contentMode");
|
|
8557
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
8558
|
-
this.currentLocalTrack = _optionalChain([options, 'optionalAccess',
|
|
8559
|
-
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess',
|
|
8605
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _235 => _235.videoContentMode]), () => ( "fill")) /* fill */;
|
|
8606
|
+
this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _236 => _236.localTrack]);
|
|
8607
|
+
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _237 => _237.remoteTrack]);
|
|
8560
8608
|
this.element = document.createElement("div");
|
|
8561
8609
|
this.element.style.position = "relative";
|
|
8562
8610
|
this.element.style.overflow = "hidden";
|
|
@@ -8715,4 +8763,4 @@ var XmaxRealtimeVideoView = class {
|
|
|
8715
8763
|
|
|
8716
8764
|
|
|
8717
8765
|
exports.XmaxEnvironment = XmaxEnvironment; exports.apiBaseURL = apiBaseURL; exports.XmaxLoggerOption = XmaxLoggerOption; exports.XmaxLogger = XmaxLogger; exports.XmaxErrorCode = XmaxErrorCode; exports.XmaxError = XmaxError; exports.RealtimeVideoEncoderPreference = RealtimeVideoEncoderPreference; exports.RealtimeVideoFormat = RealtimeVideoFormat; exports.RealtimeModel = RealtimeModel; exports.defaultFrameRate = defaultFrameRate; exports.defaultCameraVideoFormat = defaultCameraVideoFormat; exports.MediaService = MediaService; exports.StoredFile = StoredFile; exports.StorageService = StorageService; exports.CameraPosition = CameraPosition; exports.RealtimeVideoTrack = RealtimeVideoTrack; exports.RealtimeMediaStream = RealtimeMediaStream; exports.RealtimeConnectionState = RealtimeConnectionState; exports.RealtimeReason = RealtimeReason; exports.RealtimeState = RealtimeState; exports.XmaxConfiguration = XmaxConfiguration; exports.XmaxClient = XmaxClient; exports.RealtimeConfiguration = RealtimeConfiguration; exports.VideoContentMode = VideoContentMode; exports.RealtimeContext = RealtimeContext; exports.XmaxVideoView = XmaxVideoView; exports.XmaxRealtimeVideoView = XmaxRealtimeVideoView;
|
|
8718
|
-
//# sourceMappingURL=chunk-
|
|
8766
|
+
//# sourceMappingURL=chunk-JWAAS6P4.cjs.map
|