@xmaxai/web-sdk 1.0.7 → 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.7";
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,6 @@ 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
1365
  }
1366
1366
  };
1367
1367
 
@@ -4842,6 +4842,46 @@ var LocalVideoController = class {
4842
4842
  }
4843
4843
  };
4844
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 = this.track?.mediaStreamTrack;
4879
+ this.track = void 0;
4880
+ nativeTrack?.removeEventListener("ended", this.onEnded);
4881
+ nativeTrack?.stop();
4882
+ }
4883
+ };
4884
+
4845
4885
  // src/Service/Realtime/RealtimeContext.ts
4846
4886
  var RealtimeContext = class {
4847
4887
  /**
@@ -5469,6 +5509,7 @@ var RoomEvent = class _RoomEvent {
5469
5509
  static generationParameters(options) {
5470
5510
  return {
5471
5511
  model: "default",
5512
+ face_replace: options.faceRestoration ?? false,
5472
5513
  size: [options.videoFormat.width, options.videoFormat.height],
5473
5514
  target_size: options.targetSize ? [
5474
5515
  Math.round(options.targetSize.width),
@@ -5839,12 +5880,19 @@ var RoomController = class {
5839
5880
  /**
5840
5881
  * 发送生成开始信令。
5841
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 本次生成条件。
5842
5889
  * @throws 房间未就绪或信令发送失败时抛出错误。
5843
5890
  */
5844
5891
  startGeneration(options) {
5845
5892
  return this.send(
5846
5893
  RoomEvent.start({
5847
5894
  mirror: options.mirror ?? false,
5895
+ faceRestoration: options.faceRestoration ?? false,
5848
5896
  userID: this.requireUserID(),
5849
5897
  taskID: options.taskID,
5850
5898
  videoFormat: options.videoFormat,
@@ -5856,11 +5904,17 @@ var RoomController = class {
5856
5904
  /**
5857
5905
  * 发送生成条件变更信令。
5858
5906
  *
5907
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
5908
+ * @param options.taskID 当前生成任务标识。
5909
+ * @param options.videoFormat 模型生成使用的视频规格。
5910
+ * @param options.targetSize 服务端生成后的回传尺寸。
5911
+ * @param options.context 本次生成条件。
5859
5912
  * @throws 房间未就绪或信令发送失败时抛出错误。
5860
5913
  */
5861
5914
  changeGenerationCondition(options) {
5862
5915
  return this.send(
5863
5916
  RoomEvent.changeCondition({
5917
+ faceRestoration: options.faceRestoration ?? false,
5864
5918
  userID: this.requireUserID(),
5865
5919
  taskID: options.taskID,
5866
5920
  videoFormat: options.videoFormat,
@@ -6394,6 +6448,7 @@ var StreamController = class {
6394
6448
  const sending = this.roomController.startGeneration({
6395
6449
  taskID,
6396
6450
  mirror: options.mirror ?? false,
6451
+ faceRestoration: options.faceRestoration ?? false,
6397
6452
  videoFormat: options.videoFormat,
6398
6453
  targetSize: options.targetSize,
6399
6454
  context: options.context
@@ -6454,6 +6509,7 @@ var StreamController = class {
6454
6509
  try {
6455
6510
  await this.roomController.changeGenerationCondition({
6456
6511
  taskID: options.taskID,
6512
+ faceRestoration: options.faceRestoration ?? false,
6457
6513
  videoFormat: options.videoFormat,
6458
6514
  targetSize: options.targetSize,
6459
6515
  context: options.context
@@ -7638,6 +7694,16 @@ var XmaxRealtimeConnectionManager = class {
7638
7694
  * 创建会话、配置编码、进房并发布本地媒体,启动心跳后返回远端占位流。
7639
7695
  * 进房结束即记录连接耗时;可选 beforePublish 检查阻塞发布,计入连接耗时;
7640
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。
7641
7707
  * @throws 会话、进房、发布失败或操作租约已失效时抛出错误,由上层统一清理。
7642
7708
  */
7643
7709
  async connect(options) {
@@ -7966,6 +8032,15 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7966
8032
  /**
7967
8033
  * 发送生成指令并等待确认、远端就绪和音频激活,成功后返回任务标识。
7968
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 信令发送成功后的可选异步回调。
7969
8044
  */
7970
8045
  async start(options) {
7971
8046
  const context = this.validateContext(options.context);
@@ -7979,6 +8054,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7979
8054
  context,
7980
8055
  ...options.targetSize && { targetSize: options.targetSize },
7981
8056
  mirror: options.mirror ?? false,
8057
+ faceRestoration: options.faceRestoration ?? false,
7982
8058
  ...options.onStartSent && { onStartSent: options.onStartSent }
7983
8059
  });
7984
8060
  await this.awaitConfirmation(confirmation, options.signal);
@@ -7996,6 +8072,11 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
7996
8072
  }
7997
8073
  /**
7998
8074
  * 更新活动任务的生成条件;信令发送成功后才覆盖缓存,无任务或上下文时抛错。
8075
+ * @param taskID 当前活动任务标识。
8076
+ * @param options.videoFormat 模型生成使用的视频规格。
8077
+ * @param options.targetSize 服务端生成后的回传尺寸。
8078
+ * @param options.context 生成条件,缺省复用最近缓存的上下文。
8079
+ * @param options.faceRestoration 是否回贴原始人脸,默认 false。
7999
8080
  */
8000
8081
  async update(taskID, options) {
8001
8082
  const context = options.context ?? this.currentContext;
@@ -8006,6 +8087,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
8006
8087
  taskID,
8007
8088
  videoFormat: options.videoFormat,
8008
8089
  context,
8090
+ faceRestoration: options.faceRestoration ?? false,
8009
8091
  ...options.targetSize && { targetSize: options.targetSize }
8010
8092
  });
8011
8093
  if (this.activeTaskID !== taskID) throw RealtimeCoordinator.cancelledError();
@@ -8117,6 +8199,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8117
8199
  __publicField(this, "localVideoController", new LocalVideoController((error) => {
8118
8200
  void this.coordinator.terminateWithError(error, 0 /* connection */);
8119
8201
  }));
8202
+ __publicField(this, "externalVideoController", new ExternalVideoController((error) => {
8203
+ void this.coordinator.terminateWithError(error, 1 /* all */);
8204
+ }));
8120
8205
  __publicField(this, "rtcManager");
8121
8206
  /**
8122
8207
  * 启动计时与首帧通知
@@ -8211,7 +8296,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8211
8296
  throw new XmaxError("CANCELLED" /* cancelled */, "Adaptive video format update was cancelled");
8212
8297
  }
8213
8298
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
8214
- const track = this.localVideoController.currentTrack ?? this.cameraController.currentTrack;
8299
+ const track = this.currentUplinkTrack;
8215
8300
  const state2 = track && this.qualityStates.get(track);
8216
8301
  if (!track || !state2) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Adaptive video baseline is unavailable");
8217
8302
  const format = qualityVideoFormat(state2.baseline, change.to);
@@ -8523,6 +8608,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8523
8608
  *
8524
8609
  * 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
8525
8610
  *
8611
+ * @param options.videoFormat 旋转后的目标规格,尺寸按模型规则解析。
8612
+ * @param options.position 前置或后置摄像头。
8613
+ * @param options.useMicrophone 是否采集并发布麦克风音频。
8526
8614
  * @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
8527
8615
  * @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
8528
8616
  * @returns 包含本地相机视频轨道的媒体流。
@@ -8572,6 +8660,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8572
8660
  }
8573
8661
  /**
8574
8662
  * 创建网络视频源并初始化接收端 RTC;预览是否加载成功不影响服务端读取视频。
8663
+ * @param options.url 服务端可直接访问的 HTTP/HTTPS 视频地址。
8664
+ * @param options.videoFormat 模型输入及生成画面规格,不是上行编码参数。
8665
+ * @param options.sampleMethod 服务端采样方式,默认 time。
8666
+ * @param options.onFinish 服务端完成当前任务后的回调,不代表尾帧已播放完。
8575
8667
  */
8576
8668
  async createNetworkVideoStream(options) {
8577
8669
  return this.coordinator.run("media" /* media */, void 0, async (token) => {
@@ -8589,6 +8681,10 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8589
8681
  }
8590
8682
  /**
8591
8683
  * 创建文件音视频源并准备外部轨道;准备失败时统一释放本次媒体和 RTC 资源。
8684
+ * @param options.file 包含可解码视频的本地 File 或 Blob。
8685
+ * @param options.videoFormat 期望的视频规格;尺寸按宽高比匹配模型档位。
8686
+ * @param options.loop 是否循环播放,默认 true。
8687
+ * @param options.includeAudio 是否发送文件音频,默认 true。
8592
8688
  */
8593
8689
  async createLocalVideoStream(options) {
8594
8690
  return this.coordinator.run("media" /* media */, void 0, async (token) => {
@@ -8614,10 +8710,36 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8614
8710
  });
8615
8711
  }
8616
8712
  /**
8617
- * 当前 Manager 拥有的媒体源轨道。
8713
+ * 接入外部视频轨;不创建采集设备或预览,所有异步失败统一释放 SDK 副本。
8714
+ * @param options.videoTrack 用户自行采集或处理的 live 视频轨,原始轨道归调用方所有。
8715
+ * @param options.videoFormat 期望的上传及生成规格,须符合模型规则;不代表修改输入像素。
8618
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 = stream.videoTrack?.videoFormat;
8732
+ await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
8733
+ return stream;
8734
+ });
8735
+ }
8736
+ /** 当前可发布的本地视频轨,不包含服务端直接读取的网络视频。 */
8737
+ get currentUplinkTrack() {
8738
+ return this.externalVideoController.currentTrack ?? this.localVideoController.currentTrack ?? this.cameraController.currentTrack;
8739
+ }
8740
+ /** 当前 Manager 拥有的媒体源轨道。 */
8619
8741
  get currentLocalTrack() {
8620
- return this.localVideoController.currentTrack ?? this.networkVideoController.currentTrack ?? this.cameraController.currentTrack;
8742
+ return this.currentUplinkTrack ?? this.networkVideoController.currentTrack;
8621
8743
  }
8622
8744
  /**
8623
8745
  * 创建前拒绝覆盖活动源,避免旧预览或连接资源被静默遗留。
@@ -8638,14 +8760,14 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8638
8760
  * 应用完整的上行视频格式,成功后更新本地轨道元数据,不改变生成格式或生命周期。
8639
8761
  * 复用配置操作准入,避免与建连、切换摄像头或其他配置更新并发。
8640
8762
  *
8641
- * @throws 无本地相机或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
8763
+ * @throws 无本地相机、外部或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
8642
8764
  */
8643
8765
  async updateUplinkVideoFormat(videoFormat) {
8644
8766
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
8645
- const track = this.localVideoController.currentTrack ?? this.cameraController.currentTrack;
8767
+ const track = this.currentUplinkTrack;
8646
8768
  const previousFormat = track?.videoFormat;
8647
8769
  if (!track || !previousFormat) {
8648
- 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");
8649
8771
  }
8650
8772
  videoFormat.validate();
8651
8773
  this.qualityController?.stop();
@@ -8671,11 +8793,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8671
8793
  }
8672
8794
  /** 手动仅调帧接口,成功后的当前格式将成为新的自适应 L1 基准。 */
8673
8795
  async applyUplinkFrameRate(fps, token) {
8674
- const track = this.localVideoController.currentTrack ?? this.cameraController.currentTrack;
8796
+ const track = this.currentUplinkTrack;
8675
8797
  const previous = track?.videoFormat;
8676
8798
  const state2 = this.currentState.connectionState;
8677
8799
  if (!track || !previous || state2 !== "Connected" /* connected */ && state2 !== "Generating" /* generating */) {
8678
- throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Frame rate updates require a connected local camera or file stream");
8800
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Frame rate updates require a connected local camera, external or file stream");
8679
8801
  }
8680
8802
  if (!Number.isFinite(fps) || fps <= 0) {
8681
8803
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Video frame rate must be greater than zero");
@@ -8702,7 +8824,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8702
8824
  downlink.resetSamples();
8703
8825
  return;
8704
8826
  }
8705
- const track = this.localVideoController.currentTrack ?? this.cameraController.currentTrack;
8827
+ const track = this.currentUplinkTrack;
8706
8828
  if (!track) {
8707
8829
  controller.stop();
8708
8830
  } else if (!controller.snapshot.active) {
@@ -8734,7 +8856,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8734
8856
  * 停止本地相机流并释放本地预览与 RTC 资源。
8735
8857
  */
8736
8858
  async stopLocalCameraStream() {
8737
- if (this.networkVideoController.currentTrack || this.localVideoController.isActive) {
8859
+ if (this.networkVideoController.currentTrack || this.localVideoController.isActive || this.externalVideoController.currentTrack) {
8738
8860
  return;
8739
8861
  }
8740
8862
  await this.coordinator.run(
@@ -8767,6 +8889,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8767
8889
  "cameraSwitch" /* cameraSwitch */,
8768
8890
  void 0,
8769
8891
  async (token) => {
8892
+ if (this.externalVideoController.currentTrack) {
8893
+ throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External video capture is managed by the caller");
8894
+ }
8770
8895
  this.qualityController?.stop();
8771
8896
  const stream = await this.cameraController.switchCamera();
8772
8897
  token.ensureCurrent();
@@ -8781,7 +8906,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8781
8906
  * 启用帧检测时,发布前并行等待相机预热(固定 200ms),避免把黑帧推给 RTC。
8782
8907
  * 返回的远端媒体流在生成开始后承载远端生成画面。
8783
8908
  *
8784
- * @param localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
8909
+ * @param localStream 由当前 Manager 创建的摄像头、外部视频轨、本地文件或网络视频源。
8785
8910
  * @returns 远端生成结果占位的媒体流。
8786
8911
  * @throws 本地流不属于当前 Manager、已有活动连接、会话创建或进房
8787
8912
  * 发布失败时抛出错误;失败时自动释放连接资源并恢复本地预览。
@@ -8808,8 +8933,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8808
8933
  * 尚未连接时先建立实时连接;已在生成时仅更新生成条件,不重启生成。
8809
8934
  * 首次生成必须提供条件上下文,之后缺省时复用最近一次缓存的上下文。
8810
8935
  *
8811
- * @param options.localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
8936
+ * @param options.localStream 由当前 Manager 创建的摄像头、外部视频轨、本地文件或网络视频源。
8812
8937
  * @param options.context 本次生成使用的条件上下文;缺省时复用缓存。
8938
+ * @param options.faceRestoration 是否启用原始人脸回贴,默认 false;正在生成时通过 change_condition 更新。
8813
8939
  * @returns 承载远端生成画面的媒体流。
8814
8940
  * @throws 本地流不属于当前 Manager、缺少可用的条件上下文、信令发送
8815
8941
  * 或生成确认失败时抛出错误;失败时自动停止生成任务并释放连接资源。
@@ -8837,6 +8963,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8837
8963
  if (currentState.connectionState === "Generating" /* generating */) {
8838
8964
  await this.generationManager.update(currentState.taskID, {
8839
8965
  videoFormat,
8966
+ faceRestoration: options.faceRestoration ?? false,
8840
8967
  targetSize: this.downlinkQualityController ? this.downlinkQualityState?.size : void 0,
8841
8968
  context: options.context
8842
8969
  });
@@ -8852,7 +8979,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8852
8979
  if (currentState.connectionState !== "Connected" /* connected */) {
8853
8980
  await this.performConnect(options.localStream, token);
8854
8981
  }
8855
- return this.performStartGeneration(token, videoFormat, context);
8982
+ return this.performStartGeneration(token, videoFormat, context, options.faceRestoration ?? false);
8856
8983
  }
8857
8984
  );
8858
8985
  }
@@ -8911,7 +9038,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8911
9038
  if (token.signal.aborted) abortWarmup();
8912
9039
  try {
8913
9040
  let beforePublish;
8914
- if (!this.localVideoController.isActive && !this.networkVideoController.currentTrack && this.cameraController.isFrameValidationEnabled) {
9041
+ if (localTrack === this.cameraController.currentTrack && this.cameraController.isFrameValidationEnabled) {
8915
9042
  const cameraReady = this.cameraController.waitForValidCameraFrame(warmupController.signal).then(() => {
8916
9043
  token.ensureCurrent();
8917
9044
  });
@@ -8933,7 +9060,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8933
9060
  this.qualityHistory?.write("uplink", initialQuality.level);
8934
9061
  },
8935
9062
  model: this.options.model,
8936
- 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,
8937
9064
  publishLocalMedia: !this.networkVideoController.currentTrack,
8938
9065
  ensureCurrent: () => token.ensureCurrent(),
8939
9066
  onPublished: () => {
@@ -8957,7 +9084,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8957
9084
  /**
8958
9085
  * 编排插帧、首帧计时和生成状态,任务与确认由生成管理器负责。
8959
9086
  */
8960
- async performStartGeneration(token, videoFormat, context) {
9087
+ async performStartGeneration(token, videoFormat, context, faceRestoration) {
8961
9088
  token.setFailureScope(0 /* connection */);
8962
9089
  const initialLevel = this.qualityHistory?.read("downlink") ?? 1;
8963
9090
  const targetSize = this.downlinkQualityController ? qualityVideoSize(videoFormat, initialLevel) : void 0;
@@ -8970,6 +9097,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
8970
9097
  videoFormat,
8971
9098
  targetSize,
8972
9099
  context,
9100
+ faceRestoration,
8973
9101
  mirror: this.currentLocalTrack === this.cameraController.currentTrack && this.cameraController.currentTrack?.position === "front" /* front */,
8974
9102
  signal: token.signal,
8975
9103
  ensureCurrent: () => token.ensureCurrent(),
@@ -9034,12 +9162,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
9034
9162
  await this.generationManager.reset(taskID);
9035
9163
  const sessionID = await this.connectionManager.disconnect();
9036
9164
  if (scope === 1 /* all */) {
9037
- 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;
9038
9166
  this.networkVideoController.stop();
9039
9167
  this.generationVideoFormat = void 0;
9040
9168
  this.disposePermissionWatch();
9041
9169
  try {
9042
- if (hadFileSource) {
9170
+ if (hadExternalSource) {
9043
9171
  await this.rtcManager.destroy();
9044
9172
  } else {
9045
9173
  await this.cameraController.stopLocalCameraStream();
@@ -9050,6 +9178,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
9050
9178
  \u2514\u2500 ${XmaxLogger.localized("\u539F\u56E0\uFF1A", "Reason: ")}${XmaxError.from(error).message}`
9051
9179
  );
9052
9180
  } finally {
9181
+ this.externalVideoController.stop();
9053
9182
  if (this.localVideoController.isActive) {
9054
9183
  await this.localVideoController.stop();
9055
9184
  }
@@ -12700,4 +12829,4 @@ export {
12700
12829
  XmaxVideoView,
12701
12830
  XmaxRealtimeVideoView
12702
12831
  };
12703
- //# sourceMappingURL=chunk-4O5BSMUX.js.map
12832
+ //# sourceMappingURL=chunk-JGDZ3RD3.js.map