@xmaxai/web-sdk 1.0.1 → 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-FH3OPC6F.cjs → chunk-JWAAS6P4.cjs} +332 -287
- package/dist/chunk-JWAAS6P4.cjs.map +1 -0
- package/dist/{chunk-NW6YF4JT.js → chunk-YMLRUDAO.js} +221 -176
- 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 +21 -12
- package/dist/index.d.ts +21 -12
- 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-FH3OPC6F.cjs.map +0 -1
- package/dist/chunk-NW6YF4JT.js.map +0 -1
|
@@ -9,10 +9,7 @@ var XmaxEnvironment = /* @__PURE__ */ ((XmaxEnvironment2) => {
|
|
|
9
9
|
return XmaxEnvironment2;
|
|
10
10
|
})(XmaxEnvironment || {});
|
|
11
11
|
var API_BASE_URLS = {
|
|
12
|
-
|
|
13
|
-
* 临时联调环境。
|
|
14
|
-
*/
|
|
15
|
-
["china" /* china */]: "https://dev.xmaxai.com/open/api/v1",
|
|
12
|
+
["china" /* china */]: "https://cloud.xmax.22duck.cn/open/api/v1",
|
|
16
13
|
["global" /* global */]: "https://api.xmax.cloud/open/api/v1"
|
|
17
14
|
};
|
|
18
15
|
function apiBaseURL(environment) {
|
|
@@ -201,7 +198,7 @@ var XmaxError = class _XmaxError extends Error {
|
|
|
201
198
|
};
|
|
202
199
|
|
|
203
200
|
// src/Foundation/Runtime/RuntimeInfo.ts
|
|
204
|
-
var XMAX_SDK_VERSION = "1.0.
|
|
201
|
+
var XMAX_SDK_VERSION = "1.0.3";
|
|
205
202
|
var _RuntimeInfo = class _RuntimeInfo {
|
|
206
203
|
/**
|
|
207
204
|
* 序列化为接口传输使用的 snake_case 字段。
|
|
@@ -266,10 +263,12 @@ var _ApiService = class _ApiService {
|
|
|
266
263
|
}
|
|
267
264
|
/**
|
|
268
265
|
* 发送请求并返回统一响应中的数据。
|
|
266
|
+
*
|
|
267
|
+
* @param options.keepalive 为 true 时请求可存活于页面卸载之后。
|
|
269
268
|
*/
|
|
270
|
-
async request(method, path, body) {
|
|
269
|
+
async request(method, path, body, options) {
|
|
271
270
|
this.validateConfiguration();
|
|
272
|
-
const request = this.makeRequest(method, path, body);
|
|
271
|
+
const request = this.makeRequest(method, path, body, options);
|
|
273
272
|
const startedAt = Date.now();
|
|
274
273
|
let status;
|
|
275
274
|
let text;
|
|
@@ -316,8 +315,8 @@ var _ApiService = class _ApiService {
|
|
|
316
315
|
/**
|
|
317
316
|
* 发送 DELETE 请求。
|
|
318
317
|
*/
|
|
319
|
-
delete(path) {
|
|
320
|
-
return this.request("DELETE" /* delete */, path);
|
|
318
|
+
delete(path, options) {
|
|
319
|
+
return this.request("DELETE" /* delete */, path, void 0, options);
|
|
321
320
|
}
|
|
322
321
|
/**
|
|
323
322
|
* 校验 API Key 与 Base URL 配置。
|
|
@@ -347,7 +346,7 @@ var _ApiService = class _ApiService {
|
|
|
347
346
|
/**
|
|
348
347
|
* 构造请求地址、请求头与请求体;路径必须相对且与 Base URL 同源。
|
|
349
348
|
*/
|
|
350
|
-
makeRequest(method, path, body) {
|
|
349
|
+
makeRequest(method, path, body, options) {
|
|
351
350
|
const normalizedPath = path.trim();
|
|
352
351
|
if (normalizedPath.length === 0 || normalizedPath.includes("://") || normalizedPath.startsWith("//")) {
|
|
353
352
|
throw new XmaxError(
|
|
@@ -388,7 +387,8 @@ var _ApiService = class _ApiService {
|
|
|
388
387
|
"X-SDK-Version": XMAX_SDK_VERSION
|
|
389
388
|
},
|
|
390
389
|
body: encodedBody,
|
|
391
|
-
signal: AbortSignal.timeout(this.timeoutMs)
|
|
390
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
391
|
+
..._optionalChain([options, 'optionalAccess', _4 => _4.keepalive]) ? { keepalive: true } : {}
|
|
392
392
|
}
|
|
393
393
|
};
|
|
394
394
|
}
|
|
@@ -406,7 +406,7 @@ var _ApiService = class _ApiService {
|
|
|
406
406
|
}
|
|
407
407
|
const ok = status >= 200 && status < 300;
|
|
408
408
|
if (!ok || envelope.success !== true) {
|
|
409
|
-
const message = _optionalChain([envelope, 'access',
|
|
409
|
+
const message = _optionalChain([envelope, 'access', _5 => _5.message, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]);
|
|
410
410
|
throw new XmaxError(
|
|
411
411
|
"API_ERROR" /* apiError */,
|
|
412
412
|
message || "Xmax API request failed",
|
|
@@ -565,7 +565,7 @@ var RealtimeVideoFormat = class _RealtimeVideoFormat {
|
|
|
565
565
|
var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
|
|
566
566
|
RealtimeModel2["x2_0"] = "x2.0";
|
|
567
567
|
RealtimeModel2["x2_0_pro"] = "x2.0-pro";
|
|
568
|
-
RealtimeModel2["
|
|
568
|
+
RealtimeModel2["x2_0_trtc"] = "x2.0-trtc";
|
|
569
569
|
return RealtimeModel2;
|
|
570
570
|
})(RealtimeModel || {});
|
|
571
571
|
var RESOLUTION_BUCKETS = {
|
|
@@ -574,7 +574,7 @@ var RESOLUTION_BUCKETS = {
|
|
|
574
574
|
{ width: 1024, height: 1920 },
|
|
575
575
|
{ width: 1920, height: 1024 }
|
|
576
576
|
],
|
|
577
|
-
["x2-
|
|
577
|
+
["x2.0-trtc" /* x2_0_trtc */]: [
|
|
578
578
|
{ width: 1024, height: 1920 },
|
|
579
579
|
{ width: 1920, height: 1024 }
|
|
580
580
|
]
|
|
@@ -582,7 +582,7 @@ var RESOLUTION_BUCKETS = {
|
|
|
582
582
|
var MAXIMUM_INPUT_PIXELS = {
|
|
583
583
|
["x2.0" /* x2_0 */]: 128e4,
|
|
584
584
|
["x2.0-pro" /* x2_0_pro */]: 21e5,
|
|
585
|
-
["x2-
|
|
585
|
+
["x2.0-trtc" /* x2_0_trtc */]: 21e5
|
|
586
586
|
};
|
|
587
587
|
function resolutionBuckets(model) {
|
|
588
588
|
return RESOLUTION_BUCKETS[model];
|
|
@@ -612,7 +612,7 @@ async function frameInterpolationAdapter(size) {
|
|
|
612
612
|
if (size && (!Number.isSafeInteger(size.width) || !Number.isSafeInteger(size.height) || size.width <= 0 || size.height <= 0)) return null;
|
|
613
613
|
try {
|
|
614
614
|
const adapter = await navigator.gpu.requestAdapter();
|
|
615
|
-
if (!_optionalChain([adapter, 'optionalAccess',
|
|
615
|
+
if (!_optionalChain([adapter, 'optionalAccess', _8 => _8.features, 'access', _9 => _9.has, 'call', _10 => _10("shader-f16")])) return null;
|
|
616
616
|
if (size && (Math.ceil(size.width / 16) * 16 > adapter.limits.maxTextureDimension2D || Math.ceil(size.height / 16) * 16 > adapter.limits.maxTextureDimension2D)) return null;
|
|
617
617
|
return adapter;
|
|
618
618
|
} catch (e5) {
|
|
@@ -625,9 +625,9 @@ var MediaService = class {
|
|
|
625
625
|
/**
|
|
626
626
|
* 创建媒体服务。
|
|
627
627
|
*
|
|
628
|
-
* @param model 媒体输入规则使用的模型,默认为 `x2-
|
|
628
|
+
* @param model 媒体输入规则使用的模型,默认为 `x2.0-trtc`。
|
|
629
629
|
*/
|
|
630
|
-
constructor(model = "x2-
|
|
630
|
+
constructor(model = "x2.0-trtc" /* x2_0_trtc */) {
|
|
631
631
|
/**
|
|
632
632
|
* 模型约束
|
|
633
633
|
*/
|
|
@@ -826,7 +826,7 @@ var StorageService = class _StorageService {
|
|
|
826
826
|
const startedAt = Date.now();
|
|
827
827
|
try {
|
|
828
828
|
const safeName = _StorageService.validateFileName(options.fileName);
|
|
829
|
-
const contentType = _optionalChain([options, 'access',
|
|
829
|
+
const contentType = _optionalChain([options, 'access', _11 => _11.contentType, 'optionalAccess', _12 => _12.trim, 'call', _13 => _13()]) || _StorageService.inferContentType(safeName);
|
|
830
830
|
const body = _StorageService.makeBody(options.data, contentType);
|
|
831
831
|
if (body.size === 0) {
|
|
832
832
|
throw new XmaxError(
|
|
@@ -848,7 +848,7 @@ var StorageService = class _StorageService {
|
|
|
848
848
|
Key: objectKey,
|
|
849
849
|
Body: body,
|
|
850
850
|
ContentType: contentType,
|
|
851
|
-
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
|
|
852
852
|
});
|
|
853
853
|
const url = _StorageService.resolveObjectURL(
|
|
854
854
|
uploaded.Location,
|
|
@@ -880,9 +880,9 @@ var StorageService = class _StorageService {
|
|
|
880
880
|
const bucket = _StorageService.nonEmpty(payload.bucket);
|
|
881
881
|
const region = _StorageService.nonEmpty(payload.region);
|
|
882
882
|
const prefix = _StorageService.nonEmpty(payload.prefix);
|
|
883
|
-
const accessKeyID = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
884
|
-
const secretAccessKey = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
885
|
-
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]));
|
|
886
886
|
if (!bucket || !region || !prefix || !accessKeyID || !secretAccessKey || !sessionToken) {
|
|
887
887
|
throw new XmaxError("API_ERROR" /* apiError */, message);
|
|
888
888
|
}
|
|
@@ -923,7 +923,7 @@ var StorageService = class _StorageService {
|
|
|
923
923
|
reject(
|
|
924
924
|
new XmaxError(
|
|
925
925
|
"UPLOAD_ERROR" /* uploadError */,
|
|
926
|
-
_optionalChain([error, 'access',
|
|
926
|
+
_optionalChain([error, 'access', _22 => _22.message, 'optionalAccess', _23 => _23.trim, 'call', _24 => _24()]) || "Storage upload failed"
|
|
927
927
|
)
|
|
928
928
|
);
|
|
929
929
|
return;
|
|
@@ -937,14 +937,14 @@ var StorageService = class _StorageService {
|
|
|
937
937
|
* 其次拼接自定义 endpoint,最后回退到默认 COS 域名。
|
|
938
938
|
*/
|
|
939
939
|
static resolveObjectURL(location, configuration, objectKey) {
|
|
940
|
-
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess',
|
|
940
|
+
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess', _25 => _25.trim, 'call', _26 => _26()]), () => ( ""));
|
|
941
941
|
if (candidate.startsWith("//")) {
|
|
942
942
|
return `https:${candidate}`;
|
|
943
943
|
}
|
|
944
944
|
if (/^https?:\/\//i.test(candidate)) {
|
|
945
945
|
return candidate;
|
|
946
946
|
}
|
|
947
|
-
const endpoint = _optionalChain([configuration, 'access',
|
|
947
|
+
const endpoint = _optionalChain([configuration, 'access', _27 => _27.endpoint, 'optionalAccess', _28 => _28.trim, 'call', _29 => _29()]);
|
|
948
948
|
if (endpoint) {
|
|
949
949
|
const normalized = /^https?:\/\//i.test(endpoint) ? endpoint : `https://${endpoint}`;
|
|
950
950
|
return `${normalized.replace(/\/+$/, "")}/${objectKey}`;
|
|
@@ -978,7 +978,7 @@ var StorageService = class _StorageService {
|
|
|
978
978
|
* 按文件名后缀推断内容类型。
|
|
979
979
|
*/
|
|
980
980
|
static inferContentType(fileName) {
|
|
981
|
-
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()]), () => ( ""));
|
|
982
982
|
return _nullishCoalesce(CONTENT_TYPES[extension], () => ( "application/octet-stream"));
|
|
983
983
|
}
|
|
984
984
|
/**
|
|
@@ -997,7 +997,7 @@ var StorageService = class _StorageService {
|
|
|
997
997
|
* 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
|
|
998
998
|
*/
|
|
999
999
|
static nonEmpty(value) {
|
|
1000
|
-
const normalized = _optionalChain([value, 'optionalAccess',
|
|
1000
|
+
const normalized = _optionalChain([value, 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()]);
|
|
1001
1001
|
return normalized || void 0;
|
|
1002
1002
|
}
|
|
1003
1003
|
};
|
|
@@ -1009,6 +1009,68 @@ var CameraPosition = /* @__PURE__ */ ((CameraPosition3) => {
|
|
|
1009
1009
|
return CameraPosition3;
|
|
1010
1010
|
})(CameraPosition || {});
|
|
1011
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
|
+
|
|
1012
1074
|
// src/Foundation/RTC/RtcEngineManager.ts
|
|
1013
1075
|
var RtcEngineLease = class {
|
|
1014
1076
|
/**
|
|
@@ -1077,13 +1139,13 @@ var _RtcEngineManager = class _RtcEngineManager {
|
|
|
1077
1139
|
* 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
|
|
1078
1140
|
*/
|
|
1079
1141
|
release(lease) {
|
|
1080
|
-
if (_optionalChain([this, 'access',
|
|
1142
|
+
if (_optionalChain([this, 'access', _40 => _40.activeLease, 'optionalAccess', _41 => _41.id]) !== lease.id) {
|
|
1081
1143
|
return;
|
|
1082
1144
|
}
|
|
1083
1145
|
this.activeLease = void 0;
|
|
1084
1146
|
try {
|
|
1085
1147
|
lease.engine.destroy();
|
|
1086
|
-
} catch (
|
|
1148
|
+
} catch (e8) {
|
|
1087
1149
|
}
|
|
1088
1150
|
void this.fulfillNextRequest();
|
|
1089
1151
|
}
|
|
@@ -1151,10 +1213,10 @@ var RtcStatsLogger = class {
|
|
|
1151
1213
|
`${XmaxLogger.localized("\u7D2F\u8BA1\u63A5\u6536\uFF1A", "Bytes Received: ")}${this.value(stats.bytesReceived, "bytes")}`
|
|
1152
1214
|
])];
|
|
1153
1215
|
const local = stats.localStatistics;
|
|
1154
|
-
if (_optionalChain([local, 'optionalAccess',
|
|
1216
|
+
if (_optionalChain([local, 'optionalAccess', _42 => _42.audio])) {
|
|
1155
1217
|
blocks.push(this.audioBlock("\u672C\u5730\u97F3\u9891\u53D1\u9001 (Local Audio Uplink)", local.audio, false));
|
|
1156
1218
|
}
|
|
1157
|
-
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess',
|
|
1219
|
+
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _43 => _43.video]), () => ( []))) {
|
|
1158
1220
|
blocks.push(this.videoBlock("\u672C\u5730\u89C6\u9891\u53D1\u9001 (Local Video Uplink)", video, false));
|
|
1159
1221
|
}
|
|
1160
1222
|
for (const remote of _nullishCoalesce(stats.remoteStatistics, () => ( []))) {
|
|
@@ -1242,6 +1304,33 @@ var RtcStatsLogger = class {
|
|
|
1242
1304
|
}
|
|
1243
1305
|
};
|
|
1244
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
|
+
|
|
1245
1334
|
// src/Foundation/RTC/RtcManager.ts
|
|
1246
1335
|
var RTC_EVENT = {
|
|
1247
1336
|
remoteVideoAvailable: "remote-video-available",
|
|
@@ -1316,18 +1405,18 @@ var RtcManager = class {
|
|
|
1316
1405
|
this.isCapturing = false;
|
|
1317
1406
|
this.isAudioCapturing = false;
|
|
1318
1407
|
this.isInRoom = false;
|
|
1319
|
-
_optionalChain([this, 'access',
|
|
1408
|
+
_optionalChain([this, 'access', _53 => _53.removeStatsListeners, 'optionalCall', _54 => _54()]);
|
|
1320
1409
|
this.removeStatsListeners = void 0;
|
|
1321
1410
|
if (!lease) {
|
|
1322
1411
|
return;
|
|
1323
1412
|
}
|
|
1324
1413
|
try {
|
|
1325
1414
|
await lease.engine.stopLocalAudio();
|
|
1326
|
-
} catch (
|
|
1415
|
+
} catch (e9) {
|
|
1327
1416
|
}
|
|
1328
1417
|
try {
|
|
1329
1418
|
await lease.engine.stopLocalVideo();
|
|
1330
|
-
} catch (
|
|
1419
|
+
} catch (e10) {
|
|
1331
1420
|
}
|
|
1332
1421
|
this.engineManager.release(lease);
|
|
1333
1422
|
}
|
|
@@ -1346,13 +1435,17 @@ var RtcManager = class {
|
|
|
1346
1435
|
);
|
|
1347
1436
|
}
|
|
1348
1437
|
try {
|
|
1438
|
+
const captureSize = rtcOrientedVideoSize({
|
|
1439
|
+
width: options.width,
|
|
1440
|
+
height: options.height
|
|
1441
|
+
});
|
|
1349
1442
|
await engine.startLocalVideo({
|
|
1350
1443
|
publish: false,
|
|
1351
1444
|
option: {
|
|
1352
1445
|
useFrontCamera: options.position === "front" /* front */,
|
|
1353
1446
|
profile: {
|
|
1354
|
-
width:
|
|
1355
|
-
height:
|
|
1447
|
+
width: captureSize.width,
|
|
1448
|
+
height: captureSize.height,
|
|
1356
1449
|
frameRate: options.frameRate,
|
|
1357
1450
|
bitrate: CAPTURE_PLACEHOLDER_BITRATE
|
|
1358
1451
|
}
|
|
@@ -1405,7 +1498,7 @@ var RtcManager = class {
|
|
|
1405
1498
|
* 停止摄像头采集;引擎未初始化或采集未启动时不产生效果。
|
|
1406
1499
|
*/
|
|
1407
1500
|
async stopCameraCapture() {
|
|
1408
|
-
const engine = _optionalChain([this, 'access',
|
|
1501
|
+
const engine = _optionalChain([this, 'access', _55 => _55.lease, 'optionalAccess', _56 => _56.engine]);
|
|
1409
1502
|
this.isCapturing = false;
|
|
1410
1503
|
if (!engine) {
|
|
1411
1504
|
return;
|
|
@@ -1455,7 +1548,7 @@ var RtcManager = class {
|
|
|
1455
1548
|
* 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
|
|
1456
1549
|
*/
|
|
1457
1550
|
async leaveRoom() {
|
|
1458
|
-
const engine = _optionalChain([this, 'access',
|
|
1551
|
+
const engine = _optionalChain([this, 'access', _57 => _57.lease, 'optionalAccess', _58 => _58.engine]);
|
|
1459
1552
|
if (!engine || !this.isInRoom) {
|
|
1460
1553
|
return;
|
|
1461
1554
|
}
|
|
@@ -1472,7 +1565,7 @@ var RtcManager = class {
|
|
|
1472
1565
|
/**
|
|
1473
1566
|
* 配置本地视频编码参数。
|
|
1474
1567
|
*
|
|
1475
|
-
* TRTC 只接受单一目标码率,以 `
|
|
1568
|
+
* TRTC 只接受单一目标码率,以 `minimumBitrate`(流畅优先档)作为目标码率;
|
|
1476
1569
|
* 编码策略偏好映射为 TRTC 弱网偏好。
|
|
1477
1570
|
*
|
|
1478
1571
|
* @throws 摄像头采集未启动或编码参数配置失败时抛出错误。
|
|
@@ -1486,13 +1579,17 @@ var RtcManager = class {
|
|
|
1486
1579
|
);
|
|
1487
1580
|
}
|
|
1488
1581
|
try {
|
|
1582
|
+
const encodingSize = rtcOrientedVideoSize({
|
|
1583
|
+
width: configuration.width,
|
|
1584
|
+
height: configuration.height
|
|
1585
|
+
});
|
|
1489
1586
|
await engine.updateLocalVideo({
|
|
1490
1587
|
option: {
|
|
1491
1588
|
profile: {
|
|
1492
|
-
width:
|
|
1493
|
-
height:
|
|
1589
|
+
width: encodingSize.width,
|
|
1590
|
+
height: encodingSize.height,
|
|
1494
1591
|
frameRate: configuration.frameRate,
|
|
1495
|
-
bitrate: configuration.
|
|
1592
|
+
bitrate: configuration.minimumBitrate
|
|
1496
1593
|
},
|
|
1497
1594
|
qosPreference: QOS_PREFERENCE_MAP[configuration.encoderPreference]
|
|
1498
1595
|
}
|
|
@@ -1524,7 +1621,7 @@ var RtcManager = class {
|
|
|
1524
1621
|
* 停止发布本地视频流;采集保持运行,本地预览不受影响。
|
|
1525
1622
|
*/
|
|
1526
1623
|
async unpublishLocalVideo() {
|
|
1527
|
-
const engine = _optionalChain([this, 'access',
|
|
1624
|
+
const engine = _optionalChain([this, 'access', _59 => _59.lease, 'optionalAccess', _60 => _60.engine]);
|
|
1528
1625
|
if (!engine || !this.isCapturing) {
|
|
1529
1626
|
return;
|
|
1530
1627
|
}
|
|
@@ -1556,7 +1653,7 @@ var RtcManager = class {
|
|
|
1556
1653
|
* 停止发布本地音频流;麦克风采集保持运行。
|
|
1557
1654
|
*/
|
|
1558
1655
|
async unpublishLocalAudio() {
|
|
1559
|
-
const engine = _optionalChain([this, 'access',
|
|
1656
|
+
const engine = _optionalChain([this, 'access', _61 => _61.lease, 'optionalAccess', _62 => _62.engine]);
|
|
1560
1657
|
if (!engine || !this.isAudioCapturing) {
|
|
1561
1658
|
return;
|
|
1562
1659
|
}
|
|
@@ -1610,14 +1707,34 @@ var RtcManager = class {
|
|
|
1610
1707
|
throw this.mapError(error);
|
|
1611
1708
|
}
|
|
1612
1709
|
}
|
|
1710
|
+
/**
|
|
1711
|
+
* 当前平台是否支持远端音量控制(iOS Safari/WKWebView 不支持)。
|
|
1712
|
+
*/
|
|
1713
|
+
get supportsRemoteAudioVolumeControl() {
|
|
1714
|
+
return canControlRemoteAudioVolume();
|
|
1715
|
+
}
|
|
1613
1716
|
/**
|
|
1614
1717
|
* 设置指定远端用户的音频播放音量。
|
|
1615
1718
|
*
|
|
1719
|
+
* iOS Safari/WKWebView 不允许 JS 修改媒体元素音量(TRTC 官方标注
|
|
1720
|
+
* `setRemoteAudioVolume` 不支持 iOS Safari),该平台上降级为
|
|
1721
|
+
* 播放/静音二值控制:音量为 0 时停止播放该路音频,非 0 时恢复播放;
|
|
1722
|
+
* 恢复播放需要重新拉流,会有短暂缓冲。
|
|
1723
|
+
*
|
|
1616
1724
|
* @param volume 音量,取值范围为 `0...100`,越界时收敛到边界。
|
|
1617
1725
|
*/
|
|
1618
1726
|
setRemoteAudioVolume(volume, userID) {
|
|
1619
1727
|
const engine = this.requireEngine();
|
|
1620
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
|
+
}
|
|
1621
1738
|
engine.setRemoteAudioVolume(userID, normalized);
|
|
1622
1739
|
}
|
|
1623
1740
|
/**
|
|
@@ -1657,19 +1774,19 @@ var RtcManager = class {
|
|
|
1657
1774
|
registerEventBridge(engine) {
|
|
1658
1775
|
const source = engine;
|
|
1659
1776
|
const onStatistics = (stats) => {
|
|
1660
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
1777
|
+
if (this.isInRoom && _optionalChain([this, 'access', _63 => _63.lease, 'optionalAccess', _64 => _64.engine]) === engine) {
|
|
1661
1778
|
RtcStatsLogger.logStatistics(stats);
|
|
1662
|
-
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")]);
|
|
1663
1780
|
const valid = (value, minimum) => typeof value === "number" && Number.isFinite(value) && value >= minimum ? value : void 0;
|
|
1664
|
-
_optionalChain([this, 'access',
|
|
1781
|
+
_optionalChain([this, 'access', _69 => _69.eventListener, 'optionalAccess', _70 => _70.onLocalVideoStatistics, 'optionalCall', _71 => _71(video ? Object.freeze({
|
|
1665
1782
|
width: valid(video.width, 1),
|
|
1666
1783
|
height: valid(video.height, 1),
|
|
1667
1784
|
frameRate: valid(video.frameRate, 0),
|
|
1668
1785
|
bitrateKbps: valid(video.bitrate, 0)
|
|
1669
1786
|
}) : void 0)]);
|
|
1670
|
-
_optionalChain([this, 'access',
|
|
1787
|
+
_optionalChain([this, 'access', _72 => _72.eventListener, 'optionalAccess', _73 => _73.onRemoteVideoStatistics, 'optionalCall', _74 => _74(Object.freeze(
|
|
1671
1788
|
(_nullishCoalesce(stats.remoteStatistics, () => ( []))).flatMap((remote) => {
|
|
1672
|
-
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")]);
|
|
1673
1790
|
if (!video2) {
|
|
1674
1791
|
return [];
|
|
1675
1792
|
}
|
|
@@ -1691,11 +1808,11 @@ var RtcManager = class {
|
|
|
1691
1808
|
}
|
|
1692
1809
|
};
|
|
1693
1810
|
const onNetworkQuality = (stats) => {
|
|
1694
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
1811
|
+
if (this.isInRoom && _optionalChain([this, 'access', _78 => _78.lease, 'optionalAccess', _79 => _79.engine]) === engine) {
|
|
1695
1812
|
RtcStatsLogger.logNetworkQuality(stats);
|
|
1696
1813
|
const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
|
|
1697
1814
|
const rtt = (value) => Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1698
|
-
_optionalChain([this, 'access',
|
|
1815
|
+
_optionalChain([this, 'access', _80 => _80.eventListener, 'optionalAccess', _81 => _81.onNetworkStatistics, 'optionalCall', _82 => _82(Object.freeze({
|
|
1699
1816
|
uplinkQuality: quality(stats.uplinkNetworkQuality),
|
|
1700
1817
|
downlinkQuality: quality(stats.downlinkNetworkQuality),
|
|
1701
1818
|
uplinkRttMs: rtt(stats.uplinkRTT),
|
|
@@ -1713,13 +1830,13 @@ var RtcManager = class {
|
|
|
1713
1830
|
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
1714
1831
|
return;
|
|
1715
1832
|
}
|
|
1716
|
-
_optionalChain([this, 'access',
|
|
1833
|
+
_optionalChain([this, 'access', _83 => _83.eventListener, 'optionalAccess', _84 => _84.onRemoteVideoPublished, 'call', _85 => _85(event.userId, true)]);
|
|
1717
1834
|
});
|
|
1718
1835
|
source.on(RTC_EVENT.remoteVideoUnavailable, (event) => {
|
|
1719
1836
|
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
1720
1837
|
return;
|
|
1721
1838
|
}
|
|
1722
|
-
_optionalChain([this, 'access',
|
|
1839
|
+
_optionalChain([this, 'access', _86 => _86.eventListener, 'optionalAccess', _87 => _87.onRemoteVideoPublished, 'call', _88 => _88(event.userId, false)]);
|
|
1723
1840
|
});
|
|
1724
1841
|
source.on(RTC_EVENT.customMessage, (event) => {
|
|
1725
1842
|
if (event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
|
|
@@ -1728,18 +1845,18 @@ var RtcManager = class {
|
|
|
1728
1845
|
let message;
|
|
1729
1846
|
try {
|
|
1730
1847
|
message = new TextDecoder().decode(event.data);
|
|
1731
|
-
} catch (
|
|
1848
|
+
} catch (e11) {
|
|
1732
1849
|
XmaxLogger.rtc.warning(() => "\u81EA\u5B9A\u4E49\u6D88\u606F\u89E3\u7801\u5931\u8D25 (Failed to Decode Custom Message)");
|
|
1733
1850
|
return;
|
|
1734
1851
|
}
|
|
1735
|
-
_optionalChain([this, 'access',
|
|
1852
|
+
_optionalChain([this, 'access', _89 => _89.eventListener, 'optionalAccess', _90 => _90.onCustomMessageReceived, 'call', _91 => _91(event.userId, message)]);
|
|
1736
1853
|
});
|
|
1737
1854
|
}
|
|
1738
1855
|
/**
|
|
1739
1856
|
* 返回当前引擎实例;未初始化时抛出错误。
|
|
1740
1857
|
*/
|
|
1741
1858
|
requireEngine() {
|
|
1742
|
-
const engine = _optionalChain([this, 'access',
|
|
1859
|
+
const engine = _optionalChain([this, 'access', _92 => _92.lease, 'optionalAccess', _93 => _93.engine]);
|
|
1743
1860
|
if (!engine) {
|
|
1744
1861
|
throw new XmaxError(
|
|
1745
1862
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -1756,8 +1873,8 @@ var RtcManager = class {
|
|
|
1756
1873
|
return error;
|
|
1757
1874
|
}
|
|
1758
1875
|
const rtcError = error;
|
|
1759
|
-
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess',
|
|
1760
|
-
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);
|
|
1761
1878
|
if (originName === "NotAllowedError" || originName === "SecurityError" || /NotAllowed/i.test(message)) {
|
|
1762
1879
|
return new XmaxError("CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */, message);
|
|
1763
1880
|
}
|
|
@@ -1769,74 +1886,25 @@ var RtcManager = class {
|
|
|
1769
1886
|
};
|
|
1770
1887
|
|
|
1771
1888
|
// src/Foundation/Media/Camera/CameraFrameValidator.ts
|
|
1772
|
-
var
|
|
1773
|
-
var TIMEOUT_MS = 2e3;
|
|
1774
|
-
var CameraFrameValidator = class {
|
|
1775
|
-
/**
|
|
1776
|
-
* 单帧中央区域亮度达标即放行,不等待连续帧或曝光稳定。
|
|
1777
|
-
*/
|
|
1778
|
-
accept(pixels) {
|
|
1779
|
-
const size = pixels.length / 4;
|
|
1780
|
-
if (!size || !Number.isInteger(size)) return false;
|
|
1781
|
-
const histogram = new Uint32Array(256);
|
|
1782
|
-
let total = 0;
|
|
1783
|
-
let dark = 0;
|
|
1784
|
-
for (let i = 0; i < pixels.length; i += 4) {
|
|
1785
|
-
const luminance = Math.round(0.2126 * pixels[i] + 0.7152 * pixels[i + 1] + 0.0722 * pixels[i + 2]);
|
|
1786
|
-
histogram[luminance] = histogram[luminance] + 1;
|
|
1787
|
-
total += luminance;
|
|
1788
|
-
if (luminance < 12) dark++;
|
|
1789
|
-
}
|
|
1790
|
-
let median = 0;
|
|
1791
|
-
let accumulated = 0;
|
|
1792
|
-
for (; median < 255; median++) {
|
|
1793
|
-
accumulated += histogram[median];
|
|
1794
|
-
if (accumulated >= size / 2) break;
|
|
1795
|
-
}
|
|
1796
|
-
const mean = total / size;
|
|
1797
|
-
return mean >= 24 && median >= 18 && dark / size <= 0.75;
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1889
|
+
var CAMERA_WARMUP_MS = 200;
|
|
1800
1890
|
function waitForValidCameraFrame(track, signal) {
|
|
1801
1891
|
return new Promise((resolve, reject) => {
|
|
1802
|
-
let
|
|
1803
|
-
let
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
const gate = new CameraFrameValidator();
|
|
1809
|
-
const finish = (result = "valid") => {
|
|
1810
|
-
if (finished) return;
|
|
1811
|
-
finished = true;
|
|
1812
|
-
clearTimeout(timeout);
|
|
1813
|
-
clearTimeout(poll);
|
|
1814
|
-
if (video) {
|
|
1815
|
-
if (frameCallback !== void 0) video.cancelVideoFrameCallback(frameCallback);
|
|
1816
|
-
video.pause();
|
|
1817
|
-
video.srcObject = null;
|
|
1818
|
-
video.remove();
|
|
1819
|
-
}
|
|
1892
|
+
let timer;
|
|
1893
|
+
let settled = false;
|
|
1894
|
+
const finish = (error) => {
|
|
1895
|
+
if (settled) return;
|
|
1896
|
+
settled = true;
|
|
1897
|
+
clearTimeout(timer);
|
|
1820
1898
|
signal.removeEventListener("abort", abort);
|
|
1821
1899
|
track.removeEventListener("ended", ended);
|
|
1822
|
-
if (
|
|
1823
|
-
|
|
1824
|
-
reject(result);
|
|
1900
|
+
if (error) {
|
|
1901
|
+
reject(error);
|
|
1825
1902
|
} else {
|
|
1826
|
-
if (result === "timeout") {
|
|
1827
|
-
XmaxLogger.media.warning(() => XmaxLogger.localized(
|
|
1828
|
-
"\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",
|
|
1829
|
-
"Camera Frame Validation Timed Out; Continuing\n\u2514\u2500 No sufficiently bright frame received; proceeding without further waiting."
|
|
1830
|
-
));
|
|
1831
|
-
} else {
|
|
1832
|
-
XmaxLogger.media.info(() => `\u76F8\u673A\u66DD\u5149\u68C0\u67E5\u901A\u8FC7 (Camera Exposure Ready)
|
|
1833
|
-
\u2514\u2500 ${Math.round(performance.now() - started)} ms`);
|
|
1834
|
-
}
|
|
1835
1903
|
resolve();
|
|
1836
1904
|
}
|
|
1837
1905
|
};
|
|
1838
|
-
const abort = () => finish(new XmaxError("CANCELLED" /* cancelled */, "Camera
|
|
1839
|
-
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"));
|
|
1840
1908
|
signal.addEventListener("abort", abort, { once: true });
|
|
1841
1909
|
track.addEventListener("ended", ended, { once: true });
|
|
1842
1910
|
if (signal.aborted) {
|
|
@@ -1847,70 +1915,7 @@ function waitForValidCameraFrame(track, signal) {
|
|
|
1847
1915
|
ended();
|
|
1848
1916
|
return;
|
|
1849
1917
|
}
|
|
1850
|
-
|
|
1851
|
-
video = document.createElement("video");
|
|
1852
|
-
video.muted = true;
|
|
1853
|
-
video.autoplay = true;
|
|
1854
|
-
video.playsInline = true;
|
|
1855
|
-
video.setAttribute("aria-hidden", "true");
|
|
1856
|
-
video.style.cssText = "position:fixed;left:0;top:0;width:1px;height:1px;opacity:0;pointer-events:none;";
|
|
1857
|
-
const canvas = document.createElement("canvas");
|
|
1858
|
-
canvas.width = 64;
|
|
1859
|
-
canvas.height = 48;
|
|
1860
|
-
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
1861
|
-
if (!context) throw new Error("Camera exposure sampling requires a 2D canvas");
|
|
1862
|
-
video.srcObject = new MediaStream([track]);
|
|
1863
|
-
document.body.appendChild(video);
|
|
1864
|
-
const source = video;
|
|
1865
|
-
let lastFrameTime = -Infinity;
|
|
1866
|
-
const sample = (mediaTime) => {
|
|
1867
|
-
if (source.readyState < 2 || !source.videoWidth || !source.videoHeight || track.muted || !track.enabled) {
|
|
1868
|
-
return;
|
|
1869
|
-
}
|
|
1870
|
-
if (mediaTime === lastFrameTime) return;
|
|
1871
|
-
lastFrameTime = mediaTime;
|
|
1872
|
-
const width = source.videoWidth;
|
|
1873
|
-
const height = source.videoHeight;
|
|
1874
|
-
context.drawImage(source, width * 0.2, height * 0.2, width * 0.6, height * 0.6, 0, 0, 64, 48);
|
|
1875
|
-
if (gate.accept(context.getImageData(0, 0, 64, 48).data)) finish();
|
|
1876
|
-
};
|
|
1877
|
-
const fail = (error) => finish(new XmaxError(
|
|
1878
|
-
"MEDIA_ERROR" /* mediaError */,
|
|
1879
|
-
`Camera exposure check failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1880
|
-
));
|
|
1881
|
-
const schedule = () => {
|
|
1882
|
-
if (finished) return;
|
|
1883
|
-
if (typeof source.requestVideoFrameCallback === "function") {
|
|
1884
|
-
frameCallback = source.requestVideoFrameCallback((_now, metadata) => {
|
|
1885
|
-
frameCallback = void 0;
|
|
1886
|
-
try {
|
|
1887
|
-
sample(metadata.mediaTime);
|
|
1888
|
-
schedule();
|
|
1889
|
-
} catch (error) {
|
|
1890
|
-
fail(error);
|
|
1891
|
-
}
|
|
1892
|
-
});
|
|
1893
|
-
} else {
|
|
1894
|
-
poll = setTimeout(() => {
|
|
1895
|
-
try {
|
|
1896
|
-
const frameTime = typeof source.getVideoPlaybackQuality === "function" ? source.getVideoPlaybackQuality().totalVideoFrames : source.currentTime;
|
|
1897
|
-
sample(frameTime);
|
|
1898
|
-
schedule();
|
|
1899
|
-
} catch (error) {
|
|
1900
|
-
fail(error);
|
|
1901
|
-
}
|
|
1902
|
-
}, FALLBACK_POLL_INTERVAL_MS);
|
|
1903
|
-
}
|
|
1904
|
-
};
|
|
1905
|
-
timeout = setTimeout(() => finish("timeout"), TIMEOUT_MS);
|
|
1906
|
-
XmaxLogger.media.info(() => "\u7B49\u5F85\u9996\u5F20\u4EAE\u5EA6\u5408\u683C\u5E27 (Waiting for the First Sufficiently Bright Frame)");
|
|
1907
|
-
void source.play().then(schedule, fail);
|
|
1908
|
-
} catch (error) {
|
|
1909
|
-
finish(new XmaxError(
|
|
1910
|
-
"MEDIA_ERROR" /* mediaError */,
|
|
1911
|
-
`Camera exposure check failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1912
|
-
));
|
|
1913
|
-
}
|
|
1918
|
+
timer = setTimeout(() => finish(), CAMERA_WARMUP_MS);
|
|
1914
1919
|
});
|
|
1915
1920
|
}
|
|
1916
1921
|
|
|
@@ -1940,7 +1945,7 @@ var PermissionManager = class {
|
|
|
1940
1945
|
* @param deniedCode 权限被拒绝时抛出的错误码。
|
|
1941
1946
|
*/
|
|
1942
1947
|
async ensurePermission(name, deniedCode) {
|
|
1943
|
-
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access',
|
|
1948
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _97 => _97.mediaDevices, 'optionalAccess', _98 => _98.getUserMedia])) {
|
|
1944
1949
|
throw new XmaxError(
|
|
1945
1950
|
deniedCode,
|
|
1946
1951
|
"This browser does not support media capture (getUserMedia)"
|
|
@@ -1948,7 +1953,7 @@ var PermissionManager = class {
|
|
|
1948
1953
|
}
|
|
1949
1954
|
try {
|
|
1950
1955
|
const permissions = navigator.permissions;
|
|
1951
|
-
if (!_optionalChain([permissions, 'optionalAccess',
|
|
1956
|
+
if (!_optionalChain([permissions, 'optionalAccess', _99 => _99.query])) {
|
|
1952
1957
|
return;
|
|
1953
1958
|
}
|
|
1954
1959
|
const status = await permissions.query({
|
|
@@ -2128,10 +2133,10 @@ var _CameraController = class _CameraController {
|
|
|
2128
2133
|
*/
|
|
2129
2134
|
__publicField(this, "storedUseMicrophone", false);
|
|
2130
2135
|
__publicField(this, "storedFrameValidationEnabled", true);
|
|
2131
|
-
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2132
|
-
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2133
|
-
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2134
|
-
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]), () => ( (() => {
|
|
2135
2140
|
})));
|
|
2136
2141
|
}
|
|
2137
2142
|
/**
|
|
@@ -2147,23 +2152,23 @@ var _CameraController = class _CameraController {
|
|
|
2147
2152
|
return this.activeTrack !== void 0 && this.storedUseMicrophone;
|
|
2148
2153
|
}
|
|
2149
2154
|
/**
|
|
2150
|
-
*
|
|
2155
|
+
* 当前活动相机流是否启用发布前预热等待;没有活动流时为 false。
|
|
2151
2156
|
*/
|
|
2152
2157
|
get isFrameValidationEnabled() {
|
|
2153
2158
|
return this.activeTrack !== void 0 && this.storedFrameValidationEnabled;
|
|
2154
2159
|
}
|
|
2155
2160
|
/**
|
|
2156
|
-
*
|
|
2161
|
+
* 等待当前轨道预热完成(固定 200ms);禁用时跳过,取消或轨道被替换时拒绝。
|
|
2157
2162
|
*/
|
|
2158
2163
|
async waitForValidCameraFrame(signal) {
|
|
2159
2164
|
const track = this.activeTrack;
|
|
2160
|
-
const mediaTrack = _optionalChain([track, 'optionalAccess',
|
|
2165
|
+
const mediaTrack = _optionalChain([track, 'optionalAccess', _104 => _104.mediaStreamTrack]);
|
|
2161
2166
|
if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
|
|
2162
2167
|
if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
|
|
2163
2168
|
if (!this.isFrameValidationEnabled) return;
|
|
2164
2169
|
await waitForValidCameraFrame(mediaTrack, signal);
|
|
2165
2170
|
if (this.activeTrack !== track || track.mediaStreamTrack !== mediaTrack) {
|
|
2166
|
-
throw new XmaxError("CANCELLED" /* cancelled */, "Camera track changed during
|
|
2171
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Camera track changed during warmup");
|
|
2167
2172
|
}
|
|
2168
2173
|
}
|
|
2169
2174
|
/**
|
|
@@ -2182,7 +2187,7 @@ var _CameraController = class _CameraController {
|
|
|
2182
2187
|
* @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
|
|
2183
2188
|
* @param options.position 首次启动时使用的摄像头位置。
|
|
2184
2189
|
* @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
|
|
2185
|
-
* @param options.enableFrameValidation
|
|
2190
|
+
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
2186
2191
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
2187
2192
|
* @throws 已有活动相机流、格式无效、权限不足或采集启动失败时抛出错误。
|
|
2188
2193
|
*/
|
|
@@ -2257,7 +2262,7 @@ var _CameraController = class _CameraController {
|
|
|
2257
2262
|
*/
|
|
2258
2263
|
async switchCamera() {
|
|
2259
2264
|
const track = this.activeTrack;
|
|
2260
|
-
const position = _optionalChain([track, 'optionalAccess',
|
|
2265
|
+
const position = _optionalChain([track, 'optionalAccess', _105 => _105.position]);
|
|
2261
2266
|
if (!track || !position) {
|
|
2262
2267
|
throw new XmaxError(
|
|
2263
2268
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -2275,7 +2280,7 @@ var _CameraController = class _CameraController {
|
|
|
2275
2280
|
}
|
|
2276
2281
|
this.previewStream.addTrack(mediaTrack);
|
|
2277
2282
|
}
|
|
2278
|
-
_optionalChain([this, 'access',
|
|
2283
|
+
_optionalChain([this, 'access', _106 => _106.previewMirrorApplier, 'optionalCall', _107 => _107(nextPosition === "front" /* front */)]);
|
|
2279
2284
|
this.observeMediaTrack(track, mediaTrack);
|
|
2280
2285
|
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
2281
2286
|
}
|
|
@@ -2531,12 +2536,13 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2531
2536
|
this.heartbeatVersion += 1;
|
|
2532
2537
|
}
|
|
2533
2538
|
/**
|
|
2534
|
-
*
|
|
2539
|
+
* 关闭指定实时会话;请求带 keepalive,页面卸载后仍能发出。
|
|
2535
2540
|
*/
|
|
2536
2541
|
async closeSession(sessionID) {
|
|
2537
2542
|
try {
|
|
2538
2543
|
await this.apiService.delete(
|
|
2539
|
-
`/session/${sessionID}
|
|
2544
|
+
`/session/${sessionID}`,
|
|
2545
|
+
{ keepalive: true }
|
|
2540
2546
|
);
|
|
2541
2547
|
} catch (error) {
|
|
2542
2548
|
throw XmaxError.from(error);
|
|
@@ -2557,7 +2563,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2557
2563
|
return;
|
|
2558
2564
|
}
|
|
2559
2565
|
_RealtimeSessionService.ensureSessionActive(session);
|
|
2560
|
-
_optionalChain([handlers, 'access',
|
|
2566
|
+
_optionalChain([handlers, 'access', _108 => _108.onRefresh, 'optionalCall', _109 => _109(session)]);
|
|
2561
2567
|
} catch (error) {
|
|
2562
2568
|
if (this.heartbeatVersion !== version) {
|
|
2563
2569
|
return;
|
|
@@ -2650,7 +2656,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2650
2656
|
if (typeof modelExtra === "string") {
|
|
2651
2657
|
try {
|
|
2652
2658
|
return JSON.parse(modelExtra);
|
|
2653
|
-
} catch (
|
|
2659
|
+
} catch (e12) {
|
|
2654
2660
|
return void 0;
|
|
2655
2661
|
}
|
|
2656
2662
|
}
|
|
@@ -2663,7 +2669,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
2663
2669
|
* 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
|
|
2664
2670
|
*/
|
|
2665
2671
|
static nonEmpty(value) {
|
|
2666
|
-
const normalized = _optionalChain([value, 'optionalAccess',
|
|
2672
|
+
const normalized = _optionalChain([value, 'optionalAccess', _110 => _110.trim, 'call', _111 => _111()]);
|
|
2667
2673
|
return normalized || void 0;
|
|
2668
2674
|
}
|
|
2669
2675
|
};
|
|
@@ -2735,7 +2741,7 @@ var RealtimeState = class {
|
|
|
2735
2741
|
* @param other 待比较的状态。
|
|
2736
2742
|
*/
|
|
2737
2743
|
equals(other) {
|
|
2738
|
-
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]);
|
|
2739
2745
|
}
|
|
2740
2746
|
};
|
|
2741
2747
|
|
|
@@ -2904,7 +2910,7 @@ var RoomEvent = class _RoomEvent {
|
|
|
2904
2910
|
static encode(payload) {
|
|
2905
2911
|
try {
|
|
2906
2912
|
return JSON.stringify({ ...payload, runtime: RuntimeInfo.toJSON() });
|
|
2907
|
-
} catch (
|
|
2913
|
+
} catch (e13) {
|
|
2908
2914
|
throw new XmaxError(
|
|
2909
2915
|
"INTERNAL_ERROR" /* internalError */,
|
|
2910
2916
|
"Failed to encode RTC room event"
|
|
@@ -3026,7 +3032,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
3026
3032
|
let parsed;
|
|
3027
3033
|
try {
|
|
3028
3034
|
parsed = JSON.parse(message);
|
|
3029
|
-
} catch (
|
|
3035
|
+
} catch (e14) {
|
|
3030
3036
|
XmaxLogger.room.warning(() => "\u623F\u95F4\u6D88\u606F\u4E0D\u662F\u5408\u6CD5 JSON (Room Message Is Not Valid JSON)");
|
|
3031
3037
|
return void 0;
|
|
3032
3038
|
}
|
|
@@ -3057,7 +3063,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
3057
3063
|
const joined = parts.join("");
|
|
3058
3064
|
try {
|
|
3059
3065
|
return JSON.parse(joined);
|
|
3060
|
-
} catch (
|
|
3066
|
+
} catch (e15) {
|
|
3061
3067
|
XmaxLogger.room.warning(
|
|
3062
3068
|
() => `\u623F\u95F4\u6D88\u606F\u7EC4\u5305\u540E\u4E0D\u662F\u5408\u6CD5 JSON (Reassembled Message Is Not Valid JSON)
|
|
3063
3069
|
\u2514\u2500 eventId: ${chunk.eventId}`
|
|
@@ -3355,7 +3361,7 @@ var RoomController = class {
|
|
|
3355
3361
|
if (targetUserID && ownUserID && targetUserID !== ownUserID) {
|
|
3356
3362
|
return;
|
|
3357
3363
|
}
|
|
3358
|
-
_optionalChain([this, 'access',
|
|
3364
|
+
_optionalChain([this, 'access', _116 => _116.listener, 'optionalAccess', _117 => _117.onRoomMessage, 'call', _118 => _118(senderUserID, message)]);
|
|
3359
3365
|
}
|
|
3360
3366
|
/**
|
|
3361
3367
|
* 发送房间信令并输出日志。
|
|
@@ -3600,18 +3606,18 @@ var StreamController = class {
|
|
|
3600
3606
|
this.rtcManager.setEventListener({
|
|
3601
3607
|
onNetworkStatistics: (statistics) => {
|
|
3602
3608
|
if (this.state.localVideoPublished) {
|
|
3603
|
-
_optionalChain([this, 'access',
|
|
3609
|
+
_optionalChain([this, 'access', _119 => _119.networkStatisticsListener, 'optionalCall', _120 => _120(statistics)]);
|
|
3604
3610
|
}
|
|
3605
3611
|
},
|
|
3606
3612
|
onRemoteVideoStatistics: (statistics) => {
|
|
3607
|
-
const userID = _optionalChain([this, 'access',
|
|
3608
|
-
_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(
|
|
3609
3615
|
userID ? statistics.find((item) => item.userID === userID) : void 0
|
|
3610
3616
|
)]);
|
|
3611
3617
|
},
|
|
3612
3618
|
onLocalVideoStatistics: (statistics) => {
|
|
3613
3619
|
if (this.state.localVideoPublished) {
|
|
3614
|
-
_optionalChain([this, 'access',
|
|
3620
|
+
_optionalChain([this, 'access', _126 => _126.localVideoStatisticsListener, 'optionalCall', _127 => _127(statistics)]);
|
|
3615
3621
|
}
|
|
3616
3622
|
},
|
|
3617
3623
|
onCustomMessageReceived: (senderUserID, message) => {
|
|
@@ -3683,7 +3689,7 @@ var StreamController = class {
|
|
|
3683
3689
|
() => `RTC \u623F\u95F4\u5DF2\u914D\u7F6E (RTC Room Configured)
|
|
3684
3690
|
\u2514\u2500 roomID: ${connection.roomID}, botID: ${_nullishCoalesce(connection.botID, () => ( "(\u672A\u8BBE\u7F6E)"))}`
|
|
3685
3691
|
);
|
|
3686
|
-
await _optionalChain([beforePublish, 'optionalCall',
|
|
3692
|
+
await _optionalChain([beforePublish, 'optionalCall', _128 => _128()]);
|
|
3687
3693
|
ensureActive();
|
|
3688
3694
|
await this.publishLocalStream(includeLocalAudio);
|
|
3689
3695
|
}
|
|
@@ -3754,7 +3760,7 @@ var StreamController = class {
|
|
|
3754
3760
|
this.rejectGenerationStart(taskID, mapped);
|
|
3755
3761
|
try {
|
|
3756
3762
|
this.roomController.stopGeneration(taskID);
|
|
3757
|
-
} catch (
|
|
3763
|
+
} catch (e16) {
|
|
3758
3764
|
}
|
|
3759
3765
|
throw mapped;
|
|
3760
3766
|
}
|
|
@@ -3843,7 +3849,7 @@ var StreamController = class {
|
|
|
3843
3849
|
*/
|
|
3844
3850
|
configureRoom(options) {
|
|
3845
3851
|
const roomID = options.roomID.trim();
|
|
3846
|
-
const botID = _nullishCoalesce(_optionalChain([options, 'access',
|
|
3852
|
+
const botID = _nullishCoalesce(_optionalChain([options, 'access', _129 => _129.botID, 'optionalAccess', _130 => _130.trim, 'call', _131 => _131()]), () => ( ""));
|
|
3847
3853
|
if (!roomID) {
|
|
3848
3854
|
throw new XmaxError(
|
|
3849
3855
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
@@ -3920,7 +3926,7 @@ var StreamController = class {
|
|
|
3920
3926
|
return;
|
|
3921
3927
|
}
|
|
3922
3928
|
this.state.subscribedRemoteUserIDs.delete(trimmedUserID);
|
|
3923
|
-
if (_optionalChain([this, 'access',
|
|
3929
|
+
if (_optionalChain([this, 'access', _132 => _132.state, 'access', _133 => _133.activeRemoteStream, 'optionalAccess', _134 => _134.userID]) === trimmedUserID) {
|
|
3924
3930
|
await this.unsubscribeRemoteAudio(trimmedUserID);
|
|
3925
3931
|
this.state.activeRemoteStream = void 0;
|
|
3926
3932
|
this.clearRemoteStream();
|
|
@@ -3996,14 +4002,23 @@ var StreamController = class {
|
|
|
3996
4002
|
}
|
|
3997
4003
|
}
|
|
3998
4004
|
/**
|
|
3999
|
-
*
|
|
4005
|
+
* 订阅远端音频并按平台能力应用当前音量。
|
|
4006
|
+
*
|
|
4007
|
+
* 支持音量控制的平台先设音量再订阅,避免以默认音量短暂出声;
|
|
4008
|
+
* iOS 上音量降级为播放/静音二值控制,必须先完成订阅(恢复播放)
|
|
4009
|
+
* 再按需静音,否则订阅的恢复播放会覆盖音量 0 的静音状态。
|
|
4000
4010
|
*/
|
|
4001
4011
|
async subscribeRemoteAudio(userID) {
|
|
4002
4012
|
if (this.state.subscribedRemoteAudioUserIDs.has(userID)) {
|
|
4003
4013
|
return;
|
|
4004
4014
|
}
|
|
4005
|
-
this.rtcManager.
|
|
4006
|
-
|
|
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
|
+
}
|
|
4007
4022
|
this.state.subscribedRemoteAudioUserIDs.add(userID);
|
|
4008
4023
|
}
|
|
4009
4024
|
/**
|
|
@@ -4080,7 +4095,7 @@ var StreamController = class {
|
|
|
4080
4095
|
*/
|
|
4081
4096
|
resolveGenerationStart(taskID) {
|
|
4082
4097
|
const waiter = this.state.generationWaiter;
|
|
4083
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
4098
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _135 => _135.taskID]) !== taskID) {
|
|
4084
4099
|
return;
|
|
4085
4100
|
}
|
|
4086
4101
|
this.state.generationWaiter = void 0;
|
|
@@ -4092,7 +4107,7 @@ var StreamController = class {
|
|
|
4092
4107
|
*/
|
|
4093
4108
|
rejectGenerationStart(taskID, error) {
|
|
4094
4109
|
const waiter = this.state.generationWaiter;
|
|
4095
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
4110
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _136 => _136.taskID]) !== taskID) {
|
|
4096
4111
|
return;
|
|
4097
4112
|
}
|
|
4098
4113
|
this.state.generationWaiter = void 0;
|
|
@@ -4103,7 +4118,7 @@ var StreamController = class {
|
|
|
4103
4118
|
* 通知渲染层清理远端生成流;失败仅记录日志。
|
|
4104
4119
|
*/
|
|
4105
4120
|
clearRemoteStream() {
|
|
4106
|
-
_optionalChain([this, 'access',
|
|
4121
|
+
_optionalChain([this, 'access', _137 => _137.remoteVideoStatisticsListener, 'optionalCall', _138 => _138(void 0)]);
|
|
4107
4122
|
try {
|
|
4108
4123
|
this.remoteStreamListener(null);
|
|
4109
4124
|
} catch (error) {
|
|
@@ -4374,7 +4389,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4374
4389
|
}
|
|
4375
4390
|
throw _RealtimeCoordinator.cancelledError();
|
|
4376
4391
|
}
|
|
4377
|
-
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(
|
|
4378
4393
|
_nullishCoalesce(operation.lease.failureScope, () => ( 0)) /* connection */,
|
|
4379
4394
|
void 0,
|
|
4380
4395
|
RealtimeReason.normal,
|
|
@@ -4503,7 +4518,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4503
4518
|
* 结束指定操作,释放操作准入场。
|
|
4504
4519
|
*/
|
|
4505
4520
|
finish(operation) {
|
|
4506
|
-
if (_optionalChain([this, 'access',
|
|
4521
|
+
if (_optionalChain([this, 'access', _141 => _141.activeOperation, 'optionalAccess', _142 => _142.id]) === operation.id) {
|
|
4507
4522
|
this.activeOperation = void 0;
|
|
4508
4523
|
}
|
|
4509
4524
|
}
|
|
@@ -4515,7 +4530,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
4515
4530
|
return;
|
|
4516
4531
|
}
|
|
4517
4532
|
this.state = nextState;
|
|
4518
|
-
_optionalChain([this, 'access',
|
|
4533
|
+
_optionalChain([this, 'access', _143 => _143.stateListener, 'optionalCall', _144 => _144(nextState)]);
|
|
4519
4534
|
}
|
|
4520
4535
|
/**
|
|
4521
4536
|
* 构造统一的操作取消错误。
|
|
@@ -4591,17 +4606,25 @@ var RealtimeLaunchTimer = class {
|
|
|
4591
4606
|
this.notify();
|
|
4592
4607
|
return complete;
|
|
4593
4608
|
}
|
|
4609
|
+
/**
|
|
4610
|
+
* 开始等待用户授权系统媒体权限,返回授权决定时调用的记录函数。
|
|
4611
|
+
* 仅在系统弹出授权请求时使用;已授权或未弹窗不记录该阶段。
|
|
4612
|
+
*/
|
|
4613
|
+
startPermission() {
|
|
4614
|
+
return this.measure("permissionMs", performance.now());
|
|
4615
|
+
}
|
|
4594
4616
|
/**
|
|
4595
4617
|
* 开始会话与进房计时,返回连接阶段完成时调用的记录函数。
|
|
4618
|
+
* 相机预热等待计入连接耗时。
|
|
4596
4619
|
*/
|
|
4597
4620
|
startConnection() {
|
|
4598
4621
|
return this.measure("connectionMs", performance.now());
|
|
4599
4622
|
}
|
|
4600
4623
|
/**
|
|
4601
|
-
*
|
|
4624
|
+
* 开始发布本地流计时,返回发布完成时调用的记录函数。
|
|
4602
4625
|
*/
|
|
4603
|
-
|
|
4604
|
-
return this.measure("
|
|
4626
|
+
startPublish() {
|
|
4627
|
+
return this.measure("publishMs", performance.now());
|
|
4605
4628
|
}
|
|
4606
4629
|
/**
|
|
4607
4630
|
* 开始等待远端显示首帧;完成回调同时记录首帧耗时和实际总耗时。
|
|
@@ -4639,9 +4662,9 @@ var RealtimeLaunchTimer = class {
|
|
|
4639
4662
|
*/
|
|
4640
4663
|
notify() {
|
|
4641
4664
|
try {
|
|
4642
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
4665
|
+
void Promise.resolve(_optionalChain([this, 'access', _145 => _145.listener, 'optionalCall', _146 => _146(this.snapshot)])).catch(() => {
|
|
4643
4666
|
});
|
|
4644
|
-
} catch (
|
|
4667
|
+
} catch (e17) {
|
|
4645
4668
|
}
|
|
4646
4669
|
}
|
|
4647
4670
|
};
|
|
@@ -4667,7 +4690,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4667
4690
|
* 当前活动会话标识;尚未连接或清理完成后为空。
|
|
4668
4691
|
*/
|
|
4669
4692
|
get currentSessionID() {
|
|
4670
|
-
return _optionalChain([this, 'access',
|
|
4693
|
+
return _optionalChain([this, 'access', _147 => _147.activeSession, 'optionalAccess', _148 => _148.id]);
|
|
4671
4694
|
}
|
|
4672
4695
|
/**
|
|
4673
4696
|
* 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
|
|
@@ -4677,7 +4700,8 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4677
4700
|
}
|
|
4678
4701
|
/**
|
|
4679
4702
|
* 创建会话、配置编码、进房并发布本地媒体,启动心跳后返回远端占位流。
|
|
4680
|
-
* 进房结束即记录连接耗时;可选 beforePublish
|
|
4703
|
+
* 进房结束即记录连接耗时;可选 beforePublish 检查阻塞发布,计入连接耗时;
|
|
4704
|
+
* 发布本地流单独计时。
|
|
4681
4705
|
* @throws 会话、进房、发布失败或操作租约已失效时抛出错误,由上层统一清理。
|
|
4682
4706
|
*/
|
|
4683
4707
|
async connect(options) {
|
|
@@ -4704,15 +4728,17 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4704
4728
|
}
|
|
4705
4729
|
await streamController.setVideoEncoderConfig(videoFormat);
|
|
4706
4730
|
options.ensureCurrent();
|
|
4731
|
+
let completePublish;
|
|
4707
4732
|
await streamController.connect(connection, options.includeLocalAudio, () => {
|
|
4708
4733
|
options.ensureCurrent();
|
|
4709
4734
|
}, async () => {
|
|
4710
4735
|
options.ensureCurrent();
|
|
4736
|
+
await _optionalChain([options, 'access', _149 => _149.beforePublish, 'optionalCall', _150 => _150()]);
|
|
4711
4737
|
completeConnection();
|
|
4712
|
-
|
|
4713
|
-
await _optionalChain([options, 'access', _137 => _137.beforePublish, 'optionalCall', _138 => _138()]);
|
|
4738
|
+
completePublish = this.dependencies.timing.startPublish();
|
|
4714
4739
|
});
|
|
4715
4740
|
options.ensureCurrent();
|
|
4741
|
+
_optionalChain([completePublish, 'optionalCall', _151 => _151()]);
|
|
4716
4742
|
options.onPublished();
|
|
4717
4743
|
sessionService.startHeartbeat(session.id, {
|
|
4718
4744
|
onFailure: (sessionID, error) => {
|
|
@@ -4735,26 +4761,26 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4735
4761
|
* 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
|
|
4736
4762
|
*/
|
|
4737
4763
|
setFrameInterpolation(options) {
|
|
4738
|
-
_optionalChain([this, 'access',
|
|
4764
|
+
_optionalChain([this, 'access', _152 => _152.remoteTarget, 'optionalAccess', _153 => _153.setFrameInterpolation, 'optionalCall', _154 => _154(options)]);
|
|
4739
4765
|
}
|
|
4740
4766
|
/**
|
|
4741
4767
|
* 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
|
|
4742
4768
|
*/
|
|
4743
4769
|
clearRemoteMedia() {
|
|
4744
|
-
_optionalChain([this, 'access',
|
|
4770
|
+
_optionalChain([this, 'access', _155 => _155.remoteTarget, 'optionalAccess', _156 => _156.setMediaStream, 'call', _157 => _157(null)]);
|
|
4745
4771
|
}
|
|
4746
4772
|
/**
|
|
4747
4773
|
* 停止会话心跳;未配置会话服务时不执行操作。
|
|
4748
4774
|
*/
|
|
4749
4775
|
stopHeartbeat() {
|
|
4750
|
-
_optionalChain([this, 'access',
|
|
4776
|
+
_optionalChain([this, 'access', _158 => _158.dependencies, 'access', _159 => _159.sessionService, 'optionalAccess', _160 => _160.stopHeartbeat, 'call', _161 => _161()]);
|
|
4751
4777
|
}
|
|
4752
4778
|
/**
|
|
4753
4779
|
* 等待接收轨解除静音;超时只警告,取消必须立即退出并移除监听。
|
|
4754
4780
|
*/
|
|
4755
4781
|
async waitUntilRemoteTrackReady(timeoutMs, signal) {
|
|
4756
4782
|
if (signal.aborted) throw RealtimeCoordinator.cancelledError();
|
|
4757
|
-
const mediaTrack = _optionalChain([this, 'access',
|
|
4783
|
+
const mediaTrack = _optionalChain([this, 'access', _162 => _162.activeRemoteTrack, 'optionalAccess', _163 => _163.mediaStreamTrack]);
|
|
4758
4784
|
if (!mediaTrack || !mediaTrack.muted) return;
|
|
4759
4785
|
await new Promise((resolve, reject) => {
|
|
4760
4786
|
const cleanup = () => {
|
|
@@ -4791,7 +4817,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4791
4817
|
if (track) {
|
|
4792
4818
|
track.mediaStreamTrack = void 0;
|
|
4793
4819
|
}
|
|
4794
|
-
_optionalChain([this, 'access',
|
|
4820
|
+
_optionalChain([this, 'access', _164 => _164.remoteTarget, 'optionalAccess', _165 => _165.setMediaStream, 'call', _166 => _166(null)]);
|
|
4795
4821
|
return;
|
|
4796
4822
|
}
|
|
4797
4823
|
if (!track) {
|
|
@@ -4801,7 +4827,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4801
4827
|
);
|
|
4802
4828
|
}
|
|
4803
4829
|
track.mediaStreamTrack = binding.videoTrack;
|
|
4804
|
-
_optionalChain([this, 'access',
|
|
4830
|
+
_optionalChain([this, 'access', _167 => _167.remoteTarget, 'optionalAccess', _168 => _168.setMediaStream, 'call', _169 => _169(new MediaStream([binding.videoTrack]))]);
|
|
4805
4831
|
}
|
|
4806
4832
|
/**
|
|
4807
4833
|
* 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
|
|
@@ -4814,7 +4840,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4814
4840
|
}
|
|
4815
4841
|
},
|
|
4816
4842
|
attachHandler: (view) => {
|
|
4817
|
-
_optionalChain([this, 'access',
|
|
4843
|
+
_optionalChain([this, 'access', _170 => _170.remoteTarget, 'optionalAccess', _171 => _171.setFrameInterpolation, 'optionalCall', _172 => _172(void 0)]);
|
|
4818
4844
|
view.isMirrored = this.dependencies.isMirrored();
|
|
4819
4845
|
this.remoteTarget = view;
|
|
4820
4846
|
this.dependencies.onRenderAttached();
|
|
@@ -4826,7 +4852,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4826
4852
|
this.dependencies.onRenderDetached();
|
|
4827
4853
|
this.remoteTarget = void 0;
|
|
4828
4854
|
}
|
|
4829
|
-
_optionalChain([view, 'access',
|
|
4855
|
+
_optionalChain([view, 'access', _173 => _173.setFrameInterpolation, 'optionalCall', _174 => _174(void 0)]);
|
|
4830
4856
|
view.setMediaStream(null);
|
|
4831
4857
|
}
|
|
4832
4858
|
});
|
|
@@ -4886,7 +4912,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
4886
4912
|
* 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
|
|
4887
4913
|
*/
|
|
4888
4914
|
async disconnect() {
|
|
4889
|
-
const sessionID = _optionalChain([this, 'access',
|
|
4915
|
+
const sessionID = _optionalChain([this, 'access', _175 => _175.activeSession, 'optionalAccess', _176 => _176.id]);
|
|
4890
4916
|
this.stopHeartbeat();
|
|
4891
4917
|
this.clearRemoteMedia();
|
|
4892
4918
|
try {
|
|
@@ -5019,7 +5045,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
5019
5045
|
try {
|
|
5020
5046
|
await completion;
|
|
5021
5047
|
} finally {
|
|
5022
|
-
if (_optionalChain([this, 'access',
|
|
5048
|
+
if (_optionalChain([this, 'access', _177 => _177.pendingStop, 'optionalAccess', _178 => _178.completion]) === completion) this.pendingStop = void 0;
|
|
5023
5049
|
}
|
|
5024
5050
|
}
|
|
5025
5051
|
/**
|
|
@@ -5101,6 +5127,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5101
5127
|
*/
|
|
5102
5128
|
__publicField(this, "launchTimer", new RealtimeLaunchTimer());
|
|
5103
5129
|
__publicField(this, "remoteFrameDisplayHandler");
|
|
5130
|
+
/**
|
|
5131
|
+
* 媒体权限弹窗观察
|
|
5132
|
+
*/
|
|
5133
|
+
__publicField(this, "permissionWatchDispose");
|
|
5104
5134
|
/**
|
|
5105
5135
|
* 本地、远端和网络统计快照及观察者
|
|
5106
5136
|
*/
|
|
@@ -5125,18 +5155,18 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5125
5155
|
this.options = options;
|
|
5126
5156
|
this.mediaService = new MediaService(options.model);
|
|
5127
5157
|
this.interpolationRequested = options.isFrameInterpolationEnabled;
|
|
5128
|
-
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5158
|
+
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _179 => _179.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
|
|
5129
5159
|
this.errorHandler = new RealtimeErrorHandler();
|
|
5130
|
-
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5131
|
-
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({
|
|
5132
5162
|
rtcManager,
|
|
5133
5163
|
mediaService: this.mediaService,
|
|
5134
5164
|
errorListener: (error) => {
|
|
5135
5165
|
void this.errorHandler.report(error);
|
|
5136
5166
|
}
|
|
5137
5167
|
})));
|
|
5138
|
-
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
5139
|
-
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({
|
|
5140
5170
|
rtcManager,
|
|
5141
5171
|
errorListener: (error) => {
|
|
5142
5172
|
void this.errorHandler.report(error);
|
|
@@ -5150,12 +5180,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5150
5180
|
sessionService,
|
|
5151
5181
|
streamController: this.streamController,
|
|
5152
5182
|
timing: this.launchTimer,
|
|
5153
|
-
isMirrored: () => _optionalChain([this, 'access',
|
|
5183
|
+
isMirrored: () => _optionalChain([this, 'access', _185 => _185.cameraController, 'access', _186 => _186.currentTrack, 'optionalAccess', _187 => _187.position]) === "front" /* front */,
|
|
5154
5184
|
remoteAudioVolume: () => this.storedRemoteAudioVolume,
|
|
5155
5185
|
onHeartbeatFailure: (sessionID, error) => {
|
|
5156
5186
|
void this.handleHeartbeatFailure(sessionID, error);
|
|
5157
5187
|
},
|
|
5158
|
-
onFrameDisplayed: () => _optionalChain([this, 'access',
|
|
5188
|
+
onFrameDisplayed: () => _optionalChain([this, 'access', _188 => _188.remoteFrameDisplayHandler, 'optionalCall', _189 => _189()]),
|
|
5159
5189
|
onRenderAttached: () => this.applyRemoteInterpolation(),
|
|
5160
5190
|
onRenderDetached: () => {
|
|
5161
5191
|
this.interpolationRevision++;
|
|
@@ -5202,7 +5232,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5202
5232
|
*/
|
|
5203
5233
|
async setFrameInterpolationEnabled(enabled) {
|
|
5204
5234
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
5205
|
-
const format = _optionalChain([this, 'access',
|
|
5235
|
+
const format = _optionalChain([this, 'access', _190 => _190.cameraController, 'access', _191 => _191.currentTrack, 'optionalAccess', _192 => _192.videoFormat]);
|
|
5206
5236
|
const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
|
|
5207
5237
|
if (enabled && !await this.checkInterpolationSupport(size, token)) {
|
|
5208
5238
|
token.ensureCurrent();
|
|
@@ -5328,9 +5358,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5328
5358
|
*/
|
|
5329
5359
|
notifyRemoteVideoStatistics() {
|
|
5330
5360
|
try {
|
|
5331
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5361
|
+
void Promise.resolve(_optionalChain([this, 'access', _193 => _193.remoteVideoStatisticsListener, 'optionalCall', _194 => _194(this.remoteVideoStatistics)])).catch(() => {
|
|
5332
5362
|
});
|
|
5333
|
-
} catch (
|
|
5363
|
+
} catch (e18) {
|
|
5334
5364
|
}
|
|
5335
5365
|
}
|
|
5336
5366
|
/**
|
|
@@ -5345,9 +5375,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5345
5375
|
*/
|
|
5346
5376
|
notifyNetworkStatistics() {
|
|
5347
5377
|
try {
|
|
5348
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5378
|
+
void Promise.resolve(_optionalChain([this, 'access', _195 => _195.networkStatisticsListener, 'optionalCall', _196 => _196(this.networkStatistics)])).catch(() => {
|
|
5349
5379
|
});
|
|
5350
|
-
} catch (
|
|
5380
|
+
} catch (e19) {
|
|
5351
5381
|
}
|
|
5352
5382
|
}
|
|
5353
5383
|
/**
|
|
@@ -5365,9 +5395,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5365
5395
|
*/
|
|
5366
5396
|
notifyLocalVideoStatistics() {
|
|
5367
5397
|
try {
|
|
5368
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
5398
|
+
void Promise.resolve(_optionalChain([this, 'access', _197 => _197.localVideoStatisticsListener, 'optionalCall', _198 => _198(this.localVideoStatistics)])).catch(() => {
|
|
5369
5399
|
});
|
|
5370
|
-
} catch (
|
|
5400
|
+
} catch (e20) {
|
|
5371
5401
|
}
|
|
5372
5402
|
}
|
|
5373
5403
|
/**
|
|
@@ -5419,7 +5449,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5419
5449
|
*
|
|
5420
5450
|
* 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
|
|
5421
5451
|
*
|
|
5422
|
-
* @param options.enableFrameValidation
|
|
5452
|
+
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
5423
5453
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
5424
5454
|
* @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
|
|
5425
5455
|
*/
|
|
@@ -5437,11 +5467,20 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5437
5467
|
token.ensureCurrent();
|
|
5438
5468
|
const completeCamera = this.launchTimer.startCamera();
|
|
5439
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
|
+
}
|
|
5440
5478
|
let stream;
|
|
5441
5479
|
try {
|
|
5442
5480
|
token.ensureCurrent();
|
|
5443
5481
|
stream = await this.cameraController.createLocalCameraStream(options);
|
|
5444
5482
|
} catch (error) {
|
|
5483
|
+
this.disposePermissionWatch();
|
|
5445
5484
|
this.launchTimer.cancel();
|
|
5446
5485
|
throw error;
|
|
5447
5486
|
}
|
|
@@ -5454,6 +5493,13 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5454
5493
|
}
|
|
5455
5494
|
);
|
|
5456
5495
|
}
|
|
5496
|
+
/**
|
|
5497
|
+
* 移除媒体权限弹窗观察;授权决定已记录或不再需要观察时调用。
|
|
5498
|
+
*/
|
|
5499
|
+
disposePermissionWatch() {
|
|
5500
|
+
_optionalChain([this, 'access', _200 => _200.permissionWatchDispose, 'optionalCall', _201 => _201()]);
|
|
5501
|
+
this.permissionWatchDispose = void 0;
|
|
5502
|
+
}
|
|
5457
5503
|
/**
|
|
5458
5504
|
* 停止本地相机流并释放本地预览与 RTC 资源。
|
|
5459
5505
|
*/
|
|
@@ -5464,6 +5510,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5464
5510
|
async (token) => {
|
|
5465
5511
|
this.launchTimer.cancel();
|
|
5466
5512
|
this.clearVideoStatistics();
|
|
5513
|
+
this.disposePermissionWatch();
|
|
5467
5514
|
await this.cameraController.stopLocalCameraStream();
|
|
5468
5515
|
token.ensureCurrent();
|
|
5469
5516
|
await this.coordinator.commit(
|
|
@@ -5497,8 +5544,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5497
5544
|
* 使用当前 Manager 创建的本地流建立实时连接。
|
|
5498
5545
|
*
|
|
5499
5546
|
* 创建实时会话、加入 RTC 房间并发布本地流,成功后启动会话心跳。
|
|
5500
|
-
*
|
|
5501
|
-
* 记录警告并按当前画面继续发布,不因环境较暗而阻断连接。
|
|
5547
|
+
* 启用帧检测时,发布前并行等待相机预热(固定 200ms),避免把黑帧推给 RTC。
|
|
5502
5548
|
* 返回的远端媒体流在生成开始后承载远端生成画面。
|
|
5503
5549
|
*
|
|
5504
5550
|
* @param localStream 由 `createLocalCameraStream` 创建的本地媒体流。
|
|
@@ -5607,17 +5653,15 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5607
5653
|
new RealtimeState({ connectionState: "Connecting" /* connecting */ }),
|
|
5608
5654
|
token
|
|
5609
5655
|
);
|
|
5610
|
-
const
|
|
5611
|
-
const
|
|
5612
|
-
token.signal.addEventListener("abort",
|
|
5613
|
-
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();
|
|
5614
5660
|
try {
|
|
5615
5661
|
let beforePublish;
|
|
5616
5662
|
if (this.cameraController.isFrameValidationEnabled) {
|
|
5617
|
-
const
|
|
5618
|
-
const cameraReady = this.cameraController.waitForValidCameraFrame(exposureController.signal).then(() => {
|
|
5663
|
+
const cameraReady = this.cameraController.waitForValidCameraFrame(warmupController.signal).then(() => {
|
|
5619
5664
|
token.ensureCurrent();
|
|
5620
|
-
completeFrameValidation();
|
|
5621
5665
|
});
|
|
5622
5666
|
void cameraReady.catch(() => {
|
|
5623
5667
|
});
|
|
@@ -5642,8 +5686,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5642
5686
|
);
|
|
5643
5687
|
return remote;
|
|
5644
5688
|
} finally {
|
|
5645
|
-
token.signal.removeEventListener("abort",
|
|
5646
|
-
|
|
5689
|
+
token.signal.removeEventListener("abort", abortWarmup);
|
|
5690
|
+
abortWarmup();
|
|
5647
5691
|
}
|
|
5648
5692
|
}
|
|
5649
5693
|
/**
|
|
@@ -5700,6 +5744,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
5700
5744
|
await this.generationManager.reset(taskID);
|
|
5701
5745
|
const sessionID = await this.connectionManager.disconnect();
|
|
5702
5746
|
if (scope === 1 /* all */) {
|
|
5747
|
+
this.disposePermissionWatch();
|
|
5703
5748
|
try {
|
|
5704
5749
|
await this.cameraController.stopLocalCameraStream();
|
|
5705
5750
|
} catch (error) {
|
|
@@ -5815,9 +5860,9 @@ var XmaxClient = class {
|
|
|
5815
5860
|
/**
|
|
5816
5861
|
* 创建媒体处理与能力查询 Service。
|
|
5817
5862
|
*
|
|
5818
|
-
* @param model 媒体输入规则使用的模型,默认为 `x2-
|
|
5863
|
+
* @param model 媒体输入规则使用的模型,默认为 `x2.0-trtc`。
|
|
5819
5864
|
*/
|
|
5820
|
-
createMediaService(model = "x2-
|
|
5865
|
+
createMediaService(model = "x2.0-trtc" /* x2_0_trtc */) {
|
|
5821
5866
|
return new MediaService(model);
|
|
5822
5867
|
}
|
|
5823
5868
|
/**
|
|
@@ -5859,11 +5904,11 @@ var RealtimeConfiguration = class {
|
|
|
5859
5904
|
*/
|
|
5860
5905
|
__publicField(this, "frameInterpolation");
|
|
5861
5906
|
this.model = init.model;
|
|
5862
|
-
const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access',
|
|
5907
|
+
const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access', _202 => _202.frameInterpolation, 'optionalAccess', _203 => _203.targetFrameRate]), () => ( 60));
|
|
5863
5908
|
if (!Number.isFinite(targetFrameRate) || targetFrameRate < 1 || targetFrameRate > 60) {
|
|
5864
5909
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Interpolation targetFrameRate must be between 1 and 60");
|
|
5865
5910
|
}
|
|
5866
|
-
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));
|
|
5867
5912
|
this.frameInterpolation = Object.freeze({ enabled: this.isFrameInterpolationEnabled, targetFrameRate });
|
|
5868
5913
|
}
|
|
5869
5914
|
};
|
|
@@ -5893,7 +5938,7 @@ var RealtimeContext = class {
|
|
|
5893
5938
|
*/
|
|
5894
5939
|
__publicField(this, "referencePath");
|
|
5895
5940
|
this.prompt = init.prompt.trim();
|
|
5896
|
-
const normalizedReferencePath = _optionalChain([init, 'access',
|
|
5941
|
+
const normalizedReferencePath = _optionalChain([init, 'access', _206 => _206.referencePath, 'optionalAccess', _207 => _207.trim, 'call', _208 => _208()]);
|
|
5897
5942
|
this.referencePath = normalizedReferencePath || void 0;
|
|
5898
5943
|
}
|
|
5899
5944
|
};
|
|
@@ -8020,11 +8065,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
8020
8065
|
if (this.destroyed) return;
|
|
8021
8066
|
this.destroyed = true;
|
|
8022
8067
|
this.device.removeEventListener("uncapturederror", this.onGPUError);
|
|
8023
|
-
_optionalChain([this, 'access',
|
|
8068
|
+
_optionalChain([this, 'access', _209 => _209.runtime, 'optionalAccess', _210 => _210.destroy, 'call', _211 => _211()]);
|
|
8024
8069
|
this.runtime = void 0;
|
|
8025
8070
|
this.textures.forEach((texture) => texture.destroy());
|
|
8026
8071
|
this.textures = [];
|
|
8027
|
-
_optionalChain([this, 'access',
|
|
8072
|
+
_optionalChain([this, 'access', _212 => _212.context, 'optionalAccess', _213 => _213.unconfigure, 'call', _214 => _214()]);
|
|
8028
8073
|
this.device.destroy();
|
|
8029
8074
|
}
|
|
8030
8075
|
};
|
|
@@ -8203,7 +8248,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
8203
8248
|
setActive(active) {
|
|
8204
8249
|
if (active === this.active) return;
|
|
8205
8250
|
this.active = active;
|
|
8206
|
-
_optionalChain([this, 'access',
|
|
8251
|
+
_optionalChain([this, 'access', _215 => _215.options, 'access', _216 => _216.onActiveChange, 'optionalCall', _217 => _217(active)]);
|
|
8207
8252
|
}
|
|
8208
8253
|
resetTimeline() {
|
|
8209
8254
|
this.generation++;
|
|
@@ -8234,7 +8279,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
8234
8279
|
this.callback = void 0;
|
|
8235
8280
|
clearTimeout(this.initializationTimer);
|
|
8236
8281
|
this.resetTimeline();
|
|
8237
|
-
_optionalChain([this, 'access',
|
|
8282
|
+
_optionalChain([this, 'access', _218 => _218.processor, 'optionalAccess', _219 => _219.destroy, 'call', _220 => _220()]);
|
|
8238
8283
|
this.processor = void 0;
|
|
8239
8284
|
}
|
|
8240
8285
|
};
|
|
@@ -8292,7 +8337,7 @@ var XmaxVideoView = class {
|
|
|
8292
8337
|
* DOM 挂载状态
|
|
8293
8338
|
*/
|
|
8294
8339
|
__publicField(this, "detached", false);
|
|
8295
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
8340
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _221 => _221.videoContentMode]), () => ( "fill")) /* fill */;
|
|
8296
8341
|
this.element = document.createElement("div");
|
|
8297
8342
|
this.element.style.position = "relative";
|
|
8298
8343
|
this.element.style.overflow = "hidden";
|
|
@@ -8439,8 +8484,8 @@ var XmaxVideoView = class {
|
|
|
8439
8484
|
stopInterpolation() {
|
|
8440
8485
|
const pipeline = this.interpolationPipeline;
|
|
8441
8486
|
this.interpolationPipeline = void 0;
|
|
8442
|
-
_optionalChain([pipeline, 'optionalAccess',
|
|
8443
|
-
_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()]);
|
|
8444
8489
|
this.interpolationCanvas = void 0;
|
|
8445
8490
|
}
|
|
8446
8491
|
/**
|
|
@@ -8466,7 +8511,7 @@ var XmaxVideoView = class {
|
|
|
8466
8511
|
detachCurrentTrack() {
|
|
8467
8512
|
const track = this.currentTrack;
|
|
8468
8513
|
if (track) {
|
|
8469
|
-
_optionalChain([VideoRenderRegistry, 'access',
|
|
8514
|
+
_optionalChain([VideoRenderRegistry, 'access', _227 => _227.binding, 'call', _228 => _228(track), 'optionalAccess', _229 => _229.detachHandler, 'call', _230 => _230(this)]);
|
|
8470
8515
|
}
|
|
8471
8516
|
this.setFrameInterpolation(void 0);
|
|
8472
8517
|
this.cancelFrameDisplayNotification();
|
|
@@ -8486,8 +8531,8 @@ var XmaxVideoView = class {
|
|
|
8486
8531
|
}
|
|
8487
8532
|
this.hasNotifiedFrameDisplay = true;
|
|
8488
8533
|
this.cancelFrameDisplayNotification();
|
|
8489
|
-
_optionalChain([binding, 'optionalAccess',
|
|
8490
|
-
_optionalChain([this, 'access',
|
|
8534
|
+
_optionalChain([binding, 'optionalAccess', _231 => _231.frameDisplayHandler, 'optionalCall', _232 => _232()]);
|
|
8535
|
+
_optionalChain([this, 'access', _233 => _233.frameDisplayHandler, 'optionalCall', _234 => _234()]);
|
|
8491
8536
|
};
|
|
8492
8537
|
if (typeof this.videoElement.requestVideoFrameCallback === "function") {
|
|
8493
8538
|
this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
|
|
@@ -8557,9 +8602,9 @@ var XmaxRealtimeVideoView = class {
|
|
|
8557
8602
|
__publicField(this, "currentLocalTrack");
|
|
8558
8603
|
__publicField(this, "currentRemoteTrack");
|
|
8559
8604
|
__publicField(this, "contentMode");
|
|
8560
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
8561
|
-
this.currentLocalTrack = _optionalChain([options, 'optionalAccess',
|
|
8562
|
-
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]);
|
|
8563
8608
|
this.element = document.createElement("div");
|
|
8564
8609
|
this.element.style.position = "relative";
|
|
8565
8610
|
this.element.style.overflow = "hidden";
|
|
@@ -8718,4 +8763,4 @@ var XmaxRealtimeVideoView = class {
|
|
|
8718
8763
|
|
|
8719
8764
|
|
|
8720
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;
|
|
8721
|
-
//# sourceMappingURL=chunk-
|
|
8766
|
+
//# sourceMappingURL=chunk-JWAAS6P4.cjs.map
|