@xmaxai/web-sdk 1.0.6 → 1.0.8

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.
@@ -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.6";
208
+ var XMAX_SDK_VERSION = "1.0.8";
209
209
  var _RuntimeInfo = class _RuntimeInfo {
210
210
  /**
211
211
  * 序列化为接口传输使用的 snake_case 字段。
@@ -601,6 +601,7 @@ var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
601
601
  RealtimeModel2["x2_0"] = "x2.0";
602
602
  RealtimeModel2["x2_0_trtc"] = "x2.0-trtc";
603
603
  RealtimeModel2["x2_1_preview"] = "x2.1-preview";
604
+ RealtimeModel2["x2_1_preview_1014"] = "x2.1-preview-1014";
604
605
  return RealtimeModel2;
605
606
  })(RealtimeModel || {});
606
607
  function isKnownModel(model) {
@@ -615,10 +616,12 @@ function modelDefaults(model) {
615
616
  var MODEL_DISPLAY_NAMES = {
616
617
  ["x2.0" /* x2_0 */]: "X2.0",
617
618
  ["x2.0-trtc" /* x2_0_trtc */]: "X2.1-preview-trtc",
618
- ["x2.1-preview" /* x2_1_preview */]: "X2.1-preview-agora"
619
+ ["x2.1-preview" /* x2_1_preview */]: "X2.1-preview-agora",
620
+ ["x2.1-preview-1014" /* x2_1_preview_1014 */]: "X2.1-preview-1014"
619
621
  };
620
622
  var MODEL_BASE_URLS = {
621
- ["x2.1-preview" /* x2_1_preview */]: "https://cloud.xmax.22duck.cn/open/api/v1"
623
+ ["x2.1-preview" /* x2_1_preview */]: "https://cloud.xmax.22duck.cn/open/api/v1",
624
+ ["x2.1-preview-1014" /* x2_1_preview_1014 */]: "https://dev.xmaxai.com/open/api/v1"
622
625
  };
623
626
  var RESOLUTION_BUCKETS = {
624
627
  ["x2.0" /* x2_0 */]: [],
@@ -629,12 +632,17 @@ var RESOLUTION_BUCKETS = {
629
632
  ["x2.1-preview" /* x2_1_preview */]: [
630
633
  { width: 1024, height: 1920 },
631
634
  { width: 1920, height: 1024 }
635
+ ],
636
+ ["x2.1-preview-1014" /* x2_1_preview_1014 */]: [
637
+ { width: 1024, height: 1920 },
638
+ { width: 1920, height: 1024 }
632
639
  ]
633
640
  };
634
641
  var MAXIMUM_INPUT_PIXELS = {
635
642
  ["x2.0" /* x2_0 */]: 128e4,
636
643
  ["x2.0-trtc" /* x2_0_trtc */]: 21e5,
637
- ["x2.1-preview" /* x2_1_preview */]: 21e5
644
+ ["x2.1-preview" /* x2_1_preview */]: 21e5,
645
+ ["x2.1-preview-1014" /* x2_1_preview_1014 */]: 21e5
638
646
  };
639
647
  function modelDisplayName(model) {
640
648
  return isKnownModel(model) ? MODEL_DISPLAY_NAMES[model] : model;
@@ -666,7 +674,8 @@ function defaultCameraVideoFormat(model) {
666
674
  var MODEL_RTC_PROVIDERS = {
667
675
  ["x2.0" /* x2_0 */]: Object.freeze(["vertc" /* vertc */]),
668
676
  ["x2.0-trtc" /* x2_0_trtc */]: Object.freeze(["trtc" /* trtc */]),
669
- ["x2.1-preview" /* x2_1_preview */]: Object.freeze(["agora" /* agora */])
677
+ ["x2.1-preview" /* x2_1_preview */]: Object.freeze(["agora" /* agora */]),
678
+ ["x2.1-preview-1014" /* x2_1_preview_1014 */]: Object.freeze(["agora" /* agora */])
670
679
  };
671
680
  function supportedRtcProviders(model) {
672
681
  return isKnownModel(model) ? MODEL_RTC_PROVIDERS[model] : CUSTOM_MODEL_RTC_PROVIDERS;
@@ -1353,15 +1362,178 @@ var AgoraVideoSender = class {
1353
1362
  }
1354
1363
  throw new XmaxError("RTC_ERROR" /* rtcError */, "Browser did not retain WebRTC video sender parameters");
1355
1364
  }
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);
1365
1537
  }
1366
1538
  };
1367
1539
 
@@ -1381,6 +1553,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1381
1553
  __publicField(this, "initialization");
1382
1554
  __publicField(this, "lifecycle", 0);
1383
1555
  __publicField(this, "camera");
1556
+ __publicField(this, "cameraSource");
1557
+ __publicField(this, "cameraRotation");
1558
+ __publicField(this, "captureVersion", 0);
1384
1559
  __publicField(this, "microphone");
1385
1560
  __publicField(this, "externalVideo");
1386
1561
  __publicField(this, "externalAudio");
@@ -1460,7 +1635,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1460
1635
  if (typeof client.sendStreamMessage !== "function") {
1461
1636
  throw new XmaxError("RTC_ERROR" /* rtcError */, "Agora DataStream is unavailable in this SDK version");
1462
1637
  }
1463
- _AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess', _86 => _86.count]), () => ( 0))) + 1 });
1638
+ _AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess', _112 => _112.count]), () => ( 0))) + 1 });
1464
1639
  this.sdk = sdk;
1465
1640
  this.client = client;
1466
1641
  this.registerEvents(client);
@@ -1473,12 +1648,11 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1473
1648
  const client = this.client;
1474
1649
  this.clearRoom();
1475
1650
  this.client = void 0;
1476
- _optionalChain([client, 'optionalAccess', _87 => _87.removeAllListeners, 'call', _88 => _88()]);
1477
- this.releaseCameraSender();
1478
- _optionalChain([this, 'access', _89 => _89.camera, 'optionalAccess', _90 => _90.close, 'call', _91 => _91()]);
1479
- _optionalChain([this, 'access', _92 => _92.microphone, 'optionalAccess', _93 => _93.close, 'call', _94 => _94()]);
1480
- _optionalChain([this, 'access', _95 => _95.externalVideo, 'optionalAccess', _96 => _96.close, 'call', _97 => _97()]);
1481
- _optionalChain([this, 'access', _98 => _98.externalAudio, 'optionalAccess', _99 => _99.close, 'call', _100 => _100()]);
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()]);
1482
1656
  this.externalVideo = void 0;
1483
1657
  this.externalAudio = void 0;
1484
1658
  this.camera = void 0;
@@ -1486,7 +1660,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1486
1660
  const sdk = this.sdk;
1487
1661
  this.sdk = void 0;
1488
1662
  try {
1489
- await _optionalChain([client, 'optionalAccess', _101 => _101.leave, 'call', _102 => _102()]);
1663
+ await _optionalChain([client, 'optionalAccess', _124 => _124.leave, 'call', _125 => _125()]);
1490
1664
  } catch (e9) {
1491
1665
  XmaxLogger.rtc.warning(() => "Agora \u9000\u623F\u5931\u8D25\uFF0C\u5DF2\u91CA\u653E\u672C\u5730\u8D44\u6E90 (Agora Leave Failed)");
1492
1666
  } finally {
@@ -1499,19 +1673,41 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1499
1673
  */
1500
1674
  async startCameraCapture(options) {
1501
1675
  const client = this.requireClient();
1502
- if (this.camera || this.externalVideo) {
1676
+ if (this.camera || this.cameraSource || this.externalVideo) {
1503
1677
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "A local video source is already active");
1504
1678
  }
1679
+ const rotation = _nullishCoalesce(options.rotation, () => ( 0));
1680
+ validateCameraRotation(rotation);
1681
+ const version = ++this.captureVersion;
1682
+ let source;
1505
1683
  try {
1506
- const captureSize = rtcOrientedVideoSize(options);
1507
- const camera = await this.sdk.createCameraVideoTrack({
1684
+ const captureSize = rtcOrientedVideoSize(rotation === 90 || rotation === 270 ? { width: options.height, height: options.width } : options);
1685
+ source = await this.sdk.createCameraVideoTrack({
1508
1686
  facingMode: options.position === "front" /* front */ ? "user" : "environment",
1509
1687
  encoderConfig: { width: captureSize.width, height: captureSize.height, frameRate: options.frameRate }
1510
1688
  });
1511
- if (this.client !== client) {
1512
- camera.close();
1689
+ if (this.client !== client || version !== this.captureVersion) {
1690
+ source.close();
1513
1691
  throw this.cancelled();
1514
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
+ }
1515
1711
  this.camera = camera;
1516
1712
  this.cameraTransceiverListener = () => {
1517
1713
  if (this.client === client && client.localTracks.includes(camera) && this.videoPublishRequested && !this.rejoinTask) {
@@ -1525,6 +1721,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1525
1721
  camera.on("transceiver-updated", this.cameraTransceiverListener);
1526
1722
  return camera.getMediaStreamTrack();
1527
1723
  } catch (error) {
1724
+ if (version === this.captureVersion) this.releaseCameraCapture();
1528
1725
  throw this.mapError(error, "CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */);
1529
1726
  }
1530
1727
  }
@@ -1532,9 +1729,24 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1532
1729
  * 切换声网相机设备并返回切换后的原生轨道。
1533
1730
  */
1534
1731
  async switchCameraCapture(to) {
1535
- const camera = this.requireCamera();
1536
- await this.run(() => camera.setDevice({ facingMode: to === "front" /* front */ ? "user" : "environment" }));
1537
- if (this.camera !== camera) throw this.cancelled();
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
+ }
1538
1750
  if (this.videoPublishRequested) await this.restoreCameraSender(camera);
1539
1751
  return camera.getMediaStreamTrack();
1540
1752
  }
@@ -1542,17 +1754,25 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1542
1754
  * 停止采集并释放摄像头。
1543
1755
  */
1544
1756
  async stopCameraCapture() {
1757
+ this.releaseCameraCapture();
1758
+ }
1759
+ releaseCameraCapture() {
1760
+ ++this.captureVersion;
1545
1761
  const camera = this.camera;
1546
1762
  this.releaseCameraSender();
1547
1763
  this.camera = void 0;
1548
- _optionalChain([camera, 'optionalAccess', _103 => _103.close, 'call', _104 => _104()]);
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;
1549
1769
  }
1550
1770
  /**
1551
1771
  * 将外部原生轨包装为 Agora 本地轨,不申请设备权限;失败时释放本次克隆。
1552
1772
  */
1553
1773
  async setExternalMediaTracks(tracks) {
1554
1774
  this.requireClient();
1555
- if (this.camera || this.microphone || this.externalVideo) {
1775
+ if (this.camera || this.cameraSource || this.microphone || this.externalVideo) {
1556
1776
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
1557
1777
  }
1558
1778
  if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
@@ -1563,7 +1783,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1563
1783
  let wrappedVideo;
1564
1784
  let wrappedAudio;
1565
1785
  try {
1566
- audio = _optionalChain([tracks, 'access', _105 => _105.audioTrack, 'optionalAccess', _106 => _106.clone, 'call', _107 => _107()]);
1786
+ audio = _optionalChain([tracks, 'access', _143 => _143.audioTrack, 'optionalAccess', _144 => _144.clone, 'call', _145 => _145()]);
1567
1787
  wrappedVideo = this.sdk.createCustomVideoTrack({ mediaStreamTrack: video });
1568
1788
  if (audio) {
1569
1789
  wrappedAudio = this.sdk.createCustomAudioTrack({ mediaStreamTrack: audio, encoderConfig: "music_standard" });
@@ -1571,10 +1791,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1571
1791
  this.externalVideo = wrappedVideo;
1572
1792
  this.externalAudio = wrappedAudio;
1573
1793
  } catch (error) {
1574
- _optionalChain([wrappedVideo, 'optionalAccess', _108 => _108.close, 'call', _109 => _109()]);
1575
- _optionalChain([wrappedAudio, 'optionalAccess', _110 => _110.close, 'call', _111 => _111()]);
1794
+ _optionalChain([wrappedVideo, 'optionalAccess', _146 => _146.close, 'call', _147 => _147()]);
1795
+ _optionalChain([wrappedAudio, 'optionalAccess', _148 => _148.close, 'call', _149 => _149()]);
1576
1796
  video.stop();
1577
- _optionalChain([audio, 'optionalAccess', _112 => _112.stop, 'call', _113 => _113()]);
1797
+ _optionalChain([audio, 'optionalAccess', _150 => _150.stop, 'call', _151 => _151()]);
1578
1798
  throw this.mapError(error);
1579
1799
  }
1580
1800
  }
@@ -1592,7 +1812,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1592
1812
  };
1593
1813
  ensureActive2();
1594
1814
  if (this.videoPublishRequested) {
1595
- await AgoraVideoSender.apply(camera, { ...config, ...rtcOrientedVideoSize(config) }, ensureActive2);
1815
+ await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
1596
1816
  }
1597
1817
  this.cameraSenderConfiguration = { ...config };
1598
1818
  }));
@@ -1630,11 +1850,14 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1630
1850
  };
1631
1851
  ensureActive2();
1632
1852
  const config = this.cameraSenderConfiguration;
1633
- if (config) await AgoraVideoSender.apply(camera, { ...config, ...rtcOrientedVideoSize(config) }, ensureActive2);
1853
+ if (config) await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
1634
1854
  });
1635
1855
  }
1856
+ cameraEncodingConfiguration(config) {
1857
+ return this.cameraRotation ? config : { ...config, ...rtcOrientedVideoSize(config) };
1858
+ }
1636
1859
  releaseCameraSender() {
1637
- if (this.cameraTransceiverListener) _optionalChain([this, 'access', _114 => _114.camera, 'optionalAccess', _115 => _115.off, 'call', _116 => _116("transceiver-updated", this.cameraTransceiverListener)]);
1860
+ if (this.cameraTransceiverListener) _optionalChain([this, 'access', _152 => _152.camera, 'optionalAccess', _153 => _153.off, 'call', _154 => _154("transceiver-updated", this.cameraTransceiverListener)]);
1638
1861
  this.cameraTransceiverListener = void 0;
1639
1862
  this.cameraSenderConfiguration = void 0;
1640
1863
  }
@@ -1642,7 +1865,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1642
1865
  * 使用会话下发的字符串频道与 UID 入房;不采信后端区域覆盖。
1643
1866
  */
1644
1867
  async joinRoom(configuration) {
1645
- await _optionalChain([this, 'access', _117 => _117.rejoinTask, 'optionalAccess', _118 => _118.catch, 'call', _119 => _119(() => {
1868
+ await _optionalChain([this, 'access', _155 => _155.rejoinTask, 'optionalAccess', _156 => _156.catch, 'call', _157 => _157(() => {
1646
1869
  })]);
1647
1870
  const client = this.requireClient();
1648
1871
  if (configuration.provider !== "agora" /* agora */ || this.connection) {
@@ -1656,7 +1879,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1656
1879
  }
1657
1880
  this.connection = configuration;
1658
1881
  for (const user of client.remoteUsers) {
1659
- if (user.hasVideo) _optionalChain([this, 'access', _120 => _120.listener, 'optionalAccess', _121 => _121.onRemoteVideoPublished, 'call', _122 => _122(String(user.uid), true)]);
1882
+ if (user.hasVideo) _optionalChain([this, 'access', _158 => _158.listener, 'optionalAccess', _159 => _159.onRemoteVideoPublished, 'call', _160 => _160(String(user.uid), true)]);
1660
1883
  }
1661
1884
  this.statisticsTimer = setInterval(() => {
1662
1885
  if (this.client !== client || !this.connection || this.tokenExpired || this.rejoinOperation) return;
@@ -1678,7 +1901,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1678
1901
  * 应用同一频道的新 Token;即将过期时续签,已经过期时重新进房并恢复媒体。
1679
1902
  */
1680
1903
  async updateCredentials(config, signal) {
1681
- if (_optionalChain([signal, 'optionalAccess', _123 => _123.aborted])) throw this.cancelled();
1904
+ if (_optionalChain([signal, 'optionalAccess', _161 => _161.aborted])) throw this.cancelled();
1682
1905
  const current = this.connection;
1683
1906
  const client = this.requireClient();
1684
1907
  if (!current || config.provider !== "agora" /* agora */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
@@ -1694,7 +1917,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1694
1917
  }
1695
1918
  }
1696
1919
  this.ensureRoomCurrent(client, version);
1697
- if (_optionalChain([signal, 'optionalAccess', _124 => _124.aborted])) throw this.cancelled();
1920
+ if (_optionalChain([signal, 'optionalAccess', _162 => _162.aborted])) throw this.cancelled();
1698
1921
  if (this.tokenExpired) await this.rejoinRoom(client, config, signal);
1699
1922
  else this.connection = config;
1700
1923
  }
@@ -1717,21 +1940,21 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1717
1940
  reject(this.cancelled());
1718
1941
  };
1719
1942
  this.cancelRejoin = cancel;
1720
- _optionalChain([signal, 'optionalAccess', _125 => _125.addEventListener, 'call', _126 => _126("abort", cancel, { once: true })]);
1943
+ _optionalChain([signal, 'optionalAccess', _163 => _163.addEventListener, 'call', _164 => _164("abort", cancel, { once: true })]);
1721
1944
  task.then(resolve, reject);
1722
- if (_optionalChain([signal, 'optionalAccess', _127 => _127.aborted])) cancel();
1945
+ if (_optionalChain([signal, 'optionalAccess', _165 => _165.aborted])) cancel();
1723
1946
  });
1724
1947
  this.rejoinOperation = operation;
1725
1948
  try {
1726
1949
  await operation;
1727
1950
  } finally {
1728
- _optionalChain([signal, 'optionalAccess', _128 => _128.removeEventListener, 'call', _129 => _129("abort", cancel)]);
1951
+ _optionalChain([signal, 'optionalAccess', _166 => _166.removeEventListener, 'call', _167 => _167("abort", cancel)]);
1729
1952
  if (this.cancelRejoin === cancel) this.cancelRejoin = void 0;
1730
1953
  if (this.rejoinOperation === operation) this.rejoinOperation = void 0;
1731
1954
  }
1732
1955
  this.ensureRoomCurrent(client, version);
1733
1956
  for (const user of client.remoteUsers) {
1734
- if (user.hasVideo) _optionalChain([this, 'access', _130 => _130.listener, 'optionalAccess', _131 => _131.onRemoteVideoPublished, 'call', _132 => _132(String(user.uid), true)]);
1957
+ if (user.hasVideo) _optionalChain([this, 'access', _168 => _168.listener, 'optionalAccess', _169 => _169.onRemoteVideoPublished, 'call', _170 => _170(String(user.uid), true)]);
1735
1958
  }
1736
1959
  }
1737
1960
  /**
@@ -1739,10 +1962,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1739
1962
  */
1740
1963
  async performRejoin(client, config, version) {
1741
1964
  this.ensureRoomCurrent(client, version);
1742
- _optionalChain([this, 'access', _133 => _133.cancelSendDelay, 'optionalCall', _134 => _134()]);
1743
- _optionalChain([this, 'access', _135 => _135.cancelActiveSend, 'optionalCall', _136 => _136()]);
1744
- _optionalChain([this, 'access', _137 => _137.listener, 'optionalAccess', _138 => _138.onRoomRejoining, 'optionalCall', _139 => _139()]);
1745
- for (const user of client.remoteUsers) _optionalChain([user, 'access', _140 => _140.audioTrack, 'optionalAccess', _141 => _141.stop, 'call', _142 => _142()]);
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()]);
1746
1969
  await this.run(() => client.leave());
1747
1970
  this.ensureRoomCurrent(client, version);
1748
1971
  await this.run(() => client.join(config.appID, config.roomID, config.roomToken, config.userID));
@@ -1866,8 +2089,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1866
2089
  const user = client.remoteUsers.find((user2) => String(user2.uid) === userID);
1867
2090
  if (!subscribe) {
1868
2091
  this.requestedAudio.delete(userID);
1869
- _optionalChain([user, 'optionalAccess', _143 => _143.audioTrack, 'optionalAccess', _144 => _144.stop, 'call', _145 => _145()]);
1870
- if (_optionalChain([user, 'optionalAccess', _146 => _146.audioTrack]) && !this.rejoinTask) await this.run(() => client.unsubscribe(user, "audio"));
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"));
1871
2094
  return;
1872
2095
  }
1873
2096
  this.requestedAudio.add(userID);
@@ -1878,7 +2101,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1878
2101
  if (this.requestedAudio.has(userID)) await this.subscribeRemoteAudio(userID, true);
1879
2102
  return;
1880
2103
  }
1881
- if (!_optionalChain([user, 'optionalAccess', _147 => _147.hasAudio])) return;
2104
+ if (!_optionalChain([user, 'optionalAccess', _185 => _185.hasAudio])) return;
1882
2105
  const version = this.roomVersion;
1883
2106
  const track = await this.run(() => client.subscribe(user, "audio"));
1884
2107
  if (client !== this.client || version !== this.roomVersion || !this.requestedAudio.has(userID)) {
@@ -1892,9 +2115,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1892
2115
  */
1893
2116
  setRemoteAudioVolume(volume, userID) {
1894
2117
  this.audioVolumes.set(userID, Math.max(0, Math.min(100, Number.isFinite(volume) ? Math.round(volume) : 0)));
1895
- const user = _optionalChain([this, 'access', _148 => _148.client, 'optionalAccess', _149 => _149.remoteUsers, 'access', _150 => _150.find, 'call', _151 => _151((user2) => String(user2.uid) === userID)]);
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)]);
1896
2119
  if (this.rejoinTask || this.tokenExpired) {
1897
- _optionalChain([user, 'optionalAccess', _152 => _152.audioTrack, 'optionalAccess', _153 => _153.stop, 'call', _154 => _154()]);
2120
+ _optionalChain([user, 'optionalAccess', _190 => _190.audioTrack, 'optionalAccess', _191 => _191.stop, 'call', _192 => _192()]);
1898
2121
  return;
1899
2122
  }
1900
2123
  if (user) this.applyAudioVolume(user);
@@ -1983,45 +2206,45 @@ var _AgoraRtcManager = class _AgoraRtcManager {
1983
2206
  const handleExpired = () => {
1984
2207
  if (!active() || this.tokenExpired) return;
1985
2208
  this.tokenExpired = true;
1986
- _optionalChain([this, 'access', _155 => _155.listener, 'optionalAccess', _156 => _156.onNetworkStatistics, 'optionalCall', _157 => _157(void 0)]);
1987
- _optionalChain([this, 'access', _158 => _158.listener, 'optionalAccess', _159 => _159.onTokenExpired, 'optionalCall', _160 => _160()]);
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()]);
1988
2211
  };
1989
2212
  client.on("user-published", (user, kind) => {
1990
2213
  if (!mediaActive()) return;
1991
- if (kind === "video") _optionalChain([this, 'access', _161 => _161.listener, 'optionalAccess', _162 => _162.onRemoteVideoPublished, 'call', _163 => _163(String(user.uid), true)]);
2214
+ if (kind === "video") _optionalChain([this, 'access', _199 => _199.listener, 'optionalAccess', _200 => _200.onRemoteVideoPublished, 'call', _201 => _201(String(user.uid), true)]);
1992
2215
  if (kind === "audio" && this.requestedAudio.has(String(user.uid))) {
1993
2216
  void this.subscribeRemoteAudio(String(user.uid), true).catch((error) => {
1994
- if (active()) _optionalChain([this, 'access', _164 => _164.listener, 'optionalAccess', _165 => _165.onError, 'optionalCall', _166 => _166(this.mapError(error))]);
2217
+ if (active()) _optionalChain([this, 'access', _202 => _202.listener, 'optionalAccess', _203 => _203.onError, 'optionalCall', _204 => _204(this.mapError(error))]);
1995
2218
  });
1996
2219
  }
1997
2220
  });
1998
2221
  client.on("user-unpublished", (user, kind) => {
1999
2222
  if (!mediaActive()) return;
2000
- if (kind === "video") _optionalChain([this, 'access', _167 => _167.listener, 'optionalAccess', _168 => _168.onRemoteVideoPublished, 'call', _169 => _169(String(user.uid), false)]);
2001
- if (kind === "audio") _optionalChain([user, 'access', _170 => _170.audioTrack, 'optionalAccess', _171 => _171.stop, 'call', _172 => _172()]);
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()]);
2002
2225
  });
2003
2226
  client.on("user-left", (user) => {
2004
- if (mediaActive()) _optionalChain([this, 'access', _173 => _173.listener, 'optionalAccess', _174 => _174.onRemoteVideoPublished, 'call', _175 => _175(String(user.uid), false)]);
2227
+ if (mediaActive()) _optionalChain([this, 'access', _211 => _211.listener, 'optionalAccess', _212 => _212.onRemoteVideoPublished, 'call', _213 => _213(String(user.uid), false)]);
2005
2228
  });
2006
2229
  client.on("stream-message", (uid, data) => {
2007
- if (mediaActive()) _optionalChain([this, 'access', _176 => _176.listener, 'optionalAccess', _177 => _177.onCustomMessageReceived, 'call', _178 => _178(String(uid), typeof data === "string" ? data : new TextDecoder().decode(data))]);
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))]);
2008
2231
  });
2009
2232
  client.on("network-quality", (quality) => {
2010
2233
  if (mediaActive() && !this.networkQualitySuspended) AgoraRtcStatistics.network(quality, this.listener);
2011
2234
  });
2012
2235
  client.on("token-privilege-will-expire", () => {
2013
- if (active() && !this.tokenExpired) _optionalChain([this, 'access', _179 => _179.listener, 'optionalAccess', _180 => _180.onTokenWillExpire, 'optionalCall', _181 => _181()]);
2236
+ if (active() && !this.tokenExpired) _optionalChain([this, 'access', _217 => _217.listener, 'optionalAccess', _218 => _218.onTokenWillExpire, 'optionalCall', _219 => _219()]);
2014
2237
  });
2015
2238
  client.on("token-privilege-did-expire", handleExpired);
2016
2239
  client.on("connection-state-change", (state2, previous, reason) => {
2017
2240
  if (this.client === client) this.networkQualitySuspended = state2 !== "CONNECTED";
2018
- if (active() && state2 !== "CONNECTED") _optionalChain([this, 'access', _182 => _182.listener, 'optionalAccess', _183 => _183.onNetworkStatistics, 'optionalCall', _184 => _184(void 0)]);
2241
+ if (active() && state2 !== "CONNECTED") _optionalChain([this, 'access', _220 => _220.listener, 'optionalAccess', _221 => _221.onNetworkStatistics, 'optionalCall', _222 => _222(void 0)]);
2019
2242
  if (state2 === "DISCONNECTED" && reason === "TOKEN_EXPIRE") {
2020
2243
  handleExpired();
2021
2244
  return;
2022
2245
  }
2023
2246
  if (active() && !this.tokenExpired && state2 === "DISCONNECTED" && previous !== "DISCONNECTED") {
2024
- _optionalChain([this, 'access', _185 => _185.listener, 'optionalAccess', _186 => _186.onError, 'optionalCall', _187 => _187(new XmaxError("RTC_ERROR" /* rtcError */, `Agora connection disconnected: ${_nullishCoalesce(reason, () => ( "unknown"))}`))]);
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"))}`))]);
2025
2248
  }
2026
2249
  });
2027
2250
  }
@@ -2030,7 +2253,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
2030
2253
  */
2031
2254
  clearRoom() {
2032
2255
  this.roomVersion++;
2033
- _optionalChain([this, 'access', _188 => _188.cancelRejoin, 'optionalCall', _189 => _189()]);
2256
+ _optionalChain([this, 'access', _226 => _226.cancelRejoin, 'optionalCall', _227 => _227()]);
2034
2257
  this.connection = void 0;
2035
2258
  this.tokenExpired = false;
2036
2259
  this.networkQualitySuspended = false;
@@ -2038,13 +2261,13 @@ var _AgoraRtcManager = class _AgoraRtcManager {
2038
2261
  this.audioPublishRequested = false;
2039
2262
  clearInterval(this.statisticsTimer);
2040
2263
  this.statisticsTimer = void 0;
2041
- _optionalChain([this, 'access', _190 => _190.cancelSendDelay, 'optionalCall', _191 => _191()]);
2042
- _optionalChain([this, 'access', _192 => _192.cancelActiveSend, 'optionalCall', _193 => _193()]);
2264
+ _optionalChain([this, 'access', _228 => _228.cancelSendDelay, 'optionalCall', _229 => _229()]);
2265
+ _optionalChain([this, 'access', _230 => _230.cancelActiveSend, 'optionalCall', _231 => _231()]);
2043
2266
  this.sentPackets = [];
2044
2267
  this.sendTail = Promise.resolve();
2045
2268
  this.requestedAudio.clear();
2046
2269
  this.audioVolumes.clear();
2047
- for (const user of _nullishCoalesce(_optionalChain([this, 'access', _194 => _194.client, 'optionalAccess', _195 => _195.remoteUsers]), () => ( []))) _optionalChain([user, 'access', _196 => _196.audioTrack, 'optionalAccess', _197 => _197.stop, 'call', _198 => _198()]);
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()]);
2048
2271
  }
2049
2272
  /**
2050
2273
  * 判断异步恢复工作是否仍属于当前房间生命周期。
@@ -2069,8 +2292,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
2069
2292
  * 获取已启动的相机采集。
2070
2293
  */
2071
2294
  requireCamera() {
2072
- if (!this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
2073
- return this.camera;
2295
+ if (!this.cameraSource || !this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
2296
+ return this.cameraSource;
2074
2297
  }
2075
2298
  /**
2076
2299
  * 获取当前可编码、发布的视频轨,不要求来源为摄像头。
@@ -2182,7 +2405,7 @@ var _RtcEngineManager = class _RtcEngineManager {
2182
2405
  * 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
2183
2406
  */
2184
2407
  release(lease) {
2185
- if (_optionalChain([this, 'access', _199 => _199.activeLease, 'optionalAccess', _200 => _200.id]) !== lease.id) {
2408
+ if (_optionalChain([this, 'access', _237 => _237.activeLease, 'optionalAccess', _238 => _238.id]) !== lease.id) {
2186
2409
  return;
2187
2410
  }
2188
2411
  this.activeLease = void 0;
@@ -2256,10 +2479,10 @@ var RtcStatsLogger = class {
2256
2479
  `${XmaxLogger.localized("\u7D2F\u8BA1\u63A5\u6536\uFF1A", "Bytes Received: ")}${this.value(stats.bytesReceived, "bytes")}`
2257
2480
  ])];
2258
2481
  const local = stats.localStatistics;
2259
- if (_optionalChain([local, 'optionalAccess', _201 => _201.audio])) {
2482
+ if (_optionalChain([local, 'optionalAccess', _239 => _239.audio])) {
2260
2483
  blocks.push(this.audioBlock("\u672C\u5730\u97F3\u9891\u53D1\u9001 (Local Audio Uplink)", local.audio, false));
2261
2484
  }
2262
- for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _202 => _202.video]), () => ( []))) {
2485
+ for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _240 => _240.video]), () => ( []))) {
2263
2486
  blocks.push(this.videoBlock("\u672C\u5730\u89C6\u9891\u53D1\u9001 (Local Video Uplink)", video, false));
2264
2487
  }
2265
2488
  for (const remote of _nullishCoalesce(stats.remoteStatistics, () => ( []))) {
@@ -2349,8 +2572,8 @@ var RtcStatsLogger = class {
2349
2572
 
2350
2573
  // src/Foundation/RTC/TRTC/TrtcAudioVolumeSupport.ts
2351
2574
  function canControlTrtcRemoteAudioVolume(environment) {
2352
- const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _203 => _203.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
2353
- const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _204 => _204.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
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)))));
2354
2577
  const ios = /iPhone|iPad|iPod/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
2355
2578
  return !ios;
2356
2579
  }
@@ -2437,11 +2660,11 @@ var TrtcRtcManager = class {
2437
2660
  this.isCapturing = false;
2438
2661
  this.isAudioCapturing = false;
2439
2662
  this.isInRoom = false;
2440
- _optionalChain([this, 'access', _205 => _205.removeStatsListeners, 'optionalCall', _206 => _206()]);
2663
+ _optionalChain([this, 'access', _243 => _243.removeStatsListeners, 'optionalCall', _244 => _244()]);
2441
2664
  this.removeStatsListeners = void 0;
2442
2665
  if (!lease) {
2443
- _optionalChain([externalVideo, 'optionalAccess', _207 => _207.stop, 'call', _208 => _208()]);
2444
- _optionalChain([externalAudio, 'optionalAccess', _209 => _209.stop, 'call', _210 => _210()]);
2666
+ _optionalChain([externalVideo, 'optionalAccess', _245 => _245.stop, 'call', _246 => _246()]);
2667
+ _optionalChain([externalAudio, 'optionalAccess', _247 => _247.stop, 'call', _248 => _248()]);
2445
2668
  return;
2446
2669
  }
2447
2670
  try {
@@ -2452,8 +2675,8 @@ var TrtcRtcManager = class {
2452
2675
  await lease.engine.stopLocalVideo();
2453
2676
  } catch (e13) {
2454
2677
  }
2455
- _optionalChain([externalVideo, 'optionalAccess', _211 => _211.stop, 'call', _212 => _212()]);
2456
- _optionalChain([externalAudio, 'optionalAccess', _213 => _213.stop, 'call', _214 => _214()]);
2678
+ _optionalChain([externalVideo, 'optionalAccess', _249 => _249.stop, 'call', _250 => _250()]);
2679
+ _optionalChain([externalAudio, 'optionalAccess', _251 => _251.stop, 'call', _252 => _252()]);
2457
2680
  this.engineManager.release(lease);
2458
2681
  }
2459
2682
  /**
@@ -2471,10 +2694,10 @@ var TrtcRtcManager = class {
2471
2694
  this.externalVideo = video;
2472
2695
  let audio;
2473
2696
  try {
2474
- audio = _optionalChain([tracks, 'access', _215 => _215.audioTrack, 'optionalAccess', _216 => _216.clone, 'call', _217 => _217()]);
2697
+ audio = _optionalChain([tracks, 'access', _253 => _253.audioTrack, 'optionalAccess', _254 => _254.clone, 'call', _255 => _255()]);
2475
2698
  this.externalAudio = audio;
2476
2699
  await engine.startLocalVideo({ publish: false, option: { videoTrack: video } });
2477
- if (_optionalChain([this, 'access', _218 => _218.lease, 'optionalAccess', _219 => _219.engine]) !== engine) {
2700
+ if (_optionalChain([this, 'access', _256 => _256.lease, 'optionalAccess', _257 => _257.engine]) !== engine) {
2478
2701
  throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
2479
2702
  }
2480
2703
  if (audio) {
@@ -2482,12 +2705,12 @@ var TrtcRtcManager = class {
2482
2705
  publish: false,
2483
2706
  option: { audioTrack: audio, echoCancellation: false, autoGainControl: false, noiseSuppression: false }
2484
2707
  });
2485
- if (_optionalChain([this, 'access', _220 => _220.lease, 'optionalAccess', _221 => _221.engine]) !== engine) {
2708
+ if (_optionalChain([this, 'access', _258 => _258.lease, 'optionalAccess', _259 => _259.engine]) !== engine) {
2486
2709
  throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
2487
2710
  }
2488
2711
  }
2489
2712
  } catch (error) {
2490
- if (_optionalChain([this, 'access', _222 => _222.lease, 'optionalAccess', _223 => _223.engine]) === engine) {
2713
+ if (_optionalChain([this, 'access', _260 => _260.lease, 'optionalAccess', _261 => _261.engine]) === engine) {
2491
2714
  await engine.stopLocalAudio().catch(() => {
2492
2715
  });
2493
2716
  await engine.stopLocalVideo().catch(() => {
@@ -2498,7 +2721,7 @@ var TrtcRtcManager = class {
2498
2721
  this.externalAudio = void 0;
2499
2722
  }
2500
2723
  video.stop();
2501
- _optionalChain([audio, 'optionalAccess', _224 => _224.stop, 'call', _225 => _225()]);
2724
+ _optionalChain([audio, 'optionalAccess', _262 => _262.stop, 'call', _263 => _263()]);
2502
2725
  throw this.mapError(error);
2503
2726
  }
2504
2727
  }
@@ -2509,6 +2732,9 @@ var TrtcRtcManager = class {
2509
2732
  * @throws 引擎未初始化、已在采集、设备不可用或权限被拒绝时抛出错误。
2510
2733
  */
2511
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
+ }
2512
2738
  const engine = this.requireEngine();
2513
2739
  if (this.isCapturing || this.externalVideo) {
2514
2740
  throw new XmaxError(
@@ -2583,7 +2809,7 @@ var TrtcRtcManager = class {
2583
2809
  if (this.externalVideo) {
2584
2810
  return;
2585
2811
  }
2586
- const engine = _optionalChain([this, 'access', _226 => _226.lease, 'optionalAccess', _227 => _227.engine]);
2812
+ const engine = _optionalChain([this, 'access', _264 => _264.lease, 'optionalAccess', _265 => _265.engine]);
2587
2813
  this.isCapturing = false;
2588
2814
  if (!engine) {
2589
2815
  return;
@@ -2636,7 +2862,7 @@ var TrtcRtcManager = class {
2636
2862
  * 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
2637
2863
  */
2638
2864
  async leaveRoom() {
2639
- const engine = _optionalChain([this, 'access', _228 => _228.lease, 'optionalAccess', _229 => _229.engine]);
2865
+ const engine = _optionalChain([this, 'access', _266 => _266.lease, 'optionalAccess', _267 => _267.engine]);
2640
2866
  if (!engine || !this.isInRoom) {
2641
2867
  return;
2642
2868
  }
@@ -2709,7 +2935,7 @@ var TrtcRtcManager = class {
2709
2935
  * 停止发布本地视频流;采集保持运行,本地预览不受影响。
2710
2936
  */
2711
2937
  async unpublishLocalVideo() {
2712
- const engine = _optionalChain([this, 'access', _230 => _230.lease, 'optionalAccess', _231 => _231.engine]);
2938
+ const engine = _optionalChain([this, 'access', _268 => _268.lease, 'optionalAccess', _269 => _269.engine]);
2713
2939
  if (!engine || !this.isCapturing && !this.externalVideo) {
2714
2940
  return;
2715
2941
  }
@@ -2745,7 +2971,7 @@ var TrtcRtcManager = class {
2745
2971
  * 停止发布本地音频流;麦克风采集保持运行。
2746
2972
  */
2747
2973
  async unpublishLocalAudio() {
2748
- const engine = _optionalChain([this, 'access', _232 => _232.lease, 'optionalAccess', _233 => _233.engine]);
2974
+ const engine = _optionalChain([this, 'access', _270 => _270.lease, 'optionalAccess', _271 => _271.engine]);
2749
2975
  if (!engine || !this.isAudioCapturing && !this.externalAudio) {
2750
2976
  return;
2751
2977
  }
@@ -2871,19 +3097,19 @@ var TrtcRtcManager = class {
2871
3097
  registerEventBridge(engine) {
2872
3098
  const source = engine;
2873
3099
  const onStatistics = (stats) => {
2874
- if (this.isInRoom && _optionalChain([this, 'access', _234 => _234.lease, 'optionalAccess', _235 => _235.engine]) === engine) {
3100
+ if (this.isInRoom && _optionalChain([this, 'access', _272 => _272.lease, 'optionalAccess', _273 => _273.engine]) === engine) {
2875
3101
  RtcStatsLogger.logStatistics(stats);
2876
- const video = _optionalChain([stats, 'access', _236 => _236.localStatistics, 'optionalAccess', _237 => _237.video, 'optionalAccess', _238 => _238.find, 'call', _239 => _239((item) => item.videoType === "big")]);
3102
+ const video = _optionalChain([stats, 'access', _274 => _274.localStatistics, 'optionalAccess', _275 => _275.video, 'optionalAccess', _276 => _276.find, 'call', _277 => _277((item) => item.videoType === "big")]);
2877
3103
  const valid = (value, minimum) => typeof value === "number" && Number.isFinite(value) && value >= minimum ? value : void 0;
2878
- _optionalChain([this, 'access', _240 => _240.eventListener, 'optionalAccess', _241 => _241.onLocalVideoStatistics, 'optionalCall', _242 => _242(video ? Object.freeze({
3104
+ _optionalChain([this, 'access', _278 => _278.eventListener, 'optionalAccess', _279 => _279.onLocalVideoStatistics, 'optionalCall', _280 => _280(video ? Object.freeze({
2879
3105
  width: valid(video.width, 1),
2880
3106
  height: valid(video.height, 1),
2881
3107
  frameRate: valid(video.frameRate, 0),
2882
3108
  bitrateKbps: valid(video.bitrate, 0)
2883
3109
  }) : void 0)]);
2884
- _optionalChain([this, 'access', _243 => _243.eventListener, 'optionalAccess', _244 => _244.onRemoteVideoStatistics, 'optionalCall', _245 => _245(Object.freeze(
3110
+ _optionalChain([this, 'access', _281 => _281.eventListener, 'optionalAccess', _282 => _282.onRemoteVideoStatistics, 'optionalCall', _283 => _283(Object.freeze(
2885
3111
  (_nullishCoalesce(stats.remoteStatistics, () => ( []))).flatMap((remote) => {
2886
- const video2 = _optionalChain([remote, 'access', _246 => _246.video, 'optionalAccess', _247 => _247.find, 'call', _248 => _248((item) => item.videoType === "big")]);
3112
+ const video2 = _optionalChain([remote, 'access', _284 => _284.video, 'optionalAccess', _285 => _285.find, 'call', _286 => _286((item) => item.videoType === "big")]);
2887
3113
  if (!video2) {
2888
3114
  return [];
2889
3115
  }
@@ -2905,11 +3131,11 @@ var TrtcRtcManager = class {
2905
3131
  }
2906
3132
  };
2907
3133
  const onNetworkQuality = (stats) => {
2908
- if (this.isInRoom && _optionalChain([this, 'access', _249 => _249.lease, 'optionalAccess', _250 => _250.engine]) === engine) {
3134
+ if (this.isInRoom && _optionalChain([this, 'access', _287 => _287.lease, 'optionalAccess', _288 => _288.engine]) === engine) {
2909
3135
  RtcStatsLogger.logNetworkQuality(stats);
2910
3136
  const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
2911
3137
  const rtt = (value) => Number.isFinite(value) && value >= 0 ? value : void 0;
2912
- _optionalChain([this, 'access', _251 => _251.eventListener, 'optionalAccess', _252 => _252.onNetworkStatistics, 'optionalCall', _253 => _253(Object.freeze({
3138
+ _optionalChain([this, 'access', _289 => _289.eventListener, 'optionalAccess', _290 => _290.onNetworkStatistics, 'optionalCall', _291 => _291(Object.freeze({
2913
3139
  uplinkQuality: quality(stats.uplinkNetworkQuality),
2914
3140
  downlinkQuality: quality(stats.downlinkNetworkQuality),
2915
3141
  uplinkRttMs: rtt(stats.uplinkRTT),
@@ -2924,19 +3150,19 @@ var TrtcRtcManager = class {
2924
3150
  source.off(RTC_EVENT.networkQuality, onNetworkQuality);
2925
3151
  };
2926
3152
  source.on(RTC_EVENT.remoteVideoAvailable, (event) => {
2927
- if (_optionalChain([this, 'access', _254 => _254.lease, 'optionalAccess', _255 => _255.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
3153
+ if (_optionalChain([this, 'access', _292 => _292.lease, 'optionalAccess', _293 => _293.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
2928
3154
  return;
2929
3155
  }
2930
- _optionalChain([this, 'access', _256 => _256.eventListener, 'optionalAccess', _257 => _257.onRemoteVideoPublished, 'call', _258 => _258(event.userId, true)]);
3156
+ _optionalChain([this, 'access', _294 => _294.eventListener, 'optionalAccess', _295 => _295.onRemoteVideoPublished, 'call', _296 => _296(event.userId, true)]);
2931
3157
  });
2932
3158
  source.on(RTC_EVENT.remoteVideoUnavailable, (event) => {
2933
- if (_optionalChain([this, 'access', _259 => _259.lease, 'optionalAccess', _260 => _260.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
3159
+ if (_optionalChain([this, 'access', _297 => _297.lease, 'optionalAccess', _298 => _298.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
2934
3160
  return;
2935
3161
  }
2936
- _optionalChain([this, 'access', _261 => _261.eventListener, 'optionalAccess', _262 => _262.onRemoteVideoPublished, 'call', _263 => _263(event.userId, false)]);
3162
+ _optionalChain([this, 'access', _299 => _299.eventListener, 'optionalAccess', _300 => _300.onRemoteVideoPublished, 'call', _301 => _301(event.userId, false)]);
2937
3163
  });
2938
3164
  source.on(RTC_EVENT.customMessage, (event) => {
2939
- if (_optionalChain([this, 'access', _264 => _264.lease, 'optionalAccess', _265 => _265.engine]) !== engine || event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
3165
+ if (_optionalChain([this, 'access', _302 => _302.lease, 'optionalAccess', _303 => _303.engine]) !== engine || event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
2940
3166
  return;
2941
3167
  }
2942
3168
  let message;
@@ -2946,14 +3172,14 @@ var TrtcRtcManager = class {
2946
3172
  XmaxLogger.rtc.warning(() => "\u81EA\u5B9A\u4E49\u6D88\u606F\u89E3\u7801\u5931\u8D25 (Failed to Decode Custom Message)");
2947
3173
  return;
2948
3174
  }
2949
- _optionalChain([this, 'access', _266 => _266.eventListener, 'optionalAccess', _267 => _267.onCustomMessageReceived, 'call', _268 => _268(event.userId, message)]);
3175
+ _optionalChain([this, 'access', _304 => _304.eventListener, 'optionalAccess', _305 => _305.onCustomMessageReceived, 'call', _306 => _306(event.userId, message)]);
2950
3176
  });
2951
3177
  }
2952
3178
  /**
2953
3179
  * 返回当前引擎实例;未初始化时抛出错误。
2954
3180
  */
2955
3181
  requireEngine() {
2956
- const engine = _optionalChain([this, 'access', _269 => _269.lease, 'optionalAccess', _270 => _270.engine]);
3182
+ const engine = _optionalChain([this, 'access', _307 => _307.lease, 'optionalAccess', _308 => _308.engine]);
2957
3183
  if (!engine) {
2958
3184
  throw new XmaxError(
2959
3185
  "RTC_ERROR" /* rtcError */,
@@ -2970,8 +3196,8 @@ var TrtcRtcManager = class {
2970
3196
  return error;
2971
3197
  }
2972
3198
  const rtcError = error;
2973
- const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess', _271 => _271.originError, 'optionalAccess', _272 => _272.name]), () => ( ""));
2974
- const message = typeof _optionalChain([rtcError, 'optionalAccess', _273 => _273.message]) === "string" && rtcError.message.trim().length > 0 ? rtcError.message.trim() : String(error);
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);
2975
3201
  if (originName === "NotAllowedError" || originName === "SecurityError" || /NotAllowed/i.test(message)) {
2976
3202
  return new XmaxError("CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */, message);
2977
3203
  }
@@ -3094,12 +3320,12 @@ var VeRtcManager = class {
3094
3320
  this.sdk = void 0;
3095
3321
  this.camera = void 0;
3096
3322
  this.microphone = false;
3097
- _optionalChain([engine, 'optionalAccess', _274 => _274.removeAllListeners, 'call', _275 => _275()]);
3323
+ _optionalChain([engine, 'optionalAccess', _312 => _312.removeAllListeners, 'call', _313 => _313()]);
3098
3324
  try {
3099
3325
  if (engine && sdk) sdk.default.destroyEngine(engine);
3100
3326
  } finally {
3101
- _optionalChain([this, 'access', _276 => _276.externalVideo, 'optionalAccess', _277 => _277.stop, 'call', _278 => _278()]);
3102
- _optionalChain([this, 'access', _279 => _279.externalAudio, 'optionalAccess', _280 => _280.stop, 'call', _281 => _281()]);
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()]);
3103
3329
  this.externalVideo = void 0;
3104
3330
  this.externalAudio = void 0;
3105
3331
  }
@@ -3126,7 +3352,7 @@ var VeRtcManager = class {
3126
3352
  }
3127
3353
  };
3128
3354
  try {
3129
- audio = _optionalChain([tracks, 'access', _282 => _282.audioTrack, 'optionalAccess', _283 => _283.clone, 'call', _284 => _284()]);
3355
+ audio = _optionalChain([tracks, 'access', _320 => _320.audioTrack, 'optionalAccess', _321 => _321.clone, 'call', _322 => _322()]);
3130
3356
  this.externalAudio = audio;
3131
3357
  await engine.setVideoSourceType(index, sdk.VideoSourceType.VIDEO_SOURCE_TYPE_EXTERNAL);
3132
3358
  ensureCurrent();
@@ -3150,11 +3376,14 @@ var VeRtcManager = class {
3150
3376
  this.externalAudio = void 0;
3151
3377
  }
3152
3378
  video.stop();
3153
- _optionalChain([audio, 'optionalAccess', _285 => _285.stop, 'call', _286 => _286()]);
3379
+ _optionalChain([audio, 'optionalAccess', _323 => _323.stop, 'call', _324 => _324()]);
3154
3380
  throw this.mapError(error);
3155
3381
  }
3156
3382
  }
3157
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
+ }
3158
3387
  const engine = this.requireEngine();
3159
3388
  if (this.camera || this.externalVideo) {
3160
3389
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is already prepared");
@@ -3219,9 +3448,9 @@ var VeRtcManager = class {
3219
3448
  }));
3220
3449
  }
3221
3450
  async joinRoom(config) {
3222
- await _optionalChain([this, 'access', _287 => _287.joining, 'optionalAccess', _288 => _288.catch, 'call', _289 => _289(() => {
3451
+ await _optionalChain([this, 'access', _325 => _325.joining, 'optionalAccess', _326 => _326.catch, 'call', _327 => _327(() => {
3223
3452
  })]);
3224
- await _optionalChain([this, 'access', _290 => _290.recovery, 'optionalAccess', _291 => _291.catch, 'call', _292 => _292(() => {
3453
+ await _optionalChain([this, 'access', _328 => _328.recovery, 'optionalAccess', _329 => _329.catch, 'call', _330 => _330(() => {
3225
3454
  })]);
3226
3455
  const engine = this.requireEngine();
3227
3456
  if (config.provider !== "vertc" /* vertc */ || config.appID !== VERTC_APP_ID || this.connection) {
@@ -3270,7 +3499,7 @@ var VeRtcManager = class {
3270
3499
  async updateCredentials(config, signal) {
3271
3500
  const engine = this.requireEngine();
3272
3501
  const current = this.connection;
3273
- if (_optionalChain([signal, 'optionalAccess', _293 => _293.aborted])) throw this.cancelled();
3502
+ if (_optionalChain([signal, 'optionalAccess', _331 => _331.aborted])) throw this.cancelled();
3274
3503
  if (!current || config.provider !== "vertc" /* vertc */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
3275
3504
  throw new XmaxError("SESSION_ERROR" /* sessionError */, "VeRTC session binding changed");
3276
3505
  }
@@ -3298,7 +3527,7 @@ var VeRtcManager = class {
3298
3527
  const restore = this.tokenExpired || this.publishPrivilegeExpired || this.subscribePrivilegeExpired;
3299
3528
  if (restore) {
3300
3529
  this.joined = false;
3301
- _optionalChain([this, 'access', _294 => _294.listener, 'optionalAccess', _295 => _295.onRoomRejoining, 'optionalCall', _296 => _296()]);
3530
+ _optionalChain([this, 'access', _332 => _332.listener, 'optionalAccess', _333 => _333.onRoomRejoining, 'optionalCall', _334 => _334()]);
3302
3531
  this.clearPlayers();
3303
3532
  this.clearStatistics();
3304
3533
  if (this.tokenExpired) {
@@ -3469,13 +3698,13 @@ var VeRtcManager = class {
3469
3698
  if (!active()) return;
3470
3699
  if (video(mediaType)) {
3471
3700
  this.publishedVideo.add(userId);
3472
- if (mediaActive()) _optionalChain([this, 'access', _297 => _297.listener, 'optionalAccess', _298 => _298.onRemoteVideoPublished, 'call', _299 => _299(userId, true)]);
3701
+ if (mediaActive()) _optionalChain([this, 'access', _335 => _335.listener, 'optionalAccess', _336 => _336.onRemoteVideoPublished, 'call', _337 => _337(userId, true)]);
3473
3702
  }
3474
3703
  if (audio(mediaType)) {
3475
3704
  this.publishedAudio.add(userId);
3476
3705
  if (mediaActive() && this.requestedAudio.has(userId)) {
3477
3706
  void this.subscribeRemoteAudio(userId, true).catch((error) => {
3478
- if (mediaActive()) _optionalChain([this, 'access', _300 => _300.listener, 'optionalAccess', _301 => _301.onError, 'optionalCall', _302 => _302(this.mapError(error))]);
3707
+ if (mediaActive()) _optionalChain([this, 'access', _338 => _338.listener, 'optionalAccess', _339 => _339.onError, 'optionalCall', _340 => _340(this.mapError(error))]);
3479
3708
  });
3480
3709
  }
3481
3710
  }
@@ -3495,10 +3724,10 @@ var VeRtcManager = class {
3495
3724
  this.clearPlayer(userInfo.userId);
3496
3725
  });
3497
3726
  engine.on(events.onRoomMessageReceived, ({ userId, message }) => {
3498
- if (mediaActive() && typeof message === "string") _optionalChain([this, 'access', _303 => _303.listener, 'optionalAccess', _304 => _304.onCustomMessageReceived, 'call', _305 => _305(userId, message)]);
3727
+ if (mediaActive() && typeof message === "string") _optionalChain([this, 'access', _341 => _341.listener, 'optionalAccess', _342 => _342.onCustomMessageReceived, 'call', _343 => _343(userId, message)]);
3499
3728
  });
3500
3729
  const willExpire = () => {
3501
- if (active()) _optionalChain([this, 'access', _306 => _306.listener, 'optionalAccess', _307 => _307.onTokenWillExpire, 'optionalCall', _308 => _308()]);
3730
+ if (active()) _optionalChain([this, 'access', _344 => _344.listener, 'optionalAccess', _345 => _345.onTokenWillExpire, 'optionalCall', _346 => _346()]);
3502
3731
  };
3503
3732
  engine.on(events.onTokenWillExpire, willExpire);
3504
3733
  engine.on(events.onTokenPublishPrivilegeWillExpire, willExpire);
@@ -3506,13 +3735,13 @@ var VeRtcManager = class {
3506
3735
  engine.on(events.onTokenPublishPrivilegeDidExpired, () => {
3507
3736
  if (!active() || this.publishPrivilegeExpired) return;
3508
3737
  this.publishPrivilegeExpired = true;
3509
- _optionalChain([this, 'access', _309 => _309.listener, 'optionalAccess', _310 => _310.onTokenExpired, 'optionalCall', _311 => _311()]);
3738
+ _optionalChain([this, 'access', _347 => _347.listener, 'optionalAccess', _348 => _348.onTokenExpired, 'optionalCall', _349 => _349()]);
3510
3739
  });
3511
3740
  engine.on(events.onTokenSubscribePrivilegeDidExpired, () => {
3512
3741
  if (!active() || this.subscribePrivilegeExpired) return;
3513
3742
  this.subscribePrivilegeExpired = true;
3514
3743
  this.clearPlayers();
3515
- _optionalChain([this, 'access', _312 => _312.listener, 'optionalAccess', _313 => _313.onTokenExpired, 'optionalCall', _314 => _314()]);
3744
+ _optionalChain([this, 'access', _350 => _350.listener, 'optionalAccess', _351 => _351.onTokenExpired, 'optionalCall', _352 => _352()]);
3516
3745
  });
3517
3746
  engine.on(events.onError, ({ errorCode }) => {
3518
3747
  if (!active()) return;
@@ -3520,23 +3749,23 @@ var VeRtcManager = class {
3520
3749
  if (this.tokenExpired) return;
3521
3750
  this.tokenExpired = true;
3522
3751
  this.clearPlayers();
3523
- _optionalChain([this, 'access', _315 => _315.listener, 'optionalAccess', _316 => _316.onTokenExpired, 'optionalCall', _317 => _317()]);
3524
- } else _optionalChain([this, 'access', _318 => _318.listener, 'optionalAccess', _319 => _319.onError, 'optionalCall', _320 => _320(this.mapError({ code: errorCode }))]);
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 }))]);
3525
3754
  });
3526
3755
  engine.on(events.onConnectionStateChanged, ({ state: state2 }) => {
3527
3756
  if (!mediaActive() || state2 !== this.sdk.ConnectionState.CONNECTION_STATE_RECONNECTED) return;
3528
- _optionalChain([this, 'access', _321 => _321.listener, 'optionalAccess', _322 => _322.onRoomRejoining, 'optionalCall', _323 => _323()]);
3757
+ _optionalChain([this, 'access', _359 => _359.listener, 'optionalAccess', _360 => _360.onRoomRejoining, 'optionalCall', _361 => _361()]);
3529
3758
  this.clearPlayers();
3530
3759
  this.clearStatistics();
3531
3760
  this.replayVideo();
3532
3761
  for (const userID of this.requestedAudio) {
3533
3762
  void this.subscribeRemoteAudio(userID, true).catch((error) => {
3534
- if (mediaActive()) _optionalChain([this, 'access', _324 => _324.listener, 'optionalAccess', _325 => _325.onError, 'optionalCall', _326 => _326(this.mapError(error))]);
3763
+ if (mediaActive()) _optionalChain([this, 'access', _362 => _362.listener, 'optionalAccess', _363 => _363.onError, 'optionalCall', _364 => _364(this.mapError(error))]);
3535
3764
  });
3536
3765
  }
3537
3766
  });
3538
3767
  engine.on(events.onNetworkQuality, (up, down) => {
3539
- if (mediaActive()) _optionalChain([this, 'access', _327 => _327.listener, 'optionalAccess', _328 => _328.onNetworkStatistics, 'optionalCall', _329 => _329(Object.freeze({
3768
+ if (mediaActive()) _optionalChain([this, 'access', _365 => _365.listener, 'optionalAccess', _366 => _366.onNetworkStatistics, 'optionalCall', _367 => _367(Object.freeze({
3540
3769
  uplinkQuality: VeRtcStatistics.quality(up),
3541
3770
  downlinkQuality: VeRtcStatistics.quality(down)
3542
3771
  }))]);
@@ -3545,7 +3774,7 @@ var VeRtcManager = class {
3545
3774
  if (!mediaActive() || stats.isScreen || !this.videoRequested) return;
3546
3775
  const result = VeRtcStatistics.local(stats.videoStats);
3547
3776
  this.uplinkLossPercent = result.uplinkLossPercent;
3548
- _optionalChain([this, 'access', _330 => _330.listener, 'optionalAccess', _331 => _331.onLocalVideoStatistics, 'optionalCall', _332 => _332(result)]);
3777
+ _optionalChain([this, 'access', _368 => _368.listener, 'optionalAccess', _369 => _369.onLocalVideoStatistics, 'optionalCall', _370 => _370(result)]);
3549
3778
  XmaxLogger.rtc.info(() => `VeRTC local video statistics: ${JSON.stringify(result)}`, 2 /* performance */);
3550
3779
  });
3551
3780
  engine.on(events.onRemoteStreamStats, (stats) => {
@@ -3555,21 +3784,21 @@ var VeRtcManager = class {
3555
3784
  });
3556
3785
  }
3557
3786
  replayVideo() {
3558
- for (const userID of this.publishedVideo) _optionalChain([this, 'access', _333 => _333.listener, 'optionalAccess', _334 => _334.onRemoteVideoPublished, 'call', _335 => _335(userID, true)]);
3787
+ for (const userID of this.publishedVideo) _optionalChain([this, 'access', _371 => _371.listener, 'optionalAccess', _372 => _372.onRemoteVideoPublished, 'call', _373 => _373(userID, true)]);
3559
3788
  }
3560
3789
  removeVideo(userID) {
3561
3790
  this.publishedVideo.delete(userID);
3562
3791
  this.remoteStatistics.delete(userID);
3563
3792
  this.emitRemoteStatistics();
3564
- if (this.joined && !this.tokenExpired) _optionalChain([this, 'access', _336 => _336.listener, 'optionalAccess', _337 => _337.onRemoteVideoPublished, 'call', _338 => _338(userID, false)]);
3793
+ if (this.joined && !this.tokenExpired) _optionalChain([this, 'access', _374 => _374.listener, 'optionalAccess', _375 => _375.onRemoteVideoPublished, 'call', _376 => _376(userID, false)]);
3565
3794
  }
3566
3795
  emitRemoteStatistics() {
3567
- _optionalChain([this, 'access', _339 => _339.listener, 'optionalAccess', _340 => _340.onRemoteVideoStatistics, 'optionalCall', _341 => _341(Object.freeze([...this.remoteStatistics.values()]))]);
3796
+ _optionalChain([this, 'access', _377 => _377.listener, 'optionalAccess', _378 => _378.onRemoteVideoStatistics, 'optionalCall', _379 => _379(Object.freeze([...this.remoteStatistics.values()]))]);
3568
3797
  }
3569
3798
  clearStatistics() {
3570
3799
  this.remoteStatistics.clear();
3571
3800
  this.uplinkLossPercent = void 0;
3572
- _optionalChain([this, 'access', _342 => _342.listener, 'optionalAccess', _343 => _343.onLocalVideoStatistics, 'optionalCall', _344 => _344(void 0)]);
3801
+ _optionalChain([this, 'access', _380 => _380.listener, 'optionalAccess', _381 => _381.onLocalVideoStatistics, 'optionalCall', _382 => _382(void 0)]);
3573
3802
  this.emitRemoteStatistics();
3574
3803
  }
3575
3804
  clearPlayer(userID) {
@@ -3615,15 +3844,15 @@ var VeRtcManager = class {
3615
3844
  const cleanup = () => {
3616
3845
  clearTimeout(timer);
3617
3846
  roomSignal.removeEventListener("abort", cancel);
3618
- _optionalChain([signal, 'optionalAccess', _345 => _345.removeEventListener, 'call', _346 => _346("abort", cancel)]);
3847
+ _optionalChain([signal, 'optionalAccess', _383 => _383.removeEventListener, 'call', _384 => _384("abort", cancel)]);
3619
3848
  };
3620
3849
  const cancel = () => {
3621
- if (_optionalChain([signal, 'optionalAccess', _347 => _347.aborted]) && !roomSignal.aborted) this.roomVersion++;
3850
+ if (_optionalChain([signal, 'optionalAccess', _385 => _385.aborted]) && !roomSignal.aborted) this.roomVersion++;
3622
3851
  cleanup();
3623
3852
  reject(this.cancelled());
3624
3853
  };
3625
3854
  roomSignal.addEventListener("abort", cancel, { once: true });
3626
- _optionalChain([signal, 'optionalAccess', _348 => _348.addEventListener, 'call', _349 => _349("abort", cancel, { once: true })]);
3855
+ _optionalChain([signal, 'optionalAccess', _386 => _386.addEventListener, 'call', _387 => _387("abort", cancel, { once: true })]);
3627
3856
  task.then((value) => {
3628
3857
  cleanup();
3629
3858
  resolve(value);
@@ -3631,7 +3860,7 @@ var VeRtcManager = class {
3631
3860
  cleanup();
3632
3861
  reject(error);
3633
3862
  });
3634
- if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess', _350 => _350.aborted])) cancel();
3863
+ if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess', _388 => _388.aborted])) cancel();
3635
3864
  });
3636
3865
  }
3637
3866
  isCurrent(engine, version) {
@@ -3667,8 +3896,8 @@ var VeRtcManager = class {
3667
3896
  mapError(error, permissionCode) {
3668
3897
  if (error instanceof XmaxError) return error;
3669
3898
  const value = error;
3670
- const code = typeof _optionalChain([value, 'optionalAccess', _351 => _351.code]) === "string" && /^[A-Z_0-9-]{1,64}$/.test(value.code) ? value.code : "UNKNOWN";
3671
- const denied = _optionalChain([value, 'optionalAccess', _352 => _352.name]) === "NotAllowedError" || code === "PERMISSION_DENIED" || code === "DEVICE_PERMISSION_DENIED";
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";
3672
3901
  return new XmaxError(permissionCode && denied ? permissionCode : "RTC_ERROR" /* rtcError */, `VeRTC operation failed (${code})`);
3673
3902
  }
3674
3903
  cancelled() {
@@ -3750,7 +3979,7 @@ var PermissionManager = class {
3750
3979
  * @param deniedCode 权限被拒绝时抛出的错误码。
3751
3980
  */
3752
3981
  async ensurePermission(name, deniedCode) {
3753
- if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _353 => _353.mediaDevices, 'optionalAccess', _354 => _354.getUserMedia])) {
3982
+ if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _391 => _391.mediaDevices, 'optionalAccess', _392 => _392.getUserMedia])) {
3754
3983
  throw new XmaxError(
3755
3984
  deniedCode,
3756
3985
  "This browser does not support media capture (getUserMedia)"
@@ -3758,7 +3987,7 @@ var PermissionManager = class {
3758
3987
  }
3759
3988
  try {
3760
3989
  const permissions = navigator.permissions;
3761
- if (!_optionalChain([permissions, 'optionalAccess', _355 => _355.query])) {
3990
+ if (!_optionalChain([permissions, 'optionalAccess', _393 => _393.query])) {
3762
3991
  return;
3763
3992
  }
3764
3993
  const status = await permissions.query({
@@ -3938,10 +4167,10 @@ var _CameraController = class _CameraController {
3938
4167
  */
3939
4168
  __publicField(this, "storedUseMicrophone", false);
3940
4169
  __publicField(this, "storedFrameValidationEnabled", true);
3941
- this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _356 => _356.permissionManager]), () => ( new PermissionManager()));
3942
- this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _357 => _357.rtcManager]), () => ( new TrtcRtcManager()));
3943
- this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _358 => _358.mediaService]), () => ( new MediaService()));
3944
- this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _359 => _359.errorListener]), () => ( (() => {
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]), () => ( (() => {
3945
4174
  })));
3946
4175
  }
3947
4176
  /**
@@ -3967,7 +4196,7 @@ var _CameraController = class _CameraController {
3967
4196
  */
3968
4197
  async waitForValidCameraFrame(signal) {
3969
4198
  const track = this.activeTrack;
3970
- const mediaTrack = _optionalChain([track, 'optionalAccess', _360 => _360.mediaStreamTrack]);
4199
+ const mediaTrack = _optionalChain([track, 'optionalAccess', _398 => _398.mediaStreamTrack]);
3971
4200
  if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
3972
4201
  if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
3973
4202
  if (!this.isFrameValidationEnabled) return;
@@ -3991,6 +4220,7 @@ var _CameraController = class _CameraController {
3991
4220
  *
3992
4221
  * @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
3993
4222
  * @param options.position 首次启动时使用的摄像头位置。
4223
+ * @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
3994
4224
  * @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
3995
4225
  * @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
3996
4226
  * @returns 包含本地相机视频轨道的媒体流。
@@ -4003,6 +4233,7 @@ var _CameraController = class _CameraController {
4003
4233
  "Stop the current local camera stream before creating another one"
4004
4234
  );
4005
4235
  }
4236
+ validateCameraRotation(_nullishCoalesce(options.rotation, () => ( 0)));
4006
4237
  const resolvedFormat = this.resolveVideoFormat(options.videoFormat);
4007
4238
  const track = new RealtimeVideoTrack({
4008
4239
  id: _CameraController.localVideoTrackID,
@@ -4025,7 +4256,8 @@ var _CameraController = class _CameraController {
4025
4256
  width: resolvedFormat.width,
4026
4257
  height: resolvedFormat.height,
4027
4258
  frameRate: resolvedFormat.fps,
4028
- position: options.position
4259
+ position: options.position,
4260
+ ...options.rotation !== void 0 ? { rotation: options.rotation } : {}
4029
4261
  });
4030
4262
  track.mediaStreamTrack = mediaTrack;
4031
4263
  this.previewStream = new MediaStream([mediaTrack]);
@@ -4067,7 +4299,7 @@ var _CameraController = class _CameraController {
4067
4299
  */
4068
4300
  async switchCamera() {
4069
4301
  const track = this.activeTrack;
4070
- const position = _optionalChain([track, 'optionalAccess', _361 => _361.position]);
4302
+ const position = _optionalChain([track, 'optionalAccess', _399 => _399.position]);
4071
4303
  if (!track || !position) {
4072
4304
  throw new XmaxError(
4073
4305
  "RTC_ERROR" /* rtcError */,
@@ -4085,7 +4317,7 @@ var _CameraController = class _CameraController {
4085
4317
  }
4086
4318
  this.previewStream.addTrack(mediaTrack);
4087
4319
  }
4088
- _optionalChain([this, 'access', _362 => _362.previewMirrorApplier, 'optionalCall', _363 => _363(nextPosition === "front" /* front */)]);
4320
+ _optionalChain([this, 'access', _400 => _400.previewMirrorApplier, 'optionalCall', _401 => _401(nextPosition === "front" /* front */)]);
4089
4321
  this.observeMediaTrack(track, mediaTrack);
4090
4322
  return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
4091
4323
  }
@@ -4283,7 +4515,7 @@ var NetworkVideoController = class {
4283
4515
  this.ended = video.ended || this.ended;
4284
4516
  video.removeEventListener("loadedmetadata", restore);
4285
4517
  video.removeEventListener("error", fail);
4286
- _optionalChain([view, 'access', _364 => _364.setVideoURL, 'optionalCall', _365 => _365(null)]);
4518
+ _optionalChain([view, 'access', _402 => _402.setVideoURL, 'optionalCall', _403 => _403(null)]);
4287
4519
  });
4288
4520
  view.isMirrored = false;
4289
4521
  view.setVideoURL(this.reference.path);
@@ -4292,7 +4524,7 @@ var NetworkVideoController = class {
4292
4524
  * 保存预览进度并释放该视图的地址和事件监听。
4293
4525
  */
4294
4526
  detach(view) {
4295
- _optionalChain([this, 'access', _366 => _366.bindings, 'access', _367 => _367.get, 'call', _368 => _368(view), 'optionalCall', _369 => _369()]);
4527
+ _optionalChain([this, 'access', _404 => _404.bindings, 'access', _405 => _405.get, 'call', _406 => _406(view), 'optionalCall', _407 => _407()]);
4296
4528
  this.bindings.delete(view);
4297
4529
  }
4298
4530
  };
@@ -4321,13 +4553,13 @@ var LocalVideoController = class {
4321
4553
  * 准备完成的本地视频轨。
4322
4554
  */
4323
4555
  get currentTrack() {
4324
- return _optionalChain([this, 'access', _370 => _370.source, 'optionalAccess', _371 => _371.track]);
4556
+ return _optionalChain([this, 'access', _408 => _408.source, 'optionalAccess', _409 => _409.track]);
4325
4557
  }
4326
4558
  /**
4327
4559
  * 文件音频输出;禁用音频时为空,无音轨文件的 Web Audio 输出为静音。
4328
4560
  */
4329
4561
  get audioTrack() {
4330
- return _optionalChain([this, 'access', _372 => _372.source, 'optionalAccess', _373 => _373.audioDestination, 'optionalAccess', _374 => _374.stream, 'access', _375 => _375.getAudioTracks, 'call', _376 => _376(), 'access', _377 => _377[0]]);
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]]);
4331
4563
  }
4332
4564
  /**
4333
4565
  * 校验文件和格式,准备首帧与音频输出;应从用户点击事件直接调用以解锁播放。
@@ -4380,7 +4612,7 @@ var LocalVideoController = class {
4380
4612
  source.audioSource.connect(source.audioDestination);
4381
4613
  }
4382
4614
  video.src = source.url;
4383
- const resume = _optionalChain([source, 'access', _378 => _378.audioContext, 'optionalAccess', _379 => _379.resume, 'call', _380 => _380()]);
4615
+ const resume = _optionalChain([source, 'access', _416 => _416.audioContext, 'optionalAccess', _417 => _417.resume, 'call', _418 => _418()]);
4384
4616
  const playing = this.play(source, signal);
4385
4617
  await this.wait(source, Promise.all([resume, playing]), signal);
4386
4618
  video.pause();
@@ -4432,7 +4664,7 @@ var LocalVideoController = class {
4432
4664
  */
4433
4665
  async start(signal) {
4434
4666
  const source = this.source;
4435
- if (!_optionalChain([source, 'optionalAccess', _381 => _381.track])) {
4667
+ if (!_optionalChain([source, 'optionalAccess', _419 => _419.track])) {
4436
4668
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is not prepared");
4437
4669
  }
4438
4670
  if (signal.aborted) {
@@ -4440,7 +4672,7 @@ var LocalVideoController = class {
4440
4672
  }
4441
4673
  try {
4442
4674
  await this.rewind(source, signal);
4443
- await this.wait(source, Promise.all([_optionalChain([source, 'access', _382 => _382.audioContext, 'optionalAccess', _383 => _383.resume, 'call', _384 => _384()]), this.play(source, signal)]), signal);
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);
4444
4676
  } catch (error) {
4445
4677
  source.video.pause();
4446
4678
  throw error;
@@ -4450,7 +4682,7 @@ var LocalVideoController = class {
4450
4682
  * 暂停文件音视频,保留当前预览;重新开始生成时回到文件开头。
4451
4683
  */
4452
4684
  pause() {
4453
- _optionalChain([this, 'access', _385 => _385.source, 'optionalAccess', _386 => _386.video, 'access', _387 => _387.pause, 'call', _388 => _388()]);
4685
+ _optionalChain([this, 'access', _423 => _423.source, 'optionalAccess', _424 => _424.video, 'access', _425 => _425.pause, 'call', _426 => _426()]);
4454
4686
  }
4455
4687
  /**
4456
4688
  * 释放播放器、预览、定时器、轨道、音频上下文和对象 URL。
@@ -4480,12 +4712,12 @@ var LocalVideoController = class {
4480
4712
  source.video.pause();
4481
4713
  source.video.removeAttribute("src");
4482
4714
  source.video.load();
4483
- _optionalChain([source, 'access', _389 => _389.stream, 'optionalAccess', _390 => _390.getTracks, 'call', _391 => _391(), 'access', _392 => _392.forEach, 'call', _393 => _393((track) => track.stop())]);
4484
- _optionalChain([source, 'access', _394 => _394.audioDestination, 'optionalAccess', _395 => _395.stream, 'access', _396 => _396.getTracks, 'call', _397 => _397(), 'access', _398 => _398.forEach, 'call', _399 => _399((track) => track.stop())]);
4485
- _optionalChain([source, 'access', _400 => _400.audioSource, 'optionalAccess', _401 => _401.disconnect, 'call', _402 => _402()]);
4486
- _optionalChain([source, 'access', _403 => _403.audioDestination, 'optionalAccess', _404 => _404.disconnect, 'call', _405 => _405()]);
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()]);
4487
4719
  URL.revokeObjectURL(source.url);
4488
- await _optionalChain([source, 'access', _406 => _406.audioContext, 'optionalAccess', _407 => _407.close, 'call', _408 => _408(), 'access', _409 => _409.catch, 'call', _410 => _410(() => {
4720
+ await _optionalChain([source, 'access', _444 => _444.audioContext, 'optionalAccess', _445 => _445.close, 'call', _446 => _446(), 'access', _447 => _447.catch, 'call', _448 => _448(() => {
4489
4721
  })]);
4490
4722
  }
4491
4723
  /**
@@ -4610,6 +4842,46 @@ var LocalVideoController = class {
4610
4842
  }
4611
4843
  };
4612
4844
 
4845
+ // src/Media/Video/ExternalVideoController.ts
4846
+ var ExternalVideoController = class {
4847
+ constructor(onError) {
4848
+ __publicField(this, "onError", onError);
4849
+ __publicField(this, "track");
4850
+ __publicField(this, "onEnded", () => {
4851
+ this.onError(new XmaxError("MEDIA_ERROR" /* mediaError */, "External video source ended"));
4852
+ });
4853
+ }
4854
+ get currentTrack() {
4855
+ return this.track;
4856
+ }
4857
+ create(options, mediaService) {
4858
+ if (this.track) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Close the current external video first");
4859
+ const { videoTrack, videoFormat } = options;
4860
+ if (!videoTrack || videoTrack.kind !== "video" || videoTrack.readyState !== "live" || typeof videoTrack.clone !== "function") {
4861
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External video requires a live video MediaStreamTrack");
4862
+ }
4863
+ videoFormat.validate();
4864
+ const size = mediaService.resolveModelInputSize(videoFormat);
4865
+ const format = videoFormat.resized(size.width, size.height);
4866
+ const nativeTrack = videoTrack.clone();
4867
+ if (nativeTrack.readyState !== "live") {
4868
+ nativeTrack.stop();
4869
+ throw new XmaxError("MEDIA_ERROR" /* mediaError */, "External video source ended during setup");
4870
+ }
4871
+ const track = new RealtimeVideoTrack({ id: "external-video", videoFormat: format });
4872
+ track.mediaStreamTrack = nativeTrack;
4873
+ nativeTrack.addEventListener("ended", this.onEnded);
4874
+ this.track = track;
4875
+ return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
4876
+ }
4877
+ stop() {
4878
+ const nativeTrack = _optionalChain([this, 'access', _449 => _449.track, 'optionalAccess', _450 => _450.mediaStreamTrack]);
4879
+ this.track = void 0;
4880
+ _optionalChain([nativeTrack, 'optionalAccess', _451 => _451.removeEventListener, 'call', _452 => _452("ended", this.onEnded)]);
4881
+ _optionalChain([nativeTrack, 'optionalAccess', _453 => _453.stop, 'call', _454 => _454()]);
4882
+ }
4883
+ };
4884
+
4613
4885
  // src/Service/Realtime/RealtimeContext.ts
4614
4886
  var RealtimeContext = class {
4615
4887
  /**
@@ -4633,7 +4905,7 @@ var RealtimeContext = class {
4633
4905
  __publicField(this, "referencePath");
4634
4906
  this.referenceVideo = init.referenceVideo && Object.freeze({ ...init.referenceVideo });
4635
4907
  this.prompt = init.prompt.trim();
4636
- const normalizedReferencePath = _optionalChain([init, 'access', _411 => _411.referencePath, 'optionalAccess', _412 => _412.trim, 'call', _413 => _413()]);
4908
+ const normalizedReferencePath = _optionalChain([init, 'access', _455 => _455.referencePath, 'optionalAccess', _456 => _456.trim, 'call', _457 => _457()]);
4637
4909
  this.referencePath = normalizedReferencePath || void 0;
4638
4910
  }
4639
4911
  };
@@ -4901,7 +5173,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
4901
5173
  return;
4902
5174
  }
4903
5175
  _RealtimeSessionService.ensureSessionActive(session);
4904
- await _optionalChain([handlers, 'access', _414 => _414.onRefresh, 'optionalCall', _415 => _415(session)]);
5176
+ await _optionalChain([handlers, 'access', _458 => _458.onRefresh, 'optionalCall', _459 => _459(session)]);
4905
5177
  } catch (error) {
4906
5178
  if (this.heartbeatVersion !== version) {
4907
5179
  return;
@@ -5114,7 +5386,7 @@ var RealtimeState = class {
5114
5386
  * @param other 待比较的状态。
5115
5387
  */
5116
5388
  equals(other) {
5117
- return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access', _416 => _416.reason, 'optionalAccess', _417 => _417.kind]) === _optionalChain([other, 'access', _418 => _418.reason, 'optionalAccess', _419 => _419.kind]);
5389
+ return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access', _460 => _460.reason, 'optionalAccess', _461 => _461.kind]) === _optionalChain([other, 'access', _462 => _462.reason, 'optionalAccess', _463 => _463.kind]);
5118
5390
  }
5119
5391
  };
5120
5392
 
@@ -5164,8 +5436,8 @@ var RoomEvent = class _RoomEvent {
5164
5436
  ref_video_path: options.context.referenceVideo.path,
5165
5437
  sample_method: options.context.referenceVideo.sampleMethod,
5166
5438
  target_size: [
5167
- _nullishCoalesce(_optionalChain([options, 'access', _420 => _420.targetSize, 'optionalAccess', _421 => _421.width]), () => ( options.videoFormat.width)),
5168
- _nullishCoalesce(_optionalChain([options, 'access', _422 => _422.targetSize, 'optionalAccess', _423 => _423.height]), () => ( options.videoFormat.height))
5439
+ _nullishCoalesce(_optionalChain([options, 'access', _464 => _464.targetSize, 'optionalAccess', _465 => _465.width]), () => ( options.videoFormat.width)),
5440
+ _nullishCoalesce(_optionalChain([options, 'access', _466 => _466.targetSize, 'optionalAccess', _467 => _467.height]), () => ( options.videoFormat.height))
5169
5441
  ]
5170
5442
  }
5171
5443
  },
@@ -5237,6 +5509,7 @@ var RoomEvent = class _RoomEvent {
5237
5509
  static generationParameters(options) {
5238
5510
  return {
5239
5511
  model: "default",
5512
+ face_replace: _nullishCoalesce(options.faceRestoration, () => ( false)),
5240
5513
  size: [options.videoFormat.width, options.videoFormat.height],
5241
5514
  target_size: options.targetSize ? [
5242
5515
  Math.round(options.targetSize.width),
@@ -5607,12 +5880,19 @@ var RoomController = class {
5607
5880
  /**
5608
5881
  * 发送生成开始信令。
5609
5882
  *
5883
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
5884
+ * @param options.mirror 是否由后端镜像输入画面,默认 false。
5885
+ * @param options.taskID 当前生成任务标识。
5886
+ * @param options.videoFormat 模型生成使用的视频规格。
5887
+ * @param options.targetSize 服务端生成后的回传尺寸,缺省使用生成尺寸。
5888
+ * @param options.context 本次生成条件。
5610
5889
  * @throws 房间未就绪或信令发送失败时抛出错误。
5611
5890
  */
5612
5891
  startGeneration(options) {
5613
5892
  return this.send(
5614
5893
  RoomEvent.start({
5615
5894
  mirror: _nullishCoalesce(options.mirror, () => ( false)),
5895
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
5616
5896
  userID: this.requireUserID(),
5617
5897
  taskID: options.taskID,
5618
5898
  videoFormat: options.videoFormat,
@@ -5624,11 +5904,17 @@ var RoomController = class {
5624
5904
  /**
5625
5905
  * 发送生成条件变更信令。
5626
5906
  *
5907
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
5908
+ * @param options.taskID 当前生成任务标识。
5909
+ * @param options.videoFormat 模型生成使用的视频规格。
5910
+ * @param options.targetSize 服务端生成后的回传尺寸。
5911
+ * @param options.context 本次生成条件。
5627
5912
  * @throws 房间未就绪或信令发送失败时抛出错误。
5628
5913
  */
5629
5914
  changeGenerationCondition(options) {
5630
5915
  return this.send(
5631
5916
  RoomEvent.changeCondition({
5917
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
5632
5918
  userID: this.requireUserID(),
5633
5919
  taskID: options.taskID,
5634
5920
  videoFormat: options.videoFormat,
@@ -5710,7 +5996,7 @@ var RoomController = class {
5710
5996
  if (targetUserID && ownUserID && targetUserID !== ownUserID) {
5711
5997
  return;
5712
5998
  }
5713
- _optionalChain([this, 'access', _424 => _424.listener, 'optionalAccess', _425 => _425.onRoomMessage, 'call', _426 => _426(senderUserID, message)]);
5999
+ _optionalChain([this, 'access', _468 => _468.listener, 'optionalAccess', _469 => _469.onRoomMessage, 'call', _470 => _470(senderUserID, message)]);
5714
6000
  }
5715
6001
  /**
5716
6002
  * 发送房间信令并输出日志。
@@ -5992,7 +6278,7 @@ var StreamController = class {
5992
6278
  this.roomController.setListener({
5993
6279
  onRoomMessage: (sender, message) => {
5994
6280
  this.handleNetworkVideoCompletion(sender, message);
5995
- _optionalChain([this, 'access', _427 => _427.roomListener, 'optionalAccess', _428 => _428.onRoomMessage, 'call', _429 => _429(sender, message)]);
6281
+ _optionalChain([this, 'access', _471 => _471.roomListener, 'optionalAccess', _472 => _472.onRoomMessage, 'call', _473 => _473(sender, message)]);
5996
6282
  }
5997
6283
  });
5998
6284
  this.rtcManager.setEventListener({
@@ -6002,18 +6288,18 @@ var StreamController = class {
6002
6288
  onError: (error) => this.errorListener(error),
6003
6289
  onNetworkStatistics: (statistics) => {
6004
6290
  if (this.state.roomID) {
6005
- _optionalChain([this, 'access', _430 => _430.networkStatisticsListener, 'optionalCall', _431 => _431(statistics)]);
6291
+ _optionalChain([this, 'access', _474 => _474.networkStatisticsListener, 'optionalCall', _475 => _475(statistics)]);
6006
6292
  }
6007
6293
  },
6008
6294
  onRemoteVideoStatistics: (statistics) => {
6009
- const userID = _optionalChain([this, 'access', _432 => _432.state, 'access', _433 => _433.activeRemoteStream, 'optionalAccess', _434 => _434.userID]);
6010
- _optionalChain([this, 'access', _435 => _435.remoteVideoStatisticsListener, 'optionalCall', _436 => _436(
6295
+ const userID = _optionalChain([this, 'access', _476 => _476.state, 'access', _477 => _477.activeRemoteStream, 'optionalAccess', _478 => _478.userID]);
6296
+ _optionalChain([this, 'access', _479 => _479.remoteVideoStatisticsListener, 'optionalCall', _480 => _480(
6011
6297
  userID ? statistics.find((item) => item.userID === userID) : void 0
6012
6298
  )]);
6013
6299
  },
6014
6300
  onLocalVideoStatistics: (statistics) => {
6015
6301
  if (this.state.localVideoPublished) {
6016
- _optionalChain([this, 'access', _437 => _437.localVideoStatisticsListener, 'optionalCall', _438 => _438(statistics)]);
6302
+ _optionalChain([this, 'access', _481 => _481.localVideoStatisticsListener, 'optionalCall', _482 => _482(statistics)]);
6017
6303
  }
6018
6304
  },
6019
6305
  onCustomMessageReceived: (senderUserID, message) => {
@@ -6090,7 +6376,7 @@ var StreamController = class {
6090
6376
  \u2514\u2500 roomID: ${connection.roomID}, botID: ${_nullishCoalesce(connection.botID, () => ( "(\u672A\u8BBE\u7F6E)"))}`
6091
6377
  );
6092
6378
  if (publishLocalMedia) {
6093
- await _optionalChain([beforePublish, 'optionalCall', _439 => _439()]);
6379
+ await _optionalChain([beforePublish, 'optionalCall', _483 => _483()]);
6094
6380
  ensureActive2();
6095
6381
  await this.publishLocalStream(includeLocalAudio);
6096
6382
  }
@@ -6162,6 +6448,7 @@ var StreamController = class {
6162
6448
  const sending = this.roomController.startGeneration({
6163
6449
  taskID,
6164
6450
  mirror: _nullishCoalesce(options.mirror, () => ( false)),
6451
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
6165
6452
  videoFormat: options.videoFormat,
6166
6453
  targetSize: options.targetSize,
6167
6454
  context: options.context
@@ -6169,7 +6456,7 @@ var StreamController = class {
6169
6456
  const state2 = this.state;
6170
6457
  const sent = Promise.resolve(sending).then(async () => {
6171
6458
  if (this.state !== state2 || state2.generationTaskID !== taskID) return;
6172
- await _optionalChain([options, 'access', _440 => _440.onStartSent, 'optionalCall', _441 => _441()]);
6459
+ await _optionalChain([options, 'access', _484 => _484.onStartSent, 'optionalCall', _485 => _485()]);
6173
6460
  if (this.state !== state2 || state2.generationTaskID !== taskID) return;
6174
6461
  for (const userID of state2.publishedRemoteUserIDs) {
6175
6462
  void this.handleRemoteVideoPublished(userID, true);
@@ -6222,6 +6509,7 @@ var StreamController = class {
6222
6509
  try {
6223
6510
  await this.roomController.changeGenerationCondition({
6224
6511
  taskID: options.taskID,
6512
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
6225
6513
  videoFormat: options.videoFormat,
6226
6514
  targetSize: options.targetSize,
6227
6515
  context: options.context
@@ -6304,7 +6592,7 @@ var StreamController = class {
6304
6592
  deliverNetworkVideoCompletion() {
6305
6593
  const state2 = this.state;
6306
6594
  const completion = state2.networkVideoCompletion;
6307
- if (!_optionalChain([completion, 'optionalAccess', _442 => _442.finished]) || !completion.onFinish || completion.scheduled) {
6595
+ if (!_optionalChain([completion, 'optionalAccess', _486 => _486.finished]) || !completion.onFinish || completion.scheduled) {
6308
6596
  return;
6309
6597
  }
6310
6598
  completion.scheduled = true;
@@ -6313,7 +6601,7 @@ var StreamController = class {
6313
6601
  return;
6314
6602
  }
6315
6603
  try {
6316
- void Promise.resolve(_optionalChain([completion, 'access', _443 => _443.onFinish, 'optionalCall', _444 => _444()])).catch(() => {
6604
+ void Promise.resolve(_optionalChain([completion, 'access', _487 => _487.onFinish, 'optionalCall', _488 => _488()])).catch(() => {
6317
6605
  });
6318
6606
  } catch (e23) {
6319
6607
  }
@@ -6324,7 +6612,7 @@ var StreamController = class {
6324
6612
  */
6325
6613
  configureRoom(options) {
6326
6614
  const roomID = options.roomID.trim();
6327
- const botID = _nullishCoalesce(_optionalChain([options, 'access', _445 => _445.botID, 'optionalAccess', _446 => _446.trim, 'call', _447 => _447()]), () => ( ""));
6615
+ const botID = _nullishCoalesce(_optionalChain([options, 'access', _489 => _489.botID, 'optionalAccess', _490 => _490.trim, 'call', _491 => _491()]), () => ( ""));
6328
6616
  if (!roomID) {
6329
6617
  throw new XmaxError(
6330
6618
  "INVALID_CONFIGURATION" /* invalidConfiguration */,
@@ -6407,7 +6695,7 @@ var StreamController = class {
6407
6695
  return;
6408
6696
  }
6409
6697
  this.state.subscribedRemoteUserIDs.delete(trimmedUserID);
6410
- if (_optionalChain([this, 'access', _448 => _448.state, 'access', _449 => _449.activeRemoteStream, 'optionalAccess', _450 => _450.userID]) === trimmedUserID) {
6698
+ if (_optionalChain([this, 'access', _492 => _492.state, 'access', _493 => _493.activeRemoteStream, 'optionalAccess', _494 => _494.userID]) === trimmedUserID) {
6411
6699
  await this.unsubscribeRemoteAudio(trimmedUserID);
6412
6700
  this.state.activeRemoteStream = void 0;
6413
6701
  this.clearRemoteStream();
@@ -6597,7 +6885,7 @@ var StreamController = class {
6597
6885
  */
6598
6886
  resolveGenerationStart(taskID) {
6599
6887
  const waiter = this.state.generationWaiter;
6600
- if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _451 => _451.taskID]) !== taskID) {
6888
+ if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _495 => _495.taskID]) !== taskID) {
6601
6889
  return;
6602
6890
  }
6603
6891
  this.state.generationWaiter = void 0;
@@ -6609,7 +6897,7 @@ var StreamController = class {
6609
6897
  */
6610
6898
  rejectGenerationStart(taskID, error) {
6611
6899
  const waiter = this.state.generationWaiter;
6612
- if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _452 => _452.taskID]) !== taskID) {
6900
+ if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _496 => _496.taskID]) !== taskID) {
6613
6901
  return;
6614
6902
  }
6615
6903
  this.state.generationWaiter = void 0;
@@ -6620,7 +6908,7 @@ var StreamController = class {
6620
6908
  * 通知渲染层清理远端生成流;失败仅记录日志。
6621
6909
  */
6622
6910
  clearRemoteStream() {
6623
- _optionalChain([this, 'access', _453 => _453.remoteVideoStatisticsListener, 'optionalCall', _454 => _454(void 0)]);
6911
+ _optionalChain([this, 'access', _497 => _497.remoteVideoStatisticsListener, 'optionalCall', _498 => _498(void 0)]);
6624
6912
  try {
6625
6913
  this.remoteStreamListener(null);
6626
6914
  } catch (error) {
@@ -7084,7 +7372,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
7084
7372
  }
7085
7373
  throw _RealtimeCoordinator.cancelledError();
7086
7374
  }
7087
- const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access', _455 => _455.termination, 'optionalAccess', _456 => _456.task]))), async () => ( await this.requestTermination(
7375
+ const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access', _499 => _499.termination, 'optionalAccess', _500 => _500.task]))), async () => ( await this.requestTermination(
7088
7376
  _nullishCoalesce(operation.lease.failureScope, () => ( 0)) /* connection */,
7089
7377
  void 0,
7090
7378
  RealtimeReason.normal,
@@ -7213,7 +7501,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
7213
7501
  * 结束指定操作,释放操作准入场。
7214
7502
  */
7215
7503
  finish(operation) {
7216
- if (_optionalChain([this, 'access', _457 => _457.activeOperation, 'optionalAccess', _458 => _458.id]) === operation.id) {
7504
+ if (_optionalChain([this, 'access', _501 => _501.activeOperation, 'optionalAccess', _502 => _502.id]) === operation.id) {
7217
7505
  this.activeOperation = void 0;
7218
7506
  }
7219
7507
  }
@@ -7225,7 +7513,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
7225
7513
  return;
7226
7514
  }
7227
7515
  this.state = nextState;
7228
- _optionalChain([this, 'access', _459 => _459.stateListener, 'optionalCall', _460 => _460(nextState)]);
7516
+ _optionalChain([this, 'access', _503 => _503.stateListener, 'optionalCall', _504 => _504(nextState)]);
7229
7517
  }
7230
7518
  /**
7231
7519
  * 构造统一的操作取消错误。
@@ -7362,7 +7650,7 @@ var RealtimeLaunchTimer = class {
7362
7650
  */
7363
7651
  notify() {
7364
7652
  try {
7365
- void Promise.resolve(_optionalChain([this, 'access', _461 => _461.listener, 'optionalCall', _462 => _462(this.snapshot)])).catch(() => {
7653
+ void Promise.resolve(_optionalChain([this, 'access', _505 => _505.listener, 'optionalCall', _506 => _506(this.snapshot)])).catch(() => {
7366
7654
  });
7367
7655
  } catch (e26) {
7368
7656
  }
@@ -7394,7 +7682,7 @@ var XmaxRealtimeConnectionManager = class {
7394
7682
  * 当前活动会话标识;尚未连接或清理完成后为空。
7395
7683
  */
7396
7684
  get currentSessionID() {
7397
- return _optionalChain([this, 'access', _463 => _463.activeSession, 'optionalAccess', _464 => _464.id]);
7685
+ return _optionalChain([this, 'access', _507 => _507.activeSession, 'optionalAccess', _508 => _508.id]);
7398
7686
  }
7399
7687
  /**
7400
7688
  * 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
@@ -7406,6 +7694,16 @@ var XmaxRealtimeConnectionManager = class {
7406
7694
  * 创建会话、配置编码、进房并发布本地媒体,启动心跳后返回远端占位流。
7407
7695
  * 进房结束即记录连接耗时;可选 beforePublish 检查阻塞发布,计入连接耗时;
7408
7696
  * 发布本地流单独计时。
7697
+ * @param options.localTrack 当前本地媒体轨道。
7698
+ * @param options.remoteVideoFormat 原始生成及远端画面规格,缺省使用本地轨道规格。
7699
+ * @param options.localVideoFormat 发布前实际应用的上行编码格式;与原始生成及远端格式分开。
7700
+ * @param options.onVideoEncoderConfigured 上行编码配置成功后的回调。
7701
+ * @param options.model 创建业务会话使用的模型名称。
7702
+ * @param options.includeLocalAudio 是否发布本地音频。
7703
+ * @param options.ensureCurrent 校验当前操作仍有效。
7704
+ * @param options.onPublished 本地发布完成后的回调。
7705
+ * @param options.beforePublish 发布前的可选异步检查。
7706
+ * @param options.publishLocalMedia 是否发布本地媒体,默认 true;网络视频源传 false。
7409
7707
  * @throws 会话、进房、发布失败或操作租约已失效时抛出错误,由上层统一清理。
7410
7708
  */
7411
7709
  async connect(options) {
@@ -7439,7 +7737,7 @@ var XmaxRealtimeConnectionManager = class {
7439
7737
  if (publishLocalMedia) {
7440
7738
  await streamController.updateUplinkVideoFormat(videoFormat);
7441
7739
  options.ensureCurrent();
7442
- _optionalChain([options, 'access', _465 => _465.onVideoEncoderConfigured, 'optionalCall', _466 => _466()]);
7740
+ _optionalChain([options, 'access', _509 => _509.onVideoEncoderConfigured, 'optionalCall', _510 => _510()]);
7443
7741
  }
7444
7742
  options.ensureCurrent();
7445
7743
  let completePublish;
@@ -7447,13 +7745,13 @@ var XmaxRealtimeConnectionManager = class {
7447
7745
  options.ensureCurrent();
7448
7746
  }, async () => {
7449
7747
  options.ensureCurrent();
7450
- await _optionalChain([options, 'access', _467 => _467.beforePublish, 'optionalCall', _468 => _468()]);
7748
+ await _optionalChain([options, 'access', _511 => _511.beforePublish, 'optionalCall', _512 => _512()]);
7451
7749
  completeConnection();
7452
7750
  completePublish = this.dependencies.timing.startPublish();
7453
7751
  }, publishLocalMedia);
7454
7752
  options.ensureCurrent();
7455
7753
  completeConnection();
7456
- _optionalChain([completePublish, 'optionalCall', _469 => _469()]);
7754
+ _optionalChain([completePublish, 'optionalCall', _513 => _513()]);
7457
7755
  options.onPublished();
7458
7756
  sessionService.startHeartbeat(session.id, {
7459
7757
  onFailure: (sessionID, error) => {
@@ -7476,24 +7774,24 @@ var XmaxRealtimeConnectionManager = class {
7476
7774
  * 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
7477
7775
  */
7478
7776
  setFrameInterpolation(options) {
7479
- _optionalChain([this, 'access', _470 => _470.remoteTarget, 'optionalAccess', _471 => _471.setFrameInterpolation, 'optionalCall', _472 => _472(options)]);
7777
+ _optionalChain([this, 'access', _514 => _514.remoteTarget, 'optionalAccess', _515 => _515.setFrameInterpolation, 'optionalCall', _516 => _516(options)]);
7480
7778
  }
7481
7779
  /**
7482
7780
  * 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
7483
7781
  */
7484
7782
  clearRemoteMedia() {
7485
- _optionalChain([this, 'access', _473 => _473.remoteTarget, 'optionalAccess', _474 => _474.setMediaStream, 'call', _475 => _475(null)]);
7783
+ _optionalChain([this, 'access', _517 => _517.remoteTarget, 'optionalAccess', _518 => _518.setMediaStream, 'call', _519 => _519(null)]);
7486
7784
  }
7487
7785
  /**
7488
7786
  * 停止会话心跳;未配置会话服务时不执行操作。
7489
7787
  */
7490
7788
  stopHeartbeat() {
7491
7789
  this.refreshVersion++;
7492
- _optionalChain([this, 'access', _476 => _476.credentialController, 'optionalAccess', _477 => _477.abort, 'call', _478 => _478()]);
7790
+ _optionalChain([this, 'access', _520 => _520.credentialController, 'optionalAccess', _521 => _521.abort, 'call', _522 => _522()]);
7493
7791
  this.credentialController = void 0;
7494
7792
  this.credentialRefresh = void 0;
7495
7793
  this.credentialApplication = Promise.resolve();
7496
- _optionalChain([this, 'access', _479 => _479.dependencies, 'access', _480 => _480.sessionService, 'optionalAccess', _481 => _481.stopHeartbeat, 'call', _482 => _482()]);
7794
+ _optionalChain([this, 'access', _523 => _523.dependencies, 'access', _524 => _524.sessionService, 'optionalAccess', _525 => _525.stopHeartbeat, 'call', _526 => _526()]);
7497
7795
  }
7498
7796
  /**
7499
7797
  * RTC Token 过期时复用会话心跳获取新凭据,并合并同一实例的并发请求。
@@ -7501,14 +7799,14 @@ var XmaxRealtimeConnectionManager = class {
7501
7799
  async refreshCredentials() {
7502
7800
  if (this.credentialRefresh) return this.credentialRefresh;
7503
7801
  const current = this.activeSession;
7504
- if (!_optionalChain([current, 'optionalAccess', _483 => _483.connection]) || current.connection.provider === "trtc" /* trtc */) return;
7802
+ if (!_optionalChain([current, 'optionalAccess', _527 => _527.connection]) || current.connection.provider === "trtc" /* trtc */) return;
7505
7803
  const version = this.refreshVersion;
7506
7804
  const operation = (async () => {
7507
7805
  try {
7508
7806
  const session = await this.requireSessionService().heartbeatSession(current.id);
7509
7807
  await this.handleSessionRefresh(session, version, true);
7510
7808
  } catch (error) {
7511
- if (version === this.refreshVersion && _optionalChain([this, 'access', _484 => _484.activeSession, 'optionalAccess', _485 => _485.id]) === current.id) {
7809
+ if (version === this.refreshVersion && _optionalChain([this, 'access', _528 => _528.activeSession, 'optionalAccess', _529 => _529.id]) === current.id) {
7512
7810
  this.dependencies.onHeartbeatFailure(current.id, XmaxError.from(error));
7513
7811
  }
7514
7812
  }
@@ -7525,7 +7823,7 @@ var XmaxRealtimeConnectionManager = class {
7525
7823
  */
7526
7824
  async waitUntilRemoteTrackReady(timeoutMs, signal) {
7527
7825
  if (signal.aborted) throw RealtimeCoordinator.cancelledError();
7528
- const mediaTrack = _optionalChain([this, 'access', _486 => _486.activeRemoteTrack, 'optionalAccess', _487 => _487.mediaStreamTrack]);
7826
+ const mediaTrack = _optionalChain([this, 'access', _530 => _530.activeRemoteTrack, 'optionalAccess', _531 => _531.mediaStreamTrack]);
7529
7827
  if (!mediaTrack || !mediaTrack.muted) return;
7530
7828
  await new Promise((resolve, reject) => {
7531
7829
  const cleanup = () => {
@@ -7562,7 +7860,7 @@ var XmaxRealtimeConnectionManager = class {
7562
7860
  if (track) {
7563
7861
  track.mediaStreamTrack = void 0;
7564
7862
  }
7565
- _optionalChain([this, 'access', _488 => _488.remoteTarget, 'optionalAccess', _489 => _489.setMediaStream, 'call', _490 => _490(null)]);
7863
+ _optionalChain([this, 'access', _532 => _532.remoteTarget, 'optionalAccess', _533 => _533.setMediaStream, 'call', _534 => _534(null)]);
7566
7864
  return;
7567
7865
  }
7568
7866
  if (!track) {
@@ -7572,7 +7870,7 @@ var XmaxRealtimeConnectionManager = class {
7572
7870
  );
7573
7871
  }
7574
7872
  track.mediaStreamTrack = binding.videoTrack;
7575
- _optionalChain([this, 'access', _491 => _491.remoteTarget, 'optionalAccess', _492 => _492.setMediaStream, 'call', _493 => _493(new MediaStream([binding.videoTrack]))]);
7873
+ _optionalChain([this, 'access', _535 => _535.remoteTarget, 'optionalAccess', _536 => _536.setMediaStream, 'call', _537 => _537(new MediaStream([binding.videoTrack]))]);
7576
7874
  }
7577
7875
  /**
7578
7876
  * 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
@@ -7585,7 +7883,7 @@ var XmaxRealtimeConnectionManager = class {
7585
7883
  }
7586
7884
  },
7587
7885
  attachHandler: (view) => {
7588
- _optionalChain([this, 'access', _494 => _494.remoteTarget, 'optionalAccess', _495 => _495.setFrameInterpolation, 'optionalCall', _496 => _496(void 0)]);
7886
+ _optionalChain([this, 'access', _538 => _538.remoteTarget, 'optionalAccess', _539 => _539.setFrameInterpolation, 'optionalCall', _540 => _540(void 0)]);
7589
7887
  view.isMirrored = false;
7590
7888
  this.remoteTarget = view;
7591
7889
  this.dependencies.onRenderAttached();
@@ -7597,7 +7895,7 @@ var XmaxRealtimeConnectionManager = class {
7597
7895
  this.dependencies.onRenderDetached();
7598
7896
  this.remoteTarget = void 0;
7599
7897
  }
7600
- _optionalChain([view, 'access', _497 => _497.setFrameInterpolation, 'optionalCall', _498 => _498(void 0)]);
7898
+ _optionalChain([view, 'access', _541 => _541.setFrameInterpolation, 'optionalCall', _542 => _542(void 0)]);
7601
7899
  view.setMediaStream(null);
7602
7900
  }
7603
7901
  });
@@ -7647,7 +7945,7 @@ var XmaxRealtimeConnectionManager = class {
7647
7945
  return;
7648
7946
  }
7649
7947
  if (next.provider !== "trtc" /* trtc */ && (force || !previous || previous.provider === "trtc" /* trtc */ || next.roomToken !== previous.roomToken)) {
7650
- await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access', _499 => _499.credentialController, 'optionalAccess', _500 => _500.signal]));
7948
+ await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access', _543 => _543.credentialController, 'optionalAccess', _544 => _544.signal]));
7651
7949
  if (version !== this.refreshVersion || this.activeSession !== current) return;
7652
7950
  }
7653
7951
  this.activeSession = new RealtimeSession({
@@ -7662,7 +7960,7 @@ var XmaxRealtimeConnectionManager = class {
7662
7960
  * 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
7663
7961
  */
7664
7962
  async disconnect() {
7665
- const sessionID = _optionalChain([this, 'access', _501 => _501.activeSession, 'optionalAccess', _502 => _502.id]);
7963
+ const sessionID = _optionalChain([this, 'access', _545 => _545.activeSession, 'optionalAccess', _546 => _546.id]);
7666
7964
  this.stopHeartbeat();
7667
7965
  this.clearRemoteMedia();
7668
7966
  try {
@@ -7734,6 +8032,15 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7734
8032
  /**
7735
8033
  * 发送生成指令并等待确认、远端就绪和音频激活,成功后返回任务标识。
7736
8034
  * 条件上下文在生成确认后缓存;启动失败时尽力停止本次任务并保留原始错误。
8035
+ * @param options.videoFormat 模型生成使用的视频规格。
8036
+ * @param options.targetSize 服务端生成后的回传尺寸,缺省使用生成尺寸。
8037
+ * @param options.context 生成条件,缺省复用最近缓存的上下文。
8038
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
8039
+ * @param options.mirror 是否由后端水平翻转输入,默认 false;仅用于 start 信令。
8040
+ * @param options.signal 取消本次生成启动的信号。
8041
+ * @param options.ensureCurrent 校验当前操作仍有效。
8042
+ * @param options.waitUntilRemoteReady 等待远端生成流就绪。
8043
+ * @param options.onStartSent start 信令发送成功后的可选异步回调。
7737
8044
  */
7738
8045
  async start(options) {
7739
8046
  const context = this.validateContext(options.context);
@@ -7747,6 +8054,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7747
8054
  context,
7748
8055
  ...options.targetSize && { targetSize: options.targetSize },
7749
8056
  mirror: _nullishCoalesce(options.mirror, () => ( false)),
8057
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
7750
8058
  ...options.onStartSent && { onStartSent: options.onStartSent }
7751
8059
  });
7752
8060
  await this.awaitConfirmation(confirmation, options.signal);
@@ -7764,6 +8072,11 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7764
8072
  }
7765
8073
  /**
7766
8074
  * 更新活动任务的生成条件;信令发送成功后才覆盖缓存,无任务或上下文时抛错。
8075
+ * @param taskID 当前活动任务标识。
8076
+ * @param options.videoFormat 模型生成使用的视频规格。
8077
+ * @param options.targetSize 服务端生成后的回传尺寸。
8078
+ * @param options.context 生成条件,缺省复用最近缓存的上下文。
8079
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
7767
8080
  */
7768
8081
  async update(taskID, options) {
7769
8082
  const context = _nullishCoalesce(options.context, () => ( this.currentContext));
@@ -7774,6 +8087,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7774
8087
  taskID,
7775
8088
  videoFormat: options.videoFormat,
7776
8089
  context,
8090
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
7777
8091
  ...options.targetSize && { targetSize: options.targetSize }
7778
8092
  });
7779
8093
  if (this.activeTaskID !== taskID) throw RealtimeCoordinator.cancelledError();
@@ -7800,7 +8114,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7800
8114
  try {
7801
8115
  await completion;
7802
8116
  } finally {
7803
- if (_optionalChain([this, 'access', _503 => _503.pendingStop, 'optionalAccess', _504 => _504.completion]) === completion) this.pendingStop = void 0;
8117
+ if (_optionalChain([this, 'access', _547 => _547.pendingStop, 'optionalAccess', _548 => _548.completion]) === completion) this.pendingStop = void 0;
7804
8118
  }
7805
8119
  }
7806
8120
  /**
@@ -7885,6 +8199,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
7885
8199
  __publicField(this, "localVideoController", new LocalVideoController((error) => {
7886
8200
  void this.coordinator.terminateWithError(error, 0 /* connection */);
7887
8201
  }));
8202
+ __publicField(this, "externalVideoController", new ExternalVideoController((error) => {
8203
+ void this.coordinator.terminateWithError(error, 1 /* all */);
8204
+ }));
7888
8205
  __publicField(this, "rtcManager");
7889
8206
  /**
7890
8207
  * 启动计时与首帧通知
@@ -7927,19 +8244,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
7927
8244
  this.options = options;
7928
8245
  this.mediaService = new MediaService(options.model);
7929
8246
  this.interpolationRequested = options.isFrameInterpolationEnabled;
7930
- this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _505 => _505.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
8247
+ this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _549 => _549.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
7931
8248
  this.errorHandler = new RealtimeErrorHandler();
7932
- const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _506 => _506.rtcManager]), () => ( createRtcManager(options.provider, _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _507 => _507.environment]), () => ( "china")) /* china */)));
8249
+ const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _550 => _550.rtcManager]), () => ( createRtcManager(options.provider, _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _551 => _551.environment]), () => ( "china")) /* china */)));
7933
8250
  this.rtcManager = rtcManager;
7934
- this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _508 => _508.cameraController]), () => ( new CameraController({
8251
+ this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _552 => _552.cameraController]), () => ( new CameraController({
7935
8252
  rtcManager,
7936
8253
  mediaService: this.mediaService,
7937
8254
  errorListener: (error) => {
7938
8255
  void this.errorHandler.report(error);
7939
8256
  }
7940
8257
  })));
7941
- const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _509 => _509.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _510 => _510.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService, provider: options.provider }) : void 0)));
7942
- this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _511 => _511.streamController]), () => ( new StreamController({
8258
+ const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _553 => _553.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _554 => _554.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService, provider: options.provider }) : void 0)));
8259
+ this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _555 => _555.streamController]), () => ( new StreamController({
7943
8260
  rtcManager,
7944
8261
  onCredentialsRequired: () => {
7945
8262
  void this.connectionManager.refreshCredentials();
@@ -7961,7 +8278,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
7961
8278
  onHeartbeatFailure: (sessionID, error) => {
7962
8279
  void this.handleHeartbeatFailure(sessionID, error);
7963
8280
  },
7964
- onFrameDisplayed: () => _optionalChain([this, 'access', _512 => _512.remoteFrameDisplayHandler, 'optionalCall', _513 => _513()]),
8281
+ onFrameDisplayed: () => _optionalChain([this, 'access', _556 => _556.remoteFrameDisplayHandler, 'optionalCall', _557 => _557()]),
7965
8282
  onRenderAttached: () => this.applyRemoteInterpolation(),
7966
8283
  onRenderDetached: () => {
7967
8284
  this.interpolationRevision++;
@@ -7979,7 +8296,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
7979
8296
  throw new XmaxError("CANCELLED" /* cancelled */, "Adaptive video format update was cancelled");
7980
8297
  }
7981
8298
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
7982
- const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
8299
+ const track = this.currentUplinkTrack;
7983
8300
  const state2 = track && this.qualityStates.get(track);
7984
8301
  if (!track || !state2) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Adaptive video baseline is unavailable");
7985
8302
  const format = qualityVideoFormat(state2.baseline, change.to);
@@ -7988,7 +8305,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
7988
8305
  _nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = state2.baseline)));
7989
8306
  track.updateVideoFormat(format);
7990
8307
  state2.level = change.to;
7991
- _optionalChain([this, 'access', _514 => _514.qualityHistory, 'optionalAccess', _515 => _515.write, 'call', _516 => _516("uplink", change.to)]);
8308
+ _optionalChain([this, 'access', _558 => _558.qualityHistory, 'optionalAccess', _559 => _559.write, 'call', _560 => _560("uplink", change.to)]);
7992
8309
  });
7993
8310
  });
7994
8311
  this.downlinkQualityController = new QualityController(async (change, signal) => {
@@ -8034,7 +8351,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8034
8351
  */
8035
8352
  async setFrameInterpolationEnabled(enabled) {
8036
8353
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
8037
- const format = _nullishCoalesce(_nullishCoalesce(_optionalChain([this, 'access', _517 => _517.downlinkQualityState, 'optionalAccess', _518 => _518.size]), () => ( this.generationVideoFormat)), () => ( _optionalChain([this, 'access', _519 => _519.currentLocalTrack, 'optionalAccess', _520 => _520.videoFormat])));
8354
+ const format = _nullishCoalesce(_nullishCoalesce(_optionalChain([this, 'access', _561 => _561.downlinkQualityState, 'optionalAccess', _562 => _562.size]), () => ( this.generationVideoFormat)), () => ( _optionalChain([this, 'access', _563 => _563.currentLocalTrack, 'optionalAccess', _564 => _564.videoFormat])));
8038
8355
  const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
8039
8356
  if (enabled && !await this.checkInterpolationSupport(size, token)) {
8040
8357
  token.ensureCurrent();
@@ -8066,7 +8383,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8066
8383
  const state2 = this.downlinkQualityState;
8067
8384
  const ensureActive2 = () => {
8068
8385
  token.ensureCurrent();
8069
- if (_optionalChain([signal, 'optionalAccess', _521 => _521.aborted]) || !state2 || state2 !== this.downlinkQualityState || this.currentState.connectionState !== "Generating" /* generating */ || this.currentState.taskID !== state2.taskID) {
8386
+ if (_optionalChain([signal, 'optionalAccess', _565 => _565.aborted]) || !state2 || state2 !== this.downlinkQualityState || this.currentState.connectionState !== "Generating" /* generating */ || this.currentState.taskID !== state2.taskID) {
8070
8387
  throw new XmaxError("CANCELLED" /* cancelled */, "Target size update was cancelled");
8071
8388
  }
8072
8389
  };
@@ -8077,7 +8394,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8077
8394
  ensureActive2();
8078
8395
  state2.level = level;
8079
8396
  state2.size = size;
8080
- _optionalChain([this, 'access', _522 => _522.qualityHistory, 'optionalAccess', _523 => _523.write, 'call', _524 => _524("downlink", level)]);
8397
+ _optionalChain([this, 'access', _566 => _566.qualityHistory, 'optionalAccess', _567 => _567.write, 'call', _568 => _568("downlink", level)]);
8081
8398
  if (this.interpolationRequested) {
8082
8399
  this.interpolationSize = size;
8083
8400
  this.applyRemoteInterpolation();
@@ -8196,7 +8513,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8196
8513
  */
8197
8514
  notifyRemoteVideoStatistics() {
8198
8515
  try {
8199
- void Promise.resolve(_optionalChain([this, 'access', _525 => _525.remoteVideoStatisticsListener, 'optionalCall', _526 => _526(this.remoteVideoStatistics)])).catch(() => {
8516
+ void Promise.resolve(_optionalChain([this, 'access', _569 => _569.remoteVideoStatisticsListener, 'optionalCall', _570 => _570(this.remoteVideoStatistics)])).catch(() => {
8200
8517
  });
8201
8518
  } catch (e27) {
8202
8519
  }
@@ -8213,7 +8530,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8213
8530
  */
8214
8531
  notifyNetworkStatistics() {
8215
8532
  try {
8216
- void Promise.resolve(_optionalChain([this, 'access', _527 => _527.networkStatisticsListener, 'optionalCall', _528 => _528(this.networkStatistics)])).catch(() => {
8533
+ void Promise.resolve(_optionalChain([this, 'access', _571 => _571.networkStatisticsListener, 'optionalCall', _572 => _572(this.networkStatistics)])).catch(() => {
8217
8534
  });
8218
8535
  } catch (e28) {
8219
8536
  }
@@ -8233,7 +8550,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8233
8550
  */
8234
8551
  notifyLocalVideoStatistics() {
8235
8552
  try {
8236
- void Promise.resolve(_optionalChain([this, 'access', _529 => _529.localVideoStatisticsListener, 'optionalCall', _530 => _530(this.localVideoStatistics)])).catch(() => {
8553
+ void Promise.resolve(_optionalChain([this, 'access', _573 => _573.localVideoStatisticsListener, 'optionalCall', _574 => _574(this.localVideoStatistics)])).catch(() => {
8237
8554
  });
8238
8555
  } catch (e29) {
8239
8556
  }
@@ -8242,8 +8559,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8242
8559
  * 停止接收媒体统计并清空各类快照,仅对曾有数据的统计发出清空通知。
8243
8560
  */
8244
8561
  clearVideoStatistics() {
8245
- _optionalChain([this, 'access', _531 => _531.qualityController, 'optionalAccess', _532 => _532.stop, 'call', _533 => _533()]);
8246
- _optionalChain([this, 'access', _534 => _534.downlinkQualityController, 'optionalAccess', _535 => _535.stop, 'call', _536 => _536()]);
8562
+ _optionalChain([this, 'access', _575 => _575.qualityController, 'optionalAccess', _576 => _576.stop, 'call', _577 => _577()]);
8563
+ _optionalChain([this, 'access', _578 => _578.downlinkQualityController, 'optionalAccess', _579 => _579.stop, 'call', _580 => _580()]);
8247
8564
  this.downlinkQualityState = void 0;
8248
8565
  this.adaptiveQualityRevision++;
8249
8566
  this.acceptsVideoStatistics = false;
@@ -8291,7 +8608,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8291
8608
  *
8292
8609
  * 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
8293
8610
  *
8611
+ * @param options.videoFormat 旋转后的目标规格,尺寸按模型规则解析。
8612
+ * @param options.position 前置或后置摄像头。
8613
+ * @param options.useMicrophone 是否采集并发布麦克风音频。
8294
8614
  * @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
8615
+ * @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
8295
8616
  * @returns 包含本地相机视频轨道的媒体流。
8296
8617
  * @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
8297
8618
  */
@@ -8311,7 +8632,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8311
8632
  const completeCamera = this.launchTimer.startCamera();
8312
8633
  this.clearVideoStatistics();
8313
8634
  this.disposePermissionWatch();
8314
- const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _537 => _537.useMicrophone]), () => ( false)));
8635
+ const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _581 => _581.useMicrophone]), () => ( false)));
8315
8636
  if (permissionWatch) {
8316
8637
  const completePermission = this.launchTimer.startPermission();
8317
8638
  void permissionWatch.decided.then(() => completePermission()).catch(() => {
@@ -8328,7 +8649,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8328
8649
  throw error;
8329
8650
  }
8330
8651
  token.ensureCurrent();
8331
- this.generationVideoFormat = _optionalChain([stream, 'access', _538 => _538.videoTrack, 'optionalAccess', _539 => _539.videoFormat]);
8652
+ this.generationVideoFormat = _optionalChain([stream, 'access', _582 => _582.videoTrack, 'optionalAccess', _583 => _583.videoFormat]);
8332
8653
  completeCamera();
8333
8654
  this.cameraController.setPreviewReadyHandler((isCurrent) => {
8334
8655
  void this.coordinator.localPreviewDidBecomeReady(isCurrent);
@@ -8339,6 +8660,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8339
8660
  }
8340
8661
  /**
8341
8662
  * 创建网络视频源并初始化接收端 RTC;预览是否加载成功不影响服务端读取视频。
8663
+ * @param options.url 服务端可直接访问的 HTTP/HTTPS 视频地址。
8664
+ * @param options.videoFormat 模型输入及生成画面规格,不是上行编码参数。
8665
+ * @param options.sampleMethod 服务端采样方式,默认 time。
8666
+ * @param options.onFinish 服务端完成当前任务后的回调,不代表尾帧已播放完。
8342
8667
  */
8343
8668
  async createNetworkVideoStream(options) {
8344
8669
  return this.coordinator.run("media" /* media */, void 0, async (token) => {
@@ -8349,13 +8674,17 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8349
8674
  this.clearVideoStatistics();
8350
8675
  await this.rtcManager.initialize();
8351
8676
  token.ensureCurrent();
8352
- this.generationVideoFormat = _optionalChain([stream, 'access', _540 => _540.videoTrack, 'optionalAccess', _541 => _541.videoFormat]);
8677
+ this.generationVideoFormat = _optionalChain([stream, 'access', _584 => _584.videoTrack, 'optionalAccess', _585 => _585.videoFormat]);
8353
8678
  await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
8354
8679
  return stream;
8355
8680
  });
8356
8681
  }
8357
8682
  /**
8358
8683
  * 创建文件音视频源并准备外部轨道;准备失败时统一释放本次媒体和 RTC 资源。
8684
+ * @param options.file 包含可解码视频的本地 File 或 Blob。
8685
+ * @param options.videoFormat 期望的视频规格;尺寸按宽高比匹配模型档位。
8686
+ * @param options.loop 是否循环播放,默认 true。
8687
+ * @param options.includeAudio 是否发送文件音频,默认 true。
8359
8688
  */
8360
8689
  async createLocalVideoStream(options) {
8361
8690
  return this.coordinator.run("media" /* media */, void 0, async (token) => {
@@ -8375,16 +8704,42 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8375
8704
  audioTrack: this.localVideoController.audioTrack
8376
8705
  });
8377
8706
  token.ensureCurrent();
8378
- this.generationVideoFormat = _optionalChain([stream, 'access', _542 => _542.videoTrack, 'optionalAccess', _543 => _543.videoFormat]);
8707
+ this.generationVideoFormat = _optionalChain([stream, 'access', _586 => _586.videoTrack, 'optionalAccess', _587 => _587.videoFormat]);
8379
8708
  await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
8380
8709
  return stream;
8381
8710
  });
8382
8711
  }
8383
8712
  /**
8384
- * 当前 Manager 拥有的媒体源轨道。
8713
+ * 接入外部视频轨;不创建采集设备或预览,所有异步失败统一释放 SDK 副本。
8714
+ * @param options.videoTrack 用户自行采集或处理的 live 视频轨,原始轨道归调用方所有。
8715
+ * @param options.videoFormat 期望的上传及生成规格,须符合模型规则;不代表修改输入像素。
8385
8716
  */
8717
+ async createExternalVideoStream(options) {
8718
+ return this.coordinator.run("media" /* media */, void 0, async (token) => {
8719
+ this.ensureNoLocalSource();
8720
+ if (!this.rtcManager.setExternalMediaTracks) {
8721
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "The RTC provider does not support external video streams");
8722
+ }
8723
+ const stream = this.externalVideoController.create(options, this.mediaService);
8724
+ token.setFailureScope(1 /* all */);
8725
+ this.launchTimer.start();
8726
+ this.clearVideoStatistics();
8727
+ await this.rtcManager.initialize();
8728
+ token.ensureCurrent();
8729
+ await this.rtcManager.setExternalMediaTracks({ videoTrack: stream.videoTrack.mediaStreamTrack });
8730
+ token.ensureCurrent();
8731
+ this.generationVideoFormat = _optionalChain([stream, 'access', _588 => _588.videoTrack, 'optionalAccess', _589 => _589.videoFormat]);
8732
+ await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
8733
+ return stream;
8734
+ });
8735
+ }
8736
+ /** 当前可发布的本地视频轨,不包含服务端直接读取的网络视频。 */
8737
+ get currentUplinkTrack() {
8738
+ return _nullishCoalesce(_nullishCoalesce(this.externalVideoController.currentTrack, () => ( this.localVideoController.currentTrack)), () => ( this.cameraController.currentTrack));
8739
+ }
8740
+ /** 当前 Manager 拥有的媒体源轨道。 */
8386
8741
  get currentLocalTrack() {
8387
- return _nullishCoalesce(_nullishCoalesce(this.localVideoController.currentTrack, () => ( this.networkVideoController.currentTrack)), () => ( this.cameraController.currentTrack));
8742
+ return _nullishCoalesce(this.currentUplinkTrack, () => ( this.networkVideoController.currentTrack));
8388
8743
  }
8389
8744
  /**
8390
8745
  * 创建前拒绝覆盖活动源,避免旧预览或连接资源被静默遗留。
@@ -8398,51 +8753,51 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8398
8753
  * 移除媒体权限弹窗观察;授权决定已记录或不再需要观察时调用。
8399
8754
  */
8400
8755
  disposePermissionWatch() {
8401
- _optionalChain([this, 'access', _544 => _544.permissionWatchDispose, 'optionalCall', _545 => _545()]);
8756
+ _optionalChain([this, 'access', _590 => _590.permissionWatchDispose, 'optionalCall', _591 => _591()]);
8402
8757
  this.permissionWatchDispose = void 0;
8403
8758
  }
8404
8759
  /**
8405
8760
  * 应用完整的上行视频格式,成功后更新本地轨道元数据,不改变生成格式或生命周期。
8406
8761
  * 复用配置操作准入,避免与建连、切换摄像头或其他配置更新并发。
8407
8762
  *
8408
- * @throws 无本地相机或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
8763
+ * @throws 无本地相机、外部或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
8409
8764
  */
8410
8765
  async updateUplinkVideoFormat(videoFormat) {
8411
8766
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
8412
- const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
8413
- const previousFormat = _optionalChain([track, 'optionalAccess', _546 => _546.videoFormat]);
8767
+ const track = this.currentUplinkTrack;
8768
+ const previousFormat = _optionalChain([track, 'optionalAccess', _592 => _592.videoFormat]);
8414
8769
  if (!track || !previousFormat) {
8415
- throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local camera or file video stream is not started");
8770
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local camera, external or file video stream is not started");
8416
8771
  }
8417
8772
  videoFormat.validate();
8418
- _optionalChain([this, 'access', _547 => _547.qualityController, 'optionalAccess', _548 => _548.stop, 'call', _549 => _549()]);
8773
+ _optionalChain([this, 'access', _593 => _593.qualityController, 'optionalAccess', _594 => _594.stop, 'call', _595 => _595()]);
8419
8774
  await this.streamController.updateUplinkVideoFormat(videoFormat);
8420
8775
  token.ensureCurrent();
8421
8776
  _nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = previousFormat)));
8422
8777
  track.updateVideoFormat(videoFormat);
8423
8778
  this.qualityStates.set(track, { baseline: videoFormat, level: 1 });
8424
- _optionalChain([this, 'access', _550 => _550.qualityHistory, 'optionalAccess', _551 => _551.write, 'call', _552 => _552("uplink", 1)]);
8779
+ _optionalChain([this, 'access', _596 => _596.qualityHistory, 'optionalAccess', _597 => _597.write, 'call', _598 => _598("uplink", 1)]);
8425
8780
  });
8426
8781
  }
8427
8782
  /** 已连接时仅替换帧率;与其他配置及生命周期操作共享同一操作租约。 */
8428
8783
  async updateUplinkFrameRate(fps) {
8429
8784
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
8430
- _optionalChain([this, 'access', _553 => _553.qualityController, 'optionalAccess', _554 => _554.stop, 'call', _555 => _555()]);
8785
+ _optionalChain([this, 'access', _599 => _599.qualityController, 'optionalAccess', _600 => _600.stop, 'call', _601 => _601()]);
8431
8786
  await this.applyUplinkFrameRate(fps, token);
8432
8787
  const track = this.currentLocalTrack;
8433
- if (_optionalChain([track, 'optionalAccess', _556 => _556.videoFormat])) {
8788
+ if (_optionalChain([track, 'optionalAccess', _602 => _602.videoFormat])) {
8434
8789
  this.qualityStates.set(track, { baseline: track.videoFormat, level: 1 });
8435
- _optionalChain([this, 'access', _557 => _557.qualityHistory, 'optionalAccess', _558 => _558.write, 'call', _559 => _559("uplink", 1)]);
8790
+ _optionalChain([this, 'access', _603 => _603.qualityHistory, 'optionalAccess', _604 => _604.write, 'call', _605 => _605("uplink", 1)]);
8436
8791
  }
8437
8792
  });
8438
8793
  }
8439
8794
  /** 手动仅调帧接口,成功后的当前格式将成为新的自适应 L1 基准。 */
8440
8795
  async applyUplinkFrameRate(fps, token) {
8441
- const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
8442
- const previous = _optionalChain([track, 'optionalAccess', _560 => _560.videoFormat]);
8796
+ const track = this.currentUplinkTrack;
8797
+ const previous = _optionalChain([track, 'optionalAccess', _606 => _606.videoFormat]);
8443
8798
  const state2 = this.currentState.connectionState;
8444
8799
  if (!track || !previous || state2 !== "Connected" /* connected */ && state2 !== "Generating" /* generating */) {
8445
- throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Frame rate updates require a connected local camera or file stream");
8800
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Frame rate updates require a connected local camera, external or file stream");
8446
8801
  }
8447
8802
  if (!Number.isFinite(fps) || fps <= 0) {
8448
8803
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Video frame rate must be greater than zero");
@@ -8469,7 +8824,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8469
8824
  downlink.resetSamples();
8470
8825
  return;
8471
8826
  }
8472
- const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
8827
+ const track = this.currentUplinkTrack;
8473
8828
  if (!track) {
8474
8829
  controller.stop();
8475
8830
  } else if (!controller.snapshot.active) {
@@ -8501,7 +8856,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8501
8856
  * 停止本地相机流并释放本地预览与 RTC 资源。
8502
8857
  */
8503
8858
  async stopLocalCameraStream() {
8504
- if (this.networkVideoController.currentTrack || this.localVideoController.isActive) {
8859
+ if (this.networkVideoController.currentTrack || this.localVideoController.isActive || this.externalVideoController.currentTrack) {
8505
8860
  return;
8506
8861
  }
8507
8862
  await this.coordinator.run(
@@ -8534,7 +8889,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8534
8889
  "cameraSwitch" /* cameraSwitch */,
8535
8890
  void 0,
8536
8891
  async (token) => {
8537
- _optionalChain([this, 'access', _561 => _561.qualityController, 'optionalAccess', _562 => _562.stop, 'call', _563 => _563()]);
8892
+ if (this.externalVideoController.currentTrack) {
8893
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External video capture is managed by the caller");
8894
+ }
8895
+ _optionalChain([this, 'access', _607 => _607.qualityController, 'optionalAccess', _608 => _608.stop, 'call', _609 => _609()]);
8538
8896
  const stream = await this.cameraController.switchCamera();
8539
8897
  token.ensureCurrent();
8540
8898
  return stream;
@@ -8548,7 +8906,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8548
8906
  * 启用帧检测时,发布前并行等待相机预热(固定 200ms),避免把黑帧推给 RTC。
8549
8907
  * 返回的远端媒体流在生成开始后承载远端生成画面。
8550
8908
  *
8551
- * @param localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
8909
+ * @param localStream 由当前 Manager 创建的摄像头、外部视频轨、本地文件或网络视频源。
8552
8910
  * @returns 远端生成结果占位的媒体流。
8553
8911
  * @throws 本地流不属于当前 Manager、已有活动连接、会话创建或进房
8554
8912
  * 发布失败时抛出错误;失败时自动释放连接资源并恢复本地预览。
@@ -8575,8 +8933,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8575
8933
  * 尚未连接时先建立实时连接;已在生成时仅更新生成条件,不重启生成。
8576
8934
  * 首次生成必须提供条件上下文,之后缺省时复用最近一次缓存的上下文。
8577
8935
  *
8578
- * @param options.localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
8936
+ * @param options.localStream 由当前 Manager 创建的摄像头、外部视频轨、本地文件或网络视频源。
8579
8937
  * @param options.context 本次生成使用的条件上下文;缺省时复用缓存。
8938
+ * @param options.faceRestoration 是否启用原始人脸回贴,默认 false;正在生成时通过 change_condition 更新。
8580
8939
  * @returns 承载远端生成画面的媒体流。
8581
8940
  * @throws 本地流不属于当前 Manager、缺少可用的条件上下文、信令发送
8582
8941
  * 或生成确认失败时抛出错误;失败时自动停止生成任务并释放连接资源。
@@ -8604,7 +8963,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8604
8963
  if (currentState.connectionState === "Generating" /* generating */) {
8605
8964
  await this.generationManager.update(currentState.taskID, {
8606
8965
  videoFormat,
8607
- targetSize: this.downlinkQualityController ? _optionalChain([this, 'access', _564 => _564.downlinkQualityState, 'optionalAccess', _565 => _565.size]) : void 0,
8966
+ faceRestoration: _nullishCoalesce(options.faceRestoration, () => ( false)),
8967
+ targetSize: this.downlinkQualityController ? _optionalChain([this, 'access', _610 => _610.downlinkQualityState, 'optionalAccess', _611 => _611.size]) : void 0,
8608
8968
  context: options.context
8609
8969
  });
8610
8970
  token.ensureCurrent();
@@ -8619,7 +8979,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8619
8979
  if (currentState.connectionState !== "Connected" /* connected */) {
8620
8980
  await this.performConnect(options.localStream, token);
8621
8981
  }
8622
- return this.performStartGeneration(token, videoFormat, context);
8982
+ return this.performStartGeneration(token, videoFormat, context, _nullishCoalesce(options.faceRestoration, () => ( false)));
8623
8983
  }
8624
8984
  );
8625
8985
  }
@@ -8678,7 +9038,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8678
9038
  if (token.signal.aborted) abortWarmup();
8679
9039
  try {
8680
9040
  let beforePublish;
8681
- if (!this.localVideoController.isActive && !this.networkVideoController.currentTrack && this.cameraController.isFrameValidationEnabled) {
9041
+ if (localTrack === this.cameraController.currentTrack && this.cameraController.isFrameValidationEnabled) {
8682
9042
  const cameraReady = this.cameraController.waitForValidCameraFrame(warmupController.signal).then(() => {
8683
9043
  token.ensureCurrent();
8684
9044
  });
@@ -8697,10 +9057,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8697
9057
  _nullishCoalesce(this.generationVideoFormat, () => ( (this.generationVideoFormat = initialQuality.baseline)));
8698
9058
  localTrack.updateVideoFormat(initialFormat);
8699
9059
  this.qualityStates.set(localTrack, initialQuality);
8700
- _optionalChain([this, 'access', _566 => _566.qualityHistory, 'optionalAccess', _567 => _567.write, 'call', _568 => _568("uplink", initialQuality.level)]);
9060
+ _optionalChain([this, 'access', _612 => _612.qualityHistory, 'optionalAccess', _613 => _613.write, 'call', _614 => _614("uplink", initialQuality.level)]);
8701
9061
  },
8702
9062
  model: this.options.model,
8703
- includeLocalAudio: this.localVideoController.isActive ? this.localVideoController.audioTrack !== void 0 : !this.networkVideoController.currentTrack && this.cameraController.useMicrophone,
9063
+ includeLocalAudio: this.localVideoController.isActive ? this.localVideoController.audioTrack !== void 0 : localTrack === this.cameraController.currentTrack && this.cameraController.useMicrophone,
8704
9064
  publishLocalMedia: !this.networkVideoController.currentTrack,
8705
9065
  ensureCurrent: () => token.ensureCurrent(),
8706
9066
  onPublished: () => {
@@ -8724,9 +9084,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8724
9084
  /**
8725
9085
  * 编排插帧、首帧计时和生成状态,任务与确认由生成管理器负责。
8726
9086
  */
8727
- async performStartGeneration(token, videoFormat, context) {
9087
+ async performStartGeneration(token, videoFormat, context, faceRestoration) {
8728
9088
  token.setFailureScope(0 /* connection */);
8729
- const initialLevel = _nullishCoalesce(_optionalChain([this, 'access', _569 => _569.qualityHistory, 'optionalAccess', _570 => _570.read, 'call', _571 => _571("downlink")]), () => ( 1));
9089
+ const initialLevel = _nullishCoalesce(_optionalChain([this, 'access', _615 => _615.qualityHistory, 'optionalAccess', _616 => _616.read, 'call', _617 => _617("downlink")]), () => ( 1));
8730
9090
  const targetSize = this.downlinkQualityController ? qualityVideoSize(videoFormat, initialLevel) : void 0;
8731
9091
  await this.prepareFrameInterpolation(_nullishCoalesce(targetSize, () => ( videoFormat)), token);
8732
9092
  const completeFirstFrame = this.launchTimer.startFirstFrame();
@@ -8737,7 +9097,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8737
9097
  videoFormat,
8738
9098
  targetSize,
8739
9099
  context,
8740
- mirror: this.currentLocalTrack === this.cameraController.currentTrack && _optionalChain([this, 'access', _572 => _572.cameraController, 'access', _573 => _573.currentTrack, 'optionalAccess', _574 => _574.position]) === "front" /* front */,
9100
+ faceRestoration,
9101
+ mirror: this.currentLocalTrack === this.cameraController.currentTrack && _optionalChain([this, 'access', _618 => _618.cameraController, 'access', _619 => _619.currentTrack, 'optionalAccess', _620 => _620.position]) === "front" /* front */,
8741
9102
  signal: token.signal,
8742
9103
  ensureCurrent: () => token.ensureCurrent(),
8743
9104
  onStartSent: this.localVideoController.isActive ? async () => {
@@ -8754,7 +9115,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8754
9115
  if (!sessionID) {
8755
9116
  throw new XmaxError("SESSION_ERROR" /* sessionError */, "Realtime session is unavailable");
8756
9117
  }
8757
- _optionalChain([this, 'access', _575 => _575.downlinkQualityController, 'optionalAccess', _576 => _576.stop, 'call', _577 => _577()]);
9118
+ _optionalChain([this, 'access', _621 => _621.downlinkQualityController, 'optionalAccess', _622 => _622.stop, 'call', _623 => _623()]);
8758
9119
  this.downlinkQualityState = {
8759
9120
  taskID,
8760
9121
  baseline: videoFormat,
@@ -8765,7 +9126,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8765
9126
  new RealtimeState({ connectionState: "Generating" /* generating */, sessionID, taskID }),
8766
9127
  token
8767
9128
  );
8768
- _optionalChain([this, 'access', _578 => _578.qualityHistory, 'optionalAccess', _579 => _579.write, 'call', _580 => _580("downlink", initialLevel)]);
9129
+ _optionalChain([this, 'access', _624 => _624.qualityHistory, 'optionalAccess', _625 => _625.write, 'call', _626 => _626("downlink", initialLevel)]);
8769
9130
  const onFinish = this.networkVideoController.onFinish;
8770
9131
  if (this.networkVideoController.currentTrack) {
8771
9132
  this.streamController.activateNetworkVideoCompletion(onFinish && (() => {
@@ -8801,12 +9162,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8801
9162
  await this.generationManager.reset(taskID);
8802
9163
  const sessionID = await this.connectionManager.disconnect();
8803
9164
  if (scope === 1 /* all */) {
8804
- const hadFileSource = this.networkVideoController.currentTrack !== void 0 || this.localVideoController.isActive;
9165
+ const hadExternalSource = this.networkVideoController.currentTrack !== void 0 || this.localVideoController.isActive || this.externalVideoController.currentTrack !== void 0;
8805
9166
  this.networkVideoController.stop();
8806
9167
  this.generationVideoFormat = void 0;
8807
9168
  this.disposePermissionWatch();
8808
9169
  try {
8809
- if (hadFileSource) {
9170
+ if (hadExternalSource) {
8810
9171
  await this.rtcManager.destroy();
8811
9172
  } else {
8812
9173
  await this.cameraController.stopLocalCameraStream();
@@ -8817,6 +9178,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8817
9178
  \u2514\u2500 ${XmaxLogger.localized("\u539F\u56E0\uFF1A", "Reason: ")}${XmaxError.from(error).message}`
8818
9179
  );
8819
9180
  } finally {
9181
+ this.externalVideoController.stop();
8820
9182
  if (this.localVideoController.isActive) {
8821
9183
  await this.localVideoController.stop();
8822
9184
  }
@@ -8917,7 +9279,7 @@ var NonRealtimeTaskService = class {
8917
9279
  * 提交一次任务;请求结果不确定时也不自动重试,以免重复扣费。
8918
9280
  */
8919
9281
  async submitTask(options) {
8920
- const model = _optionalChain([options, 'access', _581 => _581.model, 'optionalAccess', _582 => _582.trim, 'call', _583 => _583()]);
9282
+ const model = _optionalChain([options, 'access', _627 => _627.model, 'optionalAccess', _628 => _628.trim, 'call', _629 => _629()]);
8921
9283
  if (!model) {
8922
9284
  invalid("Model must not be empty");
8923
9285
  }
@@ -9057,7 +9419,7 @@ function parseTask(value) {
9057
9419
  const uid = field(data, "uid", "string");
9058
9420
  const status = field(data, "status", "string");
9059
9421
  const quality = field(data, "quality", "string");
9060
- if (!_optionalChain([uid, 'optionalAccess', _584 => _584.trim, 'call', _585 => _585()]) || !Object.values(NonRealtimeTaskStatus).includes(status)) {
9422
+ if (!_optionalChain([uid, 'optionalAccess', _630 => _630.trim, 'call', _631 => _631()]) || !Object.values(NonRealtimeTaskStatus).includes(status)) {
9061
9423
  malformed("Missing task UID or invalid status");
9062
9424
  }
9063
9425
  if (quality !== void 0 && !Object.values(NonRealtimeQuality).includes(quality)) {
@@ -9139,7 +9501,7 @@ var XmaxNonRealtimeManager = class {
9139
9501
  * 取得任务快照,不把服务端失败终态当成查询失败。
9140
9502
  */
9141
9503
  getTask(taskUid, options) {
9142
- return this.tasks.getTask(taskUid, _optionalChain([options, 'optionalAccess', _586 => _586.signal]));
9504
+ return this.tasks.getTask(taskUid, _optionalChain([options, 'optionalAccess', _632 => _632.signal]));
9143
9505
  }
9144
9506
  /**
9145
9507
  * 批量取得任务快照。
@@ -9173,8 +9535,8 @@ var XmaxNonRealtimeManager = class {
9173
9535
  const controller = new AbortController();
9174
9536
  let timedOut = false;
9175
9537
  const abort = () => controller.abort();
9176
- _optionalChain([options, 'access', _587 => _587.signal, 'optionalAccess', _588 => _588.addEventListener, 'call', _589 => _589("abort", abort, { once: true })]);
9177
- if (_optionalChain([options, 'access', _590 => _590.signal, 'optionalAccess', _591 => _591.aborted])) {
9538
+ _optionalChain([options, 'access', _633 => _633.signal, 'optionalAccess', _634 => _634.addEventListener, 'call', _635 => _635("abort", abort, { once: true })]);
9539
+ if (_optionalChain([options, 'access', _636 => _636.signal, 'optionalAccess', _637 => _637.aborted])) {
9178
9540
  abort();
9179
9541
  }
9180
9542
  const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
@@ -9200,7 +9562,7 @@ var XmaxNonRealtimeManager = class {
9200
9562
  ensureActive(controller.signal);
9201
9563
  failures = 0;
9202
9564
  try {
9203
- void Promise.resolve(_optionalChain([options, 'access', _592 => _592.onTaskUpdated, 'optionalCall', _593 => _593(task)])).catch(() => {
9565
+ void Promise.resolve(_optionalChain([options, 'access', _638 => _638.onTaskUpdated, 'optionalCall', _639 => _639(task)])).catch(() => {
9204
9566
  });
9205
9567
  } catch (e31) {
9206
9568
  }
@@ -9230,7 +9592,7 @@ var XmaxNonRealtimeManager = class {
9230
9592
  throw error;
9231
9593
  } finally {
9232
9594
  clearTimeout(timer);
9233
- _optionalChain([options, 'access', _594 => _594.signal, 'optionalAccess', _595 => _595.removeEventListener, 'call', _596 => _596("abort", abort)]);
9595
+ _optionalChain([options, 'access', _640 => _640.signal, 'optionalAccess', _641 => _641.removeEventListener, 'call', _642 => _642("abort", abort)]);
9234
9596
  }
9235
9597
  }
9236
9598
  };
@@ -9274,7 +9636,7 @@ function isTransient(error) {
9274
9636
  }
9275
9637
  function isResultAvailable(task) {
9276
9638
  const result = task.result;
9277
- if (!_optionalChain([result, 'optionalAccess', _597 => _597.url, 'optionalAccess', _598 => _598.trim, 'call', _599 => _599()]) || _optionalChain([result, 'access', _600 => _600.uploadError, 'optionalAccess', _601 => _601.trim, 'call', _602 => _602()]) || result.uploadStatus !== void 0 && result.uploadStatus !== "success") {
9639
+ if (!_optionalChain([result, 'optionalAccess', _643 => _643.url, 'optionalAccess', _644 => _644.trim, 'call', _645 => _645()]) || _optionalChain([result, 'access', _646 => _646.uploadError, 'optionalAccess', _647 => _647.trim, 'call', _648 => _648()]) || result.uploadStatus !== void 0 && result.uploadStatus !== "success") {
9278
9640
  return false;
9279
9641
  }
9280
9642
  try {
@@ -9538,7 +9900,7 @@ var RenderStatisticsController = class {
9538
9900
  */
9539
9901
  notify(statistics) {
9540
9902
  try {
9541
- _optionalChain([this, 'access', _603 => _603.handler, 'optionalCall', _604 => _604(statistics)]);
9903
+ _optionalChain([this, 'access', _649 => _649.handler, 'optionalCall', _650 => _650(statistics)]);
9542
9904
  } catch (e33) {
9543
9905
  }
9544
9906
  }
@@ -11666,11 +12028,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
11666
12028
  if (this.destroyed) return;
11667
12029
  this.destroyed = true;
11668
12030
  this.device.removeEventListener("uncapturederror", this.onGPUError);
11669
- _optionalChain([this, 'access', _605 => _605.runtime, 'optionalAccess', _606 => _606.destroy, 'call', _607 => _607()]);
12031
+ _optionalChain([this, 'access', _651 => _651.runtime, 'optionalAccess', _652 => _652.destroy, 'call', _653 => _653()]);
11670
12032
  this.runtime = void 0;
11671
12033
  this.textures.forEach((texture) => texture.destroy());
11672
12034
  this.textures = [];
11673
- _optionalChain([this, 'access', _608 => _608.context, 'optionalAccess', _609 => _609.unconfigure, 'call', _610 => _610()]);
12035
+ _optionalChain([this, 'access', _654 => _654.context, 'optionalAccess', _655 => _655.unconfigure, 'call', _656 => _656()]);
11674
12036
  this.device.destroy();
11675
12037
  }
11676
12038
  };
@@ -11847,7 +12209,7 @@ var RemoteVideoFramePipeline = class {
11847
12209
  this.displayedTime = frame.time;
11848
12210
  this.canvas.style.visibility = "visible";
11849
12211
  this.setActive(true);
11850
- _optionalChain([this, 'access', _611 => _611.options, 'access', _612 => _612.onFramePresented, 'optionalCall', _613 => _613(_nullishCoalesce(frame.interpolated, () => ( false)))]);
12212
+ _optionalChain([this, 'access', _657 => _657.options, 'access', _658 => _658.onFramePresented, 'optionalCall', _659 => _659(_nullishCoalesce(frame.interpolated, () => ( false)))]);
11851
12213
  }
11852
12214
  async initialize() {
11853
12215
  this.loading = true;
@@ -11875,7 +12237,7 @@ var RemoteVideoFramePipeline = class {
11875
12237
  setActive(active) {
11876
12238
  if (active === this.active) return;
11877
12239
  this.active = active;
11878
- _optionalChain([this, 'access', _614 => _614.options, 'access', _615 => _615.onActiveChange, 'optionalCall', _616 => _616(active)]);
12240
+ _optionalChain([this, 'access', _660 => _660.options, 'access', _661 => _661.onActiveChange, 'optionalCall', _662 => _662(active)]);
11879
12241
  }
11880
12242
  resetTimeline(preserveGpuTimeout = false) {
11881
12243
  this.generation++;
@@ -11908,7 +12270,7 @@ var RemoteVideoFramePipeline = class {
11908
12270
  this.callback = void 0;
11909
12271
  clearTimeout(this.initializationTimer);
11910
12272
  this.resetTimeline();
11911
- _optionalChain([this, 'access', _617 => _617.processor, 'optionalAccess', _618 => _618.destroy, 'call', _619 => _619()]);
12273
+ _optionalChain([this, 'access', _663 => _663.processor, 'optionalAccess', _664 => _664.destroy, 'call', _665 => _665()]);
11912
12274
  this.processor = void 0;
11913
12275
  }
11914
12276
  };
@@ -11970,7 +12332,7 @@ var XmaxVideoView = class {
11970
12332
  * DOM 挂载状态
11971
12333
  */
11972
12334
  __publicField(this, "detached", false);
11973
- this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _620 => _620.videoContentMode]), () => ( "fill")) /* fill */;
12335
+ this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _666 => _666.videoContentMode]), () => ( "fill")) /* fill */;
11974
12336
  this.element = document.createElement("div");
11975
12337
  this.element.style.position = "relative";
11976
12338
  this.element.style.overflow = "hidden";
@@ -12155,11 +12517,11 @@ var XmaxVideoView = class {
12155
12517
  ...options,
12156
12518
  onActiveChange: (active) => {
12157
12519
  this.statisticsController.setInterpolationActive(active);
12158
- _optionalChain([options, 'access', _621 => _621.onActiveChange, 'optionalCall', _622 => _622(active)]);
12520
+ _optionalChain([options, 'access', _667 => _667.onActiveChange, 'optionalCall', _668 => _668(active)]);
12159
12521
  },
12160
12522
  onFramePresented: (interpolated) => {
12161
12523
  this.statisticsController.recordCanvasFrame(interpolated);
12162
- _optionalChain([options, 'access', _623 => _623.onFramePresented, 'optionalCall', _624 => _624(interpolated)]);
12524
+ _optionalChain([options, 'access', _669 => _669.onFramePresented, 'optionalCall', _670 => _670(interpolated)]);
12163
12525
  }
12164
12526
  });
12165
12527
  this.interpolationPipeline = pipeline;
@@ -12171,8 +12533,8 @@ var XmaxVideoView = class {
12171
12533
  stopInterpolation() {
12172
12534
  const pipeline = this.interpolationPipeline;
12173
12535
  this.interpolationPipeline = void 0;
12174
- _optionalChain([pipeline, 'optionalAccess', _625 => _625.stop, 'call', _626 => _626()]);
12175
- _optionalChain([this, 'access', _627 => _627.interpolationCanvas, 'optionalAccess', _628 => _628.remove, 'call', _629 => _629()]);
12536
+ _optionalChain([pipeline, 'optionalAccess', _671 => _671.stop, 'call', _672 => _672()]);
12537
+ _optionalChain([this, 'access', _673 => _673.interpolationCanvas, 'optionalAccess', _674 => _674.remove, 'call', _675 => _675()]);
12176
12538
  this.interpolationCanvas = void 0;
12177
12539
  }
12178
12540
  /**
@@ -12199,7 +12561,7 @@ var XmaxVideoView = class {
12199
12561
  this.statisticsController.stop();
12200
12562
  const track = this.currentTrack;
12201
12563
  if (track) {
12202
- _optionalChain([VideoRenderRegistry, 'access', _630 => _630.binding, 'call', _631 => _631(track), 'optionalAccess', _632 => _632.detachHandler, 'call', _633 => _633(this)]);
12564
+ _optionalChain([VideoRenderRegistry, 'access', _676 => _676.binding, 'call', _677 => _677(track), 'optionalAccess', _678 => _678.detachHandler, 'call', _679 => _679(this)]);
12203
12565
  }
12204
12566
  this.setFrameInterpolation(void 0);
12205
12567
  this.cancelFrameDisplayNotification();
@@ -12222,8 +12584,8 @@ var XmaxVideoView = class {
12222
12584
  }
12223
12585
  this.hasNotifiedFrameDisplay = true;
12224
12586
  this.cancelFrameDisplayNotification();
12225
- _optionalChain([binding, 'optionalAccess', _634 => _634.frameDisplayHandler, 'optionalCall', _635 => _635()]);
12226
- _optionalChain([this, 'access', _636 => _636.frameDisplayHandler, 'optionalCall', _637 => _637()]);
12587
+ _optionalChain([binding, 'optionalAccess', _680 => _680.frameDisplayHandler, 'optionalCall', _681 => _681()]);
12588
+ _optionalChain([this, 'access', _682 => _682.frameDisplayHandler, 'optionalCall', _683 => _683()]);
12227
12589
  };
12228
12590
  if (typeof this.videoElement.requestVideoFrameCallback === "function") {
12229
12591
  this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
@@ -12299,9 +12661,9 @@ var XmaxRealtimeVideoView = class {
12299
12661
  __publicField(this, "currentLocalTrack");
12300
12662
  __publicField(this, "currentRemoteTrack");
12301
12663
  __publicField(this, "contentMode");
12302
- this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _638 => _638.videoContentMode]), () => ( "fill")) /* fill */;
12303
- this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _639 => _639.localTrack]);
12304
- this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _640 => _640.remoteTrack]);
12664
+ this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _684 => _684.videoContentMode]), () => ( "fill")) /* fill */;
12665
+ this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _685 => _685.localTrack]);
12666
+ this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _686 => _686.remoteTrack]);
12305
12667
  this.element = document.createElement("div");
12306
12668
  this.element.style.position = "relative";
12307
12669
  this.element.style.overflow = "hidden";
@@ -12467,4 +12829,4 @@ var XmaxRealtimeVideoView = class {
12467
12829
 
12468
12830
 
12469
12831
  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;
12470
- //# sourceMappingURL=chunk-NWNRFTLE.cjs.map
12832
+ //# sourceMappingURL=chunk-24VPU65T.cjs.map