@xmaxai/web-sdk 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -242
- package/dist/{VideoContentMode-BM97_H8V.d.cts → VideoRenderStatistics-C7zqzfuS.d.cts} +23 -1
- package/dist/{VideoContentMode-BM97_H8V.d.ts → VideoRenderStatistics-C7zqzfuS.d.ts} +23 -1
- package/dist/{chunk-VMJXIVUF.js → chunk-4O5BSMUX.js} +1022 -61
- package/dist/chunk-4O5BSMUX.js.map +1 -0
- package/dist/{chunk-JN6HURTT.cjs → chunk-EKOYOFES.cjs} +1235 -274
- package/dist/{chunk-JN6HURTT.cjs.map → chunk-EKOYOFES.cjs.map} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -6
- package/dist/index.d.ts +47 -6
- package/dist/index.js +1 -1
- package/dist/react/index.cjs +6 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +5 -1
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.js +4 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +7 -9
- package/dist/chunk-VMJXIVUF.js.map +0 -1
|
@@ -205,7 +205,7 @@ var XmaxError = class _XmaxError extends Error {
|
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
// src/Foundation/Runtime/RuntimeInfo.ts
|
|
208
|
-
var XMAX_SDK_VERSION = "1.0.
|
|
208
|
+
var XMAX_SDK_VERSION = "1.0.7";
|
|
209
209
|
var _RuntimeInfo = class _RuntimeInfo {
|
|
210
210
|
/**
|
|
211
211
|
* 序列化为接口传输使用的 snake_case 字段。
|
|
@@ -600,7 +600,6 @@ var RtcProvider = /* @__PURE__ */ ((RtcProvider2) => {
|
|
|
600
600
|
var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
|
|
601
601
|
RealtimeModel2["x2_0"] = "x2.0";
|
|
602
602
|
RealtimeModel2["x2_0_trtc"] = "x2.0-trtc";
|
|
603
|
-
RealtimeModel2["x2_0_agora"] = "x2.0-agora";
|
|
604
603
|
RealtimeModel2["x2_1_preview"] = "x2.1-preview";
|
|
605
604
|
return RealtimeModel2;
|
|
606
605
|
})(RealtimeModel || {});
|
|
@@ -616,12 +615,10 @@ function modelDefaults(model) {
|
|
|
616
615
|
var MODEL_DISPLAY_NAMES = {
|
|
617
616
|
["x2.0" /* x2_0 */]: "X2.0",
|
|
618
617
|
["x2.0-trtc" /* x2_0_trtc */]: "X2.1-preview-trtc",
|
|
619
|
-
["x2.
|
|
620
|
-
["x2.1-preview" /* x2_1_preview */]: "X2.1-preview-vertc"
|
|
618
|
+
["x2.1-preview" /* x2_1_preview */]: "X2.1-preview-agora"
|
|
621
619
|
};
|
|
622
620
|
var MODEL_BASE_URLS = {
|
|
623
|
-
["x2.
|
|
624
|
-
["x2.1-preview" /* x2_1_preview */]: "https://dev.xmaxai.com/open/api/v1"
|
|
621
|
+
["x2.1-preview" /* x2_1_preview */]: "https://cloud.xmax.22duck.cn/open/api/v1"
|
|
625
622
|
};
|
|
626
623
|
var RESOLUTION_BUCKETS = {
|
|
627
624
|
["x2.0" /* x2_0 */]: [],
|
|
@@ -629,10 +626,6 @@ var RESOLUTION_BUCKETS = {
|
|
|
629
626
|
{ width: 1024, height: 1920 },
|
|
630
627
|
{ width: 1920, height: 1024 }
|
|
631
628
|
],
|
|
632
|
-
["x2.0-agora" /* x2_0_agora */]: [
|
|
633
|
-
{ width: 1024, height: 1920 },
|
|
634
|
-
{ width: 1920, height: 1024 }
|
|
635
|
-
],
|
|
636
629
|
["x2.1-preview" /* x2_1_preview */]: [
|
|
637
630
|
{ width: 1024, height: 1920 },
|
|
638
631
|
{ width: 1920, height: 1024 }
|
|
@@ -641,7 +634,6 @@ var RESOLUTION_BUCKETS = {
|
|
|
641
634
|
var MAXIMUM_INPUT_PIXELS = {
|
|
642
635
|
["x2.0" /* x2_0 */]: 128e4,
|
|
643
636
|
["x2.0-trtc" /* x2_0_trtc */]: 21e5,
|
|
644
|
-
["x2.0-agora" /* x2_0_agora */]: 21e5,
|
|
645
637
|
["x2.1-preview" /* x2_1_preview */]: 21e5
|
|
646
638
|
};
|
|
647
639
|
function modelDisplayName(model) {
|
|
@@ -674,8 +666,7 @@ function defaultCameraVideoFormat(model) {
|
|
|
674
666
|
var MODEL_RTC_PROVIDERS = {
|
|
675
667
|
["x2.0" /* x2_0 */]: Object.freeze(["vertc" /* vertc */]),
|
|
676
668
|
["x2.0-trtc" /* x2_0_trtc */]: Object.freeze(["trtc" /* trtc */]),
|
|
677
|
-
["x2.
|
|
678
|
-
["x2.1-preview" /* x2_1_preview */]: Object.freeze(["vertc" /* vertc */])
|
|
669
|
+
["x2.1-preview" /* x2_1_preview */]: Object.freeze(["agora" /* agora */])
|
|
679
670
|
};
|
|
680
671
|
function supportedRtcProviders(model) {
|
|
681
672
|
return isKnownModel(model) ? MODEL_RTC_PROVIDERS[model] : CUSTOM_MODEL_RTC_PROVIDERS;
|
|
@@ -1269,6 +1260,11 @@ ${JSON.stringify({
|
|
|
1269
1260
|
receivedBytes: valid(rtc.RecvBytes),
|
|
1270
1261
|
localVideo,
|
|
1271
1262
|
remoteVideo: remote,
|
|
1263
|
+
capture: {
|
|
1264
|
+
width: valid(local.captureResolutionWidth, 1),
|
|
1265
|
+
height: valid(local.captureResolutionHeight, 1),
|
|
1266
|
+
frameRate: valid(local.captureFrameRate)
|
|
1267
|
+
},
|
|
1272
1268
|
localAudio: client.getLocalAudioStats(),
|
|
1273
1269
|
remoteAudio: client.getRemoteAudioStats()
|
|
1274
1270
|
}, null, 2)}`, 2 /* performance */);
|
|
@@ -1316,6 +1312,231 @@ function rtcOrientedVideoSize(size, environment) {
|
|
|
1316
1312
|
return shouldTransposeRtcVideoSize(environment) ? { width: size.height, height: size.width } : size;
|
|
1317
1313
|
}
|
|
1318
1314
|
|
|
1315
|
+
// src/Foundation/RTC/Agora/AgoraVideoSender.ts
|
|
1316
|
+
var AgoraVideoSender = class {
|
|
1317
|
+
static async apply(track, config, ensureActive2) {
|
|
1318
|
+
ensureActive2();
|
|
1319
|
+
const sender = _optionalChain([track, 'access', _72 => _72.getRTCRtpTransceiver, 'call', _73 => _73(), 'optionalAccess', _74 => _74.sender]);
|
|
1320
|
+
if (!sender) throw new XmaxError("RTC_ERROR" /* rtcError */, "WebRTC video sender is unavailable");
|
|
1321
|
+
const capture = _optionalChain([sender, 'access', _75 => _75.track, 'optionalAccess', _76 => _76.getSettings, 'call', _77 => _77()]);
|
|
1322
|
+
if (!_optionalChain([capture, 'optionalAccess', _78 => _78.width]) || !capture.height) {
|
|
1323
|
+
throw new XmaxError("RTC_ERROR" /* rtcError */, "WebRTC capture dimensions are unavailable");
|
|
1324
|
+
}
|
|
1325
|
+
const scale = Math.max(1, capture.width / config.width, capture.height / config.height);
|
|
1326
|
+
const parameters = sender.getParameters();
|
|
1327
|
+
if (_optionalChain([parameters, 'access', _79 => _79.encodings, 'optionalAccess', _80 => _80.length]) !== 1) {
|
|
1328
|
+
throw new XmaxError("RTC_ERROR" /* rtcError */, "Sender-only configuration requires one video encoding");
|
|
1329
|
+
}
|
|
1330
|
+
const encoding = parameters.encodings[0];
|
|
1331
|
+
const previous = { ...encoding };
|
|
1332
|
+
const previousPreference = parameters.degradationPreference;
|
|
1333
|
+
encoding.scaleResolutionDownBy = scale;
|
|
1334
|
+
encoding.maxFramerate = config.frameRate;
|
|
1335
|
+
encoding.maxBitrate = Math.round(config.maximumBitrate * 1e3);
|
|
1336
|
+
parameters.degradationPreference = config.encoderPreference === "maintainFramerate" /* maintainFramerate */ ? "maintain-framerate" : "maintain-resolution";
|
|
1337
|
+
await sender.setParameters(parameters);
|
|
1338
|
+
ensureActive2();
|
|
1339
|
+
if (_optionalChain([track, 'access', _81 => _81.getRTCRtpTransceiver, 'call', _82 => _82(), 'optionalAccess', _83 => _83.sender]) !== sender) {
|
|
1340
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "WebRTC video sender changed during configuration");
|
|
1341
|
+
}
|
|
1342
|
+
const applied = sender.getParameters();
|
|
1343
|
+
const actual = _optionalChain([applied, 'access', _84 => _84.encodings, 'optionalAccess', _85 => _85[0]]);
|
|
1344
|
+
if (!actual || Math.abs((_nullishCoalesce(actual.scaleResolutionDownBy, () => ( 1))) - scale) > 1e-4 || actual.maxFramerate !== encoding.maxFramerate || actual.maxBitrate !== encoding.maxBitrate) {
|
|
1345
|
+
if (actual && applied.encodings.length === 1) {
|
|
1346
|
+
for (const key of ["scaleResolutionDownBy", "maxFramerate", "maxBitrate"]) {
|
|
1347
|
+
if (previous[key] === void 0) delete actual[key];
|
|
1348
|
+
else actual[key] = previous[key];
|
|
1349
|
+
}
|
|
1350
|
+
if (previousPreference === void 0) delete applied.degradationPreference;
|
|
1351
|
+
else applied.degradationPreference = previousPreference;
|
|
1352
|
+
await sender.setParameters(applied);
|
|
1353
|
+
}
|
|
1354
|
+
throw new XmaxError("RTC_ERROR" /* rtcError */, "Browser did not retain WebRTC video sender parameters");
|
|
1355
|
+
}
|
|
1356
|
+
XmaxLogger.rtc.info(() => `Agora \u53D1\u9001\u53C2\u6570\u5B9E\u9A8C (Agora Sender Parameters)
|
|
1357
|
+
${JSON.stringify({
|
|
1358
|
+
capture: { width: capture.width, height: capture.height, frameRate: capture.frameRate },
|
|
1359
|
+
target: { width: config.width, height: config.height, frameRate: config.frameRate },
|
|
1360
|
+
scaleResolutionDownBy: actual.scaleResolutionDownBy,
|
|
1361
|
+
maxFramerate: actual.maxFramerate,
|
|
1362
|
+
maxBitrateKbps: actual.maxBitrate / 1e3,
|
|
1363
|
+
minimumBitrateApplied: false
|
|
1364
|
+
}, null, 2)}`, 2 /* performance */);
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
// src/Foundation/Media/Camera/CameraRotation.ts
|
|
1369
|
+
function validateCameraRotation(rotation) {
|
|
1370
|
+
if (![0, 90, 180, 270].includes(rotation)) {
|
|
1371
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation must be 0, 90, 180 or 270");
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// src/Foundation/Media/Camera/CameraRotationProcessor.ts
|
|
1376
|
+
var CameraRotationProcessor = class {
|
|
1377
|
+
constructor(options) {
|
|
1378
|
+
__publicField(this, "options", options);
|
|
1379
|
+
__publicField(this, "video", document.createElement("video"));
|
|
1380
|
+
__publicField(this, "canvas", document.createElement("canvas"));
|
|
1381
|
+
__publicField(this, "context");
|
|
1382
|
+
__publicField(this, "stream");
|
|
1383
|
+
__publicField(this, "source");
|
|
1384
|
+
__publicField(this, "frameCallback");
|
|
1385
|
+
__publicField(this, "timer");
|
|
1386
|
+
__publicField(this, "cancelPending");
|
|
1387
|
+
__publicField(this, "stopped", false);
|
|
1388
|
+
__publicField(this, "version", 0);
|
|
1389
|
+
__publicField(this, "sourceEnded", () => {
|
|
1390
|
+
this.fail(new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera source ended during rotation"));
|
|
1391
|
+
});
|
|
1392
|
+
this.canvas.width = options.width;
|
|
1393
|
+
this.canvas.height = options.height;
|
|
1394
|
+
const context = this.canvas.getContext("2d", { alpha: false });
|
|
1395
|
+
if (!context || typeof this.canvas.captureStream !== "function") {
|
|
1396
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Canvas camera rotation is not supported by this browser");
|
|
1397
|
+
}
|
|
1398
|
+
this.context = context;
|
|
1399
|
+
this.video.muted = true;
|
|
1400
|
+
this.video.autoplay = true;
|
|
1401
|
+
this.video.playsInline = true;
|
|
1402
|
+
}
|
|
1403
|
+
/** 等待第一帧实际绘制成功;换摄像头时复用输出轨,不重建 sender。 */
|
|
1404
|
+
async setSource(source) {
|
|
1405
|
+
if (this.stopped) throw new XmaxError("CANCELLED" /* cancelled */, "Camera rotation has stopped");
|
|
1406
|
+
if (source.readyState === "ended") {
|
|
1407
|
+
this.stop();
|
|
1408
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera rotation requires a live source");
|
|
1409
|
+
}
|
|
1410
|
+
_optionalChain([this, 'access', _86 => _86.cancelPending, 'optionalCall', _87 => _87()]);
|
|
1411
|
+
this.cancelFrame();
|
|
1412
|
+
_optionalChain([this, 'access', _88 => _88.source, 'optionalAccess', _89 => _89.removeEventListener, 'call', _90 => _90("ended", this.sourceEnded)]);
|
|
1413
|
+
const version = ++this.version;
|
|
1414
|
+
this.source = source;
|
|
1415
|
+
source.addEventListener("ended", this.sourceEnded);
|
|
1416
|
+
this.video.srcObject = new MediaStream([source]);
|
|
1417
|
+
try {
|
|
1418
|
+
await new Promise((resolve, reject) => {
|
|
1419
|
+
let settled = false;
|
|
1420
|
+
const finish = (error) => {
|
|
1421
|
+
if (settled) return;
|
|
1422
|
+
settled = true;
|
|
1423
|
+
clearTimeout(timeout);
|
|
1424
|
+
this.cancelPending = void 0;
|
|
1425
|
+
if (error) reject(error);
|
|
1426
|
+
else resolve();
|
|
1427
|
+
};
|
|
1428
|
+
const timeout = setTimeout(() => finish(new XmaxError("TIMEOUT" /* timeout */, "Timed out waiting for a camera rotation frame")), 1e4);
|
|
1429
|
+
this.cancelPending = () => finish(new XmaxError("CANCELLED" /* cancelled */, "Camera rotation source changed"));
|
|
1430
|
+
void this.video.play().then(() => {
|
|
1431
|
+
if (settled || this.stopped || version !== this.version) return;
|
|
1432
|
+
const firstFrame = () => {
|
|
1433
|
+
if (settled || this.stopped || version !== this.version) return;
|
|
1434
|
+
try {
|
|
1435
|
+
if (!this.draw()) {
|
|
1436
|
+
this.schedule(firstFrame);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
_nullishCoalesce(this.stream, () => ( (this.stream = this.canvas.captureStream(this.options.frameRate))));
|
|
1440
|
+
if (!this.stream.getVideoTracks()[0]) throw new Error("Canvas did not produce a video track");
|
|
1441
|
+
this.requestFrame();
|
|
1442
|
+
finish();
|
|
1443
|
+
this.schedule(() => this.render(version));
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
finish(error);
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
this.schedule(firstFrame);
|
|
1449
|
+
}, finish);
|
|
1450
|
+
});
|
|
1451
|
+
if (this.stopped || version !== this.version) {
|
|
1452
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Camera rotation source changed");
|
|
1453
|
+
}
|
|
1454
|
+
return this.stream.getVideoTracks()[0];
|
|
1455
|
+
} catch (error) {
|
|
1456
|
+
if (version === this.version) this.stop();
|
|
1457
|
+
throw XmaxError.from(error);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/** 换设备前解除旧原始轨监听,保留 Canvas 最后一帧及输出轨。 */
|
|
1461
|
+
pauseSource() {
|
|
1462
|
+
++this.version;
|
|
1463
|
+
_optionalChain([this, 'access', _91 => _91.cancelPending, 'optionalCall', _92 => _92()]);
|
|
1464
|
+
this.cancelFrame();
|
|
1465
|
+
_optionalChain([this, 'access', _93 => _93.source, 'optionalAccess', _94 => _94.removeEventListener, 'call', _95 => _95("ended", this.sourceEnded)]);
|
|
1466
|
+
this.source = void 0;
|
|
1467
|
+
this.video.pause();
|
|
1468
|
+
this.video.srcObject = null;
|
|
1469
|
+
}
|
|
1470
|
+
stop() {
|
|
1471
|
+
if (this.stopped) return;
|
|
1472
|
+
this.stopped = true;
|
|
1473
|
+
++this.version;
|
|
1474
|
+
_optionalChain([this, 'access', _96 => _96.cancelPending, 'optionalCall', _97 => _97()]);
|
|
1475
|
+
this.cancelFrame();
|
|
1476
|
+
_optionalChain([this, 'access', _98 => _98.source, 'optionalAccess', _99 => _99.removeEventListener, 'call', _100 => _100("ended", this.sourceEnded)]);
|
|
1477
|
+
this.source = void 0;
|
|
1478
|
+
this.video.pause();
|
|
1479
|
+
this.video.srcObject = null;
|
|
1480
|
+
_optionalChain([this, 'access', _101 => _101.stream, 'optionalAccess', _102 => _102.getTracks, 'call', _103 => _103(), 'access', _104 => _104.forEach, 'call', _105 => _105((track) => track.stop())]);
|
|
1481
|
+
this.stream = void 0;
|
|
1482
|
+
this.canvas.width = this.canvas.height = 0;
|
|
1483
|
+
}
|
|
1484
|
+
draw() {
|
|
1485
|
+
const { videoWidth: width, videoHeight: height } = this.video;
|
|
1486
|
+
if (this.video.readyState < 2 || !width || !height) return false;
|
|
1487
|
+
const { width: outWidth, height: outHeight, rotation } = this.options;
|
|
1488
|
+
const quarterTurn = rotation === 90 || rotation === 270;
|
|
1489
|
+
const targetWidth = quarterTurn ? outHeight : outWidth;
|
|
1490
|
+
const targetHeight = quarterTurn ? outWidth : outHeight;
|
|
1491
|
+
const scale = Math.max(targetWidth / width, targetHeight / height);
|
|
1492
|
+
const cropWidth = targetWidth / scale, cropHeight = targetHeight / scale;
|
|
1493
|
+
this.context.setTransform(1, 0, 0, 1, outWidth / 2, outHeight / 2);
|
|
1494
|
+
this.context.rotate(rotation * Math.PI / 180);
|
|
1495
|
+
this.context.drawImage(
|
|
1496
|
+
this.video,
|
|
1497
|
+
(width - cropWidth) / 2,
|
|
1498
|
+
(height - cropHeight) / 2,
|
|
1499
|
+
cropWidth,
|
|
1500
|
+
cropHeight,
|
|
1501
|
+
-targetWidth / 2,
|
|
1502
|
+
-targetHeight / 2,
|
|
1503
|
+
targetWidth,
|
|
1504
|
+
targetHeight
|
|
1505
|
+
);
|
|
1506
|
+
return true;
|
|
1507
|
+
}
|
|
1508
|
+
render(version) {
|
|
1509
|
+
if (this.stopped || version !== this.version) return;
|
|
1510
|
+
try {
|
|
1511
|
+
if (this.draw()) this.requestFrame();
|
|
1512
|
+
this.schedule(() => this.render(version));
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
this.fail(XmaxError.from(error));
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
requestFrame() {
|
|
1518
|
+
const track = _optionalChain([this, 'access', _106 => _106.stream, 'optionalAccess', _107 => _107.getVideoTracks, 'call', _108 => _108(), 'access', _109 => _109[0]]);
|
|
1519
|
+
_optionalChain([track, 'optionalAccess', _110 => _110.requestFrame, 'optionalCall', _111 => _111()]);
|
|
1520
|
+
}
|
|
1521
|
+
schedule(callback) {
|
|
1522
|
+
if (typeof this.video.requestVideoFrameCallback === "function") {
|
|
1523
|
+
this.frameCallback = this.video.requestVideoFrameCallback(callback);
|
|
1524
|
+
} else {
|
|
1525
|
+
this.timer = setTimeout(callback, 1e3 / this.options.frameRate);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
cancelFrame() {
|
|
1529
|
+
if (this.frameCallback !== void 0) this.video.cancelVideoFrameCallback(this.frameCallback);
|
|
1530
|
+
clearTimeout(this.timer);
|
|
1531
|
+
this.frameCallback = void 0;
|
|
1532
|
+
this.timer = void 0;
|
|
1533
|
+
}
|
|
1534
|
+
fail(error) {
|
|
1535
|
+
this.stop();
|
|
1536
|
+
this.options.onError(error);
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
|
|
1319
1540
|
// src/Foundation/RTC/Agora/AgoraRtcManager.ts
|
|
1320
1541
|
var _AgoraRtcManager = class _AgoraRtcManager {
|
|
1321
1542
|
/**
|
|
@@ -1332,9 +1553,16 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1332
1553
|
__publicField(this, "initialization");
|
|
1333
1554
|
__publicField(this, "lifecycle", 0);
|
|
1334
1555
|
__publicField(this, "camera");
|
|
1556
|
+
__publicField(this, "cameraSource");
|
|
1557
|
+
__publicField(this, "cameraRotation");
|
|
1558
|
+
__publicField(this, "captureVersion", 0);
|
|
1335
1559
|
__publicField(this, "microphone");
|
|
1336
1560
|
__publicField(this, "externalVideo");
|
|
1337
1561
|
__publicField(this, "externalAudio");
|
|
1562
|
+
__publicField(this, "appliedOptimizationModes", /* @__PURE__ */ new WeakMap());
|
|
1563
|
+
__publicField(this, "cameraSenderConfiguration");
|
|
1564
|
+
__publicField(this, "senderUpdateTail", Promise.resolve());
|
|
1565
|
+
__publicField(this, "cameraTransceiverListener");
|
|
1338
1566
|
__publicField(this, "connection");
|
|
1339
1567
|
__publicField(this, "roomVersion", 0);
|
|
1340
1568
|
/**
|
|
@@ -1351,6 +1579,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1351
1579
|
*/
|
|
1352
1580
|
__publicField(this, "listener");
|
|
1353
1581
|
__publicField(this, "statisticsTimer");
|
|
1582
|
+
__publicField(this, "networkQualitySuspended", false);
|
|
1354
1583
|
__publicField(this, "audioVolumes", /* @__PURE__ */ new Map());
|
|
1355
1584
|
__publicField(this, "requestedAudio", /* @__PURE__ */ new Set());
|
|
1356
1585
|
/**
|
|
@@ -1406,7 +1635,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1406
1635
|
if (typeof client.sendStreamMessage !== "function") {
|
|
1407
1636
|
throw new XmaxError("RTC_ERROR" /* rtcError */, "Agora DataStream is unavailable in this SDK version");
|
|
1408
1637
|
}
|
|
1409
|
-
_AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess',
|
|
1638
|
+
_AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess', _112 => _112.count]), () => ( 0))) + 1 });
|
|
1410
1639
|
this.sdk = sdk;
|
|
1411
1640
|
this.client = client;
|
|
1412
1641
|
this.registerEvents(client);
|
|
@@ -1419,11 +1648,11 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1419
1648
|
const client = this.client;
|
|
1420
1649
|
this.clearRoom();
|
|
1421
1650
|
this.client = void 0;
|
|
1422
|
-
_optionalChain([client, 'optionalAccess',
|
|
1423
|
-
|
|
1424
|
-
_optionalChain([this, 'access',
|
|
1425
|
-
_optionalChain([this, 'access',
|
|
1426
|
-
_optionalChain([this, 'access',
|
|
1651
|
+
_optionalChain([client, 'optionalAccess', _113 => _113.removeAllListeners, 'call', _114 => _114()]);
|
|
1652
|
+
this.releaseCameraCapture();
|
|
1653
|
+
_optionalChain([this, 'access', _115 => _115.microphone, 'optionalAccess', _116 => _116.close, 'call', _117 => _117()]);
|
|
1654
|
+
_optionalChain([this, 'access', _118 => _118.externalVideo, 'optionalAccess', _119 => _119.close, 'call', _120 => _120()]);
|
|
1655
|
+
_optionalChain([this, 'access', _121 => _121.externalAudio, 'optionalAccess', _122 => _122.close, 'call', _123 => _123()]);
|
|
1427
1656
|
this.externalVideo = void 0;
|
|
1428
1657
|
this.externalAudio = void 0;
|
|
1429
1658
|
this.camera = void 0;
|
|
@@ -1431,7 +1660,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1431
1660
|
const sdk = this.sdk;
|
|
1432
1661
|
this.sdk = void 0;
|
|
1433
1662
|
try {
|
|
1434
|
-
await _optionalChain([client, 'optionalAccess',
|
|
1663
|
+
await _optionalChain([client, 'optionalAccess', _124 => _124.leave, 'call', _125 => _125()]);
|
|
1435
1664
|
} catch (e9) {
|
|
1436
1665
|
XmaxLogger.rtc.warning(() => "Agora \u9000\u623F\u5931\u8D25\uFF0C\u5DF2\u91CA\u653E\u672C\u5730\u8D44\u6E90 (Agora Leave Failed)");
|
|
1437
1666
|
} finally {
|
|
@@ -1444,22 +1673,55 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1444
1673
|
*/
|
|
1445
1674
|
async startCameraCapture(options) {
|
|
1446
1675
|
const client = this.requireClient();
|
|
1447
|
-
if (this.camera || this.externalVideo) {
|
|
1676
|
+
if (this.camera || this.cameraSource || this.externalVideo) {
|
|
1448
1677
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "A local video source is already active");
|
|
1449
1678
|
}
|
|
1679
|
+
const rotation = _nullishCoalesce(options.rotation, () => ( 0));
|
|
1680
|
+
validateCameraRotation(rotation);
|
|
1681
|
+
const version = ++this.captureVersion;
|
|
1682
|
+
let source;
|
|
1450
1683
|
try {
|
|
1451
|
-
const captureSize = rtcOrientedVideoSize(options);
|
|
1452
|
-
|
|
1684
|
+
const captureSize = rtcOrientedVideoSize(rotation === 90 || rotation === 270 ? { width: options.height, height: options.width } : options);
|
|
1685
|
+
source = await this.sdk.createCameraVideoTrack({
|
|
1453
1686
|
facingMode: options.position === "front" /* front */ ? "user" : "environment",
|
|
1454
1687
|
encoderConfig: { width: captureSize.width, height: captureSize.height, frameRate: options.frameRate }
|
|
1455
1688
|
});
|
|
1456
|
-
if (this.client !== client) {
|
|
1457
|
-
|
|
1689
|
+
if (this.client !== client || version !== this.captureVersion) {
|
|
1690
|
+
source.close();
|
|
1458
1691
|
throw this.cancelled();
|
|
1459
1692
|
}
|
|
1693
|
+
this.cameraSource = source;
|
|
1694
|
+
let camera = source;
|
|
1695
|
+
if (rotation !== 0) {
|
|
1696
|
+
const processor = new CameraRotationProcessor({
|
|
1697
|
+
...options,
|
|
1698
|
+
rotation,
|
|
1699
|
+
onError: (error) => _optionalChain([this, 'access', _126 => _126.listener, 'optionalAccess', _127 => _127.onError, 'optionalCall', _128 => _128(error)])
|
|
1700
|
+
});
|
|
1701
|
+
this.cameraRotation = processor;
|
|
1702
|
+
const output = await processor.setSource(source.getMediaStreamTrack());
|
|
1703
|
+
if (this.client !== client || version !== this.captureVersion) throw this.cancelled();
|
|
1704
|
+
camera = this.sdk.createCustomVideoTrack({
|
|
1705
|
+
mediaStreamTrack: output,
|
|
1706
|
+
width: options.width,
|
|
1707
|
+
height: options.height,
|
|
1708
|
+
frameRate: options.frameRate
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1460
1711
|
this.camera = camera;
|
|
1712
|
+
this.cameraTransceiverListener = () => {
|
|
1713
|
+
if (this.client === client && client.localTracks.includes(camera) && this.videoPublishRequested && !this.rejoinTask) {
|
|
1714
|
+
void this.restoreCameraSender(camera).catch(() => {
|
|
1715
|
+
if (this.camera === camera && this.videoPublishRequested) {
|
|
1716
|
+
XmaxLogger.rtc.warning(() => "Agora \u53D1\u9001\u53C2\u6570\u6062\u590D\u5931\u8D25 (Agora Sender Parameters Restore Failed)");
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1721
|
+
camera.on("transceiver-updated", this.cameraTransceiverListener);
|
|
1461
1722
|
return camera.getMediaStreamTrack();
|
|
1462
1723
|
} catch (error) {
|
|
1724
|
+
if (version === this.captureVersion) this.releaseCameraCapture();
|
|
1463
1725
|
throw this.mapError(error, "CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */);
|
|
1464
1726
|
}
|
|
1465
1727
|
}
|
|
@@ -1467,25 +1729,50 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1467
1729
|
* 切换声网相机设备并返回切换后的原生轨道。
|
|
1468
1730
|
*/
|
|
1469
1731
|
async switchCameraCapture(to) {
|
|
1470
|
-
const
|
|
1471
|
-
|
|
1472
|
-
|
|
1732
|
+
const source = this.requireCamera();
|
|
1733
|
+
const camera = this.camera;
|
|
1734
|
+
_optionalChain([this, 'access', _129 => _129.cameraRotation, 'optionalAccess', _130 => _130.pauseSource, 'call', _131 => _131()]);
|
|
1735
|
+
try {
|
|
1736
|
+
await this.run(() => source.setDevice({ facingMode: to === "front" /* front */ ? "user" : "environment" }));
|
|
1737
|
+
} catch (error) {
|
|
1738
|
+
if (this.camera === camera && this.cameraRotation) {
|
|
1739
|
+
await this.cameraRotation.setSource(source.getMediaStreamTrack()).catch((restoreError) => {
|
|
1740
|
+
_optionalChain([this, 'access', _132 => _132.listener, 'optionalAccess', _133 => _133.onError, 'optionalCall', _134 => _134(XmaxError.from(restoreError))]);
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
throw error;
|
|
1744
|
+
}
|
|
1745
|
+
if (this.camera !== camera || this.cameraSource !== source) throw this.cancelled();
|
|
1746
|
+
if (this.cameraRotation) {
|
|
1747
|
+
await this.cameraRotation.setSource(source.getMediaStreamTrack());
|
|
1748
|
+
if (this.camera !== camera) throw this.cancelled();
|
|
1749
|
+
}
|
|
1750
|
+
if (this.videoPublishRequested) await this.restoreCameraSender(camera);
|
|
1473
1751
|
return camera.getMediaStreamTrack();
|
|
1474
1752
|
}
|
|
1475
1753
|
/**
|
|
1476
1754
|
* 停止采集并释放摄像头。
|
|
1477
1755
|
*/
|
|
1478
1756
|
async stopCameraCapture() {
|
|
1757
|
+
this.releaseCameraCapture();
|
|
1758
|
+
}
|
|
1759
|
+
releaseCameraCapture() {
|
|
1760
|
+
++this.captureVersion;
|
|
1479
1761
|
const camera = this.camera;
|
|
1762
|
+
this.releaseCameraSender();
|
|
1480
1763
|
this.camera = void 0;
|
|
1481
|
-
_optionalChain([camera, 'optionalAccess',
|
|
1764
|
+
_optionalChain([camera, 'optionalAccess', _135 => _135.close, 'call', _136 => _136()]);
|
|
1765
|
+
_optionalChain([this, 'access', _137 => _137.cameraRotation, 'optionalAccess', _138 => _138.stop, 'call', _139 => _139()]);
|
|
1766
|
+
this.cameraRotation = void 0;
|
|
1767
|
+
if (this.cameraSource !== camera) _optionalChain([this, 'access', _140 => _140.cameraSource, 'optionalAccess', _141 => _141.close, 'call', _142 => _142()]);
|
|
1768
|
+
this.cameraSource = void 0;
|
|
1482
1769
|
}
|
|
1483
1770
|
/**
|
|
1484
1771
|
* 将外部原生轨包装为 Agora 本地轨,不申请设备权限;失败时释放本次克隆。
|
|
1485
1772
|
*/
|
|
1486
1773
|
async setExternalMediaTracks(tracks) {
|
|
1487
1774
|
this.requireClient();
|
|
1488
|
-
if (this.camera || this.microphone || this.externalVideo) {
|
|
1775
|
+
if (this.camera || this.cameraSource || this.microphone || this.externalVideo) {
|
|
1489
1776
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
|
|
1490
1777
|
}
|
|
1491
1778
|
if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
|
|
@@ -1496,7 +1783,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1496
1783
|
let wrappedVideo;
|
|
1497
1784
|
let wrappedAudio;
|
|
1498
1785
|
try {
|
|
1499
|
-
audio = _optionalChain([tracks, 'access',
|
|
1786
|
+
audio = _optionalChain([tracks, 'access', _143 => _143.audioTrack, 'optionalAccess', _144 => _144.clone, 'call', _145 => _145()]);
|
|
1500
1787
|
wrappedVideo = this.sdk.createCustomVideoTrack({ mediaStreamTrack: video });
|
|
1501
1788
|
if (audio) {
|
|
1502
1789
|
wrappedAudio = this.sdk.createCustomAudioTrack({ mediaStreamTrack: audio, encoderConfig: "music_standard" });
|
|
@@ -1504,19 +1791,34 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1504
1791
|
this.externalVideo = wrappedVideo;
|
|
1505
1792
|
this.externalAudio = wrappedAudio;
|
|
1506
1793
|
} catch (error) {
|
|
1507
|
-
_optionalChain([wrappedVideo, 'optionalAccess',
|
|
1508
|
-
_optionalChain([wrappedAudio, 'optionalAccess',
|
|
1794
|
+
_optionalChain([wrappedVideo, 'optionalAccess', _146 => _146.close, 'call', _147 => _147()]);
|
|
1795
|
+
_optionalChain([wrappedAudio, 'optionalAccess', _148 => _148.close, 'call', _149 => _149()]);
|
|
1509
1796
|
video.stop();
|
|
1510
|
-
_optionalChain([audio, 'optionalAccess',
|
|
1797
|
+
_optionalChain([audio, 'optionalAccess', _150 => _150.stop, 'call', _151 => _151()]);
|
|
1511
1798
|
throw this.mapError(error);
|
|
1512
1799
|
}
|
|
1513
1800
|
}
|
|
1514
1801
|
/**
|
|
1515
|
-
*
|
|
1802
|
+
* 摄像头实验走原生 sender(发布前暂存);外部视频仍走 Agora 编码配置。
|
|
1516
1803
|
*/
|
|
1517
1804
|
async configureVideoEncoding(config) {
|
|
1518
1805
|
const camera = this.requireLocalVideo();
|
|
1519
|
-
|
|
1806
|
+
if (camera === this.camera) {
|
|
1807
|
+
const client = this.requireClient(), version = this.roomVersion;
|
|
1808
|
+
const published = this.videoPublishRequested;
|
|
1809
|
+
await this.run(() => this.queueSenderUpdate(async () => {
|
|
1810
|
+
const ensureActive2 = () => {
|
|
1811
|
+
if (this.camera !== camera || this.client !== client || this.roomVersion !== version || published && !this.videoPublishRequested) throw this.cancelled();
|
|
1812
|
+
};
|
|
1813
|
+
ensureActive2();
|
|
1814
|
+
if (this.videoPublishRequested) {
|
|
1815
|
+
await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
|
|
1816
|
+
}
|
|
1817
|
+
this.cameraSenderConfiguration = { ...config };
|
|
1818
|
+
}));
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
const encodingSize = config;
|
|
1520
1822
|
await this.run(async () => {
|
|
1521
1823
|
await camera.setEncoderConfiguration({
|
|
1522
1824
|
width: encodingSize.width,
|
|
@@ -1525,14 +1827,45 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1525
1827
|
bitrateMin: config.minimumBitrate,
|
|
1526
1828
|
bitrateMax: config.maximumBitrate
|
|
1527
1829
|
});
|
|
1528
|
-
|
|
1830
|
+
if (this.appliedOptimizationModes.get(camera) !== config.encoderPreference) {
|
|
1831
|
+
await camera.setOptimizationMode(config.encoderPreference === "maintainFramerate" /* maintainFramerate */ ? "motion" : "detail");
|
|
1832
|
+
this.appliedOptimizationModes.set(camera, config.encoderPreference);
|
|
1833
|
+
}
|
|
1529
1834
|
});
|
|
1530
1835
|
}
|
|
1836
|
+
queueSenderUpdate(operation) {
|
|
1837
|
+
const next = this.senderUpdateTail.then(operation);
|
|
1838
|
+
this.senderUpdateTail = next.catch(() => {
|
|
1839
|
+
});
|
|
1840
|
+
return next;
|
|
1841
|
+
}
|
|
1842
|
+
/** 发布/重建 sender 后恢复最近成功的目标配置;排队时不捕获过期的参数对象。 */
|
|
1843
|
+
restoreCameraSender(camera) {
|
|
1844
|
+
const client = this.client, version = this.roomVersion;
|
|
1845
|
+
return this.queueSenderUpdate(async () => {
|
|
1846
|
+
const ensureActive2 = () => {
|
|
1847
|
+
if (this.camera !== camera || this.client !== client || this.roomVersion !== version || !this.videoPublishRequested) {
|
|
1848
|
+
throw this.cancelled();
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
ensureActive2();
|
|
1852
|
+
const config = this.cameraSenderConfiguration;
|
|
1853
|
+
if (config) await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
cameraEncodingConfiguration(config) {
|
|
1857
|
+
return this.cameraRotation ? config : { ...config, ...rtcOrientedVideoSize(config) };
|
|
1858
|
+
}
|
|
1859
|
+
releaseCameraSender() {
|
|
1860
|
+
if (this.cameraTransceiverListener) _optionalChain([this, 'access', _152 => _152.camera, 'optionalAccess', _153 => _153.off, 'call', _154 => _154("transceiver-updated", this.cameraTransceiverListener)]);
|
|
1861
|
+
this.cameraTransceiverListener = void 0;
|
|
1862
|
+
this.cameraSenderConfiguration = void 0;
|
|
1863
|
+
}
|
|
1531
1864
|
/**
|
|
1532
1865
|
* 使用会话下发的字符串频道与 UID 入房;不采信后端区域覆盖。
|
|
1533
1866
|
*/
|
|
1534
1867
|
async joinRoom(configuration) {
|
|
1535
|
-
await _optionalChain([this, 'access',
|
|
1868
|
+
await _optionalChain([this, 'access', _155 => _155.rejoinTask, 'optionalAccess', _156 => _156.catch, 'call', _157 => _157(() => {
|
|
1536
1869
|
})]);
|
|
1537
1870
|
const client = this.requireClient();
|
|
1538
1871
|
if (configuration.provider !== "agora" /* agora */ || this.connection) {
|
|
@@ -1546,7 +1879,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1546
1879
|
}
|
|
1547
1880
|
this.connection = configuration;
|
|
1548
1881
|
for (const user of client.remoteUsers) {
|
|
1549
|
-
if (user.hasVideo) _optionalChain([this, 'access',
|
|
1882
|
+
if (user.hasVideo) _optionalChain([this, 'access', _158 => _158.listener, 'optionalAccess', _159 => _159.onRemoteVideoPublished, 'call', _160 => _160(String(user.uid), true)]);
|
|
1550
1883
|
}
|
|
1551
1884
|
this.statisticsTimer = setInterval(() => {
|
|
1552
1885
|
if (this.client !== client || !this.connection || this.tokenExpired || this.rejoinOperation) return;
|
|
@@ -1568,7 +1901,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1568
1901
|
* 应用同一频道的新 Token;即将过期时续签,已经过期时重新进房并恢复媒体。
|
|
1569
1902
|
*/
|
|
1570
1903
|
async updateCredentials(config, signal) {
|
|
1571
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1904
|
+
if (_optionalChain([signal, 'optionalAccess', _161 => _161.aborted])) throw this.cancelled();
|
|
1572
1905
|
const current = this.connection;
|
|
1573
1906
|
const client = this.requireClient();
|
|
1574
1907
|
if (!current || config.provider !== "agora" /* agora */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
@@ -1584,7 +1917,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1584
1917
|
}
|
|
1585
1918
|
}
|
|
1586
1919
|
this.ensureRoomCurrent(client, version);
|
|
1587
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1920
|
+
if (_optionalChain([signal, 'optionalAccess', _162 => _162.aborted])) throw this.cancelled();
|
|
1588
1921
|
if (this.tokenExpired) await this.rejoinRoom(client, config, signal);
|
|
1589
1922
|
else this.connection = config;
|
|
1590
1923
|
}
|
|
@@ -1607,21 +1940,21 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1607
1940
|
reject(this.cancelled());
|
|
1608
1941
|
};
|
|
1609
1942
|
this.cancelRejoin = cancel;
|
|
1610
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1943
|
+
_optionalChain([signal, 'optionalAccess', _163 => _163.addEventListener, 'call', _164 => _164("abort", cancel, { once: true })]);
|
|
1611
1944
|
task.then(resolve, reject);
|
|
1612
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1945
|
+
if (_optionalChain([signal, 'optionalAccess', _165 => _165.aborted])) cancel();
|
|
1613
1946
|
});
|
|
1614
1947
|
this.rejoinOperation = operation;
|
|
1615
1948
|
try {
|
|
1616
1949
|
await operation;
|
|
1617
1950
|
} finally {
|
|
1618
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1951
|
+
_optionalChain([signal, 'optionalAccess', _166 => _166.removeEventListener, 'call', _167 => _167("abort", cancel)]);
|
|
1619
1952
|
if (this.cancelRejoin === cancel) this.cancelRejoin = void 0;
|
|
1620
1953
|
if (this.rejoinOperation === operation) this.rejoinOperation = void 0;
|
|
1621
1954
|
}
|
|
1622
1955
|
this.ensureRoomCurrent(client, version);
|
|
1623
1956
|
for (const user of client.remoteUsers) {
|
|
1624
|
-
if (user.hasVideo) _optionalChain([this, 'access',
|
|
1957
|
+
if (user.hasVideo) _optionalChain([this, 'access', _168 => _168.listener, 'optionalAccess', _169 => _169.onRemoteVideoPublished, 'call', _170 => _170(String(user.uid), true)]);
|
|
1625
1958
|
}
|
|
1626
1959
|
}
|
|
1627
1960
|
/**
|
|
@@ -1629,10 +1962,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1629
1962
|
*/
|
|
1630
1963
|
async performRejoin(client, config, version) {
|
|
1631
1964
|
this.ensureRoomCurrent(client, version);
|
|
1632
|
-
_optionalChain([this, 'access',
|
|
1633
|
-
_optionalChain([this, 'access',
|
|
1634
|
-
_optionalChain([this, 'access',
|
|
1635
|
-
for (const user of client.remoteUsers) _optionalChain([user, 'access',
|
|
1965
|
+
_optionalChain([this, 'access', _171 => _171.cancelSendDelay, 'optionalCall', _172 => _172()]);
|
|
1966
|
+
_optionalChain([this, 'access', _173 => _173.cancelActiveSend, 'optionalCall', _174 => _174()]);
|
|
1967
|
+
_optionalChain([this, 'access', _175 => _175.listener, 'optionalAccess', _176 => _176.onRoomRejoining, 'optionalCall', _177 => _177()]);
|
|
1968
|
+
for (const user of client.remoteUsers) _optionalChain([user, 'access', _178 => _178.audioTrack, 'optionalAccess', _179 => _179.stop, 'call', _180 => _180()]);
|
|
1636
1969
|
await this.run(() => client.leave());
|
|
1637
1970
|
this.ensureRoomCurrent(client, version);
|
|
1638
1971
|
await this.run(() => client.join(config.appID, config.roomID, config.roomToken, config.userID));
|
|
@@ -1645,6 +1978,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1645
1978
|
if (this.videoPublishRequested && video) {
|
|
1646
1979
|
await this.run(() => client.publish(video));
|
|
1647
1980
|
this.ensureRoomCurrent(client, version);
|
|
1981
|
+
if (video === this.camera) await this.restoreCameraSender(this.camera);
|
|
1648
1982
|
}
|
|
1649
1983
|
if (this.audioPublishRequested && audio) {
|
|
1650
1984
|
await this.run(() => client.publish(audio));
|
|
@@ -1674,6 +2008,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1674
2008
|
if (client !== this.client || !this.videoPublishRequested) throw this.cancelled();
|
|
1675
2009
|
if (client.localTracks.includes(camera)) return;
|
|
1676
2010
|
await this.run(() => client.publish(camera));
|
|
2011
|
+
if (camera === this.camera) await this.run(() => this.restoreCameraSender(this.camera));
|
|
1677
2012
|
}
|
|
1678
2013
|
/**
|
|
1679
2014
|
* 停止视频发布但保留采集与预览。
|
|
@@ -1754,8 +2089,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1754
2089
|
const user = client.remoteUsers.find((user2) => String(user2.uid) === userID);
|
|
1755
2090
|
if (!subscribe) {
|
|
1756
2091
|
this.requestedAudio.delete(userID);
|
|
1757
|
-
_optionalChain([user, 'optionalAccess',
|
|
1758
|
-
if (_optionalChain([user, 'optionalAccess',
|
|
2092
|
+
_optionalChain([user, 'optionalAccess', _181 => _181.audioTrack, 'optionalAccess', _182 => _182.stop, 'call', _183 => _183()]);
|
|
2093
|
+
if (_optionalChain([user, 'optionalAccess', _184 => _184.audioTrack]) && !this.rejoinTask) await this.run(() => client.unsubscribe(user, "audio"));
|
|
1759
2094
|
return;
|
|
1760
2095
|
}
|
|
1761
2096
|
this.requestedAudio.add(userID);
|
|
@@ -1766,7 +2101,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1766
2101
|
if (this.requestedAudio.has(userID)) await this.subscribeRemoteAudio(userID, true);
|
|
1767
2102
|
return;
|
|
1768
2103
|
}
|
|
1769
|
-
if (!_optionalChain([user, 'optionalAccess',
|
|
2104
|
+
if (!_optionalChain([user, 'optionalAccess', _185 => _185.hasAudio])) return;
|
|
1770
2105
|
const version = this.roomVersion;
|
|
1771
2106
|
const track = await this.run(() => client.subscribe(user, "audio"));
|
|
1772
2107
|
if (client !== this.client || version !== this.roomVersion || !this.requestedAudio.has(userID)) {
|
|
@@ -1780,9 +2115,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1780
2115
|
*/
|
|
1781
2116
|
setRemoteAudioVolume(volume, userID) {
|
|
1782
2117
|
this.audioVolumes.set(userID, Math.max(0, Math.min(100, Number.isFinite(volume) ? Math.round(volume) : 0)));
|
|
1783
|
-
const user = _optionalChain([this, 'access',
|
|
2118
|
+
const user = _optionalChain([this, 'access', _186 => _186.client, 'optionalAccess', _187 => _187.remoteUsers, 'access', _188 => _188.find, 'call', _189 => _189((user2) => String(user2.uid) === userID)]);
|
|
1784
2119
|
if (this.rejoinTask || this.tokenExpired) {
|
|
1785
|
-
_optionalChain([user, 'optionalAccess',
|
|
2120
|
+
_optionalChain([user, 'optionalAccess', _190 => _190.audioTrack, 'optionalAccess', _191 => _191.stop, 'call', _192 => _192()]);
|
|
1786
2121
|
return;
|
|
1787
2122
|
}
|
|
1788
2123
|
if (user) this.applyAudioVolume(user);
|
|
@@ -1871,42 +2206,45 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1871
2206
|
const handleExpired = () => {
|
|
1872
2207
|
if (!active() || this.tokenExpired) return;
|
|
1873
2208
|
this.tokenExpired = true;
|
|
1874
|
-
_optionalChain([this, 'access',
|
|
2209
|
+
_optionalChain([this, 'access', _193 => _193.listener, 'optionalAccess', _194 => _194.onNetworkStatistics, 'optionalCall', _195 => _195(void 0)]);
|
|
2210
|
+
_optionalChain([this, 'access', _196 => _196.listener, 'optionalAccess', _197 => _197.onTokenExpired, 'optionalCall', _198 => _198()]);
|
|
1875
2211
|
};
|
|
1876
2212
|
client.on("user-published", (user, kind) => {
|
|
1877
2213
|
if (!mediaActive()) return;
|
|
1878
|
-
if (kind === "video") _optionalChain([this, 'access',
|
|
2214
|
+
if (kind === "video") _optionalChain([this, 'access', _199 => _199.listener, 'optionalAccess', _200 => _200.onRemoteVideoPublished, 'call', _201 => _201(String(user.uid), true)]);
|
|
1879
2215
|
if (kind === "audio" && this.requestedAudio.has(String(user.uid))) {
|
|
1880
2216
|
void this.subscribeRemoteAudio(String(user.uid), true).catch((error) => {
|
|
1881
|
-
if (active()) _optionalChain([this, 'access',
|
|
2217
|
+
if (active()) _optionalChain([this, 'access', _202 => _202.listener, 'optionalAccess', _203 => _203.onError, 'optionalCall', _204 => _204(this.mapError(error))]);
|
|
1882
2218
|
});
|
|
1883
2219
|
}
|
|
1884
2220
|
});
|
|
1885
2221
|
client.on("user-unpublished", (user, kind) => {
|
|
1886
2222
|
if (!mediaActive()) return;
|
|
1887
|
-
if (kind === "video") _optionalChain([this, 'access',
|
|
1888
|
-
if (kind === "audio") _optionalChain([user, 'access',
|
|
2223
|
+
if (kind === "video") _optionalChain([this, 'access', _205 => _205.listener, 'optionalAccess', _206 => _206.onRemoteVideoPublished, 'call', _207 => _207(String(user.uid), false)]);
|
|
2224
|
+
if (kind === "audio") _optionalChain([user, 'access', _208 => _208.audioTrack, 'optionalAccess', _209 => _209.stop, 'call', _210 => _210()]);
|
|
1889
2225
|
});
|
|
1890
2226
|
client.on("user-left", (user) => {
|
|
1891
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
2227
|
+
if (mediaActive()) _optionalChain([this, 'access', _211 => _211.listener, 'optionalAccess', _212 => _212.onRemoteVideoPublished, 'call', _213 => _213(String(user.uid), false)]);
|
|
1892
2228
|
});
|
|
1893
2229
|
client.on("stream-message", (uid, data) => {
|
|
1894
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
2230
|
+
if (mediaActive()) _optionalChain([this, 'access', _214 => _214.listener, 'optionalAccess', _215 => _215.onCustomMessageReceived, 'call', _216 => _216(String(uid), typeof data === "string" ? data : new TextDecoder().decode(data))]);
|
|
1895
2231
|
});
|
|
1896
2232
|
client.on("network-quality", (quality) => {
|
|
1897
|
-
if (mediaActive()) AgoraRtcStatistics.network(quality, this.listener);
|
|
2233
|
+
if (mediaActive() && !this.networkQualitySuspended) AgoraRtcStatistics.network(quality, this.listener);
|
|
1898
2234
|
});
|
|
1899
2235
|
client.on("token-privilege-will-expire", () => {
|
|
1900
|
-
if (active() && !this.tokenExpired) _optionalChain([this, 'access',
|
|
2236
|
+
if (active() && !this.tokenExpired) _optionalChain([this, 'access', _217 => _217.listener, 'optionalAccess', _218 => _218.onTokenWillExpire, 'optionalCall', _219 => _219()]);
|
|
1901
2237
|
});
|
|
1902
2238
|
client.on("token-privilege-did-expire", handleExpired);
|
|
1903
2239
|
client.on("connection-state-change", (state2, previous, reason) => {
|
|
2240
|
+
if (this.client === client) this.networkQualitySuspended = state2 !== "CONNECTED";
|
|
2241
|
+
if (active() && state2 !== "CONNECTED") _optionalChain([this, 'access', _220 => _220.listener, 'optionalAccess', _221 => _221.onNetworkStatistics, 'optionalCall', _222 => _222(void 0)]);
|
|
1904
2242
|
if (state2 === "DISCONNECTED" && reason === "TOKEN_EXPIRE") {
|
|
1905
2243
|
handleExpired();
|
|
1906
2244
|
return;
|
|
1907
2245
|
}
|
|
1908
2246
|
if (active() && !this.tokenExpired && state2 === "DISCONNECTED" && previous !== "DISCONNECTED") {
|
|
1909
|
-
_optionalChain([this, 'access',
|
|
2247
|
+
_optionalChain([this, 'access', _223 => _223.listener, 'optionalAccess', _224 => _224.onError, 'optionalCall', _225 => _225(new XmaxError("RTC_ERROR" /* rtcError */, `Agora connection disconnected: ${_nullishCoalesce(reason, () => ( "unknown"))}`))]);
|
|
1910
2248
|
}
|
|
1911
2249
|
});
|
|
1912
2250
|
}
|
|
@@ -1915,20 +2253,21 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1915
2253
|
*/
|
|
1916
2254
|
clearRoom() {
|
|
1917
2255
|
this.roomVersion++;
|
|
1918
|
-
_optionalChain([this, 'access',
|
|
2256
|
+
_optionalChain([this, 'access', _226 => _226.cancelRejoin, 'optionalCall', _227 => _227()]);
|
|
1919
2257
|
this.connection = void 0;
|
|
1920
2258
|
this.tokenExpired = false;
|
|
2259
|
+
this.networkQualitySuspended = false;
|
|
1921
2260
|
this.videoPublishRequested = false;
|
|
1922
2261
|
this.audioPublishRequested = false;
|
|
1923
2262
|
clearInterval(this.statisticsTimer);
|
|
1924
2263
|
this.statisticsTimer = void 0;
|
|
1925
|
-
_optionalChain([this, 'access',
|
|
1926
|
-
_optionalChain([this, 'access',
|
|
2264
|
+
_optionalChain([this, 'access', _228 => _228.cancelSendDelay, 'optionalCall', _229 => _229()]);
|
|
2265
|
+
_optionalChain([this, 'access', _230 => _230.cancelActiveSend, 'optionalCall', _231 => _231()]);
|
|
1927
2266
|
this.sentPackets = [];
|
|
1928
2267
|
this.sendTail = Promise.resolve();
|
|
1929
2268
|
this.requestedAudio.clear();
|
|
1930
2269
|
this.audioVolumes.clear();
|
|
1931
|
-
for (const user of _nullishCoalesce(_optionalChain([this, 'access',
|
|
2270
|
+
for (const user of _nullishCoalesce(_optionalChain([this, 'access', _232 => _232.client, 'optionalAccess', _233 => _233.remoteUsers]), () => ( []))) _optionalChain([user, 'access', _234 => _234.audioTrack, 'optionalAccess', _235 => _235.stop, 'call', _236 => _236()]);
|
|
1932
2271
|
}
|
|
1933
2272
|
/**
|
|
1934
2273
|
* 判断异步恢复工作是否仍属于当前房间生命周期。
|
|
@@ -1953,8 +2292,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1953
2292
|
* 获取已启动的相机采集。
|
|
1954
2293
|
*/
|
|
1955
2294
|
requireCamera() {
|
|
1956
|
-
if (!this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
1957
|
-
return this.
|
|
2295
|
+
if (!this.cameraSource || !this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
2296
|
+
return this.cameraSource;
|
|
1958
2297
|
}
|
|
1959
2298
|
/**
|
|
1960
2299
|
* 获取当前可编码、发布的视频轨,不要求来源为摄像头。
|
|
@@ -2066,7 +2405,7 @@ var _RtcEngineManager = class _RtcEngineManager {
|
|
|
2066
2405
|
* 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
|
|
2067
2406
|
*/
|
|
2068
2407
|
release(lease) {
|
|
2069
|
-
if (_optionalChain([this, 'access',
|
|
2408
|
+
if (_optionalChain([this, 'access', _237 => _237.activeLease, 'optionalAccess', _238 => _238.id]) !== lease.id) {
|
|
2070
2409
|
return;
|
|
2071
2410
|
}
|
|
2072
2411
|
this.activeLease = void 0;
|
|
@@ -2140,10 +2479,10 @@ var RtcStatsLogger = class {
|
|
|
2140
2479
|
`${XmaxLogger.localized("\u7D2F\u8BA1\u63A5\u6536\uFF1A", "Bytes Received: ")}${this.value(stats.bytesReceived, "bytes")}`
|
|
2141
2480
|
])];
|
|
2142
2481
|
const local = stats.localStatistics;
|
|
2143
|
-
if (_optionalChain([local, 'optionalAccess',
|
|
2482
|
+
if (_optionalChain([local, 'optionalAccess', _239 => _239.audio])) {
|
|
2144
2483
|
blocks.push(this.audioBlock("\u672C\u5730\u97F3\u9891\u53D1\u9001 (Local Audio Uplink)", local.audio, false));
|
|
2145
2484
|
}
|
|
2146
|
-
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess',
|
|
2485
|
+
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _240 => _240.video]), () => ( []))) {
|
|
2147
2486
|
blocks.push(this.videoBlock("\u672C\u5730\u89C6\u9891\u53D1\u9001 (Local Video Uplink)", video, false));
|
|
2148
2487
|
}
|
|
2149
2488
|
for (const remote of _nullishCoalesce(stats.remoteStatistics, () => ( []))) {
|
|
@@ -2233,8 +2572,8 @@ var RtcStatsLogger = class {
|
|
|
2233
2572
|
|
|
2234
2573
|
// src/Foundation/RTC/TRTC/TrtcAudioVolumeSupport.ts
|
|
2235
2574
|
function canControlTrtcRemoteAudioVolume(environment) {
|
|
2236
|
-
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
2237
|
-
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
2575
|
+
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _241 => _241.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
|
|
2576
|
+
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _242 => _242.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
|
|
2238
2577
|
const ios = /iPhone|iPad|iPod/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
|
|
2239
2578
|
return !ios;
|
|
2240
2579
|
}
|
|
@@ -2321,11 +2660,11 @@ var TrtcRtcManager = class {
|
|
|
2321
2660
|
this.isCapturing = false;
|
|
2322
2661
|
this.isAudioCapturing = false;
|
|
2323
2662
|
this.isInRoom = false;
|
|
2324
|
-
_optionalChain([this, 'access',
|
|
2663
|
+
_optionalChain([this, 'access', _243 => _243.removeStatsListeners, 'optionalCall', _244 => _244()]);
|
|
2325
2664
|
this.removeStatsListeners = void 0;
|
|
2326
2665
|
if (!lease) {
|
|
2327
|
-
_optionalChain([externalVideo, 'optionalAccess',
|
|
2328
|
-
_optionalChain([externalAudio, 'optionalAccess',
|
|
2666
|
+
_optionalChain([externalVideo, 'optionalAccess', _245 => _245.stop, 'call', _246 => _246()]);
|
|
2667
|
+
_optionalChain([externalAudio, 'optionalAccess', _247 => _247.stop, 'call', _248 => _248()]);
|
|
2329
2668
|
return;
|
|
2330
2669
|
}
|
|
2331
2670
|
try {
|
|
@@ -2336,8 +2675,8 @@ var TrtcRtcManager = class {
|
|
|
2336
2675
|
await lease.engine.stopLocalVideo();
|
|
2337
2676
|
} catch (e13) {
|
|
2338
2677
|
}
|
|
2339
|
-
_optionalChain([externalVideo, 'optionalAccess',
|
|
2340
|
-
_optionalChain([externalAudio, 'optionalAccess',
|
|
2678
|
+
_optionalChain([externalVideo, 'optionalAccess', _249 => _249.stop, 'call', _250 => _250()]);
|
|
2679
|
+
_optionalChain([externalAudio, 'optionalAccess', _251 => _251.stop, 'call', _252 => _252()]);
|
|
2341
2680
|
this.engineManager.release(lease);
|
|
2342
2681
|
}
|
|
2343
2682
|
/**
|
|
@@ -2355,10 +2694,10 @@ var TrtcRtcManager = class {
|
|
|
2355
2694
|
this.externalVideo = video;
|
|
2356
2695
|
let audio;
|
|
2357
2696
|
try {
|
|
2358
|
-
audio = _optionalChain([tracks, 'access',
|
|
2697
|
+
audio = _optionalChain([tracks, 'access', _253 => _253.audioTrack, 'optionalAccess', _254 => _254.clone, 'call', _255 => _255()]);
|
|
2359
2698
|
this.externalAudio = audio;
|
|
2360
2699
|
await engine.startLocalVideo({ publish: false, option: { videoTrack: video } });
|
|
2361
|
-
if (_optionalChain([this, 'access',
|
|
2700
|
+
if (_optionalChain([this, 'access', _256 => _256.lease, 'optionalAccess', _257 => _257.engine]) !== engine) {
|
|
2362
2701
|
throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
|
|
2363
2702
|
}
|
|
2364
2703
|
if (audio) {
|
|
@@ -2366,12 +2705,12 @@ var TrtcRtcManager = class {
|
|
|
2366
2705
|
publish: false,
|
|
2367
2706
|
option: { audioTrack: audio, echoCancellation: false, autoGainControl: false, noiseSuppression: false }
|
|
2368
2707
|
});
|
|
2369
|
-
if (_optionalChain([this, 'access',
|
|
2708
|
+
if (_optionalChain([this, 'access', _258 => _258.lease, 'optionalAccess', _259 => _259.engine]) !== engine) {
|
|
2370
2709
|
throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
|
|
2371
2710
|
}
|
|
2372
2711
|
}
|
|
2373
2712
|
} catch (error) {
|
|
2374
|
-
if (_optionalChain([this, 'access',
|
|
2713
|
+
if (_optionalChain([this, 'access', _260 => _260.lease, 'optionalAccess', _261 => _261.engine]) === engine) {
|
|
2375
2714
|
await engine.stopLocalAudio().catch(() => {
|
|
2376
2715
|
});
|
|
2377
2716
|
await engine.stopLocalVideo().catch(() => {
|
|
@@ -2382,7 +2721,7 @@ var TrtcRtcManager = class {
|
|
|
2382
2721
|
this.externalAudio = void 0;
|
|
2383
2722
|
}
|
|
2384
2723
|
video.stop();
|
|
2385
|
-
_optionalChain([audio, 'optionalAccess',
|
|
2724
|
+
_optionalChain([audio, 'optionalAccess', _262 => _262.stop, 'call', _263 => _263()]);
|
|
2386
2725
|
throw this.mapError(error);
|
|
2387
2726
|
}
|
|
2388
2727
|
}
|
|
@@ -2393,6 +2732,9 @@ var TrtcRtcManager = class {
|
|
|
2393
2732
|
* @throws 引擎未初始化、已在采集、设备不可用或权限被拒绝时抛出错误。
|
|
2394
2733
|
*/
|
|
2395
2734
|
async startCameraCapture(options) {
|
|
2735
|
+
if (options.rotation !== void 0 && options.rotation !== 0) {
|
|
2736
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation currently requires Agora");
|
|
2737
|
+
}
|
|
2396
2738
|
const engine = this.requireEngine();
|
|
2397
2739
|
if (this.isCapturing || this.externalVideo) {
|
|
2398
2740
|
throw new XmaxError(
|
|
@@ -2467,7 +2809,7 @@ var TrtcRtcManager = class {
|
|
|
2467
2809
|
if (this.externalVideo) {
|
|
2468
2810
|
return;
|
|
2469
2811
|
}
|
|
2470
|
-
const engine = _optionalChain([this, 'access',
|
|
2812
|
+
const engine = _optionalChain([this, 'access', _264 => _264.lease, 'optionalAccess', _265 => _265.engine]);
|
|
2471
2813
|
this.isCapturing = false;
|
|
2472
2814
|
if (!engine) {
|
|
2473
2815
|
return;
|
|
@@ -2520,7 +2862,7 @@ var TrtcRtcManager = class {
|
|
|
2520
2862
|
* 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
|
|
2521
2863
|
*/
|
|
2522
2864
|
async leaveRoom() {
|
|
2523
|
-
const engine = _optionalChain([this, 'access',
|
|
2865
|
+
const engine = _optionalChain([this, 'access', _266 => _266.lease, 'optionalAccess', _267 => _267.engine]);
|
|
2524
2866
|
if (!engine || !this.isInRoom) {
|
|
2525
2867
|
return;
|
|
2526
2868
|
}
|
|
@@ -2593,7 +2935,7 @@ var TrtcRtcManager = class {
|
|
|
2593
2935
|
* 停止发布本地视频流;采集保持运行,本地预览不受影响。
|
|
2594
2936
|
*/
|
|
2595
2937
|
async unpublishLocalVideo() {
|
|
2596
|
-
const engine = _optionalChain([this, 'access',
|
|
2938
|
+
const engine = _optionalChain([this, 'access', _268 => _268.lease, 'optionalAccess', _269 => _269.engine]);
|
|
2597
2939
|
if (!engine || !this.isCapturing && !this.externalVideo) {
|
|
2598
2940
|
return;
|
|
2599
2941
|
}
|
|
@@ -2629,7 +2971,7 @@ var TrtcRtcManager = class {
|
|
|
2629
2971
|
* 停止发布本地音频流;麦克风采集保持运行。
|
|
2630
2972
|
*/
|
|
2631
2973
|
async unpublishLocalAudio() {
|
|
2632
|
-
const engine = _optionalChain([this, 'access',
|
|
2974
|
+
const engine = _optionalChain([this, 'access', _270 => _270.lease, 'optionalAccess', _271 => _271.engine]);
|
|
2633
2975
|
if (!engine || !this.isAudioCapturing && !this.externalAudio) {
|
|
2634
2976
|
return;
|
|
2635
2977
|
}
|
|
@@ -2755,19 +3097,19 @@ var TrtcRtcManager = class {
|
|
|
2755
3097
|
registerEventBridge(engine) {
|
|
2756
3098
|
const source = engine;
|
|
2757
3099
|
const onStatistics = (stats) => {
|
|
2758
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
3100
|
+
if (this.isInRoom && _optionalChain([this, 'access', _272 => _272.lease, 'optionalAccess', _273 => _273.engine]) === engine) {
|
|
2759
3101
|
RtcStatsLogger.logStatistics(stats);
|
|
2760
|
-
const video = _optionalChain([stats, 'access',
|
|
3102
|
+
const video = _optionalChain([stats, 'access', _274 => _274.localStatistics, 'optionalAccess', _275 => _275.video, 'optionalAccess', _276 => _276.find, 'call', _277 => _277((item) => item.videoType === "big")]);
|
|
2761
3103
|
const valid = (value, minimum) => typeof value === "number" && Number.isFinite(value) && value >= minimum ? value : void 0;
|
|
2762
|
-
_optionalChain([this, 'access',
|
|
3104
|
+
_optionalChain([this, 'access', _278 => _278.eventListener, 'optionalAccess', _279 => _279.onLocalVideoStatistics, 'optionalCall', _280 => _280(video ? Object.freeze({
|
|
2763
3105
|
width: valid(video.width, 1),
|
|
2764
3106
|
height: valid(video.height, 1),
|
|
2765
3107
|
frameRate: valid(video.frameRate, 0),
|
|
2766
3108
|
bitrateKbps: valid(video.bitrate, 0)
|
|
2767
3109
|
}) : void 0)]);
|
|
2768
|
-
_optionalChain([this, 'access',
|
|
3110
|
+
_optionalChain([this, 'access', _281 => _281.eventListener, 'optionalAccess', _282 => _282.onRemoteVideoStatistics, 'optionalCall', _283 => _283(Object.freeze(
|
|
2769
3111
|
(_nullishCoalesce(stats.remoteStatistics, () => ( []))).flatMap((remote) => {
|
|
2770
|
-
const video2 = _optionalChain([remote, 'access',
|
|
3112
|
+
const video2 = _optionalChain([remote, 'access', _284 => _284.video, 'optionalAccess', _285 => _285.find, 'call', _286 => _286((item) => item.videoType === "big")]);
|
|
2771
3113
|
if (!video2) {
|
|
2772
3114
|
return [];
|
|
2773
3115
|
}
|
|
@@ -2789,11 +3131,11 @@ var TrtcRtcManager = class {
|
|
|
2789
3131
|
}
|
|
2790
3132
|
};
|
|
2791
3133
|
const onNetworkQuality = (stats) => {
|
|
2792
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
3134
|
+
if (this.isInRoom && _optionalChain([this, 'access', _287 => _287.lease, 'optionalAccess', _288 => _288.engine]) === engine) {
|
|
2793
3135
|
RtcStatsLogger.logNetworkQuality(stats);
|
|
2794
3136
|
const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
|
|
2795
3137
|
const rtt = (value) => Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
2796
|
-
_optionalChain([this, 'access',
|
|
3138
|
+
_optionalChain([this, 'access', _289 => _289.eventListener, 'optionalAccess', _290 => _290.onNetworkStatistics, 'optionalCall', _291 => _291(Object.freeze({
|
|
2797
3139
|
uplinkQuality: quality(stats.uplinkNetworkQuality),
|
|
2798
3140
|
downlinkQuality: quality(stats.downlinkNetworkQuality),
|
|
2799
3141
|
uplinkRttMs: rtt(stats.uplinkRTT),
|
|
@@ -2808,19 +3150,19 @@ var TrtcRtcManager = class {
|
|
|
2808
3150
|
source.off(RTC_EVENT.networkQuality, onNetworkQuality);
|
|
2809
3151
|
};
|
|
2810
3152
|
source.on(RTC_EVENT.remoteVideoAvailable, (event) => {
|
|
2811
|
-
if (_optionalChain([this, 'access',
|
|
3153
|
+
if (_optionalChain([this, 'access', _292 => _292.lease, 'optionalAccess', _293 => _293.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
|
|
2812
3154
|
return;
|
|
2813
3155
|
}
|
|
2814
|
-
_optionalChain([this, 'access',
|
|
3156
|
+
_optionalChain([this, 'access', _294 => _294.eventListener, 'optionalAccess', _295 => _295.onRemoteVideoPublished, 'call', _296 => _296(event.userId, true)]);
|
|
2815
3157
|
});
|
|
2816
3158
|
source.on(RTC_EVENT.remoteVideoUnavailable, (event) => {
|
|
2817
|
-
if (_optionalChain([this, 'access',
|
|
3159
|
+
if (_optionalChain([this, 'access', _297 => _297.lease, 'optionalAccess', _298 => _298.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
|
|
2818
3160
|
return;
|
|
2819
3161
|
}
|
|
2820
|
-
_optionalChain([this, 'access',
|
|
3162
|
+
_optionalChain([this, 'access', _299 => _299.eventListener, 'optionalAccess', _300 => _300.onRemoteVideoPublished, 'call', _301 => _301(event.userId, false)]);
|
|
2821
3163
|
});
|
|
2822
3164
|
source.on(RTC_EVENT.customMessage, (event) => {
|
|
2823
|
-
if (_optionalChain([this, 'access',
|
|
3165
|
+
if (_optionalChain([this, 'access', _302 => _302.lease, 'optionalAccess', _303 => _303.engine]) !== engine || event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
|
|
2824
3166
|
return;
|
|
2825
3167
|
}
|
|
2826
3168
|
let message;
|
|
@@ -2830,14 +3172,14 @@ var TrtcRtcManager = class {
|
|
|
2830
3172
|
XmaxLogger.rtc.warning(() => "\u81EA\u5B9A\u4E49\u6D88\u606F\u89E3\u7801\u5931\u8D25 (Failed to Decode Custom Message)");
|
|
2831
3173
|
return;
|
|
2832
3174
|
}
|
|
2833
|
-
_optionalChain([this, 'access',
|
|
3175
|
+
_optionalChain([this, 'access', _304 => _304.eventListener, 'optionalAccess', _305 => _305.onCustomMessageReceived, 'call', _306 => _306(event.userId, message)]);
|
|
2834
3176
|
});
|
|
2835
3177
|
}
|
|
2836
3178
|
/**
|
|
2837
3179
|
* 返回当前引擎实例;未初始化时抛出错误。
|
|
2838
3180
|
*/
|
|
2839
3181
|
requireEngine() {
|
|
2840
|
-
const engine = _optionalChain([this, 'access',
|
|
3182
|
+
const engine = _optionalChain([this, 'access', _307 => _307.lease, 'optionalAccess', _308 => _308.engine]);
|
|
2841
3183
|
if (!engine) {
|
|
2842
3184
|
throw new XmaxError(
|
|
2843
3185
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -2854,8 +3196,8 @@ var TrtcRtcManager = class {
|
|
|
2854
3196
|
return error;
|
|
2855
3197
|
}
|
|
2856
3198
|
const rtcError = error;
|
|
2857
|
-
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess',
|
|
2858
|
-
const message = typeof _optionalChain([rtcError, 'optionalAccess',
|
|
3199
|
+
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess', _309 => _309.originError, 'optionalAccess', _310 => _310.name]), () => ( ""));
|
|
3200
|
+
const message = typeof _optionalChain([rtcError, 'optionalAccess', _311 => _311.message]) === "string" && rtcError.message.trim().length > 0 ? rtcError.message.trim() : String(error);
|
|
2859
3201
|
if (originName === "NotAllowedError" || originName === "SecurityError" || /NotAllowed/i.test(message)) {
|
|
2860
3202
|
return new XmaxError("CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */, message);
|
|
2861
3203
|
}
|
|
@@ -2978,12 +3320,12 @@ var VeRtcManager = class {
|
|
|
2978
3320
|
this.sdk = void 0;
|
|
2979
3321
|
this.camera = void 0;
|
|
2980
3322
|
this.microphone = false;
|
|
2981
|
-
_optionalChain([engine, 'optionalAccess',
|
|
3323
|
+
_optionalChain([engine, 'optionalAccess', _312 => _312.removeAllListeners, 'call', _313 => _313()]);
|
|
2982
3324
|
try {
|
|
2983
3325
|
if (engine && sdk) sdk.default.destroyEngine(engine);
|
|
2984
3326
|
} finally {
|
|
2985
|
-
_optionalChain([this, 'access',
|
|
2986
|
-
_optionalChain([this, 'access',
|
|
3327
|
+
_optionalChain([this, 'access', _314 => _314.externalVideo, 'optionalAccess', _315 => _315.stop, 'call', _316 => _316()]);
|
|
3328
|
+
_optionalChain([this, 'access', _317 => _317.externalAudio, 'optionalAccess', _318 => _318.stop, 'call', _319 => _319()]);
|
|
2987
3329
|
this.externalVideo = void 0;
|
|
2988
3330
|
this.externalAudio = void 0;
|
|
2989
3331
|
}
|
|
@@ -3010,7 +3352,7 @@ var VeRtcManager = class {
|
|
|
3010
3352
|
}
|
|
3011
3353
|
};
|
|
3012
3354
|
try {
|
|
3013
|
-
audio = _optionalChain([tracks, 'access',
|
|
3355
|
+
audio = _optionalChain([tracks, 'access', _320 => _320.audioTrack, 'optionalAccess', _321 => _321.clone, 'call', _322 => _322()]);
|
|
3014
3356
|
this.externalAudio = audio;
|
|
3015
3357
|
await engine.setVideoSourceType(index, sdk.VideoSourceType.VIDEO_SOURCE_TYPE_EXTERNAL);
|
|
3016
3358
|
ensureCurrent();
|
|
@@ -3034,11 +3376,14 @@ var VeRtcManager = class {
|
|
|
3034
3376
|
this.externalAudio = void 0;
|
|
3035
3377
|
}
|
|
3036
3378
|
video.stop();
|
|
3037
|
-
_optionalChain([audio, 'optionalAccess',
|
|
3379
|
+
_optionalChain([audio, 'optionalAccess', _323 => _323.stop, 'call', _324 => _324()]);
|
|
3038
3380
|
throw this.mapError(error);
|
|
3039
3381
|
}
|
|
3040
3382
|
}
|
|
3041
3383
|
async startCameraCapture(options) {
|
|
3384
|
+
if (options.rotation !== void 0 && options.rotation !== 0) {
|
|
3385
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation currently requires Agora");
|
|
3386
|
+
}
|
|
3042
3387
|
const engine = this.requireEngine();
|
|
3043
3388
|
if (this.camera || this.externalVideo) {
|
|
3044
3389
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is already prepared");
|
|
@@ -3103,9 +3448,9 @@ var VeRtcManager = class {
|
|
|
3103
3448
|
}));
|
|
3104
3449
|
}
|
|
3105
3450
|
async joinRoom(config) {
|
|
3106
|
-
await _optionalChain([this, 'access',
|
|
3451
|
+
await _optionalChain([this, 'access', _325 => _325.joining, 'optionalAccess', _326 => _326.catch, 'call', _327 => _327(() => {
|
|
3107
3452
|
})]);
|
|
3108
|
-
await _optionalChain([this, 'access',
|
|
3453
|
+
await _optionalChain([this, 'access', _328 => _328.recovery, 'optionalAccess', _329 => _329.catch, 'call', _330 => _330(() => {
|
|
3109
3454
|
})]);
|
|
3110
3455
|
const engine = this.requireEngine();
|
|
3111
3456
|
if (config.provider !== "vertc" /* vertc */ || config.appID !== VERTC_APP_ID || this.connection) {
|
|
@@ -3154,7 +3499,7 @@ var VeRtcManager = class {
|
|
|
3154
3499
|
async updateCredentials(config, signal) {
|
|
3155
3500
|
const engine = this.requireEngine();
|
|
3156
3501
|
const current = this.connection;
|
|
3157
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
3502
|
+
if (_optionalChain([signal, 'optionalAccess', _331 => _331.aborted])) throw this.cancelled();
|
|
3158
3503
|
if (!current || config.provider !== "vertc" /* vertc */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
3159
3504
|
throw new XmaxError("SESSION_ERROR" /* sessionError */, "VeRTC session binding changed");
|
|
3160
3505
|
}
|
|
@@ -3182,7 +3527,7 @@ var VeRtcManager = class {
|
|
|
3182
3527
|
const restore = this.tokenExpired || this.publishPrivilegeExpired || this.subscribePrivilegeExpired;
|
|
3183
3528
|
if (restore) {
|
|
3184
3529
|
this.joined = false;
|
|
3185
|
-
_optionalChain([this, 'access',
|
|
3530
|
+
_optionalChain([this, 'access', _332 => _332.listener, 'optionalAccess', _333 => _333.onRoomRejoining, 'optionalCall', _334 => _334()]);
|
|
3186
3531
|
this.clearPlayers();
|
|
3187
3532
|
this.clearStatistics();
|
|
3188
3533
|
if (this.tokenExpired) {
|
|
@@ -3353,13 +3698,13 @@ var VeRtcManager = class {
|
|
|
3353
3698
|
if (!active()) return;
|
|
3354
3699
|
if (video(mediaType)) {
|
|
3355
3700
|
this.publishedVideo.add(userId);
|
|
3356
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3701
|
+
if (mediaActive()) _optionalChain([this, 'access', _335 => _335.listener, 'optionalAccess', _336 => _336.onRemoteVideoPublished, 'call', _337 => _337(userId, true)]);
|
|
3357
3702
|
}
|
|
3358
3703
|
if (audio(mediaType)) {
|
|
3359
3704
|
this.publishedAudio.add(userId);
|
|
3360
3705
|
if (mediaActive() && this.requestedAudio.has(userId)) {
|
|
3361
3706
|
void this.subscribeRemoteAudio(userId, true).catch((error) => {
|
|
3362
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3707
|
+
if (mediaActive()) _optionalChain([this, 'access', _338 => _338.listener, 'optionalAccess', _339 => _339.onError, 'optionalCall', _340 => _340(this.mapError(error))]);
|
|
3363
3708
|
});
|
|
3364
3709
|
}
|
|
3365
3710
|
}
|
|
@@ -3379,10 +3724,10 @@ var VeRtcManager = class {
|
|
|
3379
3724
|
this.clearPlayer(userInfo.userId);
|
|
3380
3725
|
});
|
|
3381
3726
|
engine.on(events.onRoomMessageReceived, ({ userId, message }) => {
|
|
3382
|
-
if (mediaActive() && typeof message === "string") _optionalChain([this, 'access',
|
|
3727
|
+
if (mediaActive() && typeof message === "string") _optionalChain([this, 'access', _341 => _341.listener, 'optionalAccess', _342 => _342.onCustomMessageReceived, 'call', _343 => _343(userId, message)]);
|
|
3383
3728
|
});
|
|
3384
3729
|
const willExpire = () => {
|
|
3385
|
-
if (active()) _optionalChain([this, 'access',
|
|
3730
|
+
if (active()) _optionalChain([this, 'access', _344 => _344.listener, 'optionalAccess', _345 => _345.onTokenWillExpire, 'optionalCall', _346 => _346()]);
|
|
3386
3731
|
};
|
|
3387
3732
|
engine.on(events.onTokenWillExpire, willExpire);
|
|
3388
3733
|
engine.on(events.onTokenPublishPrivilegeWillExpire, willExpire);
|
|
@@ -3390,13 +3735,13 @@ var VeRtcManager = class {
|
|
|
3390
3735
|
engine.on(events.onTokenPublishPrivilegeDidExpired, () => {
|
|
3391
3736
|
if (!active() || this.publishPrivilegeExpired) return;
|
|
3392
3737
|
this.publishPrivilegeExpired = true;
|
|
3393
|
-
_optionalChain([this, 'access',
|
|
3738
|
+
_optionalChain([this, 'access', _347 => _347.listener, 'optionalAccess', _348 => _348.onTokenExpired, 'optionalCall', _349 => _349()]);
|
|
3394
3739
|
});
|
|
3395
3740
|
engine.on(events.onTokenSubscribePrivilegeDidExpired, () => {
|
|
3396
3741
|
if (!active() || this.subscribePrivilegeExpired) return;
|
|
3397
3742
|
this.subscribePrivilegeExpired = true;
|
|
3398
3743
|
this.clearPlayers();
|
|
3399
|
-
_optionalChain([this, 'access',
|
|
3744
|
+
_optionalChain([this, 'access', _350 => _350.listener, 'optionalAccess', _351 => _351.onTokenExpired, 'optionalCall', _352 => _352()]);
|
|
3400
3745
|
});
|
|
3401
3746
|
engine.on(events.onError, ({ errorCode }) => {
|
|
3402
3747
|
if (!active()) return;
|
|
@@ -3404,23 +3749,23 @@ var VeRtcManager = class {
|
|
|
3404
3749
|
if (this.tokenExpired) return;
|
|
3405
3750
|
this.tokenExpired = true;
|
|
3406
3751
|
this.clearPlayers();
|
|
3407
|
-
_optionalChain([this, 'access',
|
|
3408
|
-
} else _optionalChain([this, 'access',
|
|
3752
|
+
_optionalChain([this, 'access', _353 => _353.listener, 'optionalAccess', _354 => _354.onTokenExpired, 'optionalCall', _355 => _355()]);
|
|
3753
|
+
} else _optionalChain([this, 'access', _356 => _356.listener, 'optionalAccess', _357 => _357.onError, 'optionalCall', _358 => _358(this.mapError({ code: errorCode }))]);
|
|
3409
3754
|
});
|
|
3410
3755
|
engine.on(events.onConnectionStateChanged, ({ state: state2 }) => {
|
|
3411
3756
|
if (!mediaActive() || state2 !== this.sdk.ConnectionState.CONNECTION_STATE_RECONNECTED) return;
|
|
3412
|
-
_optionalChain([this, 'access',
|
|
3757
|
+
_optionalChain([this, 'access', _359 => _359.listener, 'optionalAccess', _360 => _360.onRoomRejoining, 'optionalCall', _361 => _361()]);
|
|
3413
3758
|
this.clearPlayers();
|
|
3414
3759
|
this.clearStatistics();
|
|
3415
3760
|
this.replayVideo();
|
|
3416
3761
|
for (const userID of this.requestedAudio) {
|
|
3417
3762
|
void this.subscribeRemoteAudio(userID, true).catch((error) => {
|
|
3418
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3763
|
+
if (mediaActive()) _optionalChain([this, 'access', _362 => _362.listener, 'optionalAccess', _363 => _363.onError, 'optionalCall', _364 => _364(this.mapError(error))]);
|
|
3419
3764
|
});
|
|
3420
3765
|
}
|
|
3421
3766
|
});
|
|
3422
3767
|
engine.on(events.onNetworkQuality, (up, down) => {
|
|
3423
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3768
|
+
if (mediaActive()) _optionalChain([this, 'access', _365 => _365.listener, 'optionalAccess', _366 => _366.onNetworkStatistics, 'optionalCall', _367 => _367(Object.freeze({
|
|
3424
3769
|
uplinkQuality: VeRtcStatistics.quality(up),
|
|
3425
3770
|
downlinkQuality: VeRtcStatistics.quality(down)
|
|
3426
3771
|
}))]);
|
|
@@ -3429,7 +3774,7 @@ var VeRtcManager = class {
|
|
|
3429
3774
|
if (!mediaActive() || stats.isScreen || !this.videoRequested) return;
|
|
3430
3775
|
const result = VeRtcStatistics.local(stats.videoStats);
|
|
3431
3776
|
this.uplinkLossPercent = result.uplinkLossPercent;
|
|
3432
|
-
_optionalChain([this, 'access',
|
|
3777
|
+
_optionalChain([this, 'access', _368 => _368.listener, 'optionalAccess', _369 => _369.onLocalVideoStatistics, 'optionalCall', _370 => _370(result)]);
|
|
3433
3778
|
XmaxLogger.rtc.info(() => `VeRTC local video statistics: ${JSON.stringify(result)}`, 2 /* performance */);
|
|
3434
3779
|
});
|
|
3435
3780
|
engine.on(events.onRemoteStreamStats, (stats) => {
|
|
@@ -3439,21 +3784,21 @@ var VeRtcManager = class {
|
|
|
3439
3784
|
});
|
|
3440
3785
|
}
|
|
3441
3786
|
replayVideo() {
|
|
3442
|
-
for (const userID of this.publishedVideo) _optionalChain([this, 'access',
|
|
3787
|
+
for (const userID of this.publishedVideo) _optionalChain([this, 'access', _371 => _371.listener, 'optionalAccess', _372 => _372.onRemoteVideoPublished, 'call', _373 => _373(userID, true)]);
|
|
3443
3788
|
}
|
|
3444
3789
|
removeVideo(userID) {
|
|
3445
3790
|
this.publishedVideo.delete(userID);
|
|
3446
3791
|
this.remoteStatistics.delete(userID);
|
|
3447
3792
|
this.emitRemoteStatistics();
|
|
3448
|
-
if (this.joined && !this.tokenExpired) _optionalChain([this, 'access',
|
|
3793
|
+
if (this.joined && !this.tokenExpired) _optionalChain([this, 'access', _374 => _374.listener, 'optionalAccess', _375 => _375.onRemoteVideoPublished, 'call', _376 => _376(userID, false)]);
|
|
3449
3794
|
}
|
|
3450
3795
|
emitRemoteStatistics() {
|
|
3451
|
-
_optionalChain([this, 'access',
|
|
3796
|
+
_optionalChain([this, 'access', _377 => _377.listener, 'optionalAccess', _378 => _378.onRemoteVideoStatistics, 'optionalCall', _379 => _379(Object.freeze([...this.remoteStatistics.values()]))]);
|
|
3452
3797
|
}
|
|
3453
3798
|
clearStatistics() {
|
|
3454
3799
|
this.remoteStatistics.clear();
|
|
3455
3800
|
this.uplinkLossPercent = void 0;
|
|
3456
|
-
_optionalChain([this, 'access',
|
|
3801
|
+
_optionalChain([this, 'access', _380 => _380.listener, 'optionalAccess', _381 => _381.onLocalVideoStatistics, 'optionalCall', _382 => _382(void 0)]);
|
|
3457
3802
|
this.emitRemoteStatistics();
|
|
3458
3803
|
}
|
|
3459
3804
|
clearPlayer(userID) {
|
|
@@ -3499,15 +3844,15 @@ var VeRtcManager = class {
|
|
|
3499
3844
|
const cleanup = () => {
|
|
3500
3845
|
clearTimeout(timer);
|
|
3501
3846
|
roomSignal.removeEventListener("abort", cancel);
|
|
3502
|
-
_optionalChain([signal, 'optionalAccess',
|
|
3847
|
+
_optionalChain([signal, 'optionalAccess', _383 => _383.removeEventListener, 'call', _384 => _384("abort", cancel)]);
|
|
3503
3848
|
};
|
|
3504
3849
|
const cancel = () => {
|
|
3505
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
3850
|
+
if (_optionalChain([signal, 'optionalAccess', _385 => _385.aborted]) && !roomSignal.aborted) this.roomVersion++;
|
|
3506
3851
|
cleanup();
|
|
3507
3852
|
reject(this.cancelled());
|
|
3508
3853
|
};
|
|
3509
3854
|
roomSignal.addEventListener("abort", cancel, { once: true });
|
|
3510
|
-
_optionalChain([signal, 'optionalAccess',
|
|
3855
|
+
_optionalChain([signal, 'optionalAccess', _386 => _386.addEventListener, 'call', _387 => _387("abort", cancel, { once: true })]);
|
|
3511
3856
|
task.then((value) => {
|
|
3512
3857
|
cleanup();
|
|
3513
3858
|
resolve(value);
|
|
@@ -3515,7 +3860,7 @@ var VeRtcManager = class {
|
|
|
3515
3860
|
cleanup();
|
|
3516
3861
|
reject(error);
|
|
3517
3862
|
});
|
|
3518
|
-
if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess',
|
|
3863
|
+
if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess', _388 => _388.aborted])) cancel();
|
|
3519
3864
|
});
|
|
3520
3865
|
}
|
|
3521
3866
|
isCurrent(engine, version) {
|
|
@@ -3551,8 +3896,8 @@ var VeRtcManager = class {
|
|
|
3551
3896
|
mapError(error, permissionCode) {
|
|
3552
3897
|
if (error instanceof XmaxError) return error;
|
|
3553
3898
|
const value = error;
|
|
3554
|
-
const code = typeof _optionalChain([value, 'optionalAccess',
|
|
3555
|
-
const denied = _optionalChain([value, 'optionalAccess',
|
|
3899
|
+
const code = typeof _optionalChain([value, 'optionalAccess', _389 => _389.code]) === "string" && /^[A-Z_0-9-]{1,64}$/.test(value.code) ? value.code : "UNKNOWN";
|
|
3900
|
+
const denied = _optionalChain([value, 'optionalAccess', _390 => _390.name]) === "NotAllowedError" || code === "PERMISSION_DENIED" || code === "DEVICE_PERMISSION_DENIED";
|
|
3556
3901
|
return new XmaxError(permissionCode && denied ? permissionCode : "RTC_ERROR" /* rtcError */, `VeRTC operation failed (${code})`);
|
|
3557
3902
|
}
|
|
3558
3903
|
cancelled() {
|
|
@@ -3634,7 +3979,7 @@ var PermissionManager = class {
|
|
|
3634
3979
|
* @param deniedCode 权限被拒绝时抛出的错误码。
|
|
3635
3980
|
*/
|
|
3636
3981
|
async ensurePermission(name, deniedCode) {
|
|
3637
|
-
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access',
|
|
3982
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _391 => _391.mediaDevices, 'optionalAccess', _392 => _392.getUserMedia])) {
|
|
3638
3983
|
throw new XmaxError(
|
|
3639
3984
|
deniedCode,
|
|
3640
3985
|
"This browser does not support media capture (getUserMedia)"
|
|
@@ -3642,7 +3987,7 @@ var PermissionManager = class {
|
|
|
3642
3987
|
}
|
|
3643
3988
|
try {
|
|
3644
3989
|
const permissions = navigator.permissions;
|
|
3645
|
-
if (!_optionalChain([permissions, 'optionalAccess',
|
|
3990
|
+
if (!_optionalChain([permissions, 'optionalAccess', _393 => _393.query])) {
|
|
3646
3991
|
return;
|
|
3647
3992
|
}
|
|
3648
3993
|
const status = await permissions.query({
|
|
@@ -3822,10 +4167,10 @@ var _CameraController = class _CameraController {
|
|
|
3822
4167
|
*/
|
|
3823
4168
|
__publicField(this, "storedUseMicrophone", false);
|
|
3824
4169
|
__publicField(this, "storedFrameValidationEnabled", true);
|
|
3825
|
-
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3826
|
-
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3827
|
-
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3828
|
-
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
4170
|
+
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _394 => _394.permissionManager]), () => ( new PermissionManager()));
|
|
4171
|
+
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _395 => _395.rtcManager]), () => ( new TrtcRtcManager()));
|
|
4172
|
+
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _396 => _396.mediaService]), () => ( new MediaService()));
|
|
4173
|
+
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _397 => _397.errorListener]), () => ( (() => {
|
|
3829
4174
|
})));
|
|
3830
4175
|
}
|
|
3831
4176
|
/**
|
|
@@ -3851,7 +4196,7 @@ var _CameraController = class _CameraController {
|
|
|
3851
4196
|
*/
|
|
3852
4197
|
async waitForValidCameraFrame(signal) {
|
|
3853
4198
|
const track = this.activeTrack;
|
|
3854
|
-
const mediaTrack = _optionalChain([track, 'optionalAccess',
|
|
4199
|
+
const mediaTrack = _optionalChain([track, 'optionalAccess', _398 => _398.mediaStreamTrack]);
|
|
3855
4200
|
if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
|
|
3856
4201
|
if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
|
|
3857
4202
|
if (!this.isFrameValidationEnabled) return;
|
|
@@ -3875,6 +4220,7 @@ var _CameraController = class _CameraController {
|
|
|
3875
4220
|
*
|
|
3876
4221
|
* @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
|
|
3877
4222
|
* @param options.position 首次启动时使用的摄像头位置。
|
|
4223
|
+
* @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
|
|
3878
4224
|
* @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
|
|
3879
4225
|
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
3880
4226
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
@@ -3887,6 +4233,7 @@ var _CameraController = class _CameraController {
|
|
|
3887
4233
|
"Stop the current local camera stream before creating another one"
|
|
3888
4234
|
);
|
|
3889
4235
|
}
|
|
4236
|
+
validateCameraRotation(_nullishCoalesce(options.rotation, () => ( 0)));
|
|
3890
4237
|
const resolvedFormat = this.resolveVideoFormat(options.videoFormat);
|
|
3891
4238
|
const track = new RealtimeVideoTrack({
|
|
3892
4239
|
id: _CameraController.localVideoTrackID,
|
|
@@ -3909,7 +4256,8 @@ var _CameraController = class _CameraController {
|
|
|
3909
4256
|
width: resolvedFormat.width,
|
|
3910
4257
|
height: resolvedFormat.height,
|
|
3911
4258
|
frameRate: resolvedFormat.fps,
|
|
3912
|
-
position: options.position
|
|
4259
|
+
position: options.position,
|
|
4260
|
+
...options.rotation !== void 0 ? { rotation: options.rotation } : {}
|
|
3913
4261
|
});
|
|
3914
4262
|
track.mediaStreamTrack = mediaTrack;
|
|
3915
4263
|
this.previewStream = new MediaStream([mediaTrack]);
|
|
@@ -3951,7 +4299,7 @@ var _CameraController = class _CameraController {
|
|
|
3951
4299
|
*/
|
|
3952
4300
|
async switchCamera() {
|
|
3953
4301
|
const track = this.activeTrack;
|
|
3954
|
-
const position = _optionalChain([track, 'optionalAccess',
|
|
4302
|
+
const position = _optionalChain([track, 'optionalAccess', _399 => _399.position]);
|
|
3955
4303
|
if (!track || !position) {
|
|
3956
4304
|
throw new XmaxError(
|
|
3957
4305
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -3969,7 +4317,7 @@ var _CameraController = class _CameraController {
|
|
|
3969
4317
|
}
|
|
3970
4318
|
this.previewStream.addTrack(mediaTrack);
|
|
3971
4319
|
}
|
|
3972
|
-
_optionalChain([this, 'access',
|
|
4320
|
+
_optionalChain([this, 'access', _400 => _400.previewMirrorApplier, 'optionalCall', _401 => _401(nextPosition === "front" /* front */)]);
|
|
3973
4321
|
this.observeMediaTrack(track, mediaTrack);
|
|
3974
4322
|
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
3975
4323
|
}
|
|
@@ -4167,7 +4515,7 @@ var NetworkVideoController = class {
|
|
|
4167
4515
|
this.ended = video.ended || this.ended;
|
|
4168
4516
|
video.removeEventListener("loadedmetadata", restore);
|
|
4169
4517
|
video.removeEventListener("error", fail);
|
|
4170
|
-
_optionalChain([view, 'access',
|
|
4518
|
+
_optionalChain([view, 'access', _402 => _402.setVideoURL, 'optionalCall', _403 => _403(null)]);
|
|
4171
4519
|
});
|
|
4172
4520
|
view.isMirrored = false;
|
|
4173
4521
|
view.setVideoURL(this.reference.path);
|
|
@@ -4176,7 +4524,7 @@ var NetworkVideoController = class {
|
|
|
4176
4524
|
* 保存预览进度并释放该视图的地址和事件监听。
|
|
4177
4525
|
*/
|
|
4178
4526
|
detach(view) {
|
|
4179
|
-
_optionalChain([this, 'access',
|
|
4527
|
+
_optionalChain([this, 'access', _404 => _404.bindings, 'access', _405 => _405.get, 'call', _406 => _406(view), 'optionalCall', _407 => _407()]);
|
|
4180
4528
|
this.bindings.delete(view);
|
|
4181
4529
|
}
|
|
4182
4530
|
};
|
|
@@ -4205,13 +4553,13 @@ var LocalVideoController = class {
|
|
|
4205
4553
|
* 准备完成的本地视频轨。
|
|
4206
4554
|
*/
|
|
4207
4555
|
get currentTrack() {
|
|
4208
|
-
return _optionalChain([this, 'access',
|
|
4556
|
+
return _optionalChain([this, 'access', _408 => _408.source, 'optionalAccess', _409 => _409.track]);
|
|
4209
4557
|
}
|
|
4210
4558
|
/**
|
|
4211
4559
|
* 文件音频输出;禁用音频时为空,无音轨文件的 Web Audio 输出为静音。
|
|
4212
4560
|
*/
|
|
4213
4561
|
get audioTrack() {
|
|
4214
|
-
return _optionalChain([this, 'access',
|
|
4562
|
+
return _optionalChain([this, 'access', _410 => _410.source, 'optionalAccess', _411 => _411.audioDestination, 'optionalAccess', _412 => _412.stream, 'access', _413 => _413.getAudioTracks, 'call', _414 => _414(), 'access', _415 => _415[0]]);
|
|
4215
4563
|
}
|
|
4216
4564
|
/**
|
|
4217
4565
|
* 校验文件和格式,准备首帧与音频输出;应从用户点击事件直接调用以解锁播放。
|
|
@@ -4264,7 +4612,7 @@ var LocalVideoController = class {
|
|
|
4264
4612
|
source.audioSource.connect(source.audioDestination);
|
|
4265
4613
|
}
|
|
4266
4614
|
video.src = source.url;
|
|
4267
|
-
const resume = _optionalChain([source, 'access',
|
|
4615
|
+
const resume = _optionalChain([source, 'access', _416 => _416.audioContext, 'optionalAccess', _417 => _417.resume, 'call', _418 => _418()]);
|
|
4268
4616
|
const playing = this.play(source, signal);
|
|
4269
4617
|
await this.wait(source, Promise.all([resume, playing]), signal);
|
|
4270
4618
|
video.pause();
|
|
@@ -4316,7 +4664,7 @@ var LocalVideoController = class {
|
|
|
4316
4664
|
*/
|
|
4317
4665
|
async start(signal) {
|
|
4318
4666
|
const source = this.source;
|
|
4319
|
-
if (!_optionalChain([source, 'optionalAccess',
|
|
4667
|
+
if (!_optionalChain([source, 'optionalAccess', _419 => _419.track])) {
|
|
4320
4668
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is not prepared");
|
|
4321
4669
|
}
|
|
4322
4670
|
if (signal.aborted) {
|
|
@@ -4324,7 +4672,7 @@ var LocalVideoController = class {
|
|
|
4324
4672
|
}
|
|
4325
4673
|
try {
|
|
4326
4674
|
await this.rewind(source, signal);
|
|
4327
|
-
await this.wait(source, Promise.all([_optionalChain([source, 'access',
|
|
4675
|
+
await this.wait(source, Promise.all([_optionalChain([source, 'access', _420 => _420.audioContext, 'optionalAccess', _421 => _421.resume, 'call', _422 => _422()]), this.play(source, signal)]), signal);
|
|
4328
4676
|
} catch (error) {
|
|
4329
4677
|
source.video.pause();
|
|
4330
4678
|
throw error;
|
|
@@ -4334,7 +4682,7 @@ var LocalVideoController = class {
|
|
|
4334
4682
|
* 暂停文件音视频,保留当前预览;重新开始生成时回到文件开头。
|
|
4335
4683
|
*/
|
|
4336
4684
|
pause() {
|
|
4337
|
-
_optionalChain([this, 'access',
|
|
4685
|
+
_optionalChain([this, 'access', _423 => _423.source, 'optionalAccess', _424 => _424.video, 'access', _425 => _425.pause, 'call', _426 => _426()]);
|
|
4338
4686
|
}
|
|
4339
4687
|
/**
|
|
4340
4688
|
* 释放播放器、预览、定时器、轨道、音频上下文和对象 URL。
|
|
@@ -4364,12 +4712,12 @@ var LocalVideoController = class {
|
|
|
4364
4712
|
source.video.pause();
|
|
4365
4713
|
source.video.removeAttribute("src");
|
|
4366
4714
|
source.video.load();
|
|
4367
|
-
_optionalChain([source, 'access',
|
|
4368
|
-
_optionalChain([source, 'access',
|
|
4369
|
-
_optionalChain([source, 'access',
|
|
4370
|
-
_optionalChain([source, 'access',
|
|
4715
|
+
_optionalChain([source, 'access', _427 => _427.stream, 'optionalAccess', _428 => _428.getTracks, 'call', _429 => _429(), 'access', _430 => _430.forEach, 'call', _431 => _431((track) => track.stop())]);
|
|
4716
|
+
_optionalChain([source, 'access', _432 => _432.audioDestination, 'optionalAccess', _433 => _433.stream, 'access', _434 => _434.getTracks, 'call', _435 => _435(), 'access', _436 => _436.forEach, 'call', _437 => _437((track) => track.stop())]);
|
|
4717
|
+
_optionalChain([source, 'access', _438 => _438.audioSource, 'optionalAccess', _439 => _439.disconnect, 'call', _440 => _440()]);
|
|
4718
|
+
_optionalChain([source, 'access', _441 => _441.audioDestination, 'optionalAccess', _442 => _442.disconnect, 'call', _443 => _443()]);
|
|
4371
4719
|
URL.revokeObjectURL(source.url);
|
|
4372
|
-
await _optionalChain([source, 'access',
|
|
4720
|
+
await _optionalChain([source, 'access', _444 => _444.audioContext, 'optionalAccess', _445 => _445.close, 'call', _446 => _446(), 'access', _447 => _447.catch, 'call', _448 => _448(() => {
|
|
4373
4721
|
})]);
|
|
4374
4722
|
}
|
|
4375
4723
|
/**
|
|
@@ -4517,7 +4865,7 @@ var RealtimeContext = class {
|
|
|
4517
4865
|
__publicField(this, "referencePath");
|
|
4518
4866
|
this.referenceVideo = init.referenceVideo && Object.freeze({ ...init.referenceVideo });
|
|
4519
4867
|
this.prompt = init.prompt.trim();
|
|
4520
|
-
const normalizedReferencePath = _optionalChain([init, 'access',
|
|
4868
|
+
const normalizedReferencePath = _optionalChain([init, 'access', _449 => _449.referencePath, 'optionalAccess', _450 => _450.trim, 'call', _451 => _451()]);
|
|
4521
4869
|
this.referencePath = normalizedReferencePath || void 0;
|
|
4522
4870
|
}
|
|
4523
4871
|
};
|
|
@@ -4785,7 +5133,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
4785
5133
|
return;
|
|
4786
5134
|
}
|
|
4787
5135
|
_RealtimeSessionService.ensureSessionActive(session);
|
|
4788
|
-
await _optionalChain([handlers, 'access',
|
|
5136
|
+
await _optionalChain([handlers, 'access', _452 => _452.onRefresh, 'optionalCall', _453 => _453(session)]);
|
|
4789
5137
|
} catch (error) {
|
|
4790
5138
|
if (this.heartbeatVersion !== version) {
|
|
4791
5139
|
return;
|
|
@@ -4998,7 +5346,7 @@ var RealtimeState = class {
|
|
|
4998
5346
|
* @param other 待比较的状态。
|
|
4999
5347
|
*/
|
|
5000
5348
|
equals(other) {
|
|
5001
|
-
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access',
|
|
5349
|
+
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access', _454 => _454.reason, 'optionalAccess', _455 => _455.kind]) === _optionalChain([other, 'access', _456 => _456.reason, 'optionalAccess', _457 => _457.kind]);
|
|
5002
5350
|
}
|
|
5003
5351
|
};
|
|
5004
5352
|
|
|
@@ -5043,12 +5391,13 @@ var RoomEvent = class _RoomEvent {
|
|
|
5043
5391
|
event: "start",
|
|
5044
5392
|
params: {
|
|
5045
5393
|
..._RoomEvent.generationParameters(options),
|
|
5394
|
+
mirror: _nullishCoalesce(options.mirror, () => ( false)),
|
|
5046
5395
|
...options.context.referenceVideo && {
|
|
5047
5396
|
ref_video_path: options.context.referenceVideo.path,
|
|
5048
5397
|
sample_method: options.context.referenceVideo.sampleMethod,
|
|
5049
5398
|
target_size: [
|
|
5050
|
-
_nullishCoalesce(_optionalChain([options, 'access',
|
|
5051
|
-
_nullishCoalesce(_optionalChain([options, 'access',
|
|
5399
|
+
_nullishCoalesce(_optionalChain([options, 'access', _458 => _458.targetSize, 'optionalAccess', _459 => _459.width]), () => ( options.videoFormat.width)),
|
|
5400
|
+
_nullishCoalesce(_optionalChain([options, 'access', _460 => _460.targetSize, 'optionalAccess', _461 => _461.height]), () => ( options.videoFormat.height))
|
|
5052
5401
|
]
|
|
5053
5402
|
}
|
|
5054
5403
|
},
|
|
@@ -5495,6 +5844,7 @@ var RoomController = class {
|
|
|
5495
5844
|
startGeneration(options) {
|
|
5496
5845
|
return this.send(
|
|
5497
5846
|
RoomEvent.start({
|
|
5847
|
+
mirror: _nullishCoalesce(options.mirror, () => ( false)),
|
|
5498
5848
|
userID: this.requireUserID(),
|
|
5499
5849
|
taskID: options.taskID,
|
|
5500
5850
|
videoFormat: options.videoFormat,
|
|
@@ -5592,7 +5942,7 @@ var RoomController = class {
|
|
|
5592
5942
|
if (targetUserID && ownUserID && targetUserID !== ownUserID) {
|
|
5593
5943
|
return;
|
|
5594
5944
|
}
|
|
5595
|
-
_optionalChain([this, 'access',
|
|
5945
|
+
_optionalChain([this, 'access', _462 => _462.listener, 'optionalAccess', _463 => _463.onRoomMessage, 'call', _464 => _464(senderUserID, message)]);
|
|
5596
5946
|
}
|
|
5597
5947
|
/**
|
|
5598
5948
|
* 发送房间信令并输出日志。
|
|
@@ -5646,6 +5996,7 @@ var _EncodingController = class _EncodingController {
|
|
|
5646
5996
|
* 基础层组件
|
|
5647
5997
|
*/
|
|
5648
5998
|
__publicField(this, "rtcManager");
|
|
5999
|
+
__publicField(this, "lastAppliedConfiguration");
|
|
5649
6000
|
this.rtcManager = options.rtcManager;
|
|
5650
6001
|
}
|
|
5651
6002
|
/**
|
|
@@ -5681,14 +6032,38 @@ var _EncodingController = class _EncodingController {
|
|
|
5681
6032
|
"Minimum bitrate must not exceed maximum bitrate after applying SDK defaults"
|
|
5682
6033
|
);
|
|
5683
6034
|
}
|
|
5684
|
-
|
|
6035
|
+
const configuration = {
|
|
5685
6036
|
width: videoFormat.width,
|
|
5686
6037
|
height: videoFormat.height,
|
|
5687
6038
|
frameRate: videoFormat.fps,
|
|
5688
6039
|
minimumBitrate: minimum,
|
|
5689
6040
|
maximumBitrate: maximum,
|
|
5690
6041
|
encoderPreference: ENCODER_PREFERENCE_MAP[videoFormat.encoderPreference]
|
|
6042
|
+
};
|
|
6043
|
+
await this.rtcManager.configureVideoEncoding(configuration);
|
|
6044
|
+
this.lastAppliedConfiguration = { ...configuration };
|
|
6045
|
+
}
|
|
6046
|
+
/** 只替换目标帧率,保留最近成功应用的尺寸、已解析码率区间和偏好。 */
|
|
6047
|
+
async updateFrameRate(fps) {
|
|
6048
|
+
const previous = this.lastAppliedConfiguration;
|
|
6049
|
+
if (!previous) {
|
|
6050
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Apply an encoder configuration before updating frame rate");
|
|
6051
|
+
}
|
|
6052
|
+
const format = new RealtimeVideoFormat({
|
|
6053
|
+
width: previous.width,
|
|
6054
|
+
height: previous.height,
|
|
6055
|
+
fps,
|
|
6056
|
+
minimumBitrate: previous.minimumBitrate,
|
|
6057
|
+
maximumBitrate: previous.maximumBitrate,
|
|
6058
|
+
encoderPreference: previous.encoderPreference === "maintainFramerate" /* maintainFramerate */ ? "maintainFramerate" /* maintainFramerate */ : "maintainQuality" /* maintainQuality */
|
|
5691
6059
|
});
|
|
6060
|
+
format.validate();
|
|
6061
|
+
if (fps !== previous.frameRate) {
|
|
6062
|
+
const next = { ...previous, frameRate: fps };
|
|
6063
|
+
await this.rtcManager.configureVideoEncoding(next);
|
|
6064
|
+
this.lastAppliedConfiguration = next;
|
|
6065
|
+
}
|
|
6066
|
+
return format;
|
|
5692
6067
|
}
|
|
5693
6068
|
/**
|
|
5694
6069
|
* 按像素面积与帧率计算码率区间(kbps):流畅优先为最低,画质优先为最高。
|
|
@@ -5849,7 +6224,7 @@ var StreamController = class {
|
|
|
5849
6224
|
this.roomController.setListener({
|
|
5850
6225
|
onRoomMessage: (sender, message) => {
|
|
5851
6226
|
this.handleNetworkVideoCompletion(sender, message);
|
|
5852
|
-
_optionalChain([this, 'access',
|
|
6227
|
+
_optionalChain([this, 'access', _465 => _465.roomListener, 'optionalAccess', _466 => _466.onRoomMessage, 'call', _467 => _467(sender, message)]);
|
|
5853
6228
|
}
|
|
5854
6229
|
});
|
|
5855
6230
|
this.rtcManager.setEventListener({
|
|
@@ -5859,18 +6234,18 @@ var StreamController = class {
|
|
|
5859
6234
|
onError: (error) => this.errorListener(error),
|
|
5860
6235
|
onNetworkStatistics: (statistics) => {
|
|
5861
6236
|
if (this.state.roomID) {
|
|
5862
|
-
_optionalChain([this, 'access',
|
|
6237
|
+
_optionalChain([this, 'access', _468 => _468.networkStatisticsListener, 'optionalCall', _469 => _469(statistics)]);
|
|
5863
6238
|
}
|
|
5864
6239
|
},
|
|
5865
6240
|
onRemoteVideoStatistics: (statistics) => {
|
|
5866
|
-
const userID = _optionalChain([this, 'access',
|
|
5867
|
-
_optionalChain([this, 'access',
|
|
6241
|
+
const userID = _optionalChain([this, 'access', _470 => _470.state, 'access', _471 => _471.activeRemoteStream, 'optionalAccess', _472 => _472.userID]);
|
|
6242
|
+
_optionalChain([this, 'access', _473 => _473.remoteVideoStatisticsListener, 'optionalCall', _474 => _474(
|
|
5868
6243
|
userID ? statistics.find((item) => item.userID === userID) : void 0
|
|
5869
6244
|
)]);
|
|
5870
6245
|
},
|
|
5871
6246
|
onLocalVideoStatistics: (statistics) => {
|
|
5872
6247
|
if (this.state.localVideoPublished) {
|
|
5873
|
-
_optionalChain([this, 'access',
|
|
6248
|
+
_optionalChain([this, 'access', _475 => _475.localVideoStatisticsListener, 'optionalCall', _476 => _476(statistics)]);
|
|
5874
6249
|
}
|
|
5875
6250
|
},
|
|
5876
6251
|
onCustomMessageReceived: (senderUserID, message) => {
|
|
@@ -5926,9 +6301,13 @@ var StreamController = class {
|
|
|
5926
6301
|
*
|
|
5927
6302
|
* @throws 格式无效、码率区间无效或 RTC 配置失败时抛出错误。
|
|
5928
6303
|
*/
|
|
5929
|
-
async
|
|
6304
|
+
async updateUplinkVideoFormat(videoFormat) {
|
|
5930
6305
|
await this.encodingController.configure(videoFormat);
|
|
5931
6306
|
}
|
|
6307
|
+
/** 不根据新帧率重新推算码率区间。 */
|
|
6308
|
+
async updateUplinkFrameRate(fps) {
|
|
6309
|
+
return this.encodingController.updateFrameRate(fps);
|
|
6310
|
+
}
|
|
5932
6311
|
/**
|
|
5933
6312
|
* 加入 RTC 房间并发布本地媒体流。
|
|
5934
6313
|
*
|
|
@@ -5943,7 +6322,7 @@ var StreamController = class {
|
|
|
5943
6322
|
\u2514\u2500 roomID: ${connection.roomID}, botID: ${_nullishCoalesce(connection.botID, () => ( "(\u672A\u8BBE\u7F6E)"))}`
|
|
5944
6323
|
);
|
|
5945
6324
|
if (publishLocalMedia) {
|
|
5946
|
-
await _optionalChain([beforePublish, 'optionalCall',
|
|
6325
|
+
await _optionalChain([beforePublish, 'optionalCall', _477 => _477()]);
|
|
5947
6326
|
ensureActive2();
|
|
5948
6327
|
await this.publishLocalStream(includeLocalAudio);
|
|
5949
6328
|
}
|
|
@@ -6014,6 +6393,7 @@ var StreamController = class {
|
|
|
6014
6393
|
try {
|
|
6015
6394
|
const sending = this.roomController.startGeneration({
|
|
6016
6395
|
taskID,
|
|
6396
|
+
mirror: _nullishCoalesce(options.mirror, () => ( false)),
|
|
6017
6397
|
videoFormat: options.videoFormat,
|
|
6018
6398
|
targetSize: options.targetSize,
|
|
6019
6399
|
context: options.context
|
|
@@ -6021,7 +6401,7 @@ var StreamController = class {
|
|
|
6021
6401
|
const state2 = this.state;
|
|
6022
6402
|
const sent = Promise.resolve(sending).then(async () => {
|
|
6023
6403
|
if (this.state !== state2 || state2.generationTaskID !== taskID) return;
|
|
6024
|
-
await _optionalChain([options, 'access',
|
|
6404
|
+
await _optionalChain([options, 'access', _478 => _478.onStartSent, 'optionalCall', _479 => _479()]);
|
|
6025
6405
|
if (this.state !== state2 || state2.generationTaskID !== taskID) return;
|
|
6026
6406
|
for (const userID of state2.publishedRemoteUserIDs) {
|
|
6027
6407
|
void this.handleRemoteVideoPublished(userID, true);
|
|
@@ -6087,7 +6467,7 @@ var StreamController = class {
|
|
|
6087
6467
|
*
|
|
6088
6468
|
* @throws 操作已取消、房间未就绪或信令发送失败时抛出错误。
|
|
6089
6469
|
*/
|
|
6090
|
-
async
|
|
6470
|
+
async updateDownlinkVideoResolution(taskID, targetSize, ensureActive2) {
|
|
6091
6471
|
try {
|
|
6092
6472
|
await this.roomController.changeTargetSize({ taskID, targetSize, ensureActive: ensureActive2 });
|
|
6093
6473
|
} catch (error) {
|
|
@@ -6156,7 +6536,7 @@ var StreamController = class {
|
|
|
6156
6536
|
deliverNetworkVideoCompletion() {
|
|
6157
6537
|
const state2 = this.state;
|
|
6158
6538
|
const completion = state2.networkVideoCompletion;
|
|
6159
|
-
if (!_optionalChain([completion, 'optionalAccess',
|
|
6539
|
+
if (!_optionalChain([completion, 'optionalAccess', _480 => _480.finished]) || !completion.onFinish || completion.scheduled) {
|
|
6160
6540
|
return;
|
|
6161
6541
|
}
|
|
6162
6542
|
completion.scheduled = true;
|
|
@@ -6165,7 +6545,7 @@ var StreamController = class {
|
|
|
6165
6545
|
return;
|
|
6166
6546
|
}
|
|
6167
6547
|
try {
|
|
6168
|
-
void Promise.resolve(_optionalChain([completion, 'access',
|
|
6548
|
+
void Promise.resolve(_optionalChain([completion, 'access', _481 => _481.onFinish, 'optionalCall', _482 => _482()])).catch(() => {
|
|
6169
6549
|
});
|
|
6170
6550
|
} catch (e23) {
|
|
6171
6551
|
}
|
|
@@ -6176,7 +6556,7 @@ var StreamController = class {
|
|
|
6176
6556
|
*/
|
|
6177
6557
|
configureRoom(options) {
|
|
6178
6558
|
const roomID = options.roomID.trim();
|
|
6179
|
-
const botID = _nullishCoalesce(_optionalChain([options, 'access',
|
|
6559
|
+
const botID = _nullishCoalesce(_optionalChain([options, 'access', _483 => _483.botID, 'optionalAccess', _484 => _484.trim, 'call', _485 => _485()]), () => ( ""));
|
|
6180
6560
|
if (!roomID) {
|
|
6181
6561
|
throw new XmaxError(
|
|
6182
6562
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
@@ -6259,7 +6639,7 @@ var StreamController = class {
|
|
|
6259
6639
|
return;
|
|
6260
6640
|
}
|
|
6261
6641
|
this.state.subscribedRemoteUserIDs.delete(trimmedUserID);
|
|
6262
|
-
if (_optionalChain([this, 'access',
|
|
6642
|
+
if (_optionalChain([this, 'access', _486 => _486.state, 'access', _487 => _487.activeRemoteStream, 'optionalAccess', _488 => _488.userID]) === trimmedUserID) {
|
|
6263
6643
|
await this.unsubscribeRemoteAudio(trimmedUserID);
|
|
6264
6644
|
this.state.activeRemoteStream = void 0;
|
|
6265
6645
|
this.clearRemoteStream();
|
|
@@ -6449,7 +6829,7 @@ var StreamController = class {
|
|
|
6449
6829
|
*/
|
|
6450
6830
|
resolveGenerationStart(taskID) {
|
|
6451
6831
|
const waiter = this.state.generationWaiter;
|
|
6452
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
6832
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _489 => _489.taskID]) !== taskID) {
|
|
6453
6833
|
return;
|
|
6454
6834
|
}
|
|
6455
6835
|
this.state.generationWaiter = void 0;
|
|
@@ -6461,7 +6841,7 @@ var StreamController = class {
|
|
|
6461
6841
|
*/
|
|
6462
6842
|
rejectGenerationStart(taskID, error) {
|
|
6463
6843
|
const waiter = this.state.generationWaiter;
|
|
6464
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
6844
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _490 => _490.taskID]) !== taskID) {
|
|
6465
6845
|
return;
|
|
6466
6846
|
}
|
|
6467
6847
|
this.state.generationWaiter = void 0;
|
|
@@ -6472,7 +6852,7 @@ var StreamController = class {
|
|
|
6472
6852
|
* 通知渲染层清理远端生成流;失败仅记录日志。
|
|
6473
6853
|
*/
|
|
6474
6854
|
clearRemoteStream() {
|
|
6475
|
-
_optionalChain([this, 'access',
|
|
6855
|
+
_optionalChain([this, 'access', _491 => _491.remoteVideoStatisticsListener, 'optionalCall', _492 => _492(void 0)]);
|
|
6476
6856
|
try {
|
|
6477
6857
|
this.remoteStreamListener(null);
|
|
6478
6858
|
} catch (error) {
|
|
@@ -6509,6 +6889,195 @@ var StreamController = class {
|
|
|
6509
6889
|
}
|
|
6510
6890
|
};
|
|
6511
6891
|
|
|
6892
|
+
// src/Stream/Quality/QualityTiers.ts
|
|
6893
|
+
var INITIAL_QUALITY_LEVEL = 2;
|
|
6894
|
+
var QUALITY_TIERS = {
|
|
6895
|
+
L1: { width: 1024, height: 1920, frameRate: 30 },
|
|
6896
|
+
L2: { width: 768, height: 1440, frameRate: 24 },
|
|
6897
|
+
L3: { width: 640, height: 1200, frameRate: 24 },
|
|
6898
|
+
L4: { width: 512, height: 960, frameRate: 20 },
|
|
6899
|
+
L5: { width: 384, height: 720, frameRate: 16 }
|
|
6900
|
+
};
|
|
6901
|
+
|
|
6902
|
+
// src/Stream/Quality/QualityPolicy.ts
|
|
6903
|
+
var DEFAULT_POLICY = {
|
|
6904
|
+
poorSamples: 3,
|
|
6905
|
+
goodSamples: 5,
|
|
6906
|
+
stabilizationMs: 4e3,
|
|
6907
|
+
probeMs: 2e4,
|
|
6908
|
+
upgradeCooldownMs: 6e4,
|
|
6909
|
+
sampleTimeoutMs: 5e3
|
|
6910
|
+
};
|
|
6911
|
+
|
|
6912
|
+
// src/Stream/Quality/QualityController.ts
|
|
6913
|
+
var ORDERED_QUALITY_TIERS = Object.values(QUALITY_TIERS);
|
|
6914
|
+
var QualityController = class {
|
|
6915
|
+
constructor(apply, now = () => performance.now(), policy = {}) {
|
|
6916
|
+
__publicField(this, "apply", apply);
|
|
6917
|
+
__publicField(this, "now", now);
|
|
6918
|
+
__publicField(this, "policy");
|
|
6919
|
+
__publicField(this, "active", false);
|
|
6920
|
+
__publicField(this, "index", 0);
|
|
6921
|
+
__publicField(this, "good", 0);
|
|
6922
|
+
__publicField(this, "poor", 0);
|
|
6923
|
+
__publicField(this, "lastSampleAt");
|
|
6924
|
+
__publicField(this, "stableUntil", 0);
|
|
6925
|
+
__publicField(this, "upgradeAfter", 0);
|
|
6926
|
+
__publicField(this, "probeUntil", 0);
|
|
6927
|
+
__publicField(this, "switching", false);
|
|
6928
|
+
__publicField(this, "lifecycle", new AbortController());
|
|
6929
|
+
this.policy = { ...DEFAULT_POLICY, ...policy };
|
|
6930
|
+
for (const value of Object.values(this.policy)) {
|
|
6931
|
+
if (!Number.isFinite(value) || value < 0) throw new Error("Invalid quality policy");
|
|
6932
|
+
}
|
|
6933
|
+
for (const value of [this.policy.poorSamples, this.policy.goodSamples]) {
|
|
6934
|
+
if (!Number.isInteger(value) || value < 1) throw new Error("Sample counts must be positive integers");
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
get snapshot() {
|
|
6938
|
+
return Object.freeze({
|
|
6939
|
+
active: this.active,
|
|
6940
|
+
level: this.index + 1,
|
|
6941
|
+
...ORDERED_QUALITY_TIERS[this.index],
|
|
6942
|
+
switching: this.switching,
|
|
6943
|
+
upgradeAfter: this.upgradeAfter
|
|
6944
|
+
});
|
|
6945
|
+
}
|
|
6946
|
+
/** 传入调用方保存的档位,不在 start 中擅自改写编码配置。 */
|
|
6947
|
+
start(level = 1) {
|
|
6948
|
+
if (!Number.isInteger(level) || level < 1 || level > ORDERED_QUALITY_TIERS.length) {
|
|
6949
|
+
throw new Error("Unsupported quality level");
|
|
6950
|
+
}
|
|
6951
|
+
this.stop();
|
|
6952
|
+
this.lifecycle = new AbortController();
|
|
6953
|
+
this.index = level - 1;
|
|
6954
|
+
this.active = true;
|
|
6955
|
+
this.stableUntil = this.upgradeAfter = this.probeUntil = 0;
|
|
6956
|
+
}
|
|
6957
|
+
/** 取消旧会话的迟到结果;底层尚未完成时仍保持串行限制。 */
|
|
6958
|
+
stop() {
|
|
6959
|
+
this.active = false;
|
|
6960
|
+
this.lifecycle.abort();
|
|
6961
|
+
this.resetSamples();
|
|
6962
|
+
}
|
|
6963
|
+
/** 前台操作期间丢弃累计样本,但保留试升失败后的冷却时间。 */
|
|
6964
|
+
resetSamples() {
|
|
6965
|
+
this.resetCounts();
|
|
6966
|
+
this.lastSampleAt = void 0;
|
|
6967
|
+
}
|
|
6968
|
+
/** 只接收质量事件,不得用定时器重复提交同一份缓存统计。异常由调用方记录。 */
|
|
6969
|
+
async observe(quality, sampleAt = this.now()) {
|
|
6970
|
+
if (!this.active || this.switching || !Number.isFinite(sampleAt)) return;
|
|
6971
|
+
const now = this.now();
|
|
6972
|
+
if (sampleAt > now) return;
|
|
6973
|
+
if (this.lastSampleAt !== void 0) {
|
|
6974
|
+
if (sampleAt <= this.lastSampleAt) return;
|
|
6975
|
+
if (sampleAt - this.lastSampleAt > this.policy.sampleTimeoutMs) this.resetCounts();
|
|
6976
|
+
}
|
|
6977
|
+
this.lastSampleAt = sampleAt;
|
|
6978
|
+
if (now - sampleAt > this.policy.sampleTimeoutMs || sampleAt < this.stableUntil) {
|
|
6979
|
+
this.resetCounts();
|
|
6980
|
+
return;
|
|
6981
|
+
}
|
|
6982
|
+
if (quality === 4 || quality === 5) {
|
|
6983
|
+
this.good = 0;
|
|
6984
|
+
this.poor++;
|
|
6985
|
+
if (this.poor >= this.policy.poorSamples && this.index < ORDERED_QUALITY_TIERS.length - 1) {
|
|
6986
|
+
return this.change(this.index + 1, now < this.probeUntil ? "failedProbe" : "poorNetwork");
|
|
6987
|
+
}
|
|
6988
|
+
} else if (quality === 1 || quality === 2) {
|
|
6989
|
+
this.poor = 0;
|
|
6990
|
+
if (sampleAt < this.upgradeAfter) {
|
|
6991
|
+
this.good = 0;
|
|
6992
|
+
return;
|
|
6993
|
+
}
|
|
6994
|
+
this.good++;
|
|
6995
|
+
if (this.good >= this.policy.goodSamples && this.index > 0) {
|
|
6996
|
+
return this.change(this.index - 1, "probeUpgrade");
|
|
6997
|
+
}
|
|
6998
|
+
} else {
|
|
6999
|
+
this.resetCounts();
|
|
7000
|
+
}
|
|
7001
|
+
return;
|
|
7002
|
+
}
|
|
7003
|
+
resetCounts() {
|
|
7004
|
+
this.good = this.poor = 0;
|
|
7005
|
+
}
|
|
7006
|
+
async change(index, reason) {
|
|
7007
|
+
const lifecycle = this.lifecycle;
|
|
7008
|
+
const change = { from: this.index + 1, to: index + 1, ...ORDERED_QUALITY_TIERS[index], reason };
|
|
7009
|
+
this.switching = true;
|
|
7010
|
+
this.resetCounts();
|
|
7011
|
+
try {
|
|
7012
|
+
await this.apply(change, lifecycle.signal);
|
|
7013
|
+
if (lifecycle.signal.aborted) return;
|
|
7014
|
+
this.index = index;
|
|
7015
|
+
const now = this.now();
|
|
7016
|
+
this.stableUntil = now + this.policy.stabilizationMs;
|
|
7017
|
+
this.probeUntil = reason === "probeUpgrade" ? now + this.policy.probeMs : 0;
|
|
7018
|
+
if (reason === "failedProbe") this.upgradeAfter = now + this.policy.upgradeCooldownMs;
|
|
7019
|
+
return change;
|
|
7020
|
+
} catch (error) {
|
|
7021
|
+
if (!lifecycle.signal.aborted) {
|
|
7022
|
+
this.stableUntil = this.now() + this.policy.stabilizationMs;
|
|
7023
|
+
throw error;
|
|
7024
|
+
}
|
|
7025
|
+
return;
|
|
7026
|
+
} finally {
|
|
7027
|
+
this.switching = false;
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
};
|
|
7031
|
+
|
|
7032
|
+
// src/Stream/Quality/QualityVideoFormat.ts
|
|
7033
|
+
function qualityVideoSize(baseline, level) {
|
|
7034
|
+
const tier = Object.values(QUALITY_TIERS)[level - 1];
|
|
7035
|
+
if (!Number.isInteger(level) || !tier) throw new Error("Unsupported quality level");
|
|
7036
|
+
baseline.validate();
|
|
7037
|
+
const scale = tier.width / QUALITY_TIERS.L1.width;
|
|
7038
|
+
const even = (value) => Math.max(2, Math.floor(value / 2) * 2);
|
|
7039
|
+
return { width: even(baseline.width * scale), height: even(baseline.height * scale) };
|
|
7040
|
+
}
|
|
7041
|
+
function qualityVideoFormat(baseline, level) {
|
|
7042
|
+
const size = qualityVideoSize(baseline, level);
|
|
7043
|
+
const tier = Object.values(QUALITY_TIERS)[level - 1];
|
|
7044
|
+
return new RealtimeVideoFormat({
|
|
7045
|
+
...baseline,
|
|
7046
|
+
...size,
|
|
7047
|
+
fps: Math.min(baseline.fps, tier.frameRate)
|
|
7048
|
+
});
|
|
7049
|
+
}
|
|
7050
|
+
|
|
7051
|
+
// src/Stream/Quality/QualityHistory.ts
|
|
7052
|
+
var QualityHistory = class {
|
|
7053
|
+
constructor(model) {
|
|
7054
|
+
__publicField(this, "model", model);
|
|
7055
|
+
}
|
|
7056
|
+
/** 无记录、损坏、SSR 或浏览器禁止存储时使用默认 L2。 */
|
|
7057
|
+
read(direction) {
|
|
7058
|
+
try {
|
|
7059
|
+
const level = Number(globalThis.localStorage.getItem(this.key(direction)));
|
|
7060
|
+
if (this.isValid(level)) return level;
|
|
7061
|
+
} catch (e24) {
|
|
7062
|
+
}
|
|
7063
|
+
return INITIAL_QUALITY_LEVEL;
|
|
7064
|
+
}
|
|
7065
|
+
/** 仅在应用成功后调用;下行成功表示信令已发送,不代表服务端已确认生效。 */
|
|
7066
|
+
write(direction, level) {
|
|
7067
|
+
if (!this.isValid(level)) return;
|
|
7068
|
+
try {
|
|
7069
|
+
globalThis.localStorage.setItem(this.key(direction), String(level));
|
|
7070
|
+
} catch (e25) {
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
7073
|
+
key(direction) {
|
|
7074
|
+
return `xmax:quality:v1:agora:${encodeURIComponent(this.model)}:${direction}`;
|
|
7075
|
+
}
|
|
7076
|
+
isValid(level) {
|
|
7077
|
+
return Number.isInteger(level) && level >= 1 && level <= Object.keys(QUALITY_TIERS).length;
|
|
7078
|
+
}
|
|
7079
|
+
};
|
|
7080
|
+
|
|
6512
7081
|
// src/Core/Realtime/RealtimeCoordinator.ts
|
|
6513
7082
|
function scopeAffects(scope, kind) {
|
|
6514
7083
|
if (scope === 1 /* all */) {
|
|
@@ -6611,6 +7180,10 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
6611
7180
|
get currentState() {
|
|
6612
7181
|
return this.state;
|
|
6613
7182
|
}
|
|
7183
|
+
/** 后台自动调档仅在没有前台操作或清理时申请操作租约。 */
|
|
7184
|
+
get isBusy() {
|
|
7185
|
+
return this.activeOperation !== void 0 || this.termination !== void 0;
|
|
7186
|
+
}
|
|
6614
7187
|
/**
|
|
6615
7188
|
* 设置实时状态监听器;设置后立即回放当前状态。
|
|
6616
7189
|
*
|
|
@@ -6743,7 +7316,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
6743
7316
|
}
|
|
6744
7317
|
throw _RealtimeCoordinator.cancelledError();
|
|
6745
7318
|
}
|
|
6746
|
-
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access',
|
|
7319
|
+
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access', _493 => _493.termination, 'optionalAccess', _494 => _494.task]))), async () => ( await this.requestTermination(
|
|
6747
7320
|
_nullishCoalesce(operation.lease.failureScope, () => ( 0)) /* connection */,
|
|
6748
7321
|
void 0,
|
|
6749
7322
|
RealtimeReason.normal,
|
|
@@ -6872,7 +7445,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
6872
7445
|
* 结束指定操作,释放操作准入场。
|
|
6873
7446
|
*/
|
|
6874
7447
|
finish(operation) {
|
|
6875
|
-
if (_optionalChain([this, 'access',
|
|
7448
|
+
if (_optionalChain([this, 'access', _495 => _495.activeOperation, 'optionalAccess', _496 => _496.id]) === operation.id) {
|
|
6876
7449
|
this.activeOperation = void 0;
|
|
6877
7450
|
}
|
|
6878
7451
|
}
|
|
@@ -6884,7 +7457,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
6884
7457
|
return;
|
|
6885
7458
|
}
|
|
6886
7459
|
this.state = nextState;
|
|
6887
|
-
_optionalChain([this, 'access',
|
|
7460
|
+
_optionalChain([this, 'access', _497 => _497.stateListener, 'optionalCall', _498 => _498(nextState)]);
|
|
6888
7461
|
}
|
|
6889
7462
|
/**
|
|
6890
7463
|
* 构造统一的操作取消错误。
|
|
@@ -7021,9 +7594,9 @@ var RealtimeLaunchTimer = class {
|
|
|
7021
7594
|
*/
|
|
7022
7595
|
notify() {
|
|
7023
7596
|
try {
|
|
7024
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
7597
|
+
void Promise.resolve(_optionalChain([this, 'access', _499 => _499.listener, 'optionalCall', _500 => _500(this.snapshot)])).catch(() => {
|
|
7025
7598
|
});
|
|
7026
|
-
} catch (
|
|
7599
|
+
} catch (e26) {
|
|
7027
7600
|
}
|
|
7028
7601
|
}
|
|
7029
7602
|
};
|
|
@@ -7053,7 +7626,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7053
7626
|
* 当前活动会话标识;尚未连接或清理完成后为空。
|
|
7054
7627
|
*/
|
|
7055
7628
|
get currentSessionID() {
|
|
7056
|
-
return _optionalChain([this, 'access',
|
|
7629
|
+
return _optionalChain([this, 'access', _501 => _501.activeSession, 'optionalAccess', _502 => _502.id]);
|
|
7057
7630
|
}
|
|
7058
7631
|
/**
|
|
7059
7632
|
* 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
|
|
@@ -7087,7 +7660,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7087
7660
|
}
|
|
7088
7661
|
const refreshVersion = ++this.refreshVersion;
|
|
7089
7662
|
this.credentialController = new AbortController();
|
|
7090
|
-
const videoFormat = options.localTrack.videoFormat;
|
|
7663
|
+
const videoFormat = _nullishCoalesce(options.localVideoFormat, () => ( options.localTrack.videoFormat));
|
|
7091
7664
|
if (!videoFormat) {
|
|
7092
7665
|
throw new XmaxError(
|
|
7093
7666
|
"INTERNAL_ERROR" /* internalError */,
|
|
@@ -7096,7 +7669,9 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7096
7669
|
}
|
|
7097
7670
|
const publishLocalMedia = _nullishCoalesce(options.publishLocalMedia, () => ( true));
|
|
7098
7671
|
if (publishLocalMedia) {
|
|
7099
|
-
await streamController.
|
|
7672
|
+
await streamController.updateUplinkVideoFormat(videoFormat);
|
|
7673
|
+
options.ensureCurrent();
|
|
7674
|
+
_optionalChain([options, 'access', _503 => _503.onVideoEncoderConfigured, 'optionalCall', _504 => _504()]);
|
|
7100
7675
|
}
|
|
7101
7676
|
options.ensureCurrent();
|
|
7102
7677
|
let completePublish;
|
|
@@ -7104,13 +7679,13 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7104
7679
|
options.ensureCurrent();
|
|
7105
7680
|
}, async () => {
|
|
7106
7681
|
options.ensureCurrent();
|
|
7107
|
-
await _optionalChain([options, 'access',
|
|
7682
|
+
await _optionalChain([options, 'access', _505 => _505.beforePublish, 'optionalCall', _506 => _506()]);
|
|
7108
7683
|
completeConnection();
|
|
7109
7684
|
completePublish = this.dependencies.timing.startPublish();
|
|
7110
7685
|
}, publishLocalMedia);
|
|
7111
7686
|
options.ensureCurrent();
|
|
7112
7687
|
completeConnection();
|
|
7113
|
-
_optionalChain([completePublish, 'optionalCall',
|
|
7688
|
+
_optionalChain([completePublish, 'optionalCall', _507 => _507()]);
|
|
7114
7689
|
options.onPublished();
|
|
7115
7690
|
sessionService.startHeartbeat(session.id, {
|
|
7116
7691
|
onFailure: (sessionID, error) => {
|
|
@@ -7133,24 +7708,24 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7133
7708
|
* 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
|
|
7134
7709
|
*/
|
|
7135
7710
|
setFrameInterpolation(options) {
|
|
7136
|
-
_optionalChain([this, 'access',
|
|
7711
|
+
_optionalChain([this, 'access', _508 => _508.remoteTarget, 'optionalAccess', _509 => _509.setFrameInterpolation, 'optionalCall', _510 => _510(options)]);
|
|
7137
7712
|
}
|
|
7138
7713
|
/**
|
|
7139
7714
|
* 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
|
|
7140
7715
|
*/
|
|
7141
7716
|
clearRemoteMedia() {
|
|
7142
|
-
_optionalChain([this, 'access',
|
|
7717
|
+
_optionalChain([this, 'access', _511 => _511.remoteTarget, 'optionalAccess', _512 => _512.setMediaStream, 'call', _513 => _513(null)]);
|
|
7143
7718
|
}
|
|
7144
7719
|
/**
|
|
7145
7720
|
* 停止会话心跳;未配置会话服务时不执行操作。
|
|
7146
7721
|
*/
|
|
7147
7722
|
stopHeartbeat() {
|
|
7148
7723
|
this.refreshVersion++;
|
|
7149
|
-
_optionalChain([this, 'access',
|
|
7724
|
+
_optionalChain([this, 'access', _514 => _514.credentialController, 'optionalAccess', _515 => _515.abort, 'call', _516 => _516()]);
|
|
7150
7725
|
this.credentialController = void 0;
|
|
7151
7726
|
this.credentialRefresh = void 0;
|
|
7152
7727
|
this.credentialApplication = Promise.resolve();
|
|
7153
|
-
_optionalChain([this, 'access',
|
|
7728
|
+
_optionalChain([this, 'access', _517 => _517.dependencies, 'access', _518 => _518.sessionService, 'optionalAccess', _519 => _519.stopHeartbeat, 'call', _520 => _520()]);
|
|
7154
7729
|
}
|
|
7155
7730
|
/**
|
|
7156
7731
|
* RTC Token 过期时复用会话心跳获取新凭据,并合并同一实例的并发请求。
|
|
@@ -7158,14 +7733,14 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7158
7733
|
async refreshCredentials() {
|
|
7159
7734
|
if (this.credentialRefresh) return this.credentialRefresh;
|
|
7160
7735
|
const current = this.activeSession;
|
|
7161
|
-
if (!_optionalChain([current, 'optionalAccess',
|
|
7736
|
+
if (!_optionalChain([current, 'optionalAccess', _521 => _521.connection]) || current.connection.provider === "trtc" /* trtc */) return;
|
|
7162
7737
|
const version = this.refreshVersion;
|
|
7163
7738
|
const operation = (async () => {
|
|
7164
7739
|
try {
|
|
7165
7740
|
const session = await this.requireSessionService().heartbeatSession(current.id);
|
|
7166
7741
|
await this.handleSessionRefresh(session, version, true);
|
|
7167
7742
|
} catch (error) {
|
|
7168
|
-
if (version === this.refreshVersion && _optionalChain([this, 'access',
|
|
7743
|
+
if (version === this.refreshVersion && _optionalChain([this, 'access', _522 => _522.activeSession, 'optionalAccess', _523 => _523.id]) === current.id) {
|
|
7169
7744
|
this.dependencies.onHeartbeatFailure(current.id, XmaxError.from(error));
|
|
7170
7745
|
}
|
|
7171
7746
|
}
|
|
@@ -7182,7 +7757,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7182
7757
|
*/
|
|
7183
7758
|
async waitUntilRemoteTrackReady(timeoutMs, signal) {
|
|
7184
7759
|
if (signal.aborted) throw RealtimeCoordinator.cancelledError();
|
|
7185
|
-
const mediaTrack = _optionalChain([this, 'access',
|
|
7760
|
+
const mediaTrack = _optionalChain([this, 'access', _524 => _524.activeRemoteTrack, 'optionalAccess', _525 => _525.mediaStreamTrack]);
|
|
7186
7761
|
if (!mediaTrack || !mediaTrack.muted) return;
|
|
7187
7762
|
await new Promise((resolve, reject) => {
|
|
7188
7763
|
const cleanup = () => {
|
|
@@ -7219,7 +7794,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7219
7794
|
if (track) {
|
|
7220
7795
|
track.mediaStreamTrack = void 0;
|
|
7221
7796
|
}
|
|
7222
|
-
_optionalChain([this, 'access',
|
|
7797
|
+
_optionalChain([this, 'access', _526 => _526.remoteTarget, 'optionalAccess', _527 => _527.setMediaStream, 'call', _528 => _528(null)]);
|
|
7223
7798
|
return;
|
|
7224
7799
|
}
|
|
7225
7800
|
if (!track) {
|
|
@@ -7229,7 +7804,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7229
7804
|
);
|
|
7230
7805
|
}
|
|
7231
7806
|
track.mediaStreamTrack = binding.videoTrack;
|
|
7232
|
-
_optionalChain([this, 'access',
|
|
7807
|
+
_optionalChain([this, 'access', _529 => _529.remoteTarget, 'optionalAccess', _530 => _530.setMediaStream, 'call', _531 => _531(new MediaStream([binding.videoTrack]))]);
|
|
7233
7808
|
}
|
|
7234
7809
|
/**
|
|
7235
7810
|
* 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
|
|
@@ -7242,8 +7817,8 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7242
7817
|
}
|
|
7243
7818
|
},
|
|
7244
7819
|
attachHandler: (view) => {
|
|
7245
|
-
_optionalChain([this, 'access',
|
|
7246
|
-
view.isMirrored =
|
|
7820
|
+
_optionalChain([this, 'access', _532 => _532.remoteTarget, 'optionalAccess', _533 => _533.setFrameInterpolation, 'optionalCall', _534 => _534(void 0)]);
|
|
7821
|
+
view.isMirrored = false;
|
|
7247
7822
|
this.remoteTarget = view;
|
|
7248
7823
|
this.dependencies.onRenderAttached();
|
|
7249
7824
|
const mediaTrack = track.mediaStreamTrack;
|
|
@@ -7254,19 +7829,11 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7254
7829
|
this.dependencies.onRenderDetached();
|
|
7255
7830
|
this.remoteTarget = void 0;
|
|
7256
7831
|
}
|
|
7257
|
-
_optionalChain([view, 'access',
|
|
7832
|
+
_optionalChain([view, 'access', _535 => _535.setFrameInterpolation, 'optionalCall', _536 => _536(void 0)]);
|
|
7258
7833
|
view.setMediaStream(null);
|
|
7259
7834
|
}
|
|
7260
7835
|
});
|
|
7261
7836
|
}
|
|
7262
|
-
/**
|
|
7263
|
-
* 同步远端结果画面的镜像状态:与当前本地摄像头位置保持一致。
|
|
7264
|
-
*/
|
|
7265
|
-
updateRemoteMirror() {
|
|
7266
|
-
if (this.remoteTarget) {
|
|
7267
|
-
this.remoteTarget.isMirrored = this.dependencies.isMirrored();
|
|
7268
|
-
}
|
|
7269
|
-
}
|
|
7270
7837
|
/**
|
|
7271
7838
|
* 构造当前远端生成结果媒体流。
|
|
7272
7839
|
*/
|
|
@@ -7312,7 +7879,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7312
7879
|
return;
|
|
7313
7880
|
}
|
|
7314
7881
|
if (next.provider !== "trtc" /* trtc */ && (force || !previous || previous.provider === "trtc" /* trtc */ || next.roomToken !== previous.roomToken)) {
|
|
7315
|
-
await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access',
|
|
7882
|
+
await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access', _537 => _537.credentialController, 'optionalAccess', _538 => _538.signal]));
|
|
7316
7883
|
if (version !== this.refreshVersion || this.activeSession !== current) return;
|
|
7317
7884
|
}
|
|
7318
7885
|
this.activeSession = new RealtimeSession({
|
|
@@ -7327,7 +7894,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
7327
7894
|
* 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
|
|
7328
7895
|
*/
|
|
7329
7896
|
async disconnect() {
|
|
7330
|
-
const sessionID = _optionalChain([this, 'access',
|
|
7897
|
+
const sessionID = _optionalChain([this, 'access', _539 => _539.activeSession, 'optionalAccess', _540 => _540.id]);
|
|
7331
7898
|
this.stopHeartbeat();
|
|
7332
7899
|
this.clearRemoteMedia();
|
|
7333
7900
|
try {
|
|
@@ -7410,6 +7977,8 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
7410
7977
|
taskID,
|
|
7411
7978
|
videoFormat: options.videoFormat,
|
|
7412
7979
|
context,
|
|
7980
|
+
...options.targetSize && { targetSize: options.targetSize },
|
|
7981
|
+
mirror: _nullishCoalesce(options.mirror, () => ( false)),
|
|
7413
7982
|
...options.onStartSent && { onStartSent: options.onStartSent }
|
|
7414
7983
|
});
|
|
7415
7984
|
await this.awaitConfirmation(confirmation, options.signal);
|
|
@@ -7436,7 +8005,8 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
7436
8005
|
await this.streamController.updateGeneration({
|
|
7437
8006
|
taskID,
|
|
7438
8007
|
videoFormat: options.videoFormat,
|
|
7439
|
-
context
|
|
8008
|
+
context,
|
|
8009
|
+
...options.targetSize && { targetSize: options.targetSize }
|
|
7440
8010
|
});
|
|
7441
8011
|
if (this.activeTaskID !== taskID) throw RealtimeCoordinator.cancelledError();
|
|
7442
8012
|
this.currentContext = context;
|
|
@@ -7462,7 +8032,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
7462
8032
|
try {
|
|
7463
8033
|
await completion;
|
|
7464
8034
|
} finally {
|
|
7465
|
-
if (_optionalChain([this, 'access',
|
|
8035
|
+
if (_optionalChain([this, 'access', _541 => _541.pendingStop, 'optionalAccess', _542 => _542.completion]) === completion) this.pendingStop = void 0;
|
|
7466
8036
|
}
|
|
7467
8037
|
}
|
|
7468
8038
|
/**
|
|
@@ -7573,6 +8143,14 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7573
8143
|
__publicField(this, "connectionManager");
|
|
7574
8144
|
__publicField(this, "generationManager");
|
|
7575
8145
|
__publicField(this, "streamController");
|
|
8146
|
+
__publicField(this, "qualityController");
|
|
8147
|
+
__publicField(this, "qualityHistory");
|
|
8148
|
+
__publicField(this, "qualityStates", /* @__PURE__ */ new WeakMap());
|
|
8149
|
+
__publicField(this, "downlinkQualityController");
|
|
8150
|
+
/** 无服务端生效 ACK;level/size 表示最后成功发送的目标,而非实际接收规格。 */
|
|
8151
|
+
__publicField(this, "downlinkQualityState");
|
|
8152
|
+
__publicField(this, "adaptiveQualityPending", false);
|
|
8153
|
+
__publicField(this, "adaptiveQualityRevision", 0);
|
|
7576
8154
|
/**
|
|
7577
8155
|
* 音量配置
|
|
7578
8156
|
*/
|
|
@@ -7581,19 +8159,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7581
8159
|
this.options = options;
|
|
7582
8160
|
this.mediaService = new MediaService(options.model);
|
|
7583
8161
|
this.interpolationRequested = options.isFrameInterpolationEnabled;
|
|
7584
|
-
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
8162
|
+
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _543 => _543.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
|
|
7585
8163
|
this.errorHandler = new RealtimeErrorHandler();
|
|
7586
|
-
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
8164
|
+
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _544 => _544.rtcManager]), () => ( createRtcManager(options.provider, _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _545 => _545.environment]), () => ( "china")) /* china */)));
|
|
7587
8165
|
this.rtcManager = rtcManager;
|
|
7588
|
-
this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
8166
|
+
this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _546 => _546.cameraController]), () => ( new CameraController({
|
|
7589
8167
|
rtcManager,
|
|
7590
8168
|
mediaService: this.mediaService,
|
|
7591
8169
|
errorListener: (error) => {
|
|
7592
8170
|
void this.errorHandler.report(error);
|
|
7593
8171
|
}
|
|
7594
8172
|
})));
|
|
7595
|
-
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
7596
|
-
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
8173
|
+
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _547 => _547.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _548 => _548.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService, provider: options.provider }) : void 0)));
|
|
8174
|
+
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _549 => _549.streamController]), () => ( new StreamController({
|
|
7597
8175
|
rtcManager,
|
|
7598
8176
|
onCredentialsRequired: () => {
|
|
7599
8177
|
void this.connectionManager.refreshCredentials();
|
|
@@ -7611,12 +8189,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7611
8189
|
sessionService,
|
|
7612
8190
|
streamController: this.streamController,
|
|
7613
8191
|
timing: this.launchTimer,
|
|
7614
|
-
isMirrored: () => _optionalChain([this, 'access', _487 => _487.cameraController, 'access', _488 => _488.currentTrack, 'optionalAccess', _489 => _489.position]) === "front" /* front */,
|
|
7615
8192
|
remoteAudioVolume: () => this.storedRemoteAudioVolume,
|
|
7616
8193
|
onHeartbeatFailure: (sessionID, error) => {
|
|
7617
8194
|
void this.handleHeartbeatFailure(sessionID, error);
|
|
7618
8195
|
},
|
|
7619
|
-
onFrameDisplayed: () => _optionalChain([this, 'access',
|
|
8196
|
+
onFrameDisplayed: () => _optionalChain([this, 'access', _550 => _550.remoteFrameDisplayHandler, 'optionalCall', _551 => _551()]),
|
|
7620
8197
|
onRenderAttached: () => this.applyRemoteInterpolation(),
|
|
7621
8198
|
onRenderDetached: () => {
|
|
7622
8199
|
this.interpolationRevision++;
|
|
@@ -7627,6 +8204,31 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7627
8204
|
errorHandler: this.errorHandler,
|
|
7628
8205
|
cleanup: (scope, taskID) => this.performCleanup(scope, taskID)
|
|
7629
8206
|
});
|
|
8207
|
+
if (options.provider === "agora" /* agora */) {
|
|
8208
|
+
this.qualityHistory = new QualityHistory(options.model);
|
|
8209
|
+
this.qualityController = new QualityController(async (change, signal) => {
|
|
8210
|
+
if (signal.aborted || this.currentState.connectionState !== "Generating" /* generating */) {
|
|
8211
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Adaptive video format update was cancelled");
|
|
8212
|
+
}
|
|
8213
|
+
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
8214
|
+
const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
|
|
8215
|
+
const state2 = track && this.qualityStates.get(track);
|
|
8216
|
+
if (!track || !state2) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Adaptive video baseline is unavailable");
|
|
8217
|
+
const format = qualityVideoFormat(state2.baseline, change.to);
|
|
8218
|
+
await this.streamController.updateUplinkVideoFormat(format);
|
|
8219
|
+
token.ensureCurrent();
|
|
8220
|
+
_nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = state2.baseline)));
|
|
8221
|
+
track.updateVideoFormat(format);
|
|
8222
|
+
state2.level = change.to;
|
|
8223
|
+
_optionalChain([this, 'access', _552 => _552.qualityHistory, 'optionalAccess', _553 => _553.write, 'call', _554 => _554("uplink", change.to)]);
|
|
8224
|
+
});
|
|
8225
|
+
});
|
|
8226
|
+
this.downlinkQualityController = new QualityController(async (change, signal) => {
|
|
8227
|
+
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
8228
|
+
await this.applyDownlinkQuality(change.to, token, signal);
|
|
8229
|
+
});
|
|
8230
|
+
});
|
|
8231
|
+
}
|
|
7630
8232
|
this.streamController.setLocalVideoStatisticsListener((statistics) => {
|
|
7631
8233
|
if (this.acceptsVideoStatistics) {
|
|
7632
8234
|
this.localVideoStatistics = statistics ? Object.freeze({ ...statistics }) : void 0;
|
|
@@ -7636,6 +8238,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7636
8238
|
this.streamController.setNetworkStatisticsListener((statistics) => {
|
|
7637
8239
|
if (this.acceptsVideoStatistics) {
|
|
7638
8240
|
this.networkStatistics = statistics ? Object.freeze({ ...statistics }) : void 0;
|
|
8241
|
+
this.handleAdaptiveQuality(statistics);
|
|
7639
8242
|
this.notifyNetworkStatistics();
|
|
7640
8243
|
}
|
|
7641
8244
|
});
|
|
@@ -7663,7 +8266,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7663
8266
|
*/
|
|
7664
8267
|
async setFrameInterpolationEnabled(enabled) {
|
|
7665
8268
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
7666
|
-
const format = _nullishCoalesce(this.generationVideoFormat, () => ( _optionalChain([this, 'access',
|
|
8269
|
+
const format = _nullishCoalesce(_nullishCoalesce(_optionalChain([this, 'access', _555 => _555.downlinkQualityState, 'optionalAccess', _556 => _556.size]), () => ( this.generationVideoFormat)), () => ( _optionalChain([this, 'access', _557 => _557.currentLocalTrack, 'optionalAccess', _558 => _558.videoFormat])));
|
|
7667
8270
|
const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
|
|
7668
8271
|
if (enabled && !await this.checkInterpolationSupport(size, token)) {
|
|
7669
8272
|
token.ensureCurrent();
|
|
@@ -7675,6 +8278,43 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7675
8278
|
this.applyRemoteInterpolation();
|
|
7676
8279
|
});
|
|
7677
8280
|
}
|
|
8281
|
+
/** 手动调试与自动调档使用同一尺寸信令路径,不修改生成或上行配置。 */
|
|
8282
|
+
async adjustDownlinkQuality(direction) {
|
|
8283
|
+
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
8284
|
+
const controller = this.downlinkQualityController;
|
|
8285
|
+
const state2 = this.downlinkQualityState;
|
|
8286
|
+
if (!controller || !state2 || this.currentState.connectionState !== "Generating" /* generating */ || direction !== "upgrade" && direction !== "downgrade") {
|
|
8287
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Downlink quality adjustment requires an active Agora generation and a valid direction");
|
|
8288
|
+
}
|
|
8289
|
+
const level = Math.max(1, Math.min(Object.keys(QUALITY_TIERS).length, state2.level + (direction === "upgrade" ? -1 : 1)));
|
|
8290
|
+
if (level === state2.level) return;
|
|
8291
|
+
this.adaptiveQualityRevision++;
|
|
8292
|
+
controller.resetSamples();
|
|
8293
|
+
await this.applyDownlinkQuality(level, token);
|
|
8294
|
+
controller.start(level);
|
|
8295
|
+
});
|
|
8296
|
+
}
|
|
8297
|
+
async applyDownlinkQuality(level, token, signal) {
|
|
8298
|
+
const state2 = this.downlinkQualityState;
|
|
8299
|
+
const ensureActive2 = () => {
|
|
8300
|
+
token.ensureCurrent();
|
|
8301
|
+
if (_optionalChain([signal, 'optionalAccess', _559 => _559.aborted]) || !state2 || state2 !== this.downlinkQualityState || this.currentState.connectionState !== "Generating" /* generating */ || this.currentState.taskID !== state2.taskID) {
|
|
8302
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Target size update was cancelled");
|
|
8303
|
+
}
|
|
8304
|
+
};
|
|
8305
|
+
ensureActive2();
|
|
8306
|
+
if (!state2) return;
|
|
8307
|
+
const size = qualityVideoSize(state2.baseline, level);
|
|
8308
|
+
await this.streamController.updateDownlinkVideoResolution(state2.taskID, size, ensureActive2);
|
|
8309
|
+
ensureActive2();
|
|
8310
|
+
state2.level = level;
|
|
8311
|
+
state2.size = size;
|
|
8312
|
+
_optionalChain([this, 'access', _560 => _560.qualityHistory, 'optionalAccess', _561 => _561.write, 'call', _562 => _562("downlink", level)]);
|
|
8313
|
+
if (this.interpolationRequested) {
|
|
8314
|
+
this.interpolationSize = size;
|
|
8315
|
+
this.applyRemoteInterpolation();
|
|
8316
|
+
}
|
|
8317
|
+
}
|
|
7678
8318
|
/**
|
|
7679
8319
|
* 根据当前视频尺寸准备插帧,能力不可用时降级为原视频,并在应用前校验租约。
|
|
7680
8320
|
*/
|
|
@@ -7788,9 +8428,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7788
8428
|
*/
|
|
7789
8429
|
notifyRemoteVideoStatistics() {
|
|
7790
8430
|
try {
|
|
7791
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
8431
|
+
void Promise.resolve(_optionalChain([this, 'access', _563 => _563.remoteVideoStatisticsListener, 'optionalCall', _564 => _564(this.remoteVideoStatistics)])).catch(() => {
|
|
7792
8432
|
});
|
|
7793
|
-
} catch (
|
|
8433
|
+
} catch (e27) {
|
|
7794
8434
|
}
|
|
7795
8435
|
}
|
|
7796
8436
|
/**
|
|
@@ -7805,9 +8445,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7805
8445
|
*/
|
|
7806
8446
|
notifyNetworkStatistics() {
|
|
7807
8447
|
try {
|
|
7808
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
8448
|
+
void Promise.resolve(_optionalChain([this, 'access', _565 => _565.networkStatisticsListener, 'optionalCall', _566 => _566(this.networkStatistics)])).catch(() => {
|
|
7809
8449
|
});
|
|
7810
|
-
} catch (
|
|
8450
|
+
} catch (e28) {
|
|
7811
8451
|
}
|
|
7812
8452
|
}
|
|
7813
8453
|
/**
|
|
@@ -7825,15 +8465,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7825
8465
|
*/
|
|
7826
8466
|
notifyLocalVideoStatistics() {
|
|
7827
8467
|
try {
|
|
7828
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
8468
|
+
void Promise.resolve(_optionalChain([this, 'access', _567 => _567.localVideoStatisticsListener, 'optionalCall', _568 => _568(this.localVideoStatistics)])).catch(() => {
|
|
7829
8469
|
});
|
|
7830
|
-
} catch (
|
|
8470
|
+
} catch (e29) {
|
|
7831
8471
|
}
|
|
7832
8472
|
}
|
|
7833
8473
|
/**
|
|
7834
8474
|
* 停止接收媒体统计并清空各类快照,仅对曾有数据的统计发出清空通知。
|
|
7835
8475
|
*/
|
|
7836
8476
|
clearVideoStatistics() {
|
|
8477
|
+
_optionalChain([this, 'access', _569 => _569.qualityController, 'optionalAccess', _570 => _570.stop, 'call', _571 => _571()]);
|
|
8478
|
+
_optionalChain([this, 'access', _572 => _572.downlinkQualityController, 'optionalAccess', _573 => _573.stop, 'call', _574 => _574()]);
|
|
8479
|
+
this.downlinkQualityState = void 0;
|
|
8480
|
+
this.adaptiveQualityRevision++;
|
|
7837
8481
|
this.acceptsVideoStatistics = false;
|
|
7838
8482
|
const hadNetworkStatistics = this.networkStatistics !== void 0;
|
|
7839
8483
|
this.networkStatistics = void 0;
|
|
@@ -7880,6 +8524,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7880
8524
|
* 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
|
|
7881
8525
|
*
|
|
7882
8526
|
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
8527
|
+
* @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
|
|
7883
8528
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
7884
8529
|
* @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
|
|
7885
8530
|
*/
|
|
@@ -7899,7 +8544,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7899
8544
|
const completeCamera = this.launchTimer.startCamera();
|
|
7900
8545
|
this.clearVideoStatistics();
|
|
7901
8546
|
this.disposePermissionWatch();
|
|
7902
|
-
const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
8547
|
+
const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _575 => _575.useMicrophone]), () => ( false)));
|
|
7903
8548
|
if (permissionWatch) {
|
|
7904
8549
|
const completePermission = this.launchTimer.startPermission();
|
|
7905
8550
|
void permissionWatch.decided.then(() => completePermission()).catch(() => {
|
|
@@ -7916,7 +8561,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7916
8561
|
throw error;
|
|
7917
8562
|
}
|
|
7918
8563
|
token.ensureCurrent();
|
|
7919
|
-
this.generationVideoFormat = _optionalChain([stream, 'access',
|
|
8564
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _576 => _576.videoTrack, 'optionalAccess', _577 => _577.videoFormat]);
|
|
7920
8565
|
completeCamera();
|
|
7921
8566
|
this.cameraController.setPreviewReadyHandler((isCurrent) => {
|
|
7922
8567
|
void this.coordinator.localPreviewDidBecomeReady(isCurrent);
|
|
@@ -7937,7 +8582,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7937
8582
|
this.clearVideoStatistics();
|
|
7938
8583
|
await this.rtcManager.initialize();
|
|
7939
8584
|
token.ensureCurrent();
|
|
7940
|
-
this.generationVideoFormat = _optionalChain([stream, 'access',
|
|
8585
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _578 => _578.videoTrack, 'optionalAccess', _579 => _579.videoFormat]);
|
|
7941
8586
|
await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
|
|
7942
8587
|
return stream;
|
|
7943
8588
|
});
|
|
@@ -7963,7 +8608,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7963
8608
|
audioTrack: this.localVideoController.audioTrack
|
|
7964
8609
|
});
|
|
7965
8610
|
token.ensureCurrent();
|
|
7966
|
-
this.generationVideoFormat = _optionalChain([stream, 'access',
|
|
8611
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _580 => _580.videoTrack, 'optionalAccess', _581 => _581.videoFormat]);
|
|
7967
8612
|
await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
|
|
7968
8613
|
return stream;
|
|
7969
8614
|
});
|
|
@@ -7986,7 +8631,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7986
8631
|
* 移除媒体权限弹窗观察;授权决定已记录或不再需要观察时调用。
|
|
7987
8632
|
*/
|
|
7988
8633
|
disposePermissionWatch() {
|
|
7989
|
-
_optionalChain([this, 'access',
|
|
8634
|
+
_optionalChain([this, 'access', _582 => _582.permissionWatchDispose, 'optionalCall', _583 => _583()]);
|
|
7990
8635
|
this.permissionWatchDispose = void 0;
|
|
7991
8636
|
}
|
|
7992
8637
|
/**
|
|
@@ -7995,18 +8640,94 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7995
8640
|
*
|
|
7996
8641
|
* @throws 无本地相机或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
|
|
7997
8642
|
*/
|
|
7998
|
-
async
|
|
8643
|
+
async updateUplinkVideoFormat(videoFormat) {
|
|
7999
8644
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
8000
8645
|
const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
|
|
8001
|
-
const previousFormat = _optionalChain([track, 'optionalAccess',
|
|
8646
|
+
const previousFormat = _optionalChain([track, 'optionalAccess', _584 => _584.videoFormat]);
|
|
8002
8647
|
if (!track || !previousFormat) {
|
|
8003
8648
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local camera or file video stream is not started");
|
|
8004
8649
|
}
|
|
8005
8650
|
videoFormat.validate();
|
|
8006
|
-
|
|
8651
|
+
_optionalChain([this, 'access', _585 => _585.qualityController, 'optionalAccess', _586 => _586.stop, 'call', _587 => _587()]);
|
|
8652
|
+
await this.streamController.updateUplinkVideoFormat(videoFormat);
|
|
8007
8653
|
token.ensureCurrent();
|
|
8008
8654
|
_nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = previousFormat)));
|
|
8009
8655
|
track.updateVideoFormat(videoFormat);
|
|
8656
|
+
this.qualityStates.set(track, { baseline: videoFormat, level: 1 });
|
|
8657
|
+
_optionalChain([this, 'access', _588 => _588.qualityHistory, 'optionalAccess', _589 => _589.write, 'call', _590 => _590("uplink", 1)]);
|
|
8658
|
+
});
|
|
8659
|
+
}
|
|
8660
|
+
/** 已连接时仅替换帧率;与其他配置及生命周期操作共享同一操作租约。 */
|
|
8661
|
+
async updateUplinkFrameRate(fps) {
|
|
8662
|
+
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
8663
|
+
_optionalChain([this, 'access', _591 => _591.qualityController, 'optionalAccess', _592 => _592.stop, 'call', _593 => _593()]);
|
|
8664
|
+
await this.applyUplinkFrameRate(fps, token);
|
|
8665
|
+
const track = this.currentLocalTrack;
|
|
8666
|
+
if (_optionalChain([track, 'optionalAccess', _594 => _594.videoFormat])) {
|
|
8667
|
+
this.qualityStates.set(track, { baseline: track.videoFormat, level: 1 });
|
|
8668
|
+
_optionalChain([this, 'access', _595 => _595.qualityHistory, 'optionalAccess', _596 => _596.write, 'call', _597 => _597("uplink", 1)]);
|
|
8669
|
+
}
|
|
8670
|
+
});
|
|
8671
|
+
}
|
|
8672
|
+
/** 手动仅调帧接口,成功后的当前格式将成为新的自适应 L1 基准。 */
|
|
8673
|
+
async applyUplinkFrameRate(fps, token) {
|
|
8674
|
+
const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
|
|
8675
|
+
const previous = _optionalChain([track, 'optionalAccess', _598 => _598.videoFormat]);
|
|
8676
|
+
const state2 = this.currentState.connectionState;
|
|
8677
|
+
if (!track || !previous || state2 !== "Connected" /* connected */ && state2 !== "Generating" /* generating */) {
|
|
8678
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Frame rate updates require a connected local camera or file stream");
|
|
8679
|
+
}
|
|
8680
|
+
if (!Number.isFinite(fps) || fps <= 0) {
|
|
8681
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Video frame rate must be greater than zero");
|
|
8682
|
+
}
|
|
8683
|
+
const format = await this.streamController.updateUplinkFrameRate(fps);
|
|
8684
|
+
token.ensureCurrent();
|
|
8685
|
+
_nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = previous)));
|
|
8686
|
+
track.updateVideoFormat(format);
|
|
8687
|
+
}
|
|
8688
|
+
/** 上下行独立判断;串行应用同一原始事件,避免同时降档争抢配置租约。 */
|
|
8689
|
+
handleAdaptiveQuality(statistics) {
|
|
8690
|
+
const revision = ++this.adaptiveQualityRevision;
|
|
8691
|
+
const controller = this.qualityController;
|
|
8692
|
+
const downlink = this.downlinkQualityController;
|
|
8693
|
+
if (!controller || !downlink) return;
|
|
8694
|
+
const taskID = this.currentState.taskID;
|
|
8695
|
+
if (this.currentState.connectionState !== "Generating" /* generating */ || !taskID) {
|
|
8696
|
+
controller.stop();
|
|
8697
|
+
downlink.stop();
|
|
8698
|
+
return;
|
|
8699
|
+
}
|
|
8700
|
+
if (!statistics || this.coordinator.isBusy || this.adaptiveQualityPending) {
|
|
8701
|
+
controller.resetSamples();
|
|
8702
|
+
downlink.resetSamples();
|
|
8703
|
+
return;
|
|
8704
|
+
}
|
|
8705
|
+
const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
|
|
8706
|
+
if (!track) {
|
|
8707
|
+
controller.stop();
|
|
8708
|
+
} else if (!controller.snapshot.active) {
|
|
8709
|
+
const format = track.videoFormat;
|
|
8710
|
+
if (format) {
|
|
8711
|
+
const state3 = _nullishCoalesce(this.qualityStates.get(track), () => ( { baseline: format, level: 1 }));
|
|
8712
|
+
this.qualityStates.set(track, state3);
|
|
8713
|
+
controller.start(state3.level);
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
const state2 = this.downlinkQualityState;
|
|
8717
|
+
if (state2 && !downlink.snapshot.active) downlink.start(state2.level);
|
|
8718
|
+
const sampleAt = performance.now();
|
|
8719
|
+
this.adaptiveQualityPending = true;
|
|
8720
|
+
void (async () => {
|
|
8721
|
+
await controller.observe(statistics.uplinkQuality, sampleAt).catch(() => {
|
|
8722
|
+
});
|
|
8723
|
+
if (revision !== this.adaptiveQualityRevision || this.currentState.taskID !== taskID || state2 !== this.downlinkQualityState || this.currentState.connectionState !== "Generating" /* generating */ || this.coordinator.isBusy) {
|
|
8724
|
+
downlink.resetSamples();
|
|
8725
|
+
return;
|
|
8726
|
+
}
|
|
8727
|
+
await downlink.observe(statistics.downlinkQuality, sampleAt).catch(() => {
|
|
8728
|
+
});
|
|
8729
|
+
})().finally(() => {
|
|
8730
|
+
this.adaptiveQualityPending = false;
|
|
8010
8731
|
});
|
|
8011
8732
|
}
|
|
8012
8733
|
/**
|
|
@@ -8046,9 +8767,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8046
8767
|
"cameraSwitch" /* cameraSwitch */,
|
|
8047
8768
|
void 0,
|
|
8048
8769
|
async (token) => {
|
|
8770
|
+
_optionalChain([this, 'access', _599 => _599.qualityController, 'optionalAccess', _600 => _600.stop, 'call', _601 => _601()]);
|
|
8049
8771
|
const stream = await this.cameraController.switchCamera();
|
|
8050
8772
|
token.ensureCurrent();
|
|
8051
|
-
this.connectionManager.updateRemoteMirror();
|
|
8052
8773
|
return stream;
|
|
8053
8774
|
}
|
|
8054
8775
|
);
|
|
@@ -8116,6 +8837,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8116
8837
|
if (currentState.connectionState === "Generating" /* generating */) {
|
|
8117
8838
|
await this.generationManager.update(currentState.taskID, {
|
|
8118
8839
|
videoFormat,
|
|
8840
|
+
targetSize: this.downlinkQualityController ? _optionalChain([this, 'access', _602 => _602.downlinkQualityState, 'optionalAccess', _603 => _603.size]) : void 0,
|
|
8119
8841
|
context: options.context
|
|
8120
8842
|
});
|
|
8121
8843
|
token.ensureCurrent();
|
|
@@ -8153,6 +8875,15 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8153
8875
|
this.clearVideoStatistics();
|
|
8154
8876
|
await this.coordinator.terminate(1 /* all */);
|
|
8155
8877
|
}
|
|
8878
|
+
/** 仅为尚无档位记录的本地上行选择初始档位;不应用配置或覆盖重连状态。 */
|
|
8879
|
+
resolveInitialUplinkQuality(track) {
|
|
8880
|
+
if (!this.qualityController) return void 0;
|
|
8881
|
+
if (this.networkVideoController.currentTrack) return void 0;
|
|
8882
|
+
if (this.qualityStates.has(track)) return void 0;
|
|
8883
|
+
const baseline = track.videoFormat;
|
|
8884
|
+
if (!baseline) return void 0;
|
|
8885
|
+
return { baseline, level: this.qualityHistory.read("uplink") };
|
|
8886
|
+
}
|
|
8156
8887
|
/**
|
|
8157
8888
|
* 建立实时连接:创建会话、进房发布、启动心跳并准备远端渲染轨道。
|
|
8158
8889
|
*
|
|
@@ -8188,9 +8919,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8188
8919
|
});
|
|
8189
8920
|
beforePublish = () => cameraReady;
|
|
8190
8921
|
}
|
|
8922
|
+
const initialQuality = this.resolveInitialUplinkQuality(localTrack);
|
|
8923
|
+
const initialFormat = initialQuality ? qualityVideoFormat(initialQuality.baseline, initialQuality.level) : void 0;
|
|
8191
8924
|
const remote = await this.connectionManager.connect({
|
|
8192
8925
|
localTrack,
|
|
8193
|
-
remoteVideoFormat: this.generationVideoFormat,
|
|
8926
|
+
remoteVideoFormat: _nullishCoalesce(this.generationVideoFormat, () => ( localTrack.videoFormat)),
|
|
8927
|
+
localVideoFormat: initialFormat,
|
|
8928
|
+
onVideoEncoderConfigured: () => {
|
|
8929
|
+
if (!initialQuality || !initialFormat) return;
|
|
8930
|
+
_nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = initialQuality.baseline)));
|
|
8931
|
+
localTrack.updateVideoFormat(initialFormat);
|
|
8932
|
+
this.qualityStates.set(localTrack, initialQuality);
|
|
8933
|
+
_optionalChain([this, 'access', _604 => _604.qualityHistory, 'optionalAccess', _605 => _605.write, 'call', _606 => _606("uplink", initialQuality.level)]);
|
|
8934
|
+
},
|
|
8194
8935
|
model: this.options.model,
|
|
8195
8936
|
includeLocalAudio: this.localVideoController.isActive ? this.localVideoController.audioTrack !== void 0 : !this.networkVideoController.currentTrack && this.cameraController.useMicrophone,
|
|
8196
8937
|
publishLocalMedia: !this.networkVideoController.currentTrack,
|
|
@@ -8218,14 +8959,18 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8218
8959
|
*/
|
|
8219
8960
|
async performStartGeneration(token, videoFormat, context) {
|
|
8220
8961
|
token.setFailureScope(0 /* connection */);
|
|
8221
|
-
|
|
8962
|
+
const initialLevel = _nullishCoalesce(_optionalChain([this, 'access', _607 => _607.qualityHistory, 'optionalAccess', _608 => _608.read, 'call', _609 => _609("downlink")]), () => ( 1));
|
|
8963
|
+
const targetSize = this.downlinkQualityController ? qualityVideoSize(videoFormat, initialLevel) : void 0;
|
|
8964
|
+
await this.prepareFrameInterpolation(_nullishCoalesce(targetSize, () => ( videoFormat)), token);
|
|
8222
8965
|
const completeFirstFrame = this.launchTimer.startFirstFrame();
|
|
8223
8966
|
this.remoteFrameDisplayHandler = () => {
|
|
8224
8967
|
if (!token.signal.aborted) completeFirstFrame();
|
|
8225
8968
|
};
|
|
8226
8969
|
const taskID = await this.generationManager.start({
|
|
8227
8970
|
videoFormat,
|
|
8971
|
+
targetSize,
|
|
8228
8972
|
context,
|
|
8973
|
+
mirror: this.currentLocalTrack === this.cameraController.currentTrack && _optionalChain([this, 'access', _610 => _610.cameraController, 'access', _611 => _611.currentTrack, 'optionalAccess', _612 => _612.position]) === "front" /* front */,
|
|
8229
8974
|
signal: token.signal,
|
|
8230
8975
|
ensureCurrent: () => token.ensureCurrent(),
|
|
8231
8976
|
onStartSent: this.localVideoController.isActive ? async () => {
|
|
@@ -8242,10 +8987,18 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8242
8987
|
if (!sessionID) {
|
|
8243
8988
|
throw new XmaxError("SESSION_ERROR" /* sessionError */, "Realtime session is unavailable");
|
|
8244
8989
|
}
|
|
8990
|
+
_optionalChain([this, 'access', _613 => _613.downlinkQualityController, 'optionalAccess', _614 => _614.stop, 'call', _615 => _615()]);
|
|
8991
|
+
this.downlinkQualityState = {
|
|
8992
|
+
taskID,
|
|
8993
|
+
baseline: videoFormat,
|
|
8994
|
+
level: initialLevel,
|
|
8995
|
+
size: _nullishCoalesce(targetSize, () => ( { width: videoFormat.width, height: videoFormat.height }))
|
|
8996
|
+
};
|
|
8245
8997
|
await this.coordinator.commit(
|
|
8246
8998
|
new RealtimeState({ connectionState: "Generating" /* generating */, sessionID, taskID }),
|
|
8247
8999
|
token
|
|
8248
9000
|
);
|
|
9001
|
+
_optionalChain([this, 'access', _616 => _616.qualityHistory, 'optionalAccess', _617 => _617.write, 'call', _618 => _618("downlink", initialLevel)]);
|
|
8249
9002
|
const onFinish = this.networkVideoController.onFinish;
|
|
8250
9003
|
if (this.networkVideoController.currentTrack) {
|
|
8251
9004
|
this.streamController.activateNetworkVideoCompletion(onFinish && (() => {
|
|
@@ -8397,7 +9150,7 @@ var NonRealtimeTaskService = class {
|
|
|
8397
9150
|
* 提交一次任务;请求结果不确定时也不自动重试,以免重复扣费。
|
|
8398
9151
|
*/
|
|
8399
9152
|
async submitTask(options) {
|
|
8400
|
-
const model = _optionalChain([options, 'access',
|
|
9153
|
+
const model = _optionalChain([options, 'access', _619 => _619.model, 'optionalAccess', _620 => _620.trim, 'call', _621 => _621()]);
|
|
8401
9154
|
if (!model) {
|
|
8402
9155
|
invalid("Model must not be empty");
|
|
8403
9156
|
}
|
|
@@ -8490,7 +9243,7 @@ function validateURL(value) {
|
|
|
8490
9243
|
let url;
|
|
8491
9244
|
try {
|
|
8492
9245
|
url = new URL(value.trim());
|
|
8493
|
-
} catch (
|
|
9246
|
+
} catch (e30) {
|
|
8494
9247
|
return invalid("Resource must be an uploaded HTTP(S) URL");
|
|
8495
9248
|
}
|
|
8496
9249
|
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password) {
|
|
@@ -8537,7 +9290,7 @@ function parseTask(value) {
|
|
|
8537
9290
|
const uid = field(data, "uid", "string");
|
|
8538
9291
|
const status = field(data, "status", "string");
|
|
8539
9292
|
const quality = field(data, "quality", "string");
|
|
8540
|
-
if (!_optionalChain([uid, 'optionalAccess',
|
|
9293
|
+
if (!_optionalChain([uid, 'optionalAccess', _622 => _622.trim, 'call', _623 => _623()]) || !Object.values(NonRealtimeTaskStatus).includes(status)) {
|
|
8541
9294
|
malformed("Missing task UID or invalid status");
|
|
8542
9295
|
}
|
|
8543
9296
|
if (quality !== void 0 && !Object.values(NonRealtimeQuality).includes(quality)) {
|
|
@@ -8619,7 +9372,7 @@ var XmaxNonRealtimeManager = class {
|
|
|
8619
9372
|
* 取得任务快照,不把服务端失败终态当成查询失败。
|
|
8620
9373
|
*/
|
|
8621
9374
|
getTask(taskUid, options) {
|
|
8622
|
-
return this.tasks.getTask(taskUid, _optionalChain([options, 'optionalAccess',
|
|
9375
|
+
return this.tasks.getTask(taskUid, _optionalChain([options, 'optionalAccess', _624 => _624.signal]));
|
|
8623
9376
|
}
|
|
8624
9377
|
/**
|
|
8625
9378
|
* 批量取得任务快照。
|
|
@@ -8653,8 +9406,8 @@ var XmaxNonRealtimeManager = class {
|
|
|
8653
9406
|
const controller = new AbortController();
|
|
8654
9407
|
let timedOut = false;
|
|
8655
9408
|
const abort = () => controller.abort();
|
|
8656
|
-
_optionalChain([options, 'access',
|
|
8657
|
-
if (_optionalChain([options, 'access',
|
|
9409
|
+
_optionalChain([options, 'access', _625 => _625.signal, 'optionalAccess', _626 => _626.addEventListener, 'call', _627 => _627("abort", abort, { once: true })]);
|
|
9410
|
+
if (_optionalChain([options, 'access', _628 => _628.signal, 'optionalAccess', _629 => _629.aborted])) {
|
|
8658
9411
|
abort();
|
|
8659
9412
|
}
|
|
8660
9413
|
const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
@@ -8680,9 +9433,9 @@ var XmaxNonRealtimeManager = class {
|
|
|
8680
9433
|
ensureActive(controller.signal);
|
|
8681
9434
|
failures = 0;
|
|
8682
9435
|
try {
|
|
8683
|
-
void Promise.resolve(_optionalChain([options, 'access',
|
|
9436
|
+
void Promise.resolve(_optionalChain([options, 'access', _630 => _630.onTaskUpdated, 'optionalCall', _631 => _631(task)])).catch(() => {
|
|
8684
9437
|
});
|
|
8685
|
-
} catch (
|
|
9438
|
+
} catch (e31) {
|
|
8686
9439
|
}
|
|
8687
9440
|
ensureActive(controller.signal);
|
|
8688
9441
|
if (task.status === "error" /* error */) {
|
|
@@ -8710,7 +9463,7 @@ var XmaxNonRealtimeManager = class {
|
|
|
8710
9463
|
throw error;
|
|
8711
9464
|
} finally {
|
|
8712
9465
|
clearTimeout(timer);
|
|
8713
|
-
_optionalChain([options, 'access',
|
|
9466
|
+
_optionalChain([options, 'access', _632 => _632.signal, 'optionalAccess', _633 => _633.removeEventListener, 'call', _634 => _634("abort", abort)]);
|
|
8714
9467
|
}
|
|
8715
9468
|
}
|
|
8716
9469
|
};
|
|
@@ -8754,13 +9507,13 @@ function isTransient(error) {
|
|
|
8754
9507
|
}
|
|
8755
9508
|
function isResultAvailable(task) {
|
|
8756
9509
|
const result = task.result;
|
|
8757
|
-
if (!_optionalChain([result, 'optionalAccess',
|
|
9510
|
+
if (!_optionalChain([result, 'optionalAccess', _635 => _635.url, 'optionalAccess', _636 => _636.trim, 'call', _637 => _637()]) || _optionalChain([result, 'access', _638 => _638.uploadError, 'optionalAccess', _639 => _639.trim, 'call', _640 => _640()]) || result.uploadStatus !== void 0 && result.uploadStatus !== "success") {
|
|
8758
9511
|
return false;
|
|
8759
9512
|
}
|
|
8760
9513
|
try {
|
|
8761
9514
|
const url = new URL(result.url);
|
|
8762
9515
|
return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password;
|
|
8763
|
-
} catch (
|
|
9516
|
+
} catch (e32) {
|
|
8764
9517
|
return false;
|
|
8765
9518
|
}
|
|
8766
9519
|
}
|
|
@@ -8884,6 +9637,146 @@ var VideoContentMode = /* @__PURE__ */ ((VideoContentMode2) => {
|
|
|
8884
9637
|
return VideoContentMode2;
|
|
8885
9638
|
})(VideoContentMode || {});
|
|
8886
9639
|
|
|
9640
|
+
// src/Render/Video/RenderStatisticsController.ts
|
|
9641
|
+
var RenderStatisticsController = class {
|
|
9642
|
+
/**
|
|
9643
|
+
* 绑定用于观察原视频帧的元素,调用 start 后才开始采集。
|
|
9644
|
+
*/
|
|
9645
|
+
constructor(video) {
|
|
9646
|
+
__publicField(this, "video", video);
|
|
9647
|
+
/**
|
|
9648
|
+
* 统计回调
|
|
9649
|
+
*/
|
|
9650
|
+
__publicField(this, "handler");
|
|
9651
|
+
/**
|
|
9652
|
+
* 帧观察与采样生命周期
|
|
9653
|
+
*/
|
|
9654
|
+
__publicField(this, "timer");
|
|
9655
|
+
__publicField(this, "callbackID");
|
|
9656
|
+
__publicField(this, "sequence", 0);
|
|
9657
|
+
/**
|
|
9658
|
+
* 采样窗口与输出方式
|
|
9659
|
+
*/
|
|
9660
|
+
__publicField(this, "startedAt", 0);
|
|
9661
|
+
__publicField(this, "originalFrames", 0);
|
|
9662
|
+
__publicField(this, "interpolatedFrames", 0);
|
|
9663
|
+
__publicField(this, "interpolationActive", false);
|
|
9664
|
+
__publicField(this, "previousPresentedFrames");
|
|
9665
|
+
}
|
|
9666
|
+
/**
|
|
9667
|
+
* 独立于统计面板可见性采集;没有监听者时不占用定时器。
|
|
9668
|
+
*/
|
|
9669
|
+
start() {
|
|
9670
|
+
if (this.timer !== void 0 || !this.video.srcObject && !this.video.getAttribute("src") || !this.handler || typeof this.video.requestVideoFrameCallback !== "function") {
|
|
9671
|
+
return;
|
|
9672
|
+
}
|
|
9673
|
+
this.reset();
|
|
9674
|
+
const sequence = this.sequence;
|
|
9675
|
+
const observe = () => {
|
|
9676
|
+
this.callbackID = this.video.requestVideoFrameCallback((_now, metadata) => {
|
|
9677
|
+
if (sequence !== this.sequence) {
|
|
9678
|
+
return;
|
|
9679
|
+
}
|
|
9680
|
+
this.callbackID = void 0;
|
|
9681
|
+
if (!this.interpolationActive && !document.hidden) {
|
|
9682
|
+
this.recordVideoFrames(metadata.presentedFrames);
|
|
9683
|
+
} else {
|
|
9684
|
+
this.previousPresentedFrames = void 0;
|
|
9685
|
+
}
|
|
9686
|
+
observe();
|
|
9687
|
+
});
|
|
9688
|
+
};
|
|
9689
|
+
observe();
|
|
9690
|
+
this.timer = setInterval(() => this.sample(), 1e3);
|
|
9691
|
+
}
|
|
9692
|
+
/**
|
|
9693
|
+
* 切换输出方式并清空采样窗口,避免原视频和画布重复计数。
|
|
9694
|
+
*/
|
|
9695
|
+
setInterpolationActive(active) {
|
|
9696
|
+
this.interpolationActive = active;
|
|
9697
|
+
this.reset();
|
|
9698
|
+
}
|
|
9699
|
+
/**
|
|
9700
|
+
* 记录实际提交到画布的原帧或插值帧,不统计未呈现的计算结果。
|
|
9701
|
+
*/
|
|
9702
|
+
recordCanvasFrame(interpolated) {
|
|
9703
|
+
if (interpolated) {
|
|
9704
|
+
this.interpolatedFrames++;
|
|
9705
|
+
} else {
|
|
9706
|
+
this.originalFrames++;
|
|
9707
|
+
}
|
|
9708
|
+
}
|
|
9709
|
+
/**
|
|
9710
|
+
* 按浏览器累计呈现帧数的增量统计,包含两次回调之间已呈现但未回调的帧。
|
|
9711
|
+
*/
|
|
9712
|
+
recordVideoFrames(presentedFrames) {
|
|
9713
|
+
if (!Number.isSafeInteger(presentedFrames) || presentedFrames < 0) {
|
|
9714
|
+
this.previousPresentedFrames = void 0;
|
|
9715
|
+
return;
|
|
9716
|
+
}
|
|
9717
|
+
const previous = this.previousPresentedFrames;
|
|
9718
|
+
this.previousPresentedFrames = presentedFrames;
|
|
9719
|
+
if (previous === void 0 || presentedFrames < previous) {
|
|
9720
|
+
this.originalFrames += presentedFrames > 0 ? 1 : 0;
|
|
9721
|
+
return;
|
|
9722
|
+
}
|
|
9723
|
+
this.originalFrames += presentedFrames - previous;
|
|
9724
|
+
}
|
|
9725
|
+
/**
|
|
9726
|
+
* 取消采样及帧观察,忽略已排队的旧回调并清空对外统计。
|
|
9727
|
+
*/
|
|
9728
|
+
stop() {
|
|
9729
|
+
this.sequence++;
|
|
9730
|
+
clearInterval(this.timer);
|
|
9731
|
+
this.timer = void 0;
|
|
9732
|
+
if (this.callbackID !== void 0) {
|
|
9733
|
+
this.video.cancelVideoFrameCallback(this.callbackID);
|
|
9734
|
+
}
|
|
9735
|
+
this.callbackID = void 0;
|
|
9736
|
+
this.reset();
|
|
9737
|
+
}
|
|
9738
|
+
/**
|
|
9739
|
+
* 清空采样计数,避免换流或切换输出方式时混入旧数据。
|
|
9740
|
+
*/
|
|
9741
|
+
reset() {
|
|
9742
|
+
this.startedAt = performance.now();
|
|
9743
|
+
this.originalFrames = 0;
|
|
9744
|
+
this.interpolatedFrames = 0;
|
|
9745
|
+
this.previousPresentedFrames = void 0;
|
|
9746
|
+
this.notify(void 0);
|
|
9747
|
+
}
|
|
9748
|
+
/**
|
|
9749
|
+
* 按实际经过的时间计算帧率;没有新呈现时输出 0,后台页面不报告帧率。
|
|
9750
|
+
*/
|
|
9751
|
+
sample() {
|
|
9752
|
+
const now = performance.now();
|
|
9753
|
+
const seconds = (now - this.startedAt) / 1e3;
|
|
9754
|
+
if (document.hidden || seconds <= 0) {
|
|
9755
|
+
this.reset();
|
|
9756
|
+
return;
|
|
9757
|
+
}
|
|
9758
|
+
const statistics = Object.freeze({
|
|
9759
|
+
source: this.interpolationActive ? "canvas" : "video",
|
|
9760
|
+
frameRate: (this.originalFrames + this.interpolatedFrames) / seconds,
|
|
9761
|
+
originalFrameRate: this.originalFrames / seconds,
|
|
9762
|
+
interpolatedFrameRate: this.interpolatedFrames / seconds
|
|
9763
|
+
});
|
|
9764
|
+
this.startedAt = now;
|
|
9765
|
+
this.originalFrames = 0;
|
|
9766
|
+
this.interpolatedFrames = 0;
|
|
9767
|
+
this.notify(statistics);
|
|
9768
|
+
}
|
|
9769
|
+
/**
|
|
9770
|
+
* 隔离接入方回调异常,避免影响播放和后续采样。
|
|
9771
|
+
*/
|
|
9772
|
+
notify(statistics) {
|
|
9773
|
+
try {
|
|
9774
|
+
_optionalChain([this, 'access', _641 => _641.handler, 'optionalCall', _642 => _642(statistics)]);
|
|
9775
|
+
} catch (e33) {
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
};
|
|
9779
|
+
|
|
8887
9780
|
// ../../node_modules/.pnpm/framegen@1.4.0/node_modules/framegen/rt.js
|
|
8888
9781
|
var WG = 8;
|
|
8889
9782
|
var texBgSeq = 0;
|
|
@@ -11006,11 +11899,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
11006
11899
|
if (this.destroyed) return;
|
|
11007
11900
|
this.destroyed = true;
|
|
11008
11901
|
this.device.removeEventListener("uncapturederror", this.onGPUError);
|
|
11009
|
-
_optionalChain([this, 'access',
|
|
11902
|
+
_optionalChain([this, 'access', _643 => _643.runtime, 'optionalAccess', _644 => _644.destroy, 'call', _645 => _645()]);
|
|
11010
11903
|
this.runtime = void 0;
|
|
11011
11904
|
this.textures.forEach((texture) => texture.destroy());
|
|
11012
11905
|
this.textures = [];
|
|
11013
|
-
_optionalChain([this, 'access',
|
|
11906
|
+
_optionalChain([this, 'access', _646 => _646.context, 'optionalAccess', _647 => _647.unconfigure, 'call', _648 => _648()]);
|
|
11014
11907
|
this.device.destroy();
|
|
11015
11908
|
}
|
|
11016
11909
|
};
|
|
@@ -11047,6 +11940,10 @@ var RemoteVideoFramePipeline = class {
|
|
|
11047
11940
|
__publicField(this, "previousPresented");
|
|
11048
11941
|
__publicField(this, "slowPairs", 0);
|
|
11049
11942
|
__publicField(this, "active", false);
|
|
11943
|
+
/**
|
|
11944
|
+
* 帧时间基准:媒体时间异常后,本管线持续使用回调时钟,避免反复切换。
|
|
11945
|
+
*/
|
|
11946
|
+
__publicField(this, "timeSource", "mediaTime");
|
|
11050
11947
|
/** vsync 显示节拍:弹出到点的帧并显示最新的一张。 */
|
|
11051
11948
|
__publicField(this, "tick", (now) => {
|
|
11052
11949
|
if (this.stopped) return;
|
|
@@ -11093,8 +11990,8 @@ var RemoteVideoFramePipeline = class {
|
|
|
11093
11990
|
if (!this.loading) void this.initialize();
|
|
11094
11991
|
return;
|
|
11095
11992
|
}
|
|
11096
|
-
const time =
|
|
11097
|
-
if (
|
|
11993
|
+
const time = this.resolveFrameTime(now, metadata);
|
|
11994
|
+
if (time === void 0) return;
|
|
11098
11995
|
const previous = this.previousTime;
|
|
11099
11996
|
const interval = previous === void 0 ? 0 : time - previous;
|
|
11100
11997
|
const consecutive = this.previousPresented === void 0 || metadata.presentedFrames === this.previousPresented + 1;
|
|
@@ -11119,6 +12016,22 @@ var RemoteVideoFramePipeline = class {
|
|
|
11119
12016
|
}
|
|
11120
12017
|
this.interpolate(previousSlot, slot, previous, time, interval);
|
|
11121
12018
|
}
|
|
12019
|
+
/**
|
|
12020
|
+
* 优先使用媒体时间;新帧的媒体时间异常时切换到单调回调时钟。
|
|
12021
|
+
*/
|
|
12022
|
+
resolveFrameTime(now, metadata) {
|
|
12023
|
+
if (this.previousPresented !== void 0 && metadata.presentedFrames <= this.previousPresented) {
|
|
12024
|
+
return void 0;
|
|
12025
|
+
}
|
|
12026
|
+
let time = this.timeSource === "mediaTime" ? metadata.mediaTime * 1e3 : now;
|
|
12027
|
+
if (!Number.isFinite(time) || this.previousTime !== void 0 && time <= this.previousTime) {
|
|
12028
|
+
if (this.timeSource === "callback" || !Number.isFinite(now)) return void 0;
|
|
12029
|
+
this.timeSource = "callback";
|
|
12030
|
+
this.resetTimeline(true);
|
|
12031
|
+
time = now;
|
|
12032
|
+
}
|
|
12033
|
+
return time;
|
|
12034
|
+
}
|
|
11122
12035
|
/** 帧按显示时间升序入队;同一时间的内容后到先出。 */
|
|
11123
12036
|
enqueue(frame) {
|
|
11124
12037
|
const index = this.queue.findIndex((queued) => queued.time >= frame.time);
|
|
@@ -11145,8 +12058,10 @@ var RemoteVideoFramePipeline = class {
|
|
|
11145
12058
|
this.fail(new Error("Interpolation exceeded the GPU frame budget for 5 consecutive pairs"));
|
|
11146
12059
|
return;
|
|
11147
12060
|
}
|
|
11148
|
-
if (this.position(performance.now()) >= midpoint)
|
|
11149
|
-
|
|
12061
|
+
if (this.position(performance.now()) >= midpoint) {
|
|
12062
|
+
return;
|
|
12063
|
+
}
|
|
12064
|
+
this.enqueue({ slot, time: midpoint, interpolated: true });
|
|
11150
12065
|
}).catch((error) => {
|
|
11151
12066
|
if (!this.stopped) this.fail(error);
|
|
11152
12067
|
});
|
|
@@ -11165,6 +12080,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
11165
12080
|
this.displayedTime = frame.time;
|
|
11166
12081
|
this.canvas.style.visibility = "visible";
|
|
11167
12082
|
this.setActive(true);
|
|
12083
|
+
_optionalChain([this, 'access', _649 => _649.options, 'access', _650 => _650.onFramePresented, 'optionalCall', _651 => _651(_nullishCoalesce(frame.interpolated, () => ( false)))]);
|
|
11168
12084
|
}
|
|
11169
12085
|
async initialize() {
|
|
11170
12086
|
this.loading = true;
|
|
@@ -11192,13 +12108,15 @@ var RemoteVideoFramePipeline = class {
|
|
|
11192
12108
|
setActive(active) {
|
|
11193
12109
|
if (active === this.active) return;
|
|
11194
12110
|
this.active = active;
|
|
11195
|
-
_optionalChain([this, 'access',
|
|
12111
|
+
_optionalChain([this, 'access', _652 => _652.options, 'access', _653 => _653.onActiveChange, 'optionalCall', _654 => _654(active)]);
|
|
11196
12112
|
}
|
|
11197
|
-
resetTimeline() {
|
|
12113
|
+
resetTimeline(preserveGpuTimeout = false) {
|
|
11198
12114
|
this.generation++;
|
|
11199
12115
|
this.queue = [];
|
|
11200
|
-
|
|
11201
|
-
|
|
12116
|
+
if (!preserveGpuTimeout) {
|
|
12117
|
+
clearTimeout(this.stallTimer);
|
|
12118
|
+
this.stallTimer = void 0;
|
|
12119
|
+
}
|
|
11202
12120
|
if (this.raf !== void 0) cancelAnimationFrame(this.raf);
|
|
11203
12121
|
this.raf = void 0;
|
|
11204
12122
|
this.anchor = void 0;
|
|
@@ -11223,7 +12141,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
11223
12141
|
this.callback = void 0;
|
|
11224
12142
|
clearTimeout(this.initializationTimer);
|
|
11225
12143
|
this.resetTimeline();
|
|
11226
|
-
_optionalChain([this, 'access',
|
|
12144
|
+
_optionalChain([this, 'access', _655 => _655.processor, 'optionalAccess', _656 => _656.destroy, 'call', _657 => _657()]);
|
|
11227
12145
|
this.processor = void 0;
|
|
11228
12146
|
}
|
|
11229
12147
|
};
|
|
@@ -11277,16 +12195,21 @@ var XmaxVideoView = class {
|
|
|
11277
12195
|
__publicField(this, "interpolationOptions");
|
|
11278
12196
|
__publicField(this, "interpolationPipeline");
|
|
11279
12197
|
__publicField(this, "interpolationCanvas");
|
|
12198
|
+
/**
|
|
12199
|
+
* 呈现统计组件
|
|
12200
|
+
*/
|
|
12201
|
+
__publicField(this, "statisticsController");
|
|
11280
12202
|
/**
|
|
11281
12203
|
* DOM 挂载状态
|
|
11282
12204
|
*/
|
|
11283
12205
|
__publicField(this, "detached", false);
|
|
11284
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
12206
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _658 => _658.videoContentMode]), () => ( "fill")) /* fill */;
|
|
11285
12207
|
this.element = document.createElement("div");
|
|
11286
12208
|
this.element.style.position = "relative";
|
|
11287
12209
|
this.element.style.overflow = "hidden";
|
|
11288
12210
|
this.element.style.backgroundColor = "black";
|
|
11289
12211
|
this.videoElement = document.createElement("video");
|
|
12212
|
+
this.statisticsController = new RenderStatisticsController(this.videoElement);
|
|
11290
12213
|
this.videoElement.autoplay = true;
|
|
11291
12214
|
this.videoElement.playsInline = true;
|
|
11292
12215
|
this.videoElement.muted = true;
|
|
@@ -11303,6 +12226,20 @@ var XmaxVideoView = class {
|
|
|
11303
12226
|
get track() {
|
|
11304
12227
|
return this.currentTrack;
|
|
11305
12228
|
}
|
|
12229
|
+
/**
|
|
12230
|
+
* 每秒接收当前视图的呈现统计;换流、卸载或不可统计时返回 undefined。
|
|
12231
|
+
*/
|
|
12232
|
+
get renderStatisticsHandler() {
|
|
12233
|
+
return this.statisticsController.handler;
|
|
12234
|
+
}
|
|
12235
|
+
/**
|
|
12236
|
+
* 更新统计回调,不影响播放;移除回调时停止采集。
|
|
12237
|
+
*/
|
|
12238
|
+
set renderStatisticsHandler(handler) {
|
|
12239
|
+
this.statisticsController.handler = handler;
|
|
12240
|
+
this.statisticsController.stop();
|
|
12241
|
+
this.startRenderStatistics();
|
|
12242
|
+
}
|
|
11306
12243
|
/**
|
|
11307
12244
|
* 解绑旧轨道后接入新轨道,并为新内容重新启用一次性首帧通知。
|
|
11308
12245
|
*/
|
|
@@ -11362,6 +12299,7 @@ var XmaxVideoView = class {
|
|
|
11362
12299
|
});
|
|
11363
12300
|
}
|
|
11364
12301
|
this.startInterpolation();
|
|
12302
|
+
this.startRenderStatistics();
|
|
11365
12303
|
if ((this.videoElement.srcObject || this.videoElement.getAttribute("src")) && !this.hasNotifiedFrameDisplay) {
|
|
11366
12304
|
this.armFrameDisplayNotification();
|
|
11367
12305
|
}
|
|
@@ -11371,6 +12309,7 @@ var XmaxVideoView = class {
|
|
|
11371
12309
|
*/
|
|
11372
12310
|
detach() {
|
|
11373
12311
|
this.detached = true;
|
|
12312
|
+
this.statisticsController.stop();
|
|
11374
12313
|
this.stopInterpolation();
|
|
11375
12314
|
this.cancelFrameDisplayNotification();
|
|
11376
12315
|
if (this.videoElement.getAttribute("src")) {
|
|
@@ -11382,6 +12321,7 @@ var XmaxVideoView = class {
|
|
|
11382
12321
|
* 设置网络视频预览;静音播放一次,不捕获或发布媒体轨道。 @internal
|
|
11383
12322
|
*/
|
|
11384
12323
|
setVideoURL(url) {
|
|
12324
|
+
this.statisticsController.stop();
|
|
11385
12325
|
this.stopInterpolation();
|
|
11386
12326
|
this.cancelFrameDisplayNotification();
|
|
11387
12327
|
this.hasNotifiedFrameDisplay = false;
|
|
@@ -11395,6 +12335,7 @@ var XmaxVideoView = class {
|
|
|
11395
12335
|
this.armFrameDisplayNotification();
|
|
11396
12336
|
}
|
|
11397
12337
|
this.videoElement.load();
|
|
12338
|
+
this.startRenderStatistics();
|
|
11398
12339
|
}
|
|
11399
12340
|
/**
|
|
11400
12341
|
* 直接设置渲染用的媒体流(绑定管线和直接渲染共用)。 @internal
|
|
@@ -11403,6 +12344,7 @@ var XmaxVideoView = class {
|
|
|
11403
12344
|
if (this.videoElement.srcObject === stream) {
|
|
11404
12345
|
return;
|
|
11405
12346
|
}
|
|
12347
|
+
this.statisticsController.stop();
|
|
11406
12348
|
this.stopInterpolation();
|
|
11407
12349
|
this.cancelFrameDisplayNotification();
|
|
11408
12350
|
this.hasNotifiedFrameDisplay = false;
|
|
@@ -11411,6 +12353,7 @@ var XmaxVideoView = class {
|
|
|
11411
12353
|
this.videoElement.autoplay = true;
|
|
11412
12354
|
this.armFrameDisplayNotification();
|
|
11413
12355
|
this.startInterpolation();
|
|
12356
|
+
this.startRenderStatistics();
|
|
11414
12357
|
}
|
|
11415
12358
|
}
|
|
11416
12359
|
/**
|
|
@@ -11440,7 +12383,18 @@ var XmaxVideoView = class {
|
|
|
11440
12383
|
this.interpolationCanvas = canvas;
|
|
11441
12384
|
this.applyContentMode();
|
|
11442
12385
|
this.element.appendChild(canvas);
|
|
11443
|
-
const
|
|
12386
|
+
const options = this.interpolationOptions;
|
|
12387
|
+
const pipeline = new RemoteVideoFramePipeline(this.videoElement, canvas, {
|
|
12388
|
+
...options,
|
|
12389
|
+
onActiveChange: (active) => {
|
|
12390
|
+
this.statisticsController.setInterpolationActive(active);
|
|
12391
|
+
_optionalChain([options, 'access', _659 => _659.onActiveChange, 'optionalCall', _660 => _660(active)]);
|
|
12392
|
+
},
|
|
12393
|
+
onFramePresented: (interpolated) => {
|
|
12394
|
+
this.statisticsController.recordCanvasFrame(interpolated);
|
|
12395
|
+
_optionalChain([options, 'access', _661 => _661.onFramePresented, 'optionalCall', _662 => _662(interpolated)]);
|
|
12396
|
+
}
|
|
12397
|
+
});
|
|
11444
12398
|
this.interpolationPipeline = pipeline;
|
|
11445
12399
|
pipeline.start();
|
|
11446
12400
|
}
|
|
@@ -11450,8 +12404,8 @@ var XmaxVideoView = class {
|
|
|
11450
12404
|
stopInterpolation() {
|
|
11451
12405
|
const pipeline = this.interpolationPipeline;
|
|
11452
12406
|
this.interpolationPipeline = void 0;
|
|
11453
|
-
_optionalChain([pipeline, 'optionalAccess',
|
|
11454
|
-
_optionalChain([this, 'access',
|
|
12407
|
+
_optionalChain([pipeline, 'optionalAccess', _663 => _663.stop, 'call', _664 => _664()]);
|
|
12408
|
+
_optionalChain([this, 'access', _665 => _665.interpolationCanvas, 'optionalAccess', _666 => _666.remove, 'call', _667 => _667()]);
|
|
11455
12409
|
this.interpolationCanvas = void 0;
|
|
11456
12410
|
}
|
|
11457
12411
|
/**
|
|
@@ -11475,9 +12429,10 @@ var XmaxVideoView = class {
|
|
|
11475
12429
|
* 解绑当前轨道并清空渲染内容。
|
|
11476
12430
|
*/
|
|
11477
12431
|
detachCurrentTrack() {
|
|
12432
|
+
this.statisticsController.stop();
|
|
11478
12433
|
const track = this.currentTrack;
|
|
11479
12434
|
if (track) {
|
|
11480
|
-
_optionalChain([VideoRenderRegistry, 'access',
|
|
12435
|
+
_optionalChain([VideoRenderRegistry, 'access', _668 => _668.binding, 'call', _669 => _669(track), 'optionalAccess', _670 => _670.detachHandler, 'call', _671 => _671(this)]);
|
|
11481
12436
|
}
|
|
11482
12437
|
this.setFrameInterpolation(void 0);
|
|
11483
12438
|
this.cancelFrameDisplayNotification();
|
|
@@ -11500,8 +12455,8 @@ var XmaxVideoView = class {
|
|
|
11500
12455
|
}
|
|
11501
12456
|
this.hasNotifiedFrameDisplay = true;
|
|
11502
12457
|
this.cancelFrameDisplayNotification();
|
|
11503
|
-
_optionalChain([binding, 'optionalAccess',
|
|
11504
|
-
_optionalChain([this, 'access',
|
|
12458
|
+
_optionalChain([binding, 'optionalAccess', _672 => _672.frameDisplayHandler, 'optionalCall', _673 => _673()]);
|
|
12459
|
+
_optionalChain([this, 'access', _674 => _674.frameDisplayHandler, 'optionalCall', _675 => _675()]);
|
|
11505
12460
|
};
|
|
11506
12461
|
if (typeof this.videoElement.requestVideoFrameCallback === "function") {
|
|
11507
12462
|
this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
|
|
@@ -11540,6 +12495,12 @@ var XmaxVideoView = class {
|
|
|
11540
12495
|
this.interpolationCanvas.style.transform = this.mirrored ? "scaleX(-1)" : "";
|
|
11541
12496
|
}
|
|
11542
12497
|
}
|
|
12498
|
+
/**
|
|
12499
|
+
* 视图未卸载时启动呈现统计,采样及媒体就绪检查由统计组件负责。
|
|
12500
|
+
*/
|
|
12501
|
+
startRenderStatistics() {
|
|
12502
|
+
if (!this.detached) this.statisticsController.start();
|
|
12503
|
+
}
|
|
11543
12504
|
};
|
|
11544
12505
|
|
|
11545
12506
|
// src/Render/Video/XmaxRealtimeVideoView.ts
|
|
@@ -11571,9 +12532,9 @@ var XmaxRealtimeVideoView = class {
|
|
|
11571
12532
|
__publicField(this, "currentLocalTrack");
|
|
11572
12533
|
__publicField(this, "currentRemoteTrack");
|
|
11573
12534
|
__publicField(this, "contentMode");
|
|
11574
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11575
|
-
this.currentLocalTrack = _optionalChain([options, 'optionalAccess',
|
|
11576
|
-
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess',
|
|
12535
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _676 => _676.videoContentMode]), () => ( "fill")) /* fill */;
|
|
12536
|
+
this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _677 => _677.localTrack]);
|
|
12537
|
+
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _678 => _678.remoteTrack]);
|
|
11577
12538
|
this.element = document.createElement("div");
|
|
11578
12539
|
this.element.style.position = "relative";
|
|
11579
12540
|
this.element.style.overflow = "hidden";
|
|
@@ -11739,4 +12700,4 @@ var XmaxRealtimeVideoView = class {
|
|
|
11739
12700
|
|
|
11740
12701
|
|
|
11741
12702
|
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.RtcProvider = RtcProvider; exports.RealtimeModel = RealtimeModel; exports.modelDisplayName = modelDisplayName; exports.defaultFrameRate = defaultFrameRate; exports.defaultCameraVideoFormat = defaultCameraVideoFormat; exports.supportedRtcProviders = supportedRtcProviders; exports.MediaService = MediaService; exports.StoredFile = StoredFile; exports.StorageService = StorageService; exports.CameraPosition = CameraPosition; exports.RealtimeVideoTrack = RealtimeVideoTrack; exports.RealtimeMediaStream = RealtimeMediaStream; exports.RealtimeVideoSampleMethod = RealtimeVideoSampleMethod; exports.RealtimeContext = RealtimeContext; exports.RealtimeConnectionState = RealtimeConnectionState; exports.RealtimeReason = RealtimeReason; exports.RealtimeState = RealtimeState; exports.XmaxConfiguration = XmaxConfiguration; exports.NonRealtimeQuality = NonRealtimeQuality; exports.NonRealtimeTaskStatus = NonRealtimeTaskStatus; exports.NonRealtimeTaskError = NonRealtimeTaskError; exports.XmaxClient = XmaxClient; exports.RealtimeConfiguration = RealtimeConfiguration; exports.VideoContentMode = VideoContentMode; exports.XmaxVideoView = XmaxVideoView; exports.XmaxRealtimeVideoView = XmaxRealtimeVideoView;
|
|
11742
|
-
//# sourceMappingURL=chunk-
|
|
12703
|
+
//# sourceMappingURL=chunk-EKOYOFES.cjs.map
|