@xmaxai/web-sdk 1.0.0 → 1.0.1

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.
@@ -9,7 +9,9 @@ var XmaxEnvironment = /* @__PURE__ */ ((XmaxEnvironment2) => {
9
9
  return XmaxEnvironment2;
10
10
  })(XmaxEnvironment || {});
11
11
  var API_BASE_URLS = {
12
- // 临时联调环境。
12
+ /**
13
+ * 临时联调环境。
14
+ */
13
15
  ["china" /* china */]: "https://dev.xmaxai.com/open/api/v1",
14
16
  ["global" /* global */]: "https://api.xmax.cloud/open/api/v1"
15
17
  };
@@ -38,8 +40,13 @@ var CONSOLE_METHOD = {
38
40
  var BRAND_BADGE_STYLE = "background:#2563eb;color:#fff;border-radius:3px;padding:1px 4px;font-weight:600;";
39
41
  var CATEGORY_BADGE_STYLE = "background:#475569;color:#fff;border-radius:3px;padding:1px 4px;font-weight:600;";
40
42
  var _XmaxLogger = class _XmaxLogger {
43
+ /**
44
+ * 创建固定业务分类的日志入口,共享全局日志选项和语言配置。
45
+ */
41
46
  constructor(category) {
42
- // 日志类别
47
+ /**
48
+ * 日志类别
49
+ */
43
50
  __publicField(this, "category");
44
51
  this.category = category;
45
52
  }
@@ -53,31 +60,45 @@ var _XmaxLogger = class _XmaxLogger {
53
60
  state.options = options;
54
61
  state.environment = environment;
55
62
  }
56
- /** 选择日志细项文案;日志标题保持原有中英双语。 */
63
+ /**
64
+ * 选择日志细项文案;日志标题保持原有中英双语。
65
+ */
57
66
  static localized(chinese, english) {
58
67
  return state.environment === "china" /* china */ ? chinese : english;
59
68
  }
60
- /** 判断指定日志类型是否已开启。 */
69
+ /**
70
+ * 判断指定日志类型是否已开启。
71
+ */
61
72
  static isEnabled(option) {
62
73
  return (state.options & option) !== 0;
63
74
  }
64
- /** 输出调试日志。 */
75
+ /**
76
+ * 输出调试日志。
77
+ */
65
78
  debug(message, option = 1 /* business */) {
66
79
  this.log("debug", message, option);
67
80
  }
68
- /** 输出信息日志。 */
81
+ /**
82
+ * 输出信息日志。
83
+ */
69
84
  info(message, option = 1 /* business */) {
70
85
  this.log("info", message, option);
71
86
  }
72
- /** 输出警告日志。 */
87
+ /**
88
+ * 输出警告日志。
89
+ */
73
90
  warning(message, option = 1 /* business */) {
74
91
  this.log("warning", message, option);
75
92
  }
76
- /** 输出错误日志。 */
93
+ /**
94
+ * 输出错误日志。
95
+ */
77
96
  error(message, option = 1 /* business */) {
78
97
  this.log("error", message, option);
79
98
  }
80
- /** 按日志类型开关输出到控制台;未开启时不求值日志内容。 */
99
+ /**
100
+ * 按日志类型开关输出到控制台;未开启时不求值日志内容。
101
+ */
81
102
  log(level, message, option) {
82
103
  if (!_XmaxLogger.isEnabled(option)) {
83
104
  return;
@@ -98,7 +119,9 @@ var _XmaxLogger = class _XmaxLogger {
98
119
  console[CONSOLE_METHOD[level]](`[Xmax][${this.category}] ${text}`);
99
120
  }
100
121
  };
101
- // 分类日志
122
+ /**
123
+ * 分类日志
124
+ */
102
125
  __publicField(_XmaxLogger, "realtime", new _XmaxLogger("Realtime"));
103
126
  __publicField(_XmaxLogger, "rtc", new _XmaxLogger("RTC"));
104
127
  __publicField(_XmaxLogger, "media", new _XmaxLogger("Media"));
@@ -142,12 +165,20 @@ var XmaxError = class _XmaxError extends Error {
142
165
  */
143
166
  constructor(code, message, options) {
144
167
  super(message);
145
- // 错误信息
146
- /** SDK 统一错误码。 */
168
+ /**
169
+ * 错误信息
170
+ */
171
+ /**
172
+ * SDK 统一错误码。
173
+ */
147
174
  __publicField(this, "code");
148
- /** Xmax API 返回的业务错误码;非 API 业务错误时为空。 */
175
+ /**
176
+ * Xmax API 返回的业务错误码;非 API 业务错误时为空。
177
+ */
149
178
  __publicField(this, "apiCode");
150
- /** HTTP 响应状态码;请求未获得响应时为空。 */
179
+ /**
180
+ * HTTP 响应状态码;请求未获得响应时为空。
181
+ */
151
182
  __publicField(this, "httpStatus");
152
183
  this.name = "XmaxError";
153
184
  this.code = code;
@@ -170,9 +201,11 @@ var XmaxError = class _XmaxError extends Error {
170
201
  };
171
202
 
172
203
  // src/Foundation/Runtime/RuntimeInfo.ts
173
- var XMAX_SDK_VERSION = "1.0.0";
204
+ var XMAX_SDK_VERSION = "1.0.1";
174
205
  var _RuntimeInfo = class _RuntimeInfo {
175
- /** 序列化为接口传输使用的 snake_case 字段。 */
206
+ /**
207
+ * 序列化为接口传输使用的 snake_case 字段。
208
+ */
176
209
  static toJSON(snapshot = _RuntimeInfo.current) {
177
210
  return {
178
211
  platform: snapshot.platform,
@@ -181,7 +214,9 @@ var _RuntimeInfo = class _RuntimeInfo {
181
214
  device_model: snapshot.deviceModel
182
215
  };
183
216
  }
184
- /** 读取浏览器 User-Agent;非浏览器环境返回 unknown。 */
217
+ /**
218
+ * 读取浏览器 User-Agent;非浏览器环境返回 unknown。
219
+ */
185
220
  static currentOSVersion() {
186
221
  if (typeof navigator !== "undefined" && navigator.userAgent) {
187
222
  return navigator.userAgent;
@@ -189,7 +224,12 @@ var _RuntimeInfo = class _RuntimeInfo {
189
224
  return "unknown";
190
225
  }
191
226
  };
192
- /** 当前运行环境快照。 */
227
+ /**
228
+ * 运行环境快照
229
+ */
230
+ /**
231
+ * 当前运行环境快照。
232
+ */
193
233
  __publicField(_RuntimeInfo, "current", {
194
234
  platform: "web",
195
235
  osVersion: _RuntimeInfo.currentOSVersion(),
@@ -209,17 +249,24 @@ var _ApiService = class _ApiService {
209
249
  * @param options.fetchImpl fetch 实现(可替换,测试用)。
210
250
  */
211
251
  constructor(options) {
212
- // 平台资源
252
+ /**
253
+ * 请求身份、地址与超时配置
254
+ */
213
255
  __publicField(this, "apiKey");
214
256
  __publicField(this, "baseURL");
215
257
  __publicField(this, "timeoutMs");
258
+ /**
259
+ * 网络传输依赖
260
+ */
216
261
  __publicField(this, "fetchImpl");
217
262
  this.apiKey = options.apiKey.trim();
218
263
  this.baseURL = options.baseURL;
219
264
  this.timeoutMs = _nullishCoalesce(options.timeoutMs, () => ( _ApiService.defaultTimeoutMs));
220
265
  this.fetchImpl = _nullishCoalesce(options.fetchImpl, () => ( ((url, init) => fetch(url, init))));
221
266
  }
222
- /** 发送请求并返回统一响应中的数据。 */
267
+ /**
268
+ * 发送请求并返回统一响应中的数据。
269
+ */
223
270
  async request(method, path, body) {
224
271
  this.validateConfiguration();
225
272
  const request = this.makeRequest(method, path, body);
@@ -248,23 +295,33 @@ var _ApiService = class _ApiService {
248
295
  throw mapped;
249
296
  }
250
297
  }
251
- /** 发送 GET 请求。 */
298
+ /**
299
+ * 发送 GET 请求。
300
+ */
252
301
  get(path) {
253
302
  return this.request("GET" /* get */, path);
254
303
  }
255
- /** 发送 POST 请求。 */
304
+ /**
305
+ * 发送 POST 请求。
306
+ */
256
307
  post(path, body) {
257
308
  return this.request("POST" /* post */, path, body);
258
309
  }
259
- /** 发送 PUT 请求。 */
310
+ /**
311
+ * 发送 PUT 请求。
312
+ */
260
313
  put(path, body) {
261
314
  return this.request("PUT" /* put */, path, body);
262
315
  }
263
- /** 发送 DELETE 请求。 */
316
+ /**
317
+ * 发送 DELETE 请求。
318
+ */
264
319
  delete(path) {
265
320
  return this.request("DELETE" /* delete */, path);
266
321
  }
267
- /** 校验 API Key 与 Base URL 配置。 */
322
+ /**
323
+ * 校验 API Key 与 Base URL 配置。
324
+ */
268
325
  validateConfiguration() {
269
326
  if (this.apiKey.length === 0) {
270
327
  throw new XmaxError("INVALID_API_KEY" /* invalidAPIKey */, "API key cannot be empty");
@@ -287,7 +344,9 @@ var _ApiService = class _ApiService {
287
344
  );
288
345
  }
289
346
  }
290
- /** 构造请求地址、请求头与请求体;路径必须相对且与 Base URL 同源。 */
347
+ /**
348
+ * 构造请求地址、请求头与请求体;路径必须相对且与 Base URL 同源。
349
+ */
291
350
  makeRequest(method, path, body) {
292
351
  const normalizedPath = path.trim();
293
352
  if (normalizedPath.length === 0 || normalizedPath.includes("://") || normalizedPath.startsWith("//")) {
@@ -333,7 +392,9 @@ var _ApiService = class _ApiService {
333
392
  }
334
393
  };
335
394
  }
336
- /** 解析统一响应信封并返回数据;业务失败或数据缺失时抛出错误。 */
395
+ /**
396
+ * 解析统一响应信封并返回数据;业务失败或数据缺失时抛出错误。
397
+ */
337
398
  static parseResponse(text, status) {
338
399
  let envelope;
339
400
  try {
@@ -348,7 +409,7 @@ var _ApiService = class _ApiService {
348
409
  const message = _optionalChain([envelope, 'access', _4 => _4.message, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]);
349
410
  throw new XmaxError(
350
411
  "API_ERROR" /* apiError */,
351
- message && message.length > 0 ? message : "Xmax API request failed",
412
+ message || "Xmax API request failed",
352
413
  { apiCode: envelope.code, httpStatus: status }
353
414
  );
354
415
  }
@@ -361,7 +422,9 @@ var _ApiService = class _ApiService {
361
422
  }
362
423
  return envelope.data;
363
424
  }
364
- /** 将传输层异常映射为 SDK 统一错误。 */
425
+ /**
426
+ * 将传输层异常映射为 SDK 统一错误。
427
+ */
365
428
  static transportError(error) {
366
429
  if (error instanceof XmaxError) {
367
430
  return error;
@@ -378,7 +441,9 @@ var _ApiService = class _ApiService {
378
441
  `HTTP request failed: ${message}`
379
442
  );
380
443
  }
381
- /** 输出失败日志。 */
444
+ /**
445
+ * 输出失败日志。
446
+ */
382
447
  logFailure(method, path, error, startedAt) {
383
448
  XmaxLogger.api.error(
384
449
  () => `API \u8BF7\u6C42\u5931\u8D25 (API Request Failed)
@@ -387,8 +452,12 @@ var _ApiService = class _ApiService {
387
452
  );
388
453
  }
389
454
  };
390
- // API 配置
391
- /** 默认请求超时时间(毫秒)。 */
455
+ /**
456
+ * API 配置
457
+ */
458
+ /**
459
+ * 默认请求超时时间(毫秒)。
460
+ */
392
461
  __publicField(_ApiService, "defaultTimeoutMs", 15e3);
393
462
  var ApiService = _ApiService;
394
463
 
@@ -410,11 +479,35 @@ var RealtimeVideoFormat = class _RealtimeVideoFormat {
410
479
  * @param init.encoderPreference 上传编码策略偏好,默认值为 maintainFramerate。
411
480
  */
412
481
  constructor(init) {
482
+ /**
483
+ * 视频规格
484
+ */
485
+ /**
486
+ * 视频宽度,单位为像素。
487
+ */
413
488
  __publicField(this, "width");
489
+ /**
490
+ * 视频高度,单位为像素。
491
+ */
414
492
  __publicField(this, "height");
493
+ /**
494
+ * 视频帧率,单位为 fps。
495
+ */
415
496
  __publicField(this, "fps");
497
+ /**
498
+ * 上传编码配置
499
+ */
500
+ /**
501
+ * 最低上传码率,单位为 kbps;未指定时由 SDK 计算,0 表示不设最低码率。
502
+ */
416
503
  __publicField(this, "minimumBitrate");
504
+ /**
505
+ * 最高上传码率,单位为 kbps;未指定时由 SDK 计算。
506
+ */
417
507
  __publicField(this, "maximumBitrate");
508
+ /**
509
+ * 弱网下优先保障帧率或分辨率的编码策略。
510
+ */
418
511
  __publicField(this, "encoderPreference");
419
512
  this.width = init.width;
420
513
  this.height = init.height;
@@ -453,7 +546,9 @@ var RealtimeVideoFormat = class _RealtimeVideoFormat {
453
546
  );
454
547
  }
455
548
  }
456
- /** 调整尺寸,保留帧率和上传编码配置。 */
549
+ /**
550
+ * 调整尺寸,保留帧率和上传编码配置。
551
+ */
457
552
  resized(width, height) {
458
553
  return new _RealtimeVideoFormat({
459
554
  width,
@@ -468,16 +563,25 @@ var RealtimeVideoFormat = class _RealtimeVideoFormat {
468
563
 
469
564
  // src/Service/Realtime/RealtimeModel.ts
470
565
  var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
566
+ RealtimeModel2["x2_0"] = "x2.0";
567
+ RealtimeModel2["x2_0_pro"] = "x2.0-pro";
471
568
  RealtimeModel2["x2_fast_1080p"] = "x2-fast-1080p";
472
569
  return RealtimeModel2;
473
570
  })(RealtimeModel || {});
474
571
  var RESOLUTION_BUCKETS = {
572
+ ["x2.0" /* x2_0 */]: [],
573
+ ["x2.0-pro" /* x2_0_pro */]: [
574
+ { width: 1024, height: 1920 },
575
+ { width: 1920, height: 1024 }
576
+ ],
475
577
  ["x2-fast-1080p" /* x2_fast_1080p */]: [
476
578
  { width: 1024, height: 1920 },
477
579
  { width: 1920, height: 1024 }
478
580
  ]
479
581
  };
480
582
  var MAXIMUM_INPUT_PIXELS = {
583
+ ["x2.0" /* x2_0 */]: 128e4,
584
+ ["x2.0-pro" /* x2_0_pro */]: 21e5,
481
585
  ["x2-fast-1080p" /* x2_fast_1080p */]: 21e5
482
586
  };
483
587
  function resolutionBuckets(model) {
@@ -495,7 +599,10 @@ function inputSizeAlignment(_model) {
495
599
  function defaultFrameRate(_model) {
496
600
  return 30;
497
601
  }
498
- function defaultCameraVideoFormat(_model) {
602
+ function defaultCameraVideoFormat(model) {
603
+ if (model === "x2.0" /* x2_0 */) {
604
+ return new RealtimeVideoFormat({ width: 832, height: 1472, fps: 30 });
605
+ }
499
606
  return new RealtimeVideoFormat({ width: 1024, height: 1920, fps: 30 });
500
607
  }
501
608
 
@@ -521,11 +628,15 @@ var MediaService = class {
521
628
  * @param model 媒体输入规则使用的模型,默认为 `x2-fast-1080p`。
522
629
  */
523
630
  constructor(model = "x2-fast-1080p" /* x2_fast_1080p */) {
524
- // 模型约束
631
+ /**
632
+ * 模型约束
633
+ */
525
634
  __publicField(this, "model");
526
635
  this.model = model;
527
636
  }
528
- /** Web 插帧保留原始尺寸;/16 对齐由 GPU 内部补边处理,不缩小回传视频。 */
637
+ /**
638
+ * Web 插帧保留原始尺寸;/16 对齐由 GPU 内部补边处理,不缩小回传视频。
639
+ */
529
640
  resolveFrameInterpolationSize(size) {
530
641
  const { width, height } = size;
531
642
  if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) {
@@ -533,10 +644,15 @@ var MediaService = class {
533
644
  }
534
645
  return { width, height };
535
646
  }
536
- /** WebGPU 适配器探测是异步的;实际性能和运行状态由渲染管线判断。 */
647
+ /**
648
+ * WebGPU 适配器探测是异步的;实际性能和运行状态由渲染管线判断。
649
+ */
537
650
  async supportsFrameInterpolation(size) {
538
651
  return await frameInterpolationAdapter(size) !== null;
539
652
  }
653
+ /**
654
+ * 按模型分辨率档位或像素预算解析输入尺寸,保持宽高比例并对齐;不支持的规格抛错。
655
+ */
540
656
  resolveModelInputSize(size) {
541
657
  const buckets = resolutionBuckets(this.model);
542
658
  if (buckets.length > 0) {
@@ -586,7 +702,9 @@ var MediaService = class {
586
702
  validated.height * scale
587
703
  );
588
704
  }
589
- /** 在对齐网格上选择满足面积限制且最接近目标的尺寸。 */
705
+ /**
706
+ * 在对齐网格上选择满足面积限制且最接近目标的尺寸。
707
+ */
590
708
  boundedAlignedSize(width, height) {
591
709
  const alignment = inputSizeAlignment(this.model);
592
710
  const unitPixels = alignment * alignment;
@@ -614,7 +732,9 @@ var MediaService = class {
614
732
  }
615
733
  return bestSize;
616
734
  }
617
- /** 校验尺寸为有限正数,并归一化为不小于 1 的整数。 */
735
+ /**
736
+ * 校验尺寸为有限正数,并归一化为不小于 1 的整数。
737
+ */
618
738
  validatedSize(size) {
619
739
  if (!Number.isFinite(size.width) || !Number.isFinite(size.height) || size.width <= 0 || size.height <= 0) {
620
740
  throw new XmaxError(
@@ -639,11 +759,20 @@ var StoredFile = class {
639
759
  * @param init.etag 对象存储返回的 ETag。
640
760
  */
641
761
  constructor(init) {
642
- /** 文件的访问地址。 */
762
+ /**
763
+ * 存储结果
764
+ */
765
+ /**
766
+ * 文件的访问地址。
767
+ */
643
768
  __publicField(this, "url");
644
- /** 对象存储中的对象键。 */
769
+ /**
770
+ * 对象存储中的对象键。
771
+ */
645
772
  __publicField(this, "objectKey");
646
- /** 对象存储返回的 ETag;未返回时为空。 */
773
+ /**
774
+ * 对象存储返回的 ETag;未返回时为空。
775
+ */
647
776
  __publicField(this, "etag");
648
777
  this.url = init.url;
649
778
  this.objectKey = init.objectKey;
@@ -672,11 +801,17 @@ var StorageService = class _StorageService {
672
801
  * @param options.identifierGenerator 标识来源(可替换,测试用)。
673
802
  */
674
803
  constructor(options) {
675
- // 服务层组件
804
+ /**
805
+ * 服务层组件
806
+ */
676
807
  __publicField(this, "apiService");
677
- // 平台资源
808
+ /**
809
+ * 平台资源
810
+ */
678
811
  __publicField(this, "clientFactory");
679
- // 标识生成
812
+ /**
813
+ * 标识生成
814
+ */
680
815
  __publicField(this, "dateGenerator");
681
816
  __publicField(this, "identifierGenerator");
682
817
  this.apiService = options.apiService;
@@ -684,7 +819,9 @@ var StorageService = class _StorageService {
684
819
  this.dateGenerator = _nullishCoalesce(options.dateGenerator, () => ( (() => /* @__PURE__ */ new Date())));
685
820
  this.identifierGenerator = _nullishCoalesce(options.identifierGenerator, () => ( (() => crypto.randomUUID().toLowerCase())));
686
821
  }
687
- /** 上传图片并返回访问地址。 */
822
+ /**
823
+ * 上传图片并返回访问地址。
824
+ */
688
825
  async uploadImage(options) {
689
826
  const startedAt = Date.now();
690
827
  try {
@@ -734,7 +871,9 @@ var StorageService = class _StorageService {
734
871
  );
735
872
  }
736
873
  }
737
- /** 获取临时存储配置;字段不完整时抛出 API 错误。 */
874
+ /**
875
+ * 获取临时存储配置;字段不完整时抛出 API 错误。
876
+ */
738
877
  async fetchStorageConfiguration() {
739
878
  const payload = await this.apiService.get("/cos/sts");
740
879
  const message = "Invalid storage credential payload";
@@ -755,12 +894,16 @@ var StorageService = class _StorageService {
755
894
  credentials: { accessKeyID, secretAccessKey, sessionToken }
756
895
  };
757
896
  }
758
- /** 生成对象键:`${prefix}${毫秒时间戳}_${标识}_${文件名}`。 */
897
+ /**
898
+ * 生成对象键:`${prefix}${毫秒时间戳}_${标识}_${文件名}`。
899
+ */
759
900
  makeObjectKey(prefix, fileName) {
760
901
  const milliseconds = Math.round(this.dateGenerator().getTime());
761
902
  return `${prefix}${milliseconds}_${this.identifierGenerator()}_${fileName}`;
762
903
  }
763
- /** 生产环境 COS 客户端工厂:动态加载 cos-js-sdk-v5 并按临时凭证创建客户端。 */
904
+ /**
905
+ * 生产环境 COS 客户端工厂:动态加载 cos-js-sdk-v5 并按临时凭证创建客户端。
906
+ */
764
907
  static async cosClientFactory(configuration) {
765
908
  const module = await Promise.resolve().then(() => _interopRequireWildcard(require("cos-js-sdk-v5")));
766
909
  const COS = module.default;
@@ -770,7 +913,9 @@ var StorageService = class _StorageService {
770
913
  SecurityToken: configuration.credentials.sessionToken
771
914
  });
772
915
  }
773
- /** 调用对象存储上传并包装为 Promise。 */
916
+ /**
917
+ * 调用对象存储上传并包装为 Promise。
918
+ */
774
919
  static putObject(client, params) {
775
920
  return new Promise((resolve, reject) => {
776
921
  client.putObject(params, (error, data) => {
@@ -806,7 +951,9 @@ var StorageService = class _StorageService {
806
951
  }
807
952
  return `https://${configuration.bucket}.cos.${configuration.region}.myqcloud.com/${objectKey}`;
808
953
  }
809
- /** 统一构造上传体。 */
954
+ /**
955
+ * 统一构造上传体。
956
+ */
810
957
  static makeBody(data, contentType) {
811
958
  if (data instanceof Blob) {
812
959
  return data;
@@ -814,7 +961,9 @@ var StorageService = class _StorageService {
814
961
  const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
815
962
  return new Blob([bytes], { type: contentType });
816
963
  }
817
- /** 校验文件名非空且不包含路径分隔符。 */
964
+ /**
965
+ * 校验文件名非空且不包含路径分隔符。
966
+ */
818
967
  static validateFileName(fileName) {
819
968
  const safeName = fileName.trim();
820
969
  if (!safeName || safeName.includes("/") || safeName.includes("\\")) {
@@ -825,12 +974,16 @@ var StorageService = class _StorageService {
825
974
  }
826
975
  return safeName;
827
976
  }
828
- /** 按文件名后缀推断内容类型。 */
977
+ /**
978
+ * 按文件名后缀推断内容类型。
979
+ */
829
980
  static inferContentType(fileName) {
830
981
  const extension = _nullishCoalesce(_optionalChain([fileName, 'access', _29 => _29.split, 'call', _30 => _30("."), 'access', _31 => _31.pop, 'call', _32 => _32(), 'optionalAccess', _33 => _33.toLowerCase, 'call', _34 => _34()]), () => ( ""));
831
982
  return _nullishCoalesce(CONTENT_TYPES[extension], () => ( "application/octet-stream"));
832
983
  }
833
- /** 格式化字节数用于日志输出。 */
984
+ /**
985
+ * 格式化字节数用于日志输出。
986
+ */
834
987
  static formatByteCount(bytes) {
835
988
  if (bytes < 1024) {
836
989
  return `${bytes} B`;
@@ -840,10 +993,12 @@ var StorageService = class _StorageService {
840
993
  }
841
994
  return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
842
995
  }
843
- /** 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。 */
996
+ /**
997
+ * 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
998
+ */
844
999
  static nonEmpty(value) {
845
1000
  const normalized = _optionalChain([value, 'optionalAccess', _35 => _35.trim, 'call', _36 => _36()]);
846
- return normalized && normalized.length > 0 ? normalized : void 0;
1001
+ return normalized || void 0;
847
1002
  }
848
1003
  };
849
1004
 
@@ -856,12 +1011,23 @@ var CameraPosition = /* @__PURE__ */ ((CameraPosition3) => {
856
1011
 
857
1012
  // src/Foundation/RTC/RtcEngineManager.ts
858
1013
  var RtcEngineLease = class {
1014
+ /**
1015
+ * 为已创建的引擎生成独占租约标识,供引擎管理器核对释放请求。
1016
+ */
859
1017
  constructor(engine) {
860
- // RTC 资源
861
- /** 租约持有的 TRTC 引擎实例。 */
1018
+ /**
1019
+ * RTC 资源
1020
+ */
1021
+ /**
1022
+ * 租约持有的 TRTC 引擎实例。
1023
+ */
862
1024
  __publicField(this, "engine");
863
- // 运行标识
864
- /** 租约标识。 */
1025
+ /**
1026
+ * 运行标识
1027
+ */
1028
+ /**
1029
+ * 租约标识。
1030
+ */
865
1031
  __publicField(this, "id");
866
1032
  this.engine = engine;
867
1033
  this.id = `lease-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -874,11 +1040,17 @@ var _RtcEngineManager = class _RtcEngineManager {
874
1040
  * @param makeEngine 引擎工厂(可替换,测试用)。
875
1041
  */
876
1042
  constructor(makeEngine = _RtcEngineManager.defaultMakeEngine) {
877
- // 依赖
1043
+ /**
1044
+ * 依赖
1045
+ */
878
1046
  __publicField(this, "makeEngine");
879
- // RTC 资源
1047
+ /**
1048
+ * RTC 资源
1049
+ */
880
1050
  __publicField(this, "activeLease");
881
- // 运行状态
1051
+ /**
1052
+ * 运行状态
1053
+ */
882
1054
  __publicField(this, "requests", []);
883
1055
  this.makeEngine = makeEngine;
884
1056
  }
@@ -901,7 +1073,9 @@ var _RtcEngineManager = class _RtcEngineManager {
901
1073
  });
902
1074
  });
903
1075
  }
904
- /** 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。 */
1076
+ /**
1077
+ * 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
1078
+ */
905
1079
  release(lease) {
906
1080
  if (_optionalChain([this, 'access', _37 => _37.activeLease, 'optionalAccess', _38 => _38.id]) !== lease.id) {
907
1081
  return;
@@ -913,13 +1087,17 @@ var _RtcEngineManager = class _RtcEngineManager {
913
1087
  }
914
1088
  void this.fulfillNextRequest();
915
1089
  }
916
- /** 动态加载 TRTC SDK 并创建引擎实例。 */
1090
+ /**
1091
+ * 动态加载 TRTC SDK 并创建引擎实例。
1092
+ */
917
1093
  static async defaultMakeEngine() {
918
1094
  const module = await Promise.resolve().then(() => _interopRequireWildcard(require("trtc-sdk-v5")));
919
1095
  module.default.setLogLevel(5);
920
1096
  return module.default.create();
921
1097
  }
922
- /** 创建新引擎租约。 */
1098
+ /**
1099
+ * 创建新引擎租约。
1100
+ */
923
1101
  async createLease() {
924
1102
  const engine = await this.makeEngine();
925
1103
  if (!engine) {
@@ -930,7 +1108,9 @@ var _RtcEngineManager = class _RtcEngineManager {
930
1108
  }
931
1109
  return new RtcEngineLease(engine);
932
1110
  }
933
- /** 满足下一个排队请求;创建失败时拒绝该请求并继续处理后续请求。 */
1111
+ /**
1112
+ * 满足下一个排队请求;创建失败时拒绝该请求并继续处理后续请求。
1113
+ */
934
1114
  async fulfillNextRequest() {
935
1115
  while (!this.activeLease && this.requests.length > 0) {
936
1116
  const request = this.requests.shift();
@@ -947,12 +1127,20 @@ var _RtcEngineManager = class _RtcEngineManager {
947
1127
  }
948
1128
  }
949
1129
  };
950
- /** 共享实例。 */
1130
+ /**
1131
+ * 共享管理入口
1132
+ */
1133
+ /**
1134
+ * 共享实例。
1135
+ */
951
1136
  __publicField(_RtcEngineManager, "shared", new _RtcEngineManager());
952
1137
  var RtcEngineManager = _RtcEngineManager;
953
1138
 
954
1139
  // src/Foundation/RTC/RtcStatsLogger.ts
955
1140
  var RtcStatsLogger = class {
1141
+ /**
1142
+ * 按上下行及音视频分组输出白名单统计指标,仅在 performance 日志启用时格式化。
1143
+ */
956
1144
  static logStatistics(stats) {
957
1145
  XmaxLogger.rtc.info(() => {
958
1146
  const blocks = [this.block("RTC \u8FD0\u884C\u7EDF\u8BA1 (RTC Statistics)", [
@@ -981,12 +1169,18 @@ var RtcStatsLogger = class {
981
1169
  return blocks.join("\n\n");
982
1170
  }, 2 /* performance */);
983
1171
  }
1172
+ /**
1173
+ * 输出上下行网络质量等级、RTT 和丢包率,遵循 performance 日志开关。
1174
+ */
984
1175
  static logNetworkQuality(stats) {
985
1176
  XmaxLogger.rtc.info(() => this.block("\u7F51\u7EDC\u8D28\u91CF (Network Quality Metrics)", [
986
1177
  `${XmaxLogger.localized("\u672C\u5730\u4E0A\u884C\uFF1A", "Local Uplink: ")}${this.quality(stats.uplinkNetworkQuality)}, RTT ${this.value(stats.uplinkRTT, "ms")}, ${XmaxLogger.localized("\u4E22\u5305\u7387 ", "Loss ")}${this.value(stats.uplinkLoss, "%")}`,
987
1178
  `${XmaxLogger.localized("\u672C\u5730\u4E0B\u884C\uFF08\u5E73\u5747\uFF09\uFF1A", "Local Downlink (Average): ")}${this.quality(stats.downlinkNetworkQuality)}, RTT ${this.value(stats.downlinkRTT, "ms")}, ${XmaxLogger.localized("\u4E22\u5305\u7387 ", "Loss ")}${this.value(stats.downlinkLoss, "%")}`
988
1179
  ]), 2 /* performance */);
989
1180
  }
1181
+ /**
1182
+ * 格式化音频码率和音量;远端音频额外包含播放延迟。
1183
+ */
990
1184
  static audioBlock(title, stats, remote) {
991
1185
  return this.block(title, [
992
1186
  `${XmaxLogger.localized("\u7801\u7387\uFF1A", "Bitrate: ")}${this.value(stats.bitrate, "kbps")}`,
@@ -994,6 +1188,9 @@ var RtcStatsLogger = class {
994
1188
  ...remote ? this.playbackLines(stats) : []
995
1189
  ]);
996
1190
  }
1191
+ /**
1192
+ * 格式化视频流类型、尺寸、帧率和码率;远端视频额外包含播放延迟。
1193
+ */
997
1194
  static videoBlock(title, stats, remote) {
998
1195
  return this.block(title, [
999
1196
  `${XmaxLogger.localized("\u6D41\u7C7B\u578B\uFF1A", "Stream Type: ")}${_nullishCoalesce(stats.videoType, () => ( "\u2014"))}`,
@@ -1003,22 +1200,33 @@ var RtcStatsLogger = class {
1003
1200
  ...remote ? this.playbackLines(stats) : []
1004
1201
  ]);
1005
1202
  }
1203
+ /**
1204
+ * 格式化 TRTC 播放缓冲及估算端到端延迟,缺失或无效指标显示占位符。
1205
+ */
1006
1206
  static playbackLines(stats) {
1007
1207
  return [
1008
1208
  `${XmaxLogger.localized("\u64AD\u653E\u7F13\u51B2\u5EF6\u8FDF\uFF1A", "Jitter Buffer Delay: ")}${this.value(stats.jitterBufferDelay, "ms")}`,
1009
1209
  `${XmaxLogger.localized("RTC \u7AEF\u5230\u7AEF\u5EF6\u8FDF\uFF08\u4F30\u7B97\uFF09\uFF1A", "RTC End-to-End Delay (Estimated): ")}${this.value(stats.point2pointDelay, "ms")}`
1010
1210
  ];
1011
1211
  }
1212
+ /**
1213
+ * 为指标列表添加标题和树形行前缀,生成一个控制台日志分组。
1214
+ */
1012
1215
  static block(title, lines) {
1013
1216
  return [title, ...lines.map((line, index) => `${index === lines.length - 1 ? "\u2514\u2500" : "\u251C\u2500"} ${line}`)].join("\n");
1014
1217
  }
1015
- /** TRTC 丢包率已是百分数,无需再乘 100。 */
1218
+ /**
1219
+ * TRTC 丢包率已是百分数,无需再乘 100。
1220
+ */
1016
1221
  static value(value, unit = "") {
1017
1222
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
1018
1223
  return "\u2014";
1019
1224
  }
1020
1225
  return `${Number(value.toFixed(2))}${unit ? `${unit === "%" ? "" : " "}${unit}` : ""}`;
1021
1226
  }
1227
+ /**
1228
+ * 将 TRTC 质量等级映射为本地化文案;未知等级回退为“未知”。
1229
+ */
1022
1230
  static quality(value) {
1023
1231
  const names = [
1024
1232
  ["\u672A\u77E5", "Unknown"],
@@ -1057,25 +1265,39 @@ var RtcManager = class {
1057
1265
  * @param engineManager 引擎租约管理组件(可替换,测试用)。
1058
1266
  */
1059
1267
  constructor(engineManager = RtcEngineManager.shared) {
1060
- // 依赖
1268
+ /**
1269
+ * 依赖
1270
+ */
1061
1271
  __publicField(this, "engineManager");
1062
- // RTC 资源
1272
+ /**
1273
+ * RTC 资源
1274
+ */
1063
1275
  __publicField(this, "lease");
1064
- // 采集状态
1276
+ /**
1277
+ * 采集状态
1278
+ */
1065
1279
  __publicField(this, "isCapturing", false);
1066
1280
  __publicField(this, "isAudioCapturing", false);
1067
- // 房间状态
1281
+ /**
1282
+ * 房间状态
1283
+ */
1068
1284
  __publicField(this, "isInRoom", false);
1069
- // 事件监听
1285
+ /**
1286
+ * 事件监听
1287
+ */
1070
1288
  __publicField(this, "eventListener");
1071
1289
  __publicField(this, "removeStatsListeners");
1072
1290
  this.engineManager = engineManager;
1073
1291
  }
1074
- /** RTC 引擎是否已初始化。 */
1292
+ /**
1293
+ * RTC 引擎是否已初始化。
1294
+ */
1075
1295
  get isInitialized() {
1076
1296
  return this.lease !== void 0;
1077
1297
  }
1078
- /** 初始化 RTC 引擎(获取独占租约)并注册事件桥接;已初始化时重复调用不产生效果。 */
1298
+ /**
1299
+ * 初始化 RTC 引擎(获取独占租约)并注册事件桥接;已初始化时重复调用不产生效果。
1300
+ */
1079
1301
  async initialize() {
1080
1302
  if (this.lease) {
1081
1303
  return;
@@ -1084,7 +1306,9 @@ var RtcManager = class {
1084
1306
  this.registerEventBridge(lease.engine);
1085
1307
  this.lease = lease;
1086
1308
  }
1087
- /** 停止采集与发布、销毁 RTC 引擎并释放租约;未初始化时重复调用不产生效果。 */
1309
+ /**
1310
+ * 停止采集与发布、销毁 RTC 引擎并释放租约;未初始化时重复调用不产生效果。
1311
+ */
1088
1312
  async destroy() {
1089
1313
  const lease = this.lease;
1090
1314
  this.lease = void 0;
@@ -1177,7 +1401,9 @@ var RtcManager = class {
1177
1401
  throw this.mapError(error);
1178
1402
  }
1179
1403
  }
1180
- /** 停止摄像头采集;引擎未初始化或采集未启动时不产生效果。 */
1404
+ /**
1405
+ * 停止摄像头采集;引擎未初始化或采集未启动时不产生效果。
1406
+ */
1181
1407
  async stopCameraCapture() {
1182
1408
  const engine = _optionalChain([this, 'access', _43 => _43.lease, 'optionalAccess', _44 => _44.engine]);
1183
1409
  this.isCapturing = false;
@@ -1225,7 +1451,9 @@ var RtcManager = class {
1225
1451
  throw this.mapError(error);
1226
1452
  }
1227
1453
  }
1228
- /** 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。 */
1454
+ /**
1455
+ * 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
1456
+ */
1229
1457
  async leaveRoom() {
1230
1458
  const engine = _optionalChain([this, 'access', _45 => _45.lease, 'optionalAccess', _46 => _46.engine]);
1231
1459
  if (!engine || !this.isInRoom) {
@@ -1292,7 +1520,9 @@ var RtcManager = class {
1292
1520
  throw this.mapError(error);
1293
1521
  }
1294
1522
  }
1295
- /** 停止发布本地视频流;采集保持运行,本地预览不受影响。 */
1523
+ /**
1524
+ * 停止发布本地视频流;采集保持运行,本地预览不受影响。
1525
+ */
1296
1526
  async unpublishLocalVideo() {
1297
1527
  const engine = _optionalChain([this, 'access', _47 => _47.lease, 'optionalAccess', _48 => _48.engine]);
1298
1528
  if (!engine || !this.isCapturing) {
@@ -1322,7 +1552,9 @@ var RtcManager = class {
1322
1552
  throw this.mapError(error);
1323
1553
  }
1324
1554
  }
1325
- /** 停止发布本地音频流;麦克风采集保持运行。 */
1555
+ /**
1556
+ * 停止发布本地音频流;麦克风采集保持运行。
1557
+ */
1326
1558
  async unpublishLocalAudio() {
1327
1559
  const engine = _optionalChain([this, 'access', _49 => _49.lease, 'optionalAccess', _50 => _50.engine]);
1328
1560
  if (!engine || !this.isAudioCapturing) {
@@ -1413,11 +1645,15 @@ var RtcManager = class {
1413
1645
  data: encoded.buffer
1414
1646
  });
1415
1647
  }
1416
- /** 设置 RTC 事件监听器,传入空值时清除监听器。 */
1648
+ /**
1649
+ * 设置 RTC 事件监听器,传入空值时清除监听器。
1650
+ */
1417
1651
  setEventListener(listener) {
1418
1652
  this.eventListener = listener;
1419
1653
  }
1420
- /** 注册引擎事件桥接:媒体、消息及性能日志。 */
1654
+ /**
1655
+ * 注册引擎事件桥接:媒体、消息及性能日志。
1656
+ */
1421
1657
  registerEventBridge(engine) {
1422
1658
  const source = engine;
1423
1659
  const onStatistics = (stats) => {
@@ -1499,7 +1735,9 @@ var RtcManager = class {
1499
1735
  _optionalChain([this, 'access', _77 => _77.eventListener, 'optionalAccess', _78 => _78.onCustomMessageReceived, 'call', _79 => _79(event.userId, message)]);
1500
1736
  });
1501
1737
  }
1502
- /** 返回当前引擎实例;未初始化时抛出错误。 */
1738
+ /**
1739
+ * 返回当前引擎实例;未初始化时抛出错误。
1740
+ */
1503
1741
  requireEngine() {
1504
1742
  const engine = _optionalChain([this, 'access', _80 => _80.lease, 'optionalAccess', _81 => _81.engine]);
1505
1743
  if (!engine) {
@@ -1510,7 +1748,9 @@ var RtcManager = class {
1510
1748
  }
1511
1749
  return engine;
1512
1750
  }
1513
- /** 将 TRTC 错误映射为 SDK 统一错误。 */
1751
+ /**
1752
+ * 将 TRTC 错误映射为 SDK 统一错误。
1753
+ */
1514
1754
  mapError(error) {
1515
1755
  if (error instanceof XmaxError) {
1516
1756
  return error;
@@ -1528,28 +1768,16 @@ var RtcManager = class {
1528
1768
  }
1529
1769
  };
1530
1770
 
1531
- // src/Foundation/Media/Camera/CameraExposureGate.ts
1532
- var SAMPLE_INTERVAL_MS = 80;
1533
- var STABLE_DURATION_MS = 400;
1534
- var TIMEOUT_MS = 5e3;
1535
- var CameraExposureGate = class {
1536
- constructor() {
1537
- __publicField(this, "baseline");
1538
- __publicField(this, "lastTime");
1539
- __publicField(this, "count", 0);
1540
- }
1541
- reset() {
1542
- this.baseline = void 0;
1543
- this.lastTime = void 0;
1544
- this.count = 0;
1545
- }
1546
- /** 只接受新的采样帧;中央区域需足够亮,并在至少 400 ms 内保持稳定。 */
1547
- accept(pixels, time) {
1771
+ // src/Foundation/Media/Camera/CameraFrameValidator.ts
1772
+ var FALLBACK_POLL_INTERVAL_MS = 16;
1773
+ var TIMEOUT_MS = 2e3;
1774
+ var CameraFrameValidator = class {
1775
+ /**
1776
+ * 单帧中央区域亮度达标即放行,不等待连续帧或曝光稳定。
1777
+ */
1778
+ accept(pixels) {
1548
1779
  const size = pixels.length / 4;
1549
- if (!size || !Number.isInteger(size)) {
1550
- this.reset();
1551
- return false;
1552
- }
1780
+ if (!size || !Number.isInteger(size)) return false;
1553
1781
  const histogram = new Uint32Array(256);
1554
1782
  let total = 0;
1555
1783
  let dark = 0;
@@ -1566,22 +1794,10 @@ var CameraExposureGate = class {
1566
1794
  if (accumulated >= size / 2) break;
1567
1795
  }
1568
1796
  const mean = total / size;
1569
- if (mean < 24 || median < 18 || dark / size > 0.75) {
1570
- this.reset();
1571
- return false;
1572
- }
1573
- const baseline = this.baseline;
1574
- const stable = baseline && this.lastTime !== void 0 && time > this.lastTime && time - this.lastTime <= 250 && Math.abs(mean - baseline.mean) <= Math.max(5, baseline.mean * 0.1) && Math.abs(median - baseline.median) <= Math.max(5, baseline.median * 0.1);
1575
- if (!stable) {
1576
- this.baseline = { mean, median, time };
1577
- this.count = 0;
1578
- }
1579
- this.lastTime = time;
1580
- this.count++;
1581
- return this.count >= 5 && time - this.baseline.time >= STABLE_DURATION_MS;
1797
+ return mean >= 24 && median >= 18 && dark / size <= 0.75;
1582
1798
  }
1583
1799
  };
1584
- function waitForCameraExposure(track, signal) {
1800
+ function waitForValidCameraFrame(track, signal) {
1585
1801
  return new Promise((resolve, reject) => {
1586
1802
  let video;
1587
1803
  let timeout;
@@ -1589,8 +1805,8 @@ function waitForCameraExposure(track, signal) {
1589
1805
  let frameCallback;
1590
1806
  let finished = false;
1591
1807
  const started = performance.now();
1592
- const gate = new CameraExposureGate();
1593
- const finish = (error) => {
1808
+ const gate = new CameraFrameValidator();
1809
+ const finish = (result = "valid") => {
1594
1810
  if (finished) return;
1595
1811
  finished = true;
1596
1812
  clearTimeout(timeout);
@@ -1603,12 +1819,19 @@ function waitForCameraExposure(track, signal) {
1603
1819
  }
1604
1820
  signal.removeEventListener("abort", abort);
1605
1821
  track.removeEventListener("ended", ended);
1606
- if (error) {
1607
- if (error.code !== "CANCELLED" /* cancelled */) XmaxLogger.media.warning(() => error.message);
1608
- reject(error);
1822
+ if (result instanceof XmaxError) {
1823
+ if (result.code !== "CANCELLED" /* cancelled */) XmaxLogger.media.warning(() => result.message);
1824
+ reject(result);
1609
1825
  } else {
1610
- XmaxLogger.media.info(() => `\u76F8\u673A\u66DD\u5149\u68C0\u67E5\u901A\u8FC7 (Camera Exposure Ready)
1826
+ if (result === "timeout") {
1827
+ XmaxLogger.media.warning(() => XmaxLogger.localized(
1828
+ "\u76F8\u673A\u4EAE\u5EA6\u68C0\u67E5\u8D85\u65F6\uFF0C\u6309\u5F53\u524D\u753B\u9762\u7EE7\u7EED\u751F\u6210 (Camera Frame Validation Timed Out; Continuing)\n\u2514\u2500 \u672A\u83B7\u5F97\u4EAE\u5EA6\u5408\u683C\u5E27\uFF0C\u4E0D\u518D\u7B49\u5F85\u3002",
1829
+ "Camera Frame Validation Timed Out; Continuing\n\u2514\u2500 No sufficiently bright frame received; proceeding without further waiting."
1830
+ ));
1831
+ } else {
1832
+ XmaxLogger.media.info(() => `\u76F8\u673A\u66DD\u5149\u68C0\u67E5\u901A\u8FC7 (Camera Exposure Ready)
1611
1833
  \u2514\u2500 ${Math.round(performance.now() - started)} ms`);
1834
+ }
1612
1835
  resolve();
1613
1836
  }
1614
1837
  };
@@ -1639,21 +1862,17 @@ function waitForCameraExposure(track, signal) {
1639
1862
  video.srcObject = new MediaStream([track]);
1640
1863
  document.body.appendChild(video);
1641
1864
  const source = video;
1642
- let lastSample = -Infinity;
1643
1865
  let lastFrameTime = -Infinity;
1644
- const sample = (now, mediaTime) => {
1645
- if (now - lastSample < SAMPLE_INTERVAL_MS) return;
1866
+ const sample = (mediaTime) => {
1646
1867
  if (source.readyState < 2 || !source.videoWidth || !source.videoHeight || track.muted || !track.enabled) {
1647
- gate.reset();
1648
1868
  return;
1649
1869
  }
1650
1870
  if (mediaTime === lastFrameTime) return;
1651
- lastSample = now;
1652
1871
  lastFrameTime = mediaTime;
1653
1872
  const width = source.videoWidth;
1654
1873
  const height = source.videoHeight;
1655
1874
  context.drawImage(source, width * 0.2, height * 0.2, width * 0.6, height * 0.6, 0, 0, 64, 48);
1656
- if (gate.accept(context.getImageData(0, 0, 64, 48).data, now)) finish();
1875
+ if (gate.accept(context.getImageData(0, 0, 64, 48).data)) finish();
1657
1876
  };
1658
1877
  const fail = (error) => finish(new XmaxError(
1659
1878
  "MEDIA_ERROR" /* mediaError */,
@@ -1662,10 +1881,10 @@ function waitForCameraExposure(track, signal) {
1662
1881
  const schedule = () => {
1663
1882
  if (finished) return;
1664
1883
  if (typeof source.requestVideoFrameCallback === "function") {
1665
- frameCallback = source.requestVideoFrameCallback((now, metadata) => {
1884
+ frameCallback = source.requestVideoFrameCallback((_now, metadata) => {
1666
1885
  frameCallback = void 0;
1667
1886
  try {
1668
- sample(now, metadata.mediaTime);
1887
+ sample(metadata.mediaTime);
1669
1888
  schedule();
1670
1889
  } catch (error) {
1671
1890
  fail(error);
@@ -1675,22 +1894,16 @@ function waitForCameraExposure(track, signal) {
1675
1894
  poll = setTimeout(() => {
1676
1895
  try {
1677
1896
  const frameTime = typeof source.getVideoPlaybackQuality === "function" ? source.getVideoPlaybackQuality().totalVideoFrames : source.currentTime;
1678
- sample(performance.now(), frameTime);
1897
+ sample(frameTime);
1679
1898
  schedule();
1680
1899
  } catch (error) {
1681
1900
  fail(error);
1682
1901
  }
1683
- }, SAMPLE_INTERVAL_MS);
1902
+ }, FALLBACK_POLL_INTERVAL_MS);
1684
1903
  }
1685
1904
  };
1686
- timeout = setTimeout(() => finish(new XmaxError(
1687
- "CAMERA_EXPOSURE_TIMEOUT" /* cameraExposureTimeout */,
1688
- XmaxLogger.localized(
1689
- "\u76F8\u673A\u753B\u9762\u8FC7\u6697\u6216\u5C1A\u672A\u7A33\u5B9A\uFF0C\u672A\u53D1\u5E03\u89C6\u9891\u3002\u8BF7\u6539\u5584\u5149\u7167\u540E\u91CD\u8BD5\u3002",
1690
- "Camera frames are too dark or not stable. Video was not published. Improve lighting and retry."
1691
- )
1692
- )), TIMEOUT_MS);
1693
- XmaxLogger.media.info(() => "\u7B49\u5F85\u76F8\u673A\u66DD\u5149\u7A33\u5B9A (Waiting for Camera Exposure)");
1905
+ timeout = setTimeout(() => finish("timeout"), TIMEOUT_MS);
1906
+ XmaxLogger.media.info(() => "\u7B49\u5F85\u9996\u5F20\u4EAE\u5EA6\u5408\u683C\u5E27 (Waiting for the First Sufficiently Bright Frame)");
1694
1907
  void source.play().then(schedule, fail);
1695
1908
  } catch (error) {
1696
1909
  finish(new XmaxError(
@@ -1760,19 +1973,31 @@ var PermissionManager = class {
1760
1973
 
1761
1974
  // src/Service/Realtime/VideoRenderBinding.ts
1762
1975
  var _VideoRenderRegistry = class _VideoRenderRegistry {
1763
- /** @internal */
1976
+ /**
1977
+ * 注册轨道的自定义渲染绑定,覆盖该轨道已有的绑定。
1978
+ * @internal
1979
+ */
1764
1980
  static register(track, binding) {
1765
1981
  _VideoRenderRegistry.bindings.set(track, binding);
1766
1982
  }
1767
- /** @internal */
1983
+ /**
1984
+ * 移除轨道的渲染绑定,不执行视图解绑或资源释放。
1985
+ * @internal
1986
+ */
1768
1987
  static unregister(track) {
1769
1988
  _VideoRenderRegistry.bindings.delete(track);
1770
1989
  }
1771
- /** @internal */
1990
+ /**
1991
+ * 查询轨道的自定义渲染绑定;未注册时返回 undefined。
1992
+ * @internal
1993
+ */
1772
1994
  static binding(forTrack) {
1773
1995
  return _VideoRenderRegistry.bindings.get(forTrack);
1774
1996
  }
1775
1997
  };
1998
+ /**
1999
+ * 轨道渲染绑定索引
2000
+ */
1776
2001
  __publicField(_VideoRenderRegistry, "bindings", /* @__PURE__ */ new WeakMap());
1777
2002
  var VideoRenderRegistry = _VideoRenderRegistry;
1778
2003
 
@@ -1786,12 +2011,20 @@ var RealtimeVideoTrack = class {
1786
2011
  * @param init.position 本地相机轨道的初始摄像头位置。
1787
2012
  */
1788
2013
  constructor(init) {
1789
- // 轨道信息
1790
- /** 视频轨道标识。 */
2014
+ /**
2015
+ * 轨道信息
2016
+ */
2017
+ /**
2018
+ * 视频轨道标识。
2019
+ */
1791
2020
  __publicField(this, "id");
1792
- // 动态元数据
2021
+ /**
2022
+ * 动态元数据
2023
+ */
1793
2024
  __publicField(this, "metadata");
1794
- // 平台资源
2025
+ /**
2026
+ * 平台资源
2027
+ */
1795
2028
  /**
1796
2029
  * SDK 内部:轨道对应的 Web 媒体轨。
1797
2030
  * 本地轨道在采集启动后可用;远端轨道在订阅成功后可用。
@@ -1803,19 +2036,27 @@ var RealtimeVideoTrack = class {
1803
2036
  position: init.position
1804
2037
  };
1805
2038
  }
1806
- /** 当前视频轨道使用的视频格式。 */
2039
+ /**
2040
+ * 当前视频轨道使用的视频格式。
2041
+ */
1807
2042
  get videoFormat() {
1808
2043
  return this.metadata.videoFormat;
1809
2044
  }
1810
- /** 本地相机轨道当前使用的摄像头位置。 */
2045
+ /**
2046
+ * 本地相机轨道当前使用的摄像头位置。
2047
+ */
1811
2048
  get position() {
1812
2049
  return this.metadata.position;
1813
2050
  }
1814
- /** 更新轨道视频格式。 @internal */
2051
+ /**
2052
+ * 更新轨道视频格式。 @internal
2053
+ */
1815
2054
  updateVideoFormat(videoFormat) {
1816
2055
  this.metadata.videoFormat = videoFormat;
1817
2056
  }
1818
- /** 更新轨道摄像头位置。 @internal */
2057
+ /**
2058
+ * 更新轨道摄像头位置。 @internal
2059
+ */
1819
2060
  updatePosition(position) {
1820
2061
  this.metadata.position = position;
1821
2062
  }
@@ -1830,9 +2071,16 @@ var RealtimeMediaStream = class {
1830
2071
  * @param init.videoTrack 媒体流包含的视频轨道。
1831
2072
  */
1832
2073
  constructor(init) {
1833
- /** 媒体流标识。 */
2074
+ /**
2075
+ * 流标识与轨道
2076
+ */
2077
+ /**
2078
+ * 媒体流标识。
2079
+ */
1834
2080
  __publicField(this, "id");
1835
- /** 媒体流包含的视频轨道。 */
2081
+ /**
2082
+ * 媒体流包含的视频轨道。
2083
+ */
1836
2084
  __publicField(this, "videoTrack");
1837
2085
  this.id = init.id;
1838
2086
  this.videoTrack = init.videoTrack;
@@ -1850,47 +2098,77 @@ var _CameraController = class _CameraController {
1850
2098
  * @param options.errorListener 运行期错误回调。
1851
2099
  */
1852
2100
  constructor(options) {
1853
- // 基础层组件
2101
+ /**
2102
+ * 基础层组件
2103
+ */
1854
2104
  __publicField(this, "permissionManager");
1855
2105
  __publicField(this, "rtcManager");
1856
- // 服务层组件
2106
+ /**
2107
+ * 服务层组件
2108
+ */
1857
2109
  __publicField(this, "mediaService");
1858
- // 事件监听
2110
+ /**
2111
+ * 事件监听
2112
+ */
1859
2113
  __publicField(this, "errorListener");
1860
2114
  __publicField(this, "previewReadyHandler");
1861
- // 本地资源
2115
+ /**
2116
+ * 本地资源
2117
+ */
1862
2118
  __publicField(this, "activeTrack");
1863
2119
  __publicField(this, "previewStream");
1864
2120
  __publicField(this, "previewMirrorApplier");
1865
- // 预览状态
2121
+ /**
2122
+ * 预览状态
2123
+ */
1866
2124
  __publicField(this, "hasCapturedFrame", false);
1867
2125
  __publicField(this, "isPreviewAttached", false);
1868
- // 麦克风配置
2126
+ /**
2127
+ * 当前相机流配置
2128
+ */
1869
2129
  __publicField(this, "storedUseMicrophone", false);
2130
+ __publicField(this, "storedFrameValidationEnabled", true);
1870
2131
  this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _88 => _88.permissionManager]), () => ( new PermissionManager()));
1871
2132
  this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.rtcManager]), () => ( new RtcManager()));
1872
2133
  this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.mediaService]), () => ( new MediaService()));
1873
2134
  this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.errorListener]), () => ( (() => {
1874
2135
  })));
1875
2136
  }
1876
- /** 当前活动的本地相机视频轨道;尚未创建时为空。 */
2137
+ /**
2138
+ * 当前活动的本地相机视频轨道;尚未创建时为空。
2139
+ */
1877
2140
  get currentTrack() {
1878
2141
  return this.activeTrack;
1879
2142
  }
1880
- /** 当前相机流是否配置为使用麦克风。 */
2143
+ /**
2144
+ * 当前相机流是否配置为使用麦克风。
2145
+ */
1881
2146
  get useMicrophone() {
1882
2147
  return this.activeTrack !== void 0 && this.storedUseMicrophone;
1883
2148
  }
1884
- async waitUntilExposureReady(signal) {
2149
+ /**
2150
+ * 当前活动相机流是否启用发布前亮度检测;没有活动流时为 false。
2151
+ */
2152
+ get isFrameValidationEnabled() {
2153
+ return this.activeTrack !== void 0 && this.storedFrameValidationEnabled;
2154
+ }
2155
+ /**
2156
+ * 等待当前轨道首张合格帧或超时放行;禁用时跳过,取消或轨道被替换时拒绝。
2157
+ */
2158
+ async waitForValidCameraFrame(signal) {
1885
2159
  const track = this.activeTrack;
1886
2160
  const mediaTrack = _optionalChain([track, 'optionalAccess', _92 => _92.mediaStreamTrack]);
1887
2161
  if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
1888
- await waitForCameraExposure(mediaTrack, signal);
2162
+ if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
2163
+ if (!this.isFrameValidationEnabled) return;
2164
+ await waitForValidCameraFrame(mediaTrack, signal);
1889
2165
  if (this.activeTrack !== track || track.mediaStreamTrack !== mediaTrack) {
1890
2166
  throw new XmaxError("CANCELLED" /* cancelled */, "Camera track changed during exposure check");
1891
2167
  }
1892
2168
  }
1893
- /** 设置当前相机流的一次性内部就绪处理;条件为已收到有效帧且预览已绑定。 */
2169
+ /**
2170
+ * 设置当前相机流的一次性内部就绪处理;条件为已收到有效帧且预览已绑定。
2171
+ */
1894
2172
  setPreviewReadyHandler(handler) {
1895
2173
  this.previewReadyHandler = handler;
1896
2174
  const track = this.activeTrack;
@@ -1904,6 +2182,7 @@ var _CameraController = class _CameraController {
1904
2182
  * @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
1905
2183
  * @param options.position 首次启动时使用的摄像头位置。
1906
2184
  * @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
2185
+ * @param options.enableFrameValidation 是否在发布前检测帧亮度,默认 true;false 跳过检测及其等待。
1907
2186
  * @returns 包含本地相机视频轨道的媒体流。
1908
2187
  * @throws 已有活动相机流、格式无效、权限不足或采集启动失败时抛出错误。
1909
2188
  */
@@ -1928,6 +2207,7 @@ var _CameraController = class _CameraController {
1928
2207
  await this.rtcManager.initialize();
1929
2208
  this.activeTrack = track;
1930
2209
  this.storedUseMicrophone = options.useMicrophone;
2210
+ this.storedFrameValidationEnabled = _nullishCoalesce(options.enableFrameValidation, () => ( true));
1931
2211
  this.hasCapturedFrame = false;
1932
2212
  this.isPreviewAttached = false;
1933
2213
  this.registerPreviewBinding(track);
@@ -1946,7 +2226,9 @@ var _CameraController = class _CameraController {
1946
2226
  throw XmaxError.from(error);
1947
2227
  }
1948
2228
  }
1949
- /** 停止相机采集并销毁 RTC 引擎,释放当前轨道及本地预览资源。 */
2229
+ /**
2230
+ * 停止相机采集并销毁 RTC 引擎,释放当前轨道及本地预览资源。
2231
+ */
1950
2232
  async stopLocalCameraStream() {
1951
2233
  const track = this.activeTrack;
1952
2234
  this.activeTrack = void 0;
@@ -1954,6 +2236,7 @@ var _CameraController = class _CameraController {
1954
2236
  this.previewStream = void 0;
1955
2237
  this.previewMirrorApplier = void 0;
1956
2238
  this.storedUseMicrophone = false;
2239
+ this.storedFrameValidationEnabled = true;
1957
2240
  this.hasCapturedFrame = false;
1958
2241
  this.isPreviewAttached = false;
1959
2242
  await this.rtcManager.stopCameraCapture();
@@ -1996,7 +2279,9 @@ var _CameraController = class _CameraController {
1996
2279
  this.observeMediaTrack(track, mediaTrack);
1997
2280
  return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
1998
2281
  }
1999
- /** 为相机轨道注册预览渲染绑定:attach 时挂流、镜像并标记预览已绑定。 */
2282
+ /**
2283
+ * 为相机轨道注册预览渲染绑定:attach 时挂流、镜像并标记预览已绑定。
2284
+ */
2000
2285
  registerPreviewBinding(track) {
2001
2286
  VideoRenderRegistry.register(track, {
2002
2287
  attachHandler: (view) => {
@@ -2022,7 +2307,9 @@ var _CameraController = class _CameraController {
2022
2307
  }
2023
2308
  });
2024
2309
  }
2025
- /** 监听媒体轨首帧与意外结束:首帧推进预览就绪,意外结束上报错误。 */
2310
+ /**
2311
+ * 监听媒体轨首帧与意外结束:首帧推进预览就绪,意外结束上报错误。
2312
+ */
2026
2313
  observeMediaTrack(track, mediaTrack) {
2027
2314
  const isCurrent = () => this.activeTrack === track && track.mediaStreamTrack === mediaTrack;
2028
2315
  if (mediaTrack.muted) {
@@ -2053,7 +2340,9 @@ var _CameraController = class _CameraController {
2053
2340
  );
2054
2341
  });
2055
2342
  }
2056
- /** 满足"已收到有效帧且预览已绑定"时触发一次性就绪回调。 */
2343
+ /**
2344
+ * 满足"已收到有效帧且预览已绑定"时触发一次性就绪回调。
2345
+ */
2057
2346
  notifyPreviewReady(track) {
2058
2347
  if (this.activeTrack !== track || !this.hasCapturedFrame || !this.isPreviewAttached || !this.previewReadyHandler) {
2059
2348
  return;
@@ -2062,7 +2351,9 @@ var _CameraController = class _CameraController {
2062
2351
  this.previewReadyHandler = void 0;
2063
2352
  handler(() => this.activeTrack === track);
2064
2353
  }
2065
- /** 按模型输入规则校验并解析目标视频规格。 */
2354
+ /**
2355
+ * 按模型输入规则校验并解析目标视频规格。
2356
+ */
2066
2357
  resolveVideoFormat(videoFormat) {
2067
2358
  videoFormat.validate();
2068
2359
  const targetSize = this.mediaService.resolveModelInputSize({
@@ -2074,7 +2365,9 @@ var _CameraController = class _CameraController {
2074
2365
  return resolvedFormat;
2075
2366
  }
2076
2367
  };
2077
- // 轨道标识
2368
+ /**
2369
+ * 轨道标识
2370
+ */
2078
2371
  __publicField(_CameraController, "localVideoTrackID", "video0");
2079
2372
  var CameraController = _CameraController;
2080
2373
 
@@ -2090,18 +2383,34 @@ var RealtimeSession = class {
2090
2383
  * @param init.closeReason 会话关闭原因。
2091
2384
  */
2092
2385
  constructor(init) {
2093
- // 会话信息
2094
- /** 会话标识(sessionUid)。 */
2386
+ /**
2387
+ * 会话信息
2388
+ */
2389
+ /**
2390
+ * 会话标识(sessionUid)。
2391
+ */
2095
2392
  __publicField(this, "id");
2096
- /** 业务用户标识。 */
2393
+ /**
2394
+ * 业务用户标识。
2395
+ */
2097
2396
  __publicField(this, "userID");
2098
- // 运行状态
2099
- /** 会话状态(如 ACTIVE);响应未携带时为空。 */
2397
+ /**
2398
+ * 运行状态
2399
+ */
2400
+ /**
2401
+ * 会话状态(如 ACTIVE);响应未携带时为空。
2402
+ */
2100
2403
  __publicField(this, "status");
2101
- /** 会话关闭原因。 */
2404
+ /**
2405
+ * 会话关闭原因。
2406
+ */
2102
2407
  __publicField(this, "closeReason");
2103
- // RTC 连接
2104
- /** RTC 连接参数;心跳等响应未携带完整参数时为空。 */
2408
+ /**
2409
+ * RTC 连接
2410
+ */
2411
+ /**
2412
+ * RTC 连接参数;心跳等响应未携带完整参数时为空。
2413
+ */
2105
2414
  __publicField(this, "connection");
2106
2415
  this.id = init.id;
2107
2416
  this.userID = init.userID;
@@ -2125,22 +2434,42 @@ var RealtimeSessionConnection = class {
2125
2434
  * @param init.botID 房间内生成 Bot 的用户标识。
2126
2435
  */
2127
2436
  constructor(init) {
2128
- // RTC 提供方
2129
- /** RTC 提供方标识(当前仅支持 `trtc`)。 */
2437
+ /**
2438
+ * RTC 提供方
2439
+ */
2440
+ /**
2441
+ * RTC 提供方标识(当前仅支持 `trtc`)。
2442
+ */
2130
2443
  __publicField(this, "provider");
2131
- // 进房参数
2132
- /** TRTC 房间号(字符串房间号)。 */
2444
+ /**
2445
+ * 进房参数
2446
+ */
2447
+ /**
2448
+ * TRTC 房间号(字符串房间号)。
2449
+ */
2133
2450
  __publicField(this, "roomID");
2134
- /** TRTC SDKAppID(按字符串处理)。 */
2451
+ /**
2452
+ * TRTC SDKAppID(按字符串处理)。
2453
+ */
2135
2454
  __publicField(this, "sdkAppID");
2136
- /** TRTC 登录身份(`rtc_user_id`,不是业务 `user_id`)。 */
2455
+ /**
2456
+ * TRTC 登录身份(`rtc_user_id`,不是业务 `user_id`)。
2457
+ */
2137
2458
  __publicField(this, "userID");
2138
- /** TRTC 登录签名。 */
2459
+ /**
2460
+ * TRTC 登录签名。
2461
+ */
2139
2462
  __publicField(this, "userSig");
2140
- /** TRTC 进房鉴权字段(字符串房间号对应的 privateMapKey)。 */
2463
+ /**
2464
+ * TRTC 进房鉴权字段(字符串房间号对应的 privateMapKey)。
2465
+ */
2141
2466
  __publicField(this, "privateMapKey");
2142
- // 房间成员
2143
- /** 房间内生成 Bot 的用户标识,用于匹配远端结果流。 */
2467
+ /**
2468
+ * 房间成员
2469
+ */
2470
+ /**
2471
+ * 房间内生成 Bot 的用户标识,用于匹配远端结果流。
2472
+ */
2144
2473
  __publicField(this, "botID");
2145
2474
  this.provider = init.provider;
2146
2475
  this.roomID = init.roomID;
@@ -2162,34 +2491,48 @@ var RealtimeSessionService = class _RealtimeSessionService {
2162
2491
  * @param options.sleep 心跳等待实现(可替换,测试用)。
2163
2492
  */
2164
2493
  constructor(options) {
2165
- // 服务层组件
2494
+ /**
2495
+ * 服务层组件
2496
+ */
2166
2497
  __publicField(this, "apiService");
2167
- // 心跳配置
2498
+ /**
2499
+ * 心跳配置
2500
+ */
2168
2501
  __publicField(this, "heartbeatIntervalMs");
2169
2502
  __publicField(this, "sleep");
2170
- // 运行状态
2503
+ /**
2504
+ * 运行状态
2505
+ */
2171
2506
  __publicField(this, "heartbeatVersion", 0);
2172
2507
  this.apiService = options.apiService;
2173
2508
  this.heartbeatIntervalMs = _nullishCoalesce(options.heartbeatIntervalMs, () => ( 1e4));
2174
2509
  this.sleep = _nullishCoalesce(options.sleep, () => ( ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))));
2175
2510
  }
2176
- /** 创建实时会话并返回 RTC 连接信息。 */
2511
+ /**
2512
+ * 创建实时会话并返回 RTC 连接信息。
2513
+ */
2177
2514
  async createSession(model) {
2178
2515
  const payload = await this.apiService.post("/session", {
2179
2516
  model
2180
2517
  });
2181
2518
  return _RealtimeSessionService.makeSession(payload, true);
2182
2519
  }
2183
- /** 启动指定会话的周期心跳;重复启动会替换当前心跳。 */
2520
+ /**
2521
+ * 启动指定会话的周期心跳;重复启动会替换当前心跳。
2522
+ */
2184
2523
  startHeartbeat(sessionID, handlers) {
2185
2524
  const version = ++this.heartbeatVersion;
2186
2525
  void this.runHeartbeat(version, sessionID, handlers);
2187
2526
  }
2188
- /** 停止当前心跳;已经失效的迟到结果不会再触发回调。 */
2527
+ /**
2528
+ * 停止当前心跳;已经失效的迟到结果不会再触发回调。
2529
+ */
2189
2530
  stopHeartbeat() {
2190
2531
  this.heartbeatVersion += 1;
2191
2532
  }
2192
- /** 关闭指定实时会话。 */
2533
+ /**
2534
+ * 关闭指定实时会话。
2535
+ */
2193
2536
  async closeSession(sessionID) {
2194
2537
  try {
2195
2538
  await this.apiService.delete(
@@ -2199,7 +2542,9 @@ var RealtimeSessionService = class _RealtimeSessionService {
2199
2542
  throw XmaxError.from(error);
2200
2543
  }
2201
2544
  }
2202
- /** 周期心跳:等待 → 请求 → 校验会话活跃并回调刷新;失败时失效版本并回调。 */
2545
+ /**
2546
+ * 周期心跳:等待 → 请求 → 校验会话活跃并回调刷新;失败时失效版本并回调。
2547
+ */
2203
2548
  async runHeartbeat(version, sessionID, handlers) {
2204
2549
  while (this.heartbeatVersion === version) {
2205
2550
  await this.sleep(this.heartbeatIntervalMs);
@@ -2223,14 +2568,18 @@ var RealtimeSessionService = class _RealtimeSessionService {
2223
2568
  }
2224
2569
  }
2225
2570
  }
2226
- /** 发送一次心跳请求并解析会话数据(不要求携带完整连接参数)。 */
2571
+ /**
2572
+ * 发送一次心跳请求并解析会话数据(不要求携带完整连接参数)。
2573
+ */
2227
2574
  async heartbeatSession(sessionID) {
2228
2575
  const payload = await this.apiService.put(
2229
2576
  `/session/${sessionID}/heartbeat`
2230
2577
  );
2231
2578
  return _RealtimeSessionService.makeSession(payload, false);
2232
2579
  }
2233
- /** 校验会话仍处于活跃状态;状态明确非 ACTIVE 时抛出会话错误。 */
2580
+ /**
2581
+ * 校验会话仍处于活跃状态;状态明确非 ACTIVE 时抛出会话错误。
2582
+ */
2234
2583
  static ensureSessionActive(session) {
2235
2584
  if (!session.status || session.status === "ACTIVE") {
2236
2585
  return;
@@ -2240,7 +2589,9 @@ var RealtimeSessionService = class _RealtimeSessionService {
2240
2589
  _nullishCoalesce(session.closeReason, () => ( `Session is no longer active: ${session.status}`))
2241
2590
  );
2242
2591
  }
2243
- /** 由会话接口数据构造会话模型;`requiresConnection` 要求携带完整 RTC 连接参数。 */
2592
+ /**
2593
+ * 由会话接口数据构造会话模型;`requiresConnection` 要求携带完整 RTC 连接参数。
2594
+ */
2244
2595
  static makeSession(payload, requiresConnection) {
2245
2596
  const sessionID = _RealtimeSessionService.nonEmpty(payload.sessionUid);
2246
2597
  if (!sessionID) {
@@ -2261,7 +2612,9 @@ var RealtimeSessionService = class _RealtimeSessionService {
2261
2612
  closeReason: _RealtimeSessionService.nonEmpty(payload.closeReason)
2262
2613
  });
2263
2614
  }
2264
- /** 解析 `modelExtra` 中的 TRTC 连接参数;字段不完整或提供方不支持时返回空。 */
2615
+ /**
2616
+ * 解析 `modelExtra` 中的 TRTC 连接参数;字段不完整或提供方不支持时返回空。
2617
+ */
2265
2618
  static makeConnection(modelExtra) {
2266
2619
  const payload = _RealtimeSessionService.decodeConnectionPayload(modelExtra);
2267
2620
  if (!payload) {
@@ -2290,7 +2643,9 @@ var RealtimeSessionService = class _RealtimeSessionService {
2290
2643
  botID: _RealtimeSessionService.nonEmpty(payload.rtc_bot_id)
2291
2644
  });
2292
2645
  }
2293
- /** `modelExtra` 可能为对象或 JSON 字符串,统一解析为连接参数字段。 */
2646
+ /**
2647
+ * `modelExtra` 可能为对象或 JSON 字符串,统一解析为连接参数字段。
2648
+ */
2294
2649
  static decodeConnectionPayload(modelExtra) {
2295
2650
  if (typeof modelExtra === "string") {
2296
2651
  try {
@@ -2304,10 +2659,12 @@ var RealtimeSessionService = class _RealtimeSessionService {
2304
2659
  }
2305
2660
  return void 0;
2306
2661
  }
2307
- /** 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。 */
2662
+ /**
2663
+ * 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
2664
+ */
2308
2665
  static nonEmpty(value) {
2309
2666
  const normalized = _optionalChain([value, 'optionalAccess', _98 => _98.trim, 'call', _99 => _99()]);
2310
- return normalized && normalized.length > 0 ? normalized : void 0;
2667
+ return normalized || void 0;
2311
2668
  }
2312
2669
  };
2313
2670
 
@@ -2325,6 +2682,9 @@ var RealtimeConnectionState = /* @__PURE__ */ ((RealtimeConnectionState2) => {
2325
2682
  var RealtimeReason = {
2326
2683
  normal: { kind: "normal" },
2327
2684
  orientationChanged: { kind: "orientationChanged" },
2685
+ /**
2686
+ * 将 SDK 错误包装为状态切换原因,保留错误码和原始说明。
2687
+ */
2328
2688
  failure(error) {
2329
2689
  return { kind: "failure", error };
2330
2690
  }
@@ -2339,13 +2699,30 @@ var RealtimeState = class {
2339
2699
  * @param init.reason 状态变化原因,默认无。
2340
2700
  */
2341
2701
  constructor(init) {
2342
- /** 当前连接生命周期状态。 */
2702
+ /**
2703
+ * 连接生命周期
2704
+ */
2705
+ /**
2706
+ * 当前连接生命周期状态。
2707
+ */
2343
2708
  __publicField(this, "connectionState");
2344
- /** 当前或最近一次实时 Session 标识。 */
2709
+ /**
2710
+ * 业务标识
2711
+ */
2712
+ /**
2713
+ * 当前或最近一次实时 Session 标识。
2714
+ */
2345
2715
  __publicField(this, "sessionID");
2346
- /** 当前生成任务标识。 */
2716
+ /**
2717
+ * 当前生成任务标识。
2718
+ */
2347
2719
  __publicField(this, "taskID");
2348
- /** 进入当前状态的原因;正常开始新的操作时清空。 */
2720
+ /**
2721
+ * 状态变化原因
2722
+ */
2723
+ /**
2724
+ * 进入当前状态的原因;正常开始新的操作时清空。
2725
+ */
2349
2726
  __publicField(this, "reason");
2350
2727
  this.connectionState = init.connectionState;
2351
2728
  this.sessionID = init.sessionID;
@@ -2371,15 +2748,23 @@ var RemoteStream = class {
2371
2748
  * @param init.userID 远端流所属用户标识。
2372
2749
  */
2373
2750
  constructor(init) {
2374
- // 流标识
2375
- /** 远端流所在房间号。 */
2751
+ /**
2752
+ * 流标识
2753
+ */
2754
+ /**
2755
+ * 远端流所在房间号。
2756
+ */
2376
2757
  __publicField(this, "roomID");
2377
- /** 远端流所属用户标识。 */
2758
+ /**
2759
+ * 远端流所属用户标识。
2760
+ */
2378
2761
  __publicField(this, "userID");
2379
2762
  this.roomID = init.roomID;
2380
2763
  this.userID = init.userID;
2381
2764
  }
2382
- /** 跨房间唯一的远端流键。 */
2765
+ /**
2766
+ * 跨房间唯一的远端流键。
2767
+ */
2383
2768
  get key() {
2384
2769
  return `${this.roomID}:${this.userID}`;
2385
2770
  }
@@ -2397,16 +2782,28 @@ var RoomJoinConfiguration = class {
2397
2782
  * @param init.privateMapKey TRTC 进房鉴权字段。
2398
2783
  */
2399
2784
  constructor(init) {
2400
- // 进房参数
2401
- /** TRTC 房间号(字符串房间号)。 */
2785
+ /**
2786
+ * 进房参数
2787
+ */
2788
+ /**
2789
+ * TRTC 房间号(字符串房间号)。
2790
+ */
2402
2791
  __publicField(this, "roomID");
2403
- /** TRTC 登录身份(`rtc_user_id`)。 */
2792
+ /**
2793
+ * TRTC 登录身份(`rtc_user_id`)。
2794
+ */
2404
2795
  __publicField(this, "userID");
2405
- /** TRTC SDKAppID(字符串形式,进房时转换为数值)。 */
2796
+ /**
2797
+ * TRTC SDKAppID(字符串形式,进房时转换为数值)。
2798
+ */
2406
2799
  __publicField(this, "sdkAppID");
2407
- /** TRTC 登录签名。 */
2800
+ /**
2801
+ * TRTC 登录签名。
2802
+ */
2408
2803
  __publicField(this, "userSig");
2409
- /** TRTC 进房鉴权字段(字符串房间号对应的 privateMapKey)。 */
2804
+ /**
2805
+ * TRTC 进房鉴权字段(字符串房间号对应的 privateMapKey)。
2806
+ */
2410
2807
  __publicField(this, "privateMapKey");
2411
2808
  this.roomID = init.roomID;
2412
2809
  this.userID = init.userID;
@@ -2418,7 +2815,9 @@ var RoomJoinConfiguration = class {
2418
2815
 
2419
2816
  // src/Stream/Room/RoomEvent.ts
2420
2817
  var RoomEvent = class _RoomEvent {
2421
- /** 生成开始信令。 */
2818
+ /**
2819
+ * 生成开始信令。
2820
+ */
2422
2821
  static start(options) {
2423
2822
  return _RoomEvent.encode({
2424
2823
  event: "start",
@@ -2427,7 +2826,9 @@ var RoomEvent = class _RoomEvent {
2427
2826
  uid: options.taskID
2428
2827
  });
2429
2828
  }
2430
- /** 生成条件变更信令。 */
2829
+ /**
2830
+ * 生成条件变更信令。
2831
+ */
2431
2832
  static changeCondition(options) {
2432
2833
  return _RoomEvent.encode({
2433
2834
  event: "change_condition",
@@ -2436,7 +2837,9 @@ var RoomEvent = class _RoomEvent {
2436
2837
  uid: options.taskID
2437
2838
  });
2438
2839
  }
2439
- /** 回传尺寸调整信令。 */
2840
+ /**
2841
+ * 回传尺寸调整信令。
2842
+ */
2440
2843
  static changeTargetSize(options) {
2441
2844
  return _RoomEvent.encode({
2442
2845
  event: "change_target_size",
@@ -2450,7 +2853,9 @@ var RoomEvent = class _RoomEvent {
2450
2853
  uid: options.taskID
2451
2854
  });
2452
2855
  }
2453
- /** 生成停止信令。 */
2856
+ /**
2857
+ * 生成停止信令。
2858
+ */
2454
2859
  static stop(options) {
2455
2860
  return _RoomEvent.encode({
2456
2861
  event: "stop",
@@ -2458,7 +2863,9 @@ var RoomEvent = class _RoomEvent {
2458
2863
  uid: options.taskID
2459
2864
  });
2460
2865
  }
2461
- /** 交互轨迹信令。 */
2866
+ /**
2867
+ * 交互轨迹信令。
2868
+ */
2462
2869
  static tracks(options) {
2463
2870
  return _RoomEvent.encode({
2464
2871
  event: "tracks",
@@ -2467,14 +2874,18 @@ var RoomEvent = class _RoomEvent {
2467
2874
  uid: options.taskID
2468
2875
  });
2469
2876
  }
2470
- /** 房间心跳信令。 */
2877
+ /**
2878
+ * 房间心跳信令。
2879
+ */
2471
2880
  static heartbeat(options) {
2472
2881
  return _RoomEvent.encode({
2473
2882
  event: "heartbeat",
2474
2883
  user_id: options.userID
2475
2884
  });
2476
2885
  }
2477
- /** 生成条件参数:模型、生成尺寸、回传尺寸、文本与参考图路径。 */
2886
+ /**
2887
+ * 生成条件参数:模型、生成尺寸、回传尺寸、文本与参考图路径。
2888
+ */
2478
2889
  static generationParameters(options) {
2479
2890
  return {
2480
2891
  model: "default",
@@ -2487,7 +2898,9 @@ var RoomEvent = class _RoomEvent {
2487
2898
  ref_image_path: options.context.referencePath
2488
2899
  };
2489
2900
  }
2490
- /** 业务字段外加 `runtime` 运行环境信息并序列化为 JSON 文本。 */
2901
+ /**
2902
+ * 业务字段外加 `runtime` 运行环境信息并序列化为 JSON 文本。
2903
+ */
2491
2904
  static encode(payload) {
2492
2905
  try {
2493
2906
  return JSON.stringify({ ...payload, runtime: RuntimeInfo.toJSON() });
@@ -2510,27 +2923,39 @@ var RoomHeartbeat = class {
2510
2923
  * @param options.sleep 心跳等待实现(可替换,测试用)。
2511
2924
  */
2512
2925
  constructor(options) {
2513
- // 基础层组件
2926
+ /**
2927
+ * 基础层组件
2928
+ */
2514
2929
  __publicField(this, "rtcManager");
2515
- // 心跳配置
2930
+ /**
2931
+ * 心跳配置
2932
+ */
2516
2933
  __publicField(this, "intervalMs");
2517
2934
  __publicField(this, "sleep");
2518
- // 运行状态
2935
+ /**
2936
+ * 运行状态
2937
+ */
2519
2938
  __publicField(this, "cycleVersion", 0);
2520
2939
  this.rtcManager = options.rtcManager;
2521
2940
  this.intervalMs = _nullishCoalesce(options.intervalMs, () => ( 1e4));
2522
2941
  this.sleep = _nullishCoalesce(options.sleep, () => ( ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))));
2523
2942
  }
2524
- /** 启动周期心跳;重复启动会替换当前周期。 */
2943
+ /**
2944
+ * 启动周期心跳;重复启动会替换当前周期。
2945
+ */
2525
2946
  start(userID) {
2526
2947
  const version = ++this.cycleVersion;
2527
2948
  void this.run(version, userID);
2528
2949
  }
2529
- /** 停止当前心跳周期;迟到结果不会再发送。 */
2950
+ /**
2951
+ * 停止当前心跳周期;迟到结果不会再发送。
2952
+ */
2530
2953
  stop() {
2531
2954
  this.cycleVersion += 1;
2532
2955
  }
2533
- /** 周期循环:等待后发送心跳;发送失败仅记录日志,周期继续。 */
2956
+ /**
2957
+ * 周期循环:等待后发送心跳;发送失败仅记录日志,周期继续。
2958
+ */
2534
2959
  async run(version, userID) {
2535
2960
  while (this.cycleVersion === version) {
2536
2961
  await this.sleep(this.intervalMs);
@@ -2556,7 +2981,9 @@ var RoomHeartbeat = class {
2556
2981
  var CHUNK_EVENT = "__trtc_chunk__";
2557
2982
  var _RoomMessageCodec = class _RoomMessageCodec {
2558
2983
  constructor() {
2559
- // 接收缓存
2984
+ /**
2985
+ * 接收缓存
2986
+ */
2560
2987
  __publicField(this, "records", /* @__PURE__ */ new Map());
2561
2988
  }
2562
2989
  /**
@@ -2592,13 +3019,20 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2592
3019
  /**
2593
3020
  * 处理入站消息。
2594
3021
  *
2595
- * @returns 普通业务消息原样返回;分片未收齐或组包结果不是合法
2596
- * JSON 时返回 `undefined`;分片收齐后返回完整消息并从缓存移除。
3022
+ * @returns 返回解析后的业务消息;分片未收齐或 JSON 非法时返回
3023
+ * `undefined`;分片收齐后从缓存移除并解析完整消息。
2597
3024
  */
2598
3025
  processIncoming(senderUserID, message) {
2599
- const chunk = _RoomMessageCodec.parseChunk(message);
3026
+ let parsed;
3027
+ try {
3028
+ parsed = JSON.parse(message);
3029
+ } catch (e12) {
3030
+ XmaxLogger.room.warning(() => "\u623F\u95F4\u6D88\u606F\u4E0D\u662F\u5408\u6CD5 JSON (Room Message Is Not Valid JSON)");
3031
+ return void 0;
3032
+ }
3033
+ const chunk = _RoomMessageCodec.parseChunk(parsed);
2600
3034
  if (!chunk) {
2601
- return message;
3035
+ return parsed;
2602
3036
  }
2603
3037
  const key = `${senderUserID}:${chunk.eventId}`;
2604
3038
  let record = this.records.get(key);
@@ -2622,28 +3056,25 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2622
3056
  }
2623
3057
  const joined = parts.join("");
2624
3058
  try {
2625
- JSON.parse(joined);
2626
- } catch (e12) {
3059
+ return JSON.parse(joined);
3060
+ } catch (e13) {
2627
3061
  XmaxLogger.room.warning(
2628
3062
  () => `\u623F\u95F4\u6D88\u606F\u7EC4\u5305\u540E\u4E0D\u662F\u5408\u6CD5 JSON (Reassembled Message Is Not Valid JSON)
2629
3063
  \u2514\u2500 eventId: ${chunk.eventId}`
2630
3064
  );
2631
3065
  return void 0;
2632
3066
  }
2633
- return joined;
2634
3067
  }
2635
- /** 清空未完成的组包缓存。 */
3068
+ /**
3069
+ * 清空未完成的组包缓存。
3070
+ */
2636
3071
  reset() {
2637
3072
  this.records.clear();
2638
3073
  }
2639
- /** 识别分片消息;字段不完整时按普通业务消息处理。 */
2640
- static parseChunk(message) {
2641
- let parsed;
2642
- try {
2643
- parsed = JSON.parse(message);
2644
- } catch (e13) {
2645
- return void 0;
2646
- }
3074
+ /**
3075
+ * 从已解析的值识别分片消息;字段不完整时按普通业务消息处理。
3076
+ */
3077
+ static parseChunk(parsed) {
2647
3078
  if (typeof parsed !== "object" || parsed === null) {
2648
3079
  return void 0;
2649
3080
  }
@@ -2658,7 +3089,9 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2658
3089
  }
2659
3090
  return { eventId: record.eventId, index, count, data: record.data };
2660
3091
  }
2661
- /** 淘汰最旧的未完成记录,保持缓存不超过上限。 */
3092
+ /**
3093
+ * 淘汰最旧的未完成记录,保持缓存不超过上限。
3094
+ */
2662
3095
  evictOverflow() {
2663
3096
  while (this.records.size > _RoomMessageCodec.cacheLimit) {
2664
3097
  const oldest = this.records.keys().next().value;
@@ -2668,7 +3101,9 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2668
3101
  this.records.delete(oldest);
2669
3102
  }
2670
3103
  }
2671
- /** 按 UTF-8 字节预算切分字符串,不拆分多字节字符。 */
3104
+ /**
3105
+ * 按 UTF-8 字节预算切分字符串,不拆分多字节字符。
3106
+ */
2672
3107
  static sliceByByteBudget(message, budget) {
2673
3108
  const slices = [];
2674
3109
  let current = "";
@@ -2688,11 +3123,15 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2688
3123
  }
2689
3124
  return slices;
2690
3125
  }
2691
- /** 计算字符串的 UTF-8 字节长度。 */
3126
+ /**
3127
+ * 计算字符串的 UTF-8 字节长度。
3128
+ */
2692
3129
  static byteLength(value) {
2693
3130
  return new TextEncoder().encode(value).byteLength;
2694
3131
  }
2695
- /** 生成拆包事件标识(32 位十六进制)。 */
3132
+ /**
3133
+ * 生成拆包事件标识(32 位十六进制)。
3134
+ */
2696
3135
  static makeEventId() {
2697
3136
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
2698
3137
  return crypto.randomUUID().replace(/-/g, "");
@@ -2703,12 +3142,20 @@ var _RoomMessageCodec = class _RoomMessageCodec {
2703
3142
  ).join("");
2704
3143
  }
2705
3144
  };
2706
- // 协议常量
2707
- /** 触发拆包的消息字节阈值。 */
3145
+ /**
3146
+ * 协议常量
3147
+ */
3148
+ /**
3149
+ * 触发拆包的消息字节阈值。
3150
+ */
2708
3151
  __publicField(_RoomMessageCodec, "chunkThresholdBytes", 800);
2709
- /** 单个分片正文的字节预算,保证分片 JSON 自身不超过阈值。 */
3152
+ /**
3153
+ * 单个分片正文的字节预算,保证分片 JSON 自身不超过阈值。
3154
+ */
2710
3155
  __publicField(_RoomMessageCodec, "chunkDataBudgetBytes", 600);
2711
- /** 未完成组包记录的缓存上限(LRU)。 */
3156
+ /**
3157
+ * 未完成组包记录的缓存上限(LRU)。
3158
+ */
2712
3159
  __publicField(_RoomMessageCodec, "cacheLimit", 1e3);
2713
3160
  var RoomMessageCodec = _RoomMessageCodec;
2714
3161
 
@@ -2722,14 +3169,22 @@ var RoomController = class {
2722
3169
  * @param options.codec 房间消息编解码组件(可替换,测试用)。
2723
3170
  */
2724
3171
  constructor(options) {
2725
- // 基础层组件
3172
+ /**
3173
+ * 基础层组件
3174
+ */
2726
3175
  __publicField(this, "rtcManager");
2727
- // 传输层组件
3176
+ /**
3177
+ * 传输层组件
3178
+ */
2728
3179
  __publicField(this, "heartbeat");
2729
3180
  __publicField(this, "codec");
2730
- // 事件监听
3181
+ /**
3182
+ * 事件监听
3183
+ */
2731
3184
  __publicField(this, "listener");
2732
- // 房间资源
3185
+ /**
3186
+ * 房间资源
3187
+ */
2733
3188
  __publicField(this, "state", { kind: "idle" });
2734
3189
  __publicField(this, "leaveOperation");
2735
3190
  this.rtcManager = options.rtcManager;
@@ -2784,7 +3239,9 @@ var RoomController = class {
2784
3239
  throw XmaxError.from(error);
2785
3240
  }
2786
3241
  }
2787
- /** 停止房间心跳并离开当前 RTC 房间;并发的离开操作共享同一个任务。 */
3242
+ /**
3243
+ * 停止房间心跳并离开当前 RTC 房间;并发的离开操作共享同一个任务。
3244
+ */
2788
3245
  async leave() {
2789
3246
  if (this.leaveOperation) {
2790
3247
  await this.leaveOperation;
@@ -2844,14 +3301,18 @@ var RoomController = class {
2844
3301
  })
2845
3302
  );
2846
3303
  }
2847
- /** 尝试发送生成停止信令;未进房或任务标识为空时忽略。 */
3304
+ /**
3305
+ * 尝试发送生成停止信令;未进房或任务标识为空时忽略。
3306
+ */
2848
3307
  stopGeneration(taskID) {
2849
3308
  if (!taskID || this.state.kind !== "joined") {
2850
3309
  return;
2851
3310
  }
2852
3311
  this.send(RoomEvent.stop({ userID: this.state.userID, taskID }));
2853
3312
  }
2854
- /** 发送生成任务的交互轨迹;任务标识或轨迹为空时忽略。 */
3313
+ /**
3314
+ * 发送生成任务的交互轨迹;任务标识或轨迹为空时忽略。
3315
+ */
2855
3316
  sendTracks(taskID, points) {
2856
3317
  if (!taskID || points.length === 0) {
2857
3318
  return;
@@ -2864,11 +3325,15 @@ var RoomController = class {
2864
3325
  })
2865
3326
  );
2866
3327
  }
2867
- /** 设置房间事件监听器,传入空值时清除监听器。 */
3328
+ /**
3329
+ * 设置房间事件监听器,传入空值时清除监听器。
3330
+ */
2868
3331
  setListener(listener) {
2869
3332
  this.listener = listener;
2870
3333
  }
2871
- /** 执行离开:复位状态、停止心跳、清空组包缓存并退房。 */
3334
+ /**
3335
+ * 执行离开:复位状态、停止心跳、清空组包缓存并退房。
3336
+ */
2872
3337
  async performLeave() {
2873
3338
  this.state = { kind: "idle" };
2874
3339
  this.heartbeat.stop();
@@ -2876,19 +3341,11 @@ var RoomController = class {
2876
3341
  await this.rtcManager.leaveRoom();
2877
3342
  this.leaveOperation = void 0;
2878
3343
  }
2879
- /** 组包入站消息并按目标用户过滤后分发完整业务消息。 */
3344
+ /**
3345
+ * 组包入站消息并按目标用户过滤后分发完整业务消息。
3346
+ */
2880
3347
  handleIncomingMessage(senderUserID, raw) {
2881
- const complete = this.codec.processIncoming(senderUserID, raw);
2882
- if (complete === void 0) {
2883
- return;
2884
- }
2885
- let parsed;
2886
- try {
2887
- parsed = JSON.parse(complete);
2888
- } catch (e14) {
2889
- XmaxLogger.room.warning(() => "\u623F\u95F4\u6D88\u606F\u4E0D\u662F\u5408\u6CD5 JSON (Room Message Is Not Valid JSON)");
2890
- return;
2891
- }
3348
+ const parsed = this.codec.processIncoming(senderUserID, raw);
2892
3349
  if (typeof parsed !== "object" || parsed === null) {
2893
3350
  return;
2894
3351
  }
@@ -2900,7 +3357,9 @@ var RoomController = class {
2900
3357
  }
2901
3358
  _optionalChain([this, 'access', _104 => _104.listener, 'optionalAccess', _105 => _105.onRoomMessage, 'call', _106 => _106(senderUserID, message)]);
2902
3359
  }
2903
- /** 发送房间信令并输出日志。 */
3360
+ /**
3361
+ * 发送房间信令并输出日志。
3362
+ */
2904
3363
  send(message) {
2905
3364
  for (const packet of this.codec.encodeOutgoing(message)) {
2906
3365
  try {
@@ -2915,7 +3374,9 @@ var RoomController = class {
2915
3374
  ${JSON.stringify(JSON.parse(message), null, 2)}`
2916
3375
  );
2917
3376
  }
2918
- /** 返回当前房间中的用户标识;未进房时抛出错误。 */
3377
+ /**
3378
+ * 返回当前房间中的用户标识;未进房时抛出错误。
3379
+ */
2919
3380
  requireUserID() {
2920
3381
  if (this.state.kind !== "joined") {
2921
3382
  throw new XmaxError("RTC_ERROR" /* rtcError */, "RTC room is not joined");
@@ -2936,10 +3397,15 @@ var _EncodingController = class _EncodingController {
2936
3397
  * @param options.rtcManager RTC 引擎与媒体传输组件。
2937
3398
  */
2938
3399
  constructor(options) {
2939
- // 基础层组件
3400
+ /**
3401
+ * 基础层组件
3402
+ */
2940
3403
  __publicField(this, "rtcManager");
2941
3404
  this.rtcManager = options.rtcManager;
2942
3405
  }
3406
+ /**
3407
+ * 校验视频格式,解析显式或推荐码率范围后配置 RTC 编码器;参数或配置失败时抛错。
3408
+ */
2943
3409
  async configure(videoFormat) {
2944
3410
  videoFormat.validate();
2945
3411
  let minimum;
@@ -2959,8 +3425,8 @@ var _EncodingController = class _EncodingController {
2959
3425
  "Realtime video format exceeds the supported bitrate range"
2960
3426
  );
2961
3427
  }
2962
- const defaultMinimum = Math.max(1, Math.trunc(Math.round(bitrates.minimum)));
2963
- const defaultMaximum = Math.max(defaultMinimum + 1, Math.trunc(maximumBitrate));
3428
+ const defaultMinimum = Math.max(1, Math.round(bitrates.minimum));
3429
+ const defaultMaximum = Math.max(defaultMinimum + 1, maximumBitrate);
2964
3430
  minimum = _nullishCoalesce(videoFormat.minimumBitrate, () => ( defaultMinimum));
2965
3431
  maximum = _nullishCoalesce(videoFormat.maximumBitrate, () => ( defaultMaximum));
2966
3432
  }
@@ -2979,7 +3445,9 @@ var _EncodingController = class _EncodingController {
2979
3445
  encoderPreference: ENCODER_PREFERENCE_MAP[videoFormat.encoderPreference]
2980
3446
  });
2981
3447
  }
2982
- /** 按像素面积与帧率计算码率区间(kbps):流畅优先为最低,画质优先为最高。 */
3448
+ /**
3449
+ * 按像素面积与帧率计算码率区间(kbps):流畅优先为最低,画质优先为最高。
3450
+ */
2983
3451
  static resolveBitrates(pixels, fps) {
2984
3452
  const bitrate15 = _EncodingController.interpolate(
2985
3453
  pixels,
@@ -3017,7 +3485,9 @@ var _EncodingController = class _EncodingController {
3017
3485
  ])
3018
3486
  };
3019
3487
  }
3020
- /** 在相邻参考点间线性插值,表外按最近端点的比例外推。 */
3488
+ /**
3489
+ * 在相邻参考点间线性插值,表外按最近端点的比例外推。
3490
+ */
3021
3491
  static interpolate(value, points) {
3022
3492
  const first = points[0];
3023
3493
  if (value <= first.value) {
@@ -3035,7 +3505,9 @@ var _EncodingController = class _EncodingController {
3035
3505
  return last.bitrate * (value / last.value);
3036
3506
  }
3037
3507
  };
3038
- // 流畅优先码率参考,按像素面积升序排列,单位为 kbps。
3508
+ /**
3509
+ * 流畅优先码率参考,按像素面积升序排列,单位为 kbps。
3510
+ */
3039
3511
  __publicField(_EncodingController, "referenceBitratesAt15FPS", [
3040
3512
  { value: 120 * 120, bitrate: 50 },
3041
3513
  { value: 160 * 120, bitrate: 65 },
@@ -3088,22 +3560,34 @@ var StreamController = class {
3088
3560
  * @param options.generationTimeoutMs 生成开始确认超时时间(毫秒);默认 30 秒。
3089
3561
  */
3090
3562
  constructor(options) {
3091
- // 基础层组件
3563
+ /**
3564
+ * 基础层组件
3565
+ */
3092
3566
  __publicField(this, "rtcManager");
3093
- // 传输层组件
3567
+ /**
3568
+ * 传输层组件
3569
+ */
3094
3570
  __publicField(this, "roomController");
3095
3571
  __publicField(this, "encodingController");
3096
- // 事件监听
3572
+ /**
3573
+ * 事件监听
3574
+ */
3097
3575
  __publicField(this, "errorListener");
3098
3576
  __publicField(this, "remoteStreamListener");
3099
3577
  __publicField(this, "localVideoStatisticsListener");
3100
3578
  __publicField(this, "networkStatisticsListener");
3101
3579
  __publicField(this, "remoteVideoStatisticsListener");
3102
- // 生成配置
3580
+ /**
3581
+ * 生成配置
3582
+ */
3103
3583
  __publicField(this, "generationTimeoutMs");
3104
- // 音频配置
3584
+ /**
3585
+ * 音频配置
3586
+ */
3105
3587
  __publicField(this, "remoteAudioVolumePercentage", 100);
3106
- // 运行状态
3588
+ /**
3589
+ * 运行状态
3590
+ */
3107
3591
  __publicField(this, "state", makeInitialState());
3108
3592
  this.rtcManager = options.rtcManager;
3109
3593
  this.roomController = _nullishCoalesce(options.roomController, () => ( new RoomController({ rtcManager: options.rtcManager })));
@@ -3138,27 +3622,39 @@ var StreamController = class {
3138
3622
  }
3139
3623
  });
3140
3624
  }
3141
- /** 当前是否存在正在启动或已经运行的生成任务。 */
3625
+ /**
3626
+ * 当前是否存在正在启动或已经运行的生成任务。
3627
+ */
3142
3628
  get hasGenerationTask() {
3143
3629
  return this.state.generationTaskID !== void 0;
3144
3630
  }
3145
- /** 设置本地主视频流统计监听器,不改变 RTC 事件监听权。 */
3631
+ /**
3632
+ * 设置本地主视频流统计监听器,不改变 RTC 事件监听权。
3633
+ */
3146
3634
  setLocalVideoStatisticsListener(listener) {
3147
3635
  this.localVideoStatisticsListener = listener;
3148
3636
  }
3149
- /** 网络统计不按远端用户过滤,连接发布完成后即可回调。 */
3637
+ /**
3638
+ * 网络统计不按远端用户过滤,连接发布完成后即可回调。
3639
+ */
3150
3640
  setNetworkStatisticsListener(listener) {
3151
3641
  this.networkStatisticsListener = listener;
3152
3642
  }
3153
- /** 监听当前实际生成结果流的统计,不按会话下发的 botID 猜测结果流身份。 */
3643
+ /**
3644
+ * 监听当前实际生成结果流的统计,不按会话下发的 botID 猜测结果流身份。
3645
+ */
3154
3646
  setRemoteVideoStatisticsListener(listener) {
3155
3647
  this.remoteVideoStatisticsListener = listener;
3156
3648
  }
3157
- /** 当前远端生成音频播放音量,取值范围为 `0...1`。 */
3649
+ /**
3650
+ * 当前远端生成音频播放音量,取值范围为 `0...1`。
3651
+ */
3158
3652
  get remoteAudioVolume() {
3159
3653
  return this.remoteAudioVolumePercentage / 100;
3160
3654
  }
3161
- /** 设置远端生成音频播放音量,并应用到所有已订阅的远端音频。 */
3655
+ /**
3656
+ * 设置远端生成音频播放音量,并应用到所有已订阅的远端音频。
3657
+ */
3162
3658
  setRemoteAudioVolume(volume) {
3163
3659
  const rtcVolume = Math.min(Math.max(Math.round(volume * 100), 0), 100);
3164
3660
  for (const userID of [...this.state.subscribedRemoteAudioUserIDs].sort()) {
@@ -3191,7 +3687,9 @@ var StreamController = class {
3191
3687
  ensureActive();
3192
3688
  await this.publishLocalStream(includeLocalAudio);
3193
3689
  }
3194
- /** 清理生成状态、本地发布和远端订阅,并离开当前 RTC 房间。 */
3690
+ /**
3691
+ * 清理生成状态、本地发布和远端订阅,并离开当前 RTC 房间。
3692
+ */
3195
3693
  async disconnect() {
3196
3694
  await this.resetStream();
3197
3695
  await this.roomController.leave();
@@ -3256,7 +3754,7 @@ var StreamController = class {
3256
3754
  this.rejectGenerationStart(taskID, mapped);
3257
3755
  try {
3258
3756
  this.roomController.stopGeneration(taskID);
3259
- } catch (e15) {
3757
+ } catch (e14) {
3260
3758
  }
3261
3759
  throw mapped;
3262
3760
  }
@@ -3334,11 +3832,15 @@ var StreamController = class {
3334
3832
  throw XmaxError.from(error);
3335
3833
  }
3336
3834
  }
3337
- /** 设置房间业务消息监听器,传入空值时清除监听器。 */
3835
+ /**
3836
+ * 设置房间业务消息监听器,传入空值时清除监听器。
3837
+ */
3338
3838
  setRoomListener(listener) {
3339
3839
  this.roomController.setListener(listener);
3340
3840
  }
3341
- /** 配置当前房间;已有发布、订阅或生成任务时拒绝重新配置。 */
3841
+ /**
3842
+ * 配置当前房间;已有发布、订阅或生成任务时拒绝重新配置。
3843
+ */
3342
3844
  configureRoom(options) {
3343
3845
  const roomID = options.roomID.trim();
3344
3846
  const botID = _nullishCoalesce(_optionalChain([options, 'access', _117 => _117.botID, 'optionalAccess', _118 => _118.trim, 'call', _119 => _119()]), () => ( ""));
@@ -3357,7 +3859,9 @@ var StreamController = class {
3357
3859
  this.state.roomID = roomID;
3358
3860
  this.state.botID = botID;
3359
3861
  }
3360
- /** 发布本地视频,按需发布本地音频;音频发布失败时回滚视频发布。 */
3862
+ /**
3863
+ * 发布本地视频,按需发布本地音频;音频发布失败时回滚视频发布。
3864
+ */
3361
3865
  async publishLocalStream(includeAudio) {
3362
3866
  if (!this.state.roomID) {
3363
3867
  throw new XmaxError(
@@ -3383,7 +3887,9 @@ var StreamController = class {
3383
3887
  throw XmaxError.from(error);
3384
3888
  }
3385
3889
  }
3386
- /** 处理远端视频发布状态变化:按机器人标识过滤后订阅或清理。 */
3890
+ /**
3891
+ * 处理远端视频发布状态变化:按机器人标识过滤后订阅或清理。
3892
+ */
3387
3893
  async handleRemoteVideoPublished(userID, published) {
3388
3894
  const trimmedUserID = userID.trim();
3389
3895
  if (!trimmedUserID) {
@@ -3420,7 +3926,9 @@ var StreamController = class {
3420
3926
  this.clearRemoteStream();
3421
3927
  }
3422
3928
  }
3423
- /** 订阅远端视频并在成功后就绪或确认生成任务。 */
3929
+ /**
3930
+ * 订阅远端视频并在成功后就绪或确认生成任务。
3931
+ */
3424
3932
  async subscribeRemoteVideo(userID) {
3425
3933
  if (this.state.subscribedRemoteUserIDs.has(userID)) {
3426
3934
  return;
@@ -3452,7 +3960,9 @@ var StreamController = class {
3452
3960
  }
3453
3961
  }
3454
3962
  }
3455
- /** 订阅成功后就绪远端流:有待确认的生成任务时确认它,否则更新当前绑定。 */
3963
+ /**
3964
+ * 订阅成功后就绪远端流:有待确认的生成任务时确认它,否则更新当前绑定。
3965
+ */
3456
3966
  confirmOrUpdateRemoteStream(userID, track) {
3457
3967
  const waiter = this.state.generationWaiter;
3458
3968
  const taskID = this.state.generationTaskID;
@@ -3485,7 +3995,9 @@ var StreamController = class {
3485
3995
  }
3486
3996
  }
3487
3997
  }
3488
- /** 订阅远端音频:先应用当前音量再订阅。 */
3998
+ /**
3999
+ * 订阅远端音频:先应用当前音量再订阅。
4000
+ */
3489
4001
  async subscribeRemoteAudio(userID) {
3490
4002
  if (this.state.subscribedRemoteAudioUserIDs.has(userID)) {
3491
4003
  return;
@@ -3494,7 +4006,9 @@ var StreamController = class {
3494
4006
  await this.rtcManager.subscribeRemoteAudio(userID, true);
3495
4007
  this.state.subscribedRemoteAudioUserIDs.add(userID);
3496
4008
  }
3497
- /** 取消订阅远端音频;失败仅记录日志。 */
4009
+ /**
4010
+ * 取消订阅远端音频;失败仅记录日志。
4011
+ */
3498
4012
  async unsubscribeRemoteAudio(userID) {
3499
4013
  if (!this.state.subscribedRemoteAudioUserIDs.delete(userID)) {
3500
4014
  return;
@@ -3533,7 +4047,9 @@ var StreamController = class {
3533
4047
  this.clearRemoteStream();
3534
4048
  return currentTaskID;
3535
4049
  }
3536
- /** 复位传输层:停止生成、取消全部远端订阅、取消本地发布。 */
4050
+ /**
4051
+ * 复位传输层:停止生成、取消全部远端订阅、取消本地发布。
4052
+ */
3537
4053
  async resetStream() {
3538
4054
  await this.stopStreamGeneration("");
3539
4055
  const previousState = this.state;
@@ -3559,7 +4075,9 @@ var StreamController = class {
3559
4075
  );
3560
4076
  }
3561
4077
  }
3562
- /** 确认生成开始:清理等待器并兑现确认 Promise。 */
4078
+ /**
4079
+ * 确认生成开始:清理等待器并兑现确认 Promise。
4080
+ */
3563
4081
  resolveGenerationStart(taskID) {
3564
4082
  const waiter = this.state.generationWaiter;
3565
4083
  if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _123 => _123.taskID]) !== taskID) {
@@ -3569,7 +4087,9 @@ var StreamController = class {
3569
4087
  clearTimeout(waiter.timeoutTimer);
3570
4088
  waiter.resolve();
3571
4089
  }
3572
- /** 拒绝生成开始:清理等待器并拒绝确认 Promise。 */
4090
+ /**
4091
+ * 拒绝生成开始:清理等待器并拒绝确认 Promise。
4092
+ */
3573
4093
  rejectGenerationStart(taskID, error) {
3574
4094
  const waiter = this.state.generationWaiter;
3575
4095
  if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _124 => _124.taskID]) !== taskID) {
@@ -3579,7 +4099,9 @@ var StreamController = class {
3579
4099
  clearTimeout(waiter.timeoutTimer);
3580
4100
  waiter.reject(error);
3581
4101
  }
3582
- /** 通知渲染层清理远端生成流;失败仅记录日志。 */
4102
+ /**
4103
+ * 通知渲染层清理远端生成流;失败仅记录日志。
4104
+ */
3583
4105
  clearRemoteStream() {
3584
4106
  _optionalChain([this, 'access', _125 => _125.remoteVideoStatisticsListener, 'optionalCall', _126 => _126(void 0)]);
3585
4107
  try {
@@ -3591,7 +4113,9 @@ var StreamController = class {
3591
4113
  );
3592
4114
  }
3593
4115
  }
3594
- /** 回滚本地视频发布;失败仅记录日志。 */
4116
+ /**
4117
+ * 回滚本地视频发布;失败仅记录日志。
4118
+ */
3595
4119
  async rollbackLocalVideoPublication() {
3596
4120
  await this.performCleanup(
3597
4121
  "\u56DE\u6EDA RTC \u672C\u5730\u89C6\u9891\u53D1\u5E03\u5931\u8D25 (Failed to Roll Back RTC Local Video Publication)",
@@ -3601,7 +4125,9 @@ var StreamController = class {
3601
4125
  }
3602
4126
  );
3603
4127
  }
3604
- /** 执行清理动作;失败仅记录日志。 */
4128
+ /**
4129
+ * 执行清理动作;失败仅记录日志。
4130
+ */
3605
4131
  async performCleanup(title, action) {
3606
4132
  try {
3607
4133
  await action();
@@ -3622,31 +4148,52 @@ function scopeAffects(scope, kind) {
3622
4148
  return kind !== "media" /* media */;
3623
4149
  }
3624
4150
  var OperationLease = class {
4151
+ /**
4152
+ * 创建操作租约;未指定失败范围时不自动扩大资源清理范围。
4153
+ */
3625
4154
  constructor(failureScope) {
3626
- // 并发状态
4155
+ /**
4156
+ * 并发状态
4157
+ */
3627
4158
  __publicField(this, "valid", true);
3628
4159
  __publicField(this, "terminalError");
3629
4160
  __publicField(this, "storedFailureScope");
3630
4161
  __publicField(this, "abortController", new AbortController());
3631
4162
  this.storedFailureScope = failureScope;
3632
4163
  }
4164
+ /**
4165
+ * 租约是否仍然有效,可用于异步结果提交前的快速判断。
4166
+ */
3633
4167
  get isCurrent() {
3634
4168
  return this.valid;
3635
4169
  }
4170
+ /**
4171
+ * 首次使租约失效的错误;主动取消且未指定原因时为空。
4172
+ */
3636
4173
  get failure() {
3637
4174
  return this.terminalError;
3638
4175
  }
4176
+ /**
4177
+ * 当前操作失败或取消时需要清理的资源范围。
4178
+ */
3639
4179
  get failureScope() {
3640
4180
  return this.storedFailureScope;
3641
4181
  }
4182
+ /**
4183
+ * 租约失效时同步触发的取消信号。
4184
+ */
3642
4185
  get signal() {
3643
4186
  return this.abortController.signal;
3644
4187
  }
3645
- /** 更新当前操作失败或被调用方取消时需要释放的资源范围。 */
4188
+ /**
4189
+ * 更新当前操作失败或被调用方取消时需要释放的资源范围。
4190
+ */
3646
4191
  setFailureScope(scope) {
3647
4192
  this.storedFailureScope = scope;
3648
4193
  }
3649
- /** 作废租约并触发中止信号;首个终止原因被保留。 */
4194
+ /**
4195
+ * 作废租约并触发中止信号;首个终止原因被保留。
4196
+ */
3650
4197
  invalidate(error) {
3651
4198
  this.valid = false;
3652
4199
  if (!this.terminalError) {
@@ -3654,7 +4201,9 @@ var OperationLease = class {
3654
4201
  }
3655
4202
  this.abortController.abort();
3656
4203
  }
3657
- /** 在异步边界后校验当前操作仍拥有实时生命周期。 */
4204
+ /**
4205
+ * 在异步边界后校验当前操作仍拥有实时生命周期。
4206
+ */
3658
4207
  ensureCurrent() {
3659
4208
  if (!this.valid) {
3660
4209
  throw _nullishCoalesce(this.terminalError, () => ( RealtimeCoordinator.cancelledError()));
@@ -3663,22 +4212,33 @@ var OperationLease = class {
3663
4212
  };
3664
4213
  var operationSequence = 0;
3665
4214
  var RealtimeCoordinator = class _RealtimeCoordinator {
4215
+ /**
4216
+ * 注入错误分发与资源清理逻辑,初始状态为 idle。
4217
+ */
3666
4218
  constructor(options) {
3667
- // 业务组件
4219
+ /**
4220
+ * 业务组件
4221
+ */
3668
4222
  __publicField(this, "errorHandler");
3669
4223
  __publicField(this, "cleanup");
3670
- // 状态管理
4224
+ /**
4225
+ * 状态管理
4226
+ */
3671
4227
  __publicField(this, "state", new RealtimeState({
3672
4228
  connectionState: "Idle" /* idle */
3673
4229
  }));
3674
4230
  __publicField(this, "stateListener");
3675
- // 操作管理
4231
+ /**
4232
+ * 操作管理
4233
+ */
3676
4234
  __publicField(this, "activeOperation");
3677
4235
  __publicField(this, "termination");
3678
4236
  this.errorHandler = options.errorHandler;
3679
4237
  this.cleanup = options.cleanup;
3680
4238
  }
3681
- /** 当前实时状态快照。 */
4239
+ /**
4240
+ * 当前实时状态快照。
4241
+ */
3682
4242
  get currentState() {
3683
4243
  return this.state;
3684
4244
  }
@@ -3734,12 +4294,16 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3734
4294
  return this.handleFailure(error, operation);
3735
4295
  }
3736
4296
  }
3737
- /** 仅当前操作可以提交新的公开状态。 */
4297
+ /**
4298
+ * 仅当前操作可以提交新的公开状态。
4299
+ */
3738
4300
  async commit(nextState, token) {
3739
4301
  token.ensureCurrent();
3740
4302
  await this.setState(nextState);
3741
4303
  }
3742
- /** 当前本地预览满足就绪条件后,结束媒体准备状态。 */
4304
+ /**
4305
+ * 当前本地预览满足就绪条件后,结束媒体准备状态。
4306
+ */
3743
4307
  async localPreviewDidBecomeReady(isCurrent) {
3744
4308
  if (this.state.connectionState !== "Preparing" /* preparing */ || !isCurrent()) {
3745
4309
  return;
@@ -3748,12 +4312,16 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3748
4312
  new RealtimeState({ connectionState: "Ready" /* ready */ })
3749
4313
  );
3750
4314
  }
3751
- /** 断开实时连接;尚未提交连接状态的活跃操作也会被取消。 */
4315
+ /**
4316
+ * 断开实时连接;尚未提交连接状态的活跃操作也会被取消。
4317
+ */
3752
4318
  async disconnect(reason = RealtimeReason.normal) {
3753
4319
  const task = await this.beginDisconnect(reason);
3754
4320
  await task;
3755
4321
  }
3756
- /** 发起断开并返回收尾任务,使本地媒体调整不必等待网络资源释放。 */
4322
+ /**
4323
+ * 发起断开并返回收尾任务,使本地媒体调整不必等待网络资源释放。
4324
+ */
3757
4325
  async beginDisconnect(reason) {
3758
4326
  const hasConnectionOperation = this.activeOperation ? scopeAffects(0 /* connection */, this.activeOperation.kind) : false;
3759
4327
  const state2 = this.state.connectionState;
@@ -3767,12 +4335,16 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3767
4335
  reason
3768
4336
  );
3769
4337
  }
3770
- /** 终止指定范围并等待资源清理完成;并发终止请求会合并为最大范围。 */
4338
+ /**
4339
+ * 终止指定范围并等待资源清理完成;并发终止请求会合并为最大范围。
4340
+ */
3771
4341
  async terminate(target, reason = RealtimeReason.normal) {
3772
4342
  const task = await this.requestTermination(target, void 0, reason);
3773
4343
  await task;
3774
4344
  }
3775
- /** 清理仍属于当前生命周期的后台故障,并通过最终状态提供原因。 */
4345
+ /**
4346
+ * 清理仍属于当前生命周期的后台故障,并通过最终状态提供原因。
4347
+ */
3776
4348
  async terminateWithError(error, target, isCurrent = () => true) {
3777
4349
  if (!isCurrent()) {
3778
4350
  return;
@@ -3787,7 +4359,9 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3787
4359
  );
3788
4360
  await task;
3789
4361
  }
3790
- /** 操作失败处理:取消走终止流程,错误按失败范围清理或直接上报。 */
4362
+ /**
4363
+ * 操作失败处理:取消走终止流程,错误按失败范围清理或直接上报。
4364
+ */
3791
4365
  async handleFailure(error, operation) {
3792
4366
  const operationWasCancelled = error instanceof XmaxError && error.code === "CANCELLED" /* cancelled */ || error instanceof DOMException && error.name === "AbortError" || !operation.lease.isCurrent;
3793
4367
  if (operationWasCancelled) {
@@ -3832,7 +4406,9 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3832
4406
  this.finish(operation);
3833
4407
  throw resolvedError;
3834
4408
  }
3835
- /** 发起或合并终止请求,作废旧操作并进入断开中状态。 */
4409
+ /**
4410
+ * 发起或合并终止请求,作废旧操作并进入断开中状态。
4411
+ */
3836
4412
  async requestTermination(target, error, reason, origin) {
3837
4413
  let pending = this.termination;
3838
4414
  if (pending) {
@@ -3875,7 +4451,9 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3875
4451
  );
3876
4452
  return pending.task;
3877
4453
  }
3878
- /** 执行终止:等待旧操作收尾,分级清理资源,提交最终状态。 */
4454
+ /**
4455
+ * 执行终止:等待旧操作收尾,分级清理资源,提交最终状态。
4456
+ */
3879
4457
  async performTermination(id) {
3880
4458
  const pending = this.termination;
3881
4459
  if (!pending || pending.id !== id) {
@@ -3921,13 +4499,17 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3921
4499
  return;
3922
4500
  }
3923
4501
  }
3924
- /** 结束指定操作,释放操作准入场。 */
4502
+ /**
4503
+ * 结束指定操作,释放操作准入场。
4504
+ */
3925
4505
  finish(operation) {
3926
4506
  if (_optionalChain([this, 'access', _129 => _129.activeOperation, 'optionalAccess', _130 => _130.id]) === operation.id) {
3927
4507
  this.activeOperation = void 0;
3928
4508
  }
3929
4509
  }
3930
- /** 提交新状态并通知监听器;状态未变化时不通知。 */
4510
+ /**
4511
+ * 提交新状态并通知监听器;状态未变化时不通知。
4512
+ */
3931
4513
  async setState(nextState) {
3932
4514
  if (this.state.equals(nextState)) {
3933
4515
  return;
@@ -3935,7 +4517,9 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3935
4517
  this.state = nextState;
3936
4518
  _optionalChain([this, 'access', _131 => _131.stateListener, 'optionalCall', _132 => _132(nextState)]);
3937
4519
  }
3938
- /** 构造统一的操作取消错误。 */
4520
+ /**
4521
+ * 构造统一的操作取消错误。
4522
+ */
3939
4523
  static cancelledError() {
3940
4524
  return new XmaxError(
3941
4525
  "CANCELLED" /* cancelled */,
@@ -3947,10 +4531,14 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
3947
4531
  // src/Core/Realtime/RealtimeErrorHandler.ts
3948
4532
  var RealtimeErrorHandler = class {
3949
4533
  constructor() {
3950
- // 运行状态
4534
+ /**
4535
+ * 运行状态
4536
+ */
3951
4537
  __publicField(this, "pendingFailures", []);
3952
4538
  }
3953
- /** 上报错误;当前通过日志输出,后续里程碑接入状态原因上报。 */
4539
+ /**
4540
+ * 上报错误;当前通过日志输出,后续里程碑接入状态原因上报。
4541
+ */
3954
4542
  async report(error) {
3955
4543
  if (error.code === "CANCELLED" /* cancelled */) {
3956
4544
  return;
@@ -3961,7 +4549,9 @@ var RealtimeErrorHandler = class {
3961
4549
  \u2514\u2500 ${XmaxLogger.localized("\u539F\u56E0\uFF1A", "Reason: ")}${error.code} ${error.message}`
3962
4550
  );
3963
4551
  }
3964
- /** 清理仍属于已终止生命周期的后台故障。 */
4552
+ /**
4553
+ * 清理仍属于已终止生命周期的后台故障。
4554
+ */
3965
4555
  invalidatePendingFailures(_target) {
3966
4556
  this.pendingFailures = [];
3967
4557
  }
@@ -3970,16 +4560,28 @@ var RealtimeErrorHandler = class {
3970
4560
  // src/Core/Realtime/RealtimeLaunchTimer.ts
3971
4561
  var RealtimeLaunchTimer = class {
3972
4562
  constructor() {
4563
+ /**
4564
+ * 统计快照与观察者
4565
+ */
3973
4566
  __publicField(this, "snapshot", Object.freeze({}));
3974
4567
  __publicField(this, "listener");
4568
+ /**
4569
+ * 当前启动周期与计时起点
4570
+ */
3975
4571
  __publicField(this, "sequence", 0);
3976
4572
  __publicField(this, "active", false);
3977
4573
  __publicField(this, "startedAt", 0);
3978
4574
  }
4575
+ /**
4576
+ * 设置统计监听器并立即回放当前快照;传 undefined 取消监听。
4577
+ */
3979
4578
  setListener(listener) {
3980
4579
  this.listener = listener;
3981
4580
  this.notify();
3982
4581
  }
4582
+ /**
4583
+ * 开始新的启动周期并清空旧快照,返回记录相机创建完成的一次性回调。
4584
+ */
3983
4585
  startCamera() {
3984
4586
  this.sequence += 1;
3985
4587
  this.active = true;
@@ -3989,17 +4591,34 @@ var RealtimeLaunchTimer = class {
3989
4591
  this.notify();
3990
4592
  return complete;
3991
4593
  }
4594
+ /**
4595
+ * 开始会话与进房计时,返回连接阶段完成时调用的记录函数。
4596
+ */
3992
4597
  startConnection() {
3993
4598
  return this.measure("connectionMs", performance.now());
3994
4599
  }
4600
+ /**
4601
+ * 开始亮度检测计时;合格帧到达或超时放行时调用返回的记录函数。
4602
+ */
4603
+ startFrameValidation() {
4604
+ return this.measure("frameValidationMs", performance.now());
4605
+ }
4606
+ /**
4607
+ * 开始等待远端显示首帧;完成回调同时记录首帧耗时和实际总耗时。
4608
+ */
3995
4609
  startFirstFrame() {
3996
4610
  return this.measure("firstFrameMs", performance.now());
3997
4611
  }
3998
- /** 冻结本轮结果,令尚未完成的回调失效;下一轮相机启动才重置。 */
4612
+ /**
4613
+ * 冻结本轮结果,令尚未完成的回调失效;下一轮相机启动才重置。
4614
+ */
3999
4615
  cancel() {
4000
4616
  this.active = false;
4001
4617
  this.sequence += 1;
4002
4618
  }
4619
+ /**
4620
+ * 创建当前周期的一次性计时回调;周期失效或该阶段已记录时忽略调用。
4621
+ */
4003
4622
  measure(key, startedAt) {
4004
4623
  const sequence = this.sequence;
4005
4624
  return () => {
@@ -4015,34 +4634,52 @@ var RealtimeLaunchTimer = class {
4015
4634
  this.notify();
4016
4635
  };
4017
4636
  }
4637
+ /**
4638
+ * 分发不可变快照;隔离同步和异步观察者异常,避免影响媒体生命周期。
4639
+ */
4018
4640
  notify() {
4019
4641
  try {
4020
4642
  void Promise.resolve(_optionalChain([this, 'access', _133 => _133.listener, 'optionalCall', _134 => _134(this.snapshot)])).catch(() => {
4021
4643
  });
4022
- } catch (e16) {
4644
+ } catch (e15) {
4023
4645
  }
4024
4646
  }
4025
4647
  };
4026
4648
 
4027
4649
  // src/Core/Realtime/XmaxRealtimeConnectionManager.ts
4028
4650
  var XmaxRealtimeConnectionManager = class {
4651
+ /**
4652
+ * 注入会话、传输、计时和渲染回调依赖;连接资源在 connect 时创建。
4653
+ */
4029
4654
  constructor(dependencies) {
4030
4655
  __publicField(this, "dependencies", dependencies);
4656
+ /**
4657
+ * 会话资源
4658
+ */
4031
4659
  __publicField(this, "activeSession");
4660
+ /**
4661
+ * 远端轨道与渲染绑定
4662
+ */
4032
4663
  __publicField(this, "activeRemoteTrack");
4033
- __publicField(this, "remoteBinding");
4034
- __publicField(this, "targetSize");
4664
+ __publicField(this, "remoteTarget");
4035
4665
  }
4666
+ /**
4667
+ * 当前活动会话标识;尚未连接或清理完成后为空。
4668
+ */
4036
4669
  get currentSessionID() {
4037
4670
  return _optionalChain([this, 'access', _135 => _135.activeSession, 'optionalAccess', _136 => _136.id]);
4038
4671
  }
4039
- get currentTargetSize() {
4040
- return this.targetSize;
4041
- }
4042
- /** 未配置 API 服务时在连接操作开始前报错,不影响本地预览。 */
4672
+ /**
4673
+ * 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
4674
+ */
4043
4675
  validateConfiguration() {
4044
4676
  this.requireSessionService();
4045
4677
  }
4678
+ /**
4679
+ * 创建会话、配置编码、进房并发布本地媒体,启动心跳后返回远端占位流。
4680
+ * 进房结束即记录连接耗时;可选 beforePublish 检查只阻塞发布,不计入连接耗时。
4681
+ * @throws 会话、进房、发布失败或操作租约已失效时抛出错误,由上层统一清理。
4682
+ */
4046
4683
  async connect(options) {
4047
4684
  const sessionService = this.requireSessionService();
4048
4685
  const streamController = this.dependencies.streamController;
@@ -4069,9 +4706,12 @@ var XmaxRealtimeConnectionManager = class {
4069
4706
  options.ensureCurrent();
4070
4707
  await streamController.connect(connection, options.includeLocalAudio, () => {
4071
4708
  options.ensureCurrent();
4072
- }, options.beforePublish);
4073
- options.ensureCurrent();
4074
- completeConnection();
4709
+ }, async () => {
4710
+ options.ensureCurrent();
4711
+ completeConnection();
4712
+ options.ensureCurrent();
4713
+ await _optionalChain([options, 'access', _137 => _137.beforePublish, 'optionalCall', _138 => _138()]);
4714
+ });
4075
4715
  options.ensureCurrent();
4076
4716
  options.onPublished();
4077
4717
  sessionService.startHeartbeat(session.id, {
@@ -4091,19 +4731,30 @@ var XmaxRealtimeConnectionManager = class {
4091
4731
  streamController.setRemoteAudioVolume(this.dependencies.remoteAudioVolume());
4092
4732
  return new RealtimeMediaStream({ id: "stream1" /* remote */, videoTrack: remoteTrack });
4093
4733
  }
4734
+ /**
4735
+ * 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
4736
+ */
4094
4737
  setFrameInterpolation(options) {
4095
- _optionalChain([this, 'access', _137 => _137.remoteBinding, 'optionalAccess', _138 => _138.setFrameInterpolation, 'call', _139 => _139(options)]);
4738
+ _optionalChain([this, 'access', _139 => _139.remoteTarget, 'optionalAccess', _140 => _140.setFrameInterpolation, 'optionalCall', _141 => _141(options)]);
4096
4739
  }
4740
+ /**
4741
+ * 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
4742
+ */
4097
4743
  clearRemoteMedia() {
4098
- _optionalChain([this, 'access', _140 => _140.remoteBinding, 'optionalAccess', _141 => _141.setMediaStream, 'call', _142 => _142(null)]);
4744
+ _optionalChain([this, 'access', _142 => _142.remoteTarget, 'optionalAccess', _143 => _143.setMediaStream, 'call', _144 => _144(null)]);
4099
4745
  }
4746
+ /**
4747
+ * 停止会话心跳;未配置会话服务时不执行操作。
4748
+ */
4100
4749
  stopHeartbeat() {
4101
- _optionalChain([this, 'access', _143 => _143.dependencies, 'access', _144 => _144.sessionService, 'optionalAccess', _145 => _145.stopHeartbeat, 'call', _146 => _146()]);
4750
+ _optionalChain([this, 'access', _145 => _145.dependencies, 'access', _146 => _146.sessionService, 'optionalAccess', _147 => _147.stopHeartbeat, 'call', _148 => _148()]);
4102
4751
  }
4103
- /** 等待接收轨解除静音;超时只警告,取消必须立即退出并移除监听。 */
4752
+ /**
4753
+ * 等待接收轨解除静音;超时只警告,取消必须立即退出并移除监听。
4754
+ */
4104
4755
  async waitUntilRemoteTrackReady(timeoutMs, signal) {
4105
4756
  if (signal.aborted) throw RealtimeCoordinator.cancelledError();
4106
- const mediaTrack = _optionalChain([this, 'access', _147 => _147.activeRemoteTrack, 'optionalAccess', _148 => _148.mediaStreamTrack]);
4757
+ const mediaTrack = _optionalChain([this, 'access', _149 => _149.activeRemoteTrack, 'optionalAccess', _150 => _150.mediaStreamTrack]);
4107
4758
  if (!mediaTrack || !mediaTrack.muted) return;
4108
4759
  await new Promise((resolve, reject) => {
4109
4760
  const cleanup = () => {
@@ -4140,7 +4791,7 @@ var XmaxRealtimeConnectionManager = class {
4140
4791
  if (track) {
4141
4792
  track.mediaStreamTrack = void 0;
4142
4793
  }
4143
- _optionalChain([this, 'access', _149 => _149.remoteBinding, 'optionalAccess', _150 => _150.setMediaStream, 'call', _151 => _151(null)]);
4794
+ _optionalChain([this, 'access', _151 => _151.remoteTarget, 'optionalAccess', _152 => _152.setMediaStream, 'call', _153 => _153(null)]);
4144
4795
  return;
4145
4796
  }
4146
4797
  if (!track) {
@@ -4150,9 +4801,11 @@ var XmaxRealtimeConnectionManager = class {
4150
4801
  );
4151
4802
  }
4152
4803
  track.mediaStreamTrack = binding.videoTrack;
4153
- _optionalChain([this, 'access', _152 => _152.remoteBinding, 'optionalAccess', _153 => _153.setMediaStream, 'call', _154 => _154(new MediaStream([binding.videoTrack]))]);
4804
+ _optionalChain([this, 'access', _154 => _154.remoteTarget, 'optionalAccess', _155 => _155.setMediaStream, 'call', _156 => _156(new MediaStream([binding.videoTrack]))]);
4154
4805
  }
4155
- /** 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。 */
4806
+ /**
4807
+ * 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
4808
+ */
4156
4809
  registerRemoteBinding(track) {
4157
4810
  VideoRenderRegistry.register(track, {
4158
4811
  frameDisplayHandler: () => {
@@ -4161,39 +4814,34 @@ var XmaxRealtimeConnectionManager = class {
4161
4814
  }
4162
4815
  },
4163
4816
  attachHandler: (view) => {
4164
- _optionalChain([this, 'access', _155 => _155.remoteBinding, 'optionalAccess', _156 => _156.setFrameInterpolation, 'call', _157 => _157(void 0)]);
4817
+ _optionalChain([this, 'access', _157 => _157.remoteTarget, 'optionalAccess', _158 => _158.setFrameInterpolation, 'optionalCall', _159 => _159(void 0)]);
4165
4818
  view.isMirrored = this.dependencies.isMirrored();
4166
- this.remoteBinding = {
4167
- target: view,
4168
- setFrameInterpolation: (options) => _optionalChain([view, 'access', _158 => _158.setFrameInterpolation, 'optionalCall', _159 => _159(options)]),
4169
- setMediaStream: (stream) => {
4170
- view.setMediaStream(stream);
4171
- },
4172
- setMirrored: (mirrored) => {
4173
- view.isMirrored = mirrored;
4174
- }
4175
- };
4819
+ this.remoteTarget = view;
4176
4820
  this.dependencies.onRenderAttached();
4177
4821
  const mediaTrack = track.mediaStreamTrack;
4178
4822
  view.setMediaStream(mediaTrack ? new MediaStream([mediaTrack]) : null);
4179
4823
  },
4180
4824
  detachHandler: (view) => {
4181
- if (_optionalChain([this, 'access', _160 => _160.remoteBinding, 'optionalAccess', _161 => _161.target]) === view) {
4825
+ if (this.remoteTarget === view) {
4182
4826
  this.dependencies.onRenderDetached();
4183
- this.remoteBinding = void 0;
4827
+ this.remoteTarget = void 0;
4184
4828
  }
4185
- _optionalChain([view, 'access', _162 => _162.setFrameInterpolation, 'optionalCall', _163 => _163(void 0)]);
4829
+ _optionalChain([view, 'access', _160 => _160.setFrameInterpolation, 'optionalCall', _161 => _161(void 0)]);
4186
4830
  view.setMediaStream(null);
4187
4831
  }
4188
4832
  });
4189
4833
  }
4190
- /** 同步远端结果画面的镜像状态:与当前本地摄像头位置保持一致。 */
4834
+ /**
4835
+ * 同步远端结果画面的镜像状态:与当前本地摄像头位置保持一致。
4836
+ */
4191
4837
  updateRemoteMirror() {
4192
- _optionalChain([this, 'access', _164 => _164.remoteBinding, 'optionalAccess', _165 => _165.setMirrored, 'call', _166 => _166(
4193
- this.dependencies.isMirrored()
4194
- )]);
4838
+ if (this.remoteTarget) {
4839
+ this.remoteTarget.isMirrored = this.dependencies.isMirrored();
4840
+ }
4195
4841
  }
4196
- /** 构造当前远端生成结果媒体流。 */
4842
+ /**
4843
+ * 构造当前远端生成结果媒体流。
4844
+ */
4197
4845
  makeRemoteStream() {
4198
4846
  const track = this.activeRemoteTrack;
4199
4847
  if (!track) {
@@ -4234,9 +4882,11 @@ var XmaxRealtimeConnectionManager = class {
4234
4882
  closeReason: session.closeReason
4235
4883
  });
4236
4884
  }
4237
- /** 尽力清理全部连接资源,即使退房失败也关闭服务端会话。 */
4885
+ /**
4886
+ * 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
4887
+ */
4238
4888
  async disconnect() {
4239
- const sessionID = _optionalChain([this, 'access', _167 => _167.activeSession, 'optionalAccess', _168 => _168.id]);
4889
+ const sessionID = _optionalChain([this, 'access', _162 => _162.activeSession, 'optionalAccess', _163 => _163.id]);
4240
4890
  this.stopHeartbeat();
4241
4891
  this.clearRemoteMedia();
4242
4892
  try {
@@ -4252,8 +4902,7 @@ var XmaxRealtimeConnectionManager = class {
4252
4902
  }
4253
4903
  this.activeSession = void 0;
4254
4904
  this.activeRemoteTrack = void 0;
4255
- this.remoteBinding = void 0;
4256
- this.targetSize = void 0;
4905
+ this.remoteTarget = void 0;
4257
4906
  if (sessionID && this.dependencies.sessionService) {
4258
4907
  try {
4259
4908
  await this.dependencies.sessionService.closeSession(sessionID);
@@ -4264,7 +4913,9 @@ var XmaxRealtimeConnectionManager = class {
4264
4913
  }
4265
4914
  return sessionID;
4266
4915
  }
4267
- /** 获取会话 Service;未配置 API 服务时抛出配置错误。 */
4916
+ /**
4917
+ * 获取会话 Service;未配置 API 服务时抛出配置错误。
4918
+ */
4268
4919
  requireSessionService() {
4269
4920
  if (!this.dependencies.sessionService) {
4270
4921
  throw new XmaxError(
@@ -4278,14 +4929,25 @@ var XmaxRealtimeConnectionManager = class {
4278
4929
 
4279
4930
  // src/Core/Realtime/XmaxRealtimeGenerationManager.ts
4280
4931
  var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4932
+ /**
4933
+ * 注入房间传输组件和任务标识生成器,不创建会话或启动生成。
4934
+ */
4281
4935
  constructor(streamController, taskIDGenerator = _XmaxRealtimeGenerationManager.createTaskID) {
4282
4936
  __publicField(this, "streamController", streamController);
4283
4937
  __publicField(this, "taskIDGenerator", taskIDGenerator);
4938
+ /**
4939
+ * 当前生成条件与任务标识
4940
+ */
4284
4941
  __publicField(this, "currentContext");
4285
4942
  __publicField(this, "activeTaskID");
4943
+ /**
4944
+ * 并发停止操作的共享结果
4945
+ */
4286
4946
  __publicField(this, "pendingStop");
4287
4947
  }
4288
- /** 首次请求在建立连接前校验条件;后续请求可复用缓存。 */
4948
+ /**
4949
+ * 首次请求在建立连接前校验条件;后续请求可复用缓存。
4950
+ */
4289
4951
  validateContext(context) {
4290
4952
  const resolved = _nullishCoalesce(context, () => ( this.currentContext));
4291
4953
  if (!resolved) {
@@ -4293,6 +4955,10 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4293
4955
  }
4294
4956
  return resolved;
4295
4957
  }
4958
+ /**
4959
+ * 发送生成指令并等待确认、远端就绪和音频激活,成功后返回任务标识。
4960
+ * 条件上下文在生成确认后缓存;启动失败时尽力停止本次任务并保留原始错误。
4961
+ */
4296
4962
  async start(options) {
4297
4963
  const context = this.validateContext(options.context);
4298
4964
  options.ensureCurrent();
@@ -4302,7 +4968,6 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4302
4968
  const confirmation = this.streamController.beginGeneration({
4303
4969
  taskID,
4304
4970
  videoFormat: options.videoFormat,
4305
- targetSize: options.targetSize,
4306
4971
  context
4307
4972
  });
4308
4973
  await this.awaitConfirmation(confirmation, options.signal);
@@ -4318,6 +4983,9 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4318
4983
  throw error;
4319
4984
  }
4320
4985
  }
4986
+ /**
4987
+ * 更新活动任务的生成条件;信令发送成功后才覆盖缓存,无任务或上下文时抛错。
4988
+ */
4321
4989
  update(taskID, options) {
4322
4990
  const context = _nullishCoalesce(options.context, () => ( this.currentContext));
4323
4991
  if (!taskID || !context) {
@@ -4326,11 +4994,13 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4326
4994
  this.streamController.updateGeneration({
4327
4995
  taskID,
4328
4996
  videoFormat: options.videoFormat,
4329
- targetSize: options.targetSize,
4330
4997
  context
4331
4998
  });
4332
4999
  this.currentContext = context;
4333
5000
  }
5001
+ /**
5002
+ * 幂等停止指定活动任务;并发调用共享结果,停止失败仅记录日志。
5003
+ */
4334
5004
  async stop(taskID = this.activeTaskID) {
4335
5005
  if (this.pendingStop && (!taskID || this.pendingStop.taskID === taskID)) {
4336
5006
  return this.pendingStop.completion;
@@ -4349,13 +5019,19 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4349
5019
  try {
4350
5020
  await completion;
4351
5021
  } finally {
4352
- if (_optionalChain([this, 'access', _169 => _169.pendingStop, 'optionalAccess', _170 => _170.completion]) === completion) this.pendingStop = void 0;
5022
+ if (_optionalChain([this, 'access', _164 => _164.pendingStop, 'optionalAccess', _165 => _165.completion]) === completion) this.pendingStop = void 0;
4353
5023
  }
4354
5024
  }
5025
+ /**
5026
+ * 清空缓存的生成条件并等待活动任务停止,供断连和关闭流程使用。
5027
+ */
4355
5028
  async reset(taskID) {
4356
5029
  this.currentContext = void 0;
4357
5030
  await this.stop(_nullishCoalesce(this.activeTaskID, () => ( (taskID || void 0))));
4358
5031
  }
5032
+ /**
5033
+ * 等待生成确认;取消时立即拒绝,并在所有结束路径移除取消监听。
5034
+ */
4359
5035
  async awaitConfirmation(confirmation, signal) {
4360
5036
  await new Promise((resolve, reject) => {
4361
5037
  const cleanup = () => signal.removeEventListener("abort", abort);
@@ -4377,7 +5053,9 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
4377
5053
  if (signal.aborted) abort();
4378
5054
  });
4379
5055
  }
4380
- /** 生成当前生成任务的唯一标识。 */
5056
+ /**
5057
+ * 生成当前生成任务的唯一标识。
5058
+ */
4381
5059
  static createTaskID() {
4382
5060
  const hex = crypto.randomUUID().replace(/-/g, "");
4383
5061
  let binary = "";
@@ -4400,19 +5078,32 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4400
5078
  * 相机控制器与传输层共享同一个 RTC 引擎。
4401
5079
  */
4402
5080
  constructor(options, dependencies) {
4403
- // 业务配置
5081
+ /**
5082
+ * 业务配置
5083
+ */
4404
5084
  __publicField(this, "options");
4405
5085
  __publicField(this, "mediaService");
5086
+ /**
5087
+ * 插帧能力、用户配置与渲染版本
5088
+ */
4406
5089
  __publicField(this, "supportsInterpolation");
4407
5090
  __publicField(this, "interpolationRequested");
4408
5091
  __publicField(this, "interpolationSize");
4409
5092
  __publicField(this, "interpolationRevision", 0);
4410
- // 业务组件
5093
+ /**
5094
+ * 业务组件
5095
+ */
4411
5096
  __publicField(this, "coordinator");
4412
5097
  __publicField(this, "errorHandler");
4413
5098
  __publicField(this, "cameraController");
5099
+ /**
5100
+ * 启动计时与首帧通知
5101
+ */
4414
5102
  __publicField(this, "launchTimer", new RealtimeLaunchTimer());
4415
5103
  __publicField(this, "remoteFrameDisplayHandler");
5104
+ /**
5105
+ * 本地、远端和网络统计快照及观察者
5106
+ */
4416
5107
  __publicField(this, "localVideoStatistics");
4417
5108
  __publicField(this, "localVideoStatisticsListener");
4418
5109
  __publicField(this, "remoteVideoStatistics");
@@ -4420,28 +5111,32 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4420
5111
  __publicField(this, "acceptsVideoStatistics", false);
4421
5112
  __publicField(this, "networkStatistics");
4422
5113
  __publicField(this, "networkStatisticsListener");
4423
- // 实时业务管理组件;状态所有权分别归连接和生成管理器。
5114
+ /**
5115
+ * 实时业务管理组件;状态所有权分别归连接和生成管理器。
5116
+ */
4424
5117
  __publicField(this, "connectionManager");
4425
5118
  __publicField(this, "generationManager");
4426
5119
  __publicField(this, "streamController");
4427
- // 音量配置
5120
+ /**
5121
+ * 音量配置
5122
+ */
4428
5123
  __publicField(this, "storedLocalAudioVolume", 1);
4429
5124
  __publicField(this, "storedRemoteAudioVolume", 0);
4430
5125
  this.options = options;
4431
5126
  this.mediaService = new MediaService(options.model);
4432
5127
  this.interpolationRequested = options.isFrameInterpolationEnabled;
4433
- this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _171 => _171.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
5128
+ this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _166 => _166.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
4434
5129
  this.errorHandler = new RealtimeErrorHandler();
4435
- const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _172 => _172.rtcManager]), () => ( new RtcManager()));
4436
- this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _173 => _173.cameraController]), () => ( new CameraController({
5130
+ const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _167 => _167.rtcManager]), () => ( new RtcManager()));
5131
+ this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _168 => _168.cameraController]), () => ( new CameraController({
4437
5132
  rtcManager,
4438
- mediaService: new MediaService(options.model),
5133
+ mediaService: this.mediaService,
4439
5134
  errorListener: (error) => {
4440
5135
  void this.errorHandler.report(error);
4441
5136
  }
4442
5137
  })));
4443
- const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _174 => _174.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _175 => _175.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService }) : void 0)));
4444
- this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _176 => _176.streamController]), () => ( new StreamController({
5138
+ const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _169 => _169.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _170 => _170.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService }) : void 0)));
5139
+ this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _171 => _171.streamController]), () => ( new StreamController({
4445
5140
  rtcManager,
4446
5141
  errorListener: (error) => {
4447
5142
  void this.errorHandler.report(error);
@@ -4455,12 +5150,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4455
5150
  sessionService,
4456
5151
  streamController: this.streamController,
4457
5152
  timing: this.launchTimer,
4458
- isMirrored: () => _optionalChain([this, 'access', _177 => _177.cameraController, 'access', _178 => _178.currentTrack, 'optionalAccess', _179 => _179.position]) === "front" /* front */,
5153
+ isMirrored: () => _optionalChain([this, 'access', _172 => _172.cameraController, 'access', _173 => _173.currentTrack, 'optionalAccess', _174 => _174.position]) === "front" /* front */,
4459
5154
  remoteAudioVolume: () => this.storedRemoteAudioVolume,
4460
5155
  onHeartbeatFailure: (sessionID, error) => {
4461
5156
  void this.handleHeartbeatFailure(sessionID, error);
4462
5157
  },
4463
- onFrameDisplayed: () => _optionalChain([this, 'access', _180 => _180.remoteFrameDisplayHandler, 'optionalCall', _181 => _181()]),
5158
+ onFrameDisplayed: () => _optionalChain([this, 'access', _175 => _175.remoteFrameDisplayHandler, 'optionalCall', _176 => _176()]),
4464
5159
  onRenderAttached: () => this.applyRemoteInterpolation(),
4465
5160
  onRenderDetached: () => {
4466
5161
  this.interpolationRevision++;
@@ -4490,16 +5185,24 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4490
5185
  }
4491
5186
  });
4492
5187
  }
4493
- /** 当前实时连接与生成状态。 */
5188
+ /**
5189
+ * 当前实时连接与生成状态。
5190
+ */
4494
5191
  get currentState() {
4495
5192
  return this.coordinator.currentState;
4496
5193
  }
5194
+ /**
5195
+ * 当前是否请求启用插帧;能力探测或运行期降级后可能为 false。
5196
+ */
4497
5197
  get isFrameInterpolationEnabled() {
4498
5198
  return this.interpolationRequested;
4499
5199
  }
5200
+ /**
5201
+ * 串行更新插帧开关;开启前验证能力,不支持时抛错并保留原配置,不改变回传尺寸。
5202
+ */
4500
5203
  async setFrameInterpolationEnabled(enabled) {
4501
5204
  await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
4502
- const format = _optionalChain([this, 'access', _182 => _182.cameraController, 'access', _183 => _183.currentTrack, 'optionalAccess', _184 => _184.videoFormat]);
5205
+ const format = _optionalChain([this, 'access', _177 => _177.cameraController, 'access', _178 => _178.currentTrack, 'optionalAccess', _179 => _179.videoFormat]);
4503
5206
  const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
4504
5207
  if (enabled && !await this.checkInterpolationSupport(size, token)) {
4505
5208
  token.ensureCurrent();
@@ -4511,6 +5214,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4511
5214
  this.applyRemoteInterpolation();
4512
5215
  });
4513
5216
  }
5217
+ /**
5218
+ * 根据当前视频尺寸准备插帧,能力不可用时降级为原视频,并在应用前校验租约。
5219
+ */
4514
5220
  async prepareFrameInterpolation(format, token) {
4515
5221
  let size;
4516
5222
  if (this.interpolationRequested) {
@@ -4527,6 +5233,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4527
5233
  this.interpolationSize = size;
4528
5234
  this.applyRemoteInterpolation();
4529
5235
  }
5236
+ /**
5237
+ * 在 5 秒预算内探测插帧能力;超时或探测失败返回 false,主动取消则拒绝。
5238
+ */
4530
5239
  checkInterpolationSupport(size, token) {
4531
5240
  return new Promise((resolve, reject) => {
4532
5241
  const finish = (supported) => {
@@ -4550,6 +5259,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4550
5259
  void this.supportsInterpolation(size).then(finish, () => finish(false));
4551
5260
  });
4552
5261
  }
5262
+ /**
5263
+ * 将当前插帧配置同步到远端绑定,并用版本号忽略旧管线的迟到失败。
5264
+ */
4553
5265
  applyRemoteInterpolation() {
4554
5266
  const revision = ++this.interpolationRevision;
4555
5267
  const size = this.interpolationSize;
@@ -4561,6 +5273,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4561
5273
  }
4562
5274
  } : void 0);
4563
5275
  }
5276
+ /**
5277
+ * 关闭已失败的插帧配置并记录降级原因,保持原始视频渲染可用。
5278
+ */
4564
5279
  handleInterpolationFailure(error) {
4565
5280
  this.interpolationRequested = false;
4566
5281
  this.interpolationSize = void 0;
@@ -4568,11 +5283,15 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4568
5283
  XmaxLogger.render.warning(() => `\u63D2\u5E27\u5DF2\u964D\u7EA7 (Frame Interpolation Disabled)
4569
5284
  \u2514\u2500 ${XmaxError.from(error).message}`);
4570
5285
  }
4571
- /** 当前本地媒体预览音量,取值范围为 `0...1`。 */
5286
+ /**
5287
+ * 当前本地媒体预览音量,取值范围为 `0...1`。
5288
+ */
4572
5289
  get localAudioVolume() {
4573
5290
  return this.storedLocalAudioVolume;
4574
5291
  }
4575
- /** 当前远端生成音频播放音量,取值范围为 `0...1`。 */
5292
+ /**
5293
+ * 当前远端生成音频播放音量,取值范围为 `0...1`。
5294
+ */
4576
5295
  get remoteAudioVolume() {
4577
5296
  return this.storedRemoteAudioVolume;
4578
5297
  }
@@ -4584,39 +5303,56 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4584
5303
  async setStateListener(listener) {
4585
5304
  await this.coordinator.setStateListener(listener);
4586
5305
  }
4587
- /** 监听启动耗时;设置后立即回放,传 undefined 取消监听。 */
5306
+ /**
5307
+ * 监听启动耗时;设置后立即回放,传 undefined 取消监听。
5308
+ */
4588
5309
  async setLaunchTimingListener(listener) {
4589
5310
  this.launchTimer.setListener(listener);
4590
5311
  }
4591
- /** 监听本地主视频流的实际运行统计;立即回放最新快照。 */
5312
+ /**
5313
+ * 监听本地主视频流的实际运行统计;立即回放最新快照。
5314
+ */
4592
5315
  async setLocalVideoStatisticsListener(listener) {
4593
5316
  this.localVideoStatisticsListener = listener;
4594
5317
  this.notifyLocalVideoStatistics();
4595
5318
  }
4596
- /** 监听当前生成结果流的实际运行统计;立即回放最新快照。 */
5319
+ /**
5320
+ * 监听当前生成结果流的实际运行统计;立即回放最新快照。
5321
+ */
4597
5322
  async setRemoteVideoStatisticsListener(listener) {
4598
5323
  this.remoteVideoStatisticsListener = listener;
4599
5324
  this.notifyRemoteVideoStatistics();
4600
5325
  }
5326
+ /**
5327
+ * 回放当前远端视频统计,隔离观察者的同步和异步异常。
5328
+ */
4601
5329
  notifyRemoteVideoStatistics() {
4602
5330
  try {
4603
- void Promise.resolve(_optionalChain([this, 'access', _185 => _185.remoteVideoStatisticsListener, 'optionalCall', _186 => _186(this.remoteVideoStatistics)])).catch(() => {
5331
+ void Promise.resolve(_optionalChain([this, 'access', _180 => _180.remoteVideoStatisticsListener, 'optionalCall', _181 => _181(this.remoteVideoStatistics)])).catch(() => {
4604
5332
  });
4605
- } catch (e17) {
5333
+ } catch (e16) {
4606
5334
  }
4607
5335
  }
4608
- /** 网络统计立即回放最新快照,无数据或断开后为 undefined。 */
5336
+ /**
5337
+ * 网络统计立即回放最新快照,无数据或断开后为 undefined。
5338
+ */
4609
5339
  async setNetworkStatisticsListener(listener) {
4610
5340
  this.networkStatisticsListener = listener;
4611
5341
  this.notifyNetworkStatistics();
4612
5342
  }
5343
+ /**
5344
+ * 回放当前网络统计,隔离观察者的同步和异步异常。
5345
+ */
4613
5346
  notifyNetworkStatistics() {
4614
5347
  try {
4615
- void Promise.resolve(_optionalChain([this, 'access', _187 => _187.networkStatisticsListener, 'optionalCall', _188 => _188(this.networkStatistics)])).catch(() => {
5348
+ void Promise.resolve(_optionalChain([this, 'access', _182 => _182.networkStatisticsListener, 'optionalCall', _183 => _183(this.networkStatistics)])).catch(() => {
4616
5349
  });
4617
- } catch (e18) {
5350
+ } catch (e17) {
4618
5351
  }
4619
5352
  }
5353
+ /**
5354
+ * 清除远端视频统计;原先存在数据时通知观察者数据已失效。
5355
+ */
4620
5356
  clearRemoteVideoStatistics() {
4621
5357
  const hadStatistics = this.remoteVideoStatistics !== void 0;
4622
5358
  this.remoteVideoStatistics = void 0;
@@ -4624,13 +5360,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4624
5360
  this.notifyRemoteVideoStatistics();
4625
5361
  }
4626
5362
  }
5363
+ /**
5364
+ * 回放当前本地视频统计,隔离观察者的同步和异步异常。
5365
+ */
4627
5366
  notifyLocalVideoStatistics() {
4628
5367
  try {
4629
- void Promise.resolve(_optionalChain([this, 'access', _189 => _189.localVideoStatisticsListener, 'optionalCall', _190 => _190(this.localVideoStatistics)])).catch(() => {
5368
+ void Promise.resolve(_optionalChain([this, 'access', _184 => _184.localVideoStatisticsListener, 'optionalCall', _185 => _185(this.localVideoStatistics)])).catch(() => {
4630
5369
  });
4631
- } catch (e19) {
5370
+ } catch (e18) {
4632
5371
  }
4633
5372
  }
5373
+ /**
5374
+ * 停止接收媒体统计并清空各类快照,仅对曾有数据的统计发出清空通知。
5375
+ */
4634
5376
  clearVideoStatistics() {
4635
5377
  this.acceptsVideoStatistics = false;
4636
5378
  const hadNetworkStatistics = this.networkStatistics !== void 0;
@@ -4677,6 +5419,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4677
5419
  *
4678
5420
  * 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
4679
5421
  *
5422
+ * @param options.enableFrameValidation 是否在发布前检测帧亮度,默认 true;false 跳过检测及其等待。
4680
5423
  * @returns 包含本地相机视频轨道的媒体流。
4681
5424
  * @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
4682
5425
  */
@@ -4711,7 +5454,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4711
5454
  }
4712
5455
  );
4713
5456
  }
4714
- /** 停止本地相机流并释放本地预览与 RTC 资源。 */
5457
+ /**
5458
+ * 停止本地相机流并释放本地预览与 RTC 资源。
5459
+ */
4715
5460
  async stopLocalCameraStream() {
4716
5461
  await this.coordinator.run(
4717
5462
  "media" /* media */,
@@ -4752,8 +5497,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4752
5497
  * 使用当前 Manager 创建的本地流建立实时连接。
4753
5498
  *
4754
5499
  * 创建实时会话、加入 RTC 房间并发布本地流,成功后启动会话心跳。
4755
- * 发布前并行检查相机亮度稳定性;5 秒内未通过检查时抛出
4756
- * `cameraExposureTimeout`,不发布媒体,接入方可改善光照后重试。
5500
+ * 启用帧检测时,发布前并行检查相机亮度,首张合格帧即放行;2 秒内未通过检查则
5501
+ * 记录警告并按当前画面继续发布,不因环境较暗而阻断连接。
4757
5502
  * 返回的远端媒体流在生成开始后承载远端生成画面。
4758
5503
  *
4759
5504
  * @param localStream 由 `createLocalCameraStream` 创建的本地媒体流。
@@ -4812,7 +5557,6 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4812
5557
  if (currentState.connectionState === "Generating" /* generating */) {
4813
5558
  this.generationManager.update(currentState.taskID, {
4814
5559
  videoFormat,
4815
- targetSize: this.connectionManager.currentTargetSize,
4816
5560
  context: options.context
4817
5561
  });
4818
5562
  return this.connectionManager.makeRemoteStream();
@@ -4825,7 +5569,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4825
5569
  }
4826
5570
  );
4827
5571
  }
4828
- /** 断开实时连接并保留当前本地媒体预览。 */
5572
+ /**
5573
+ * 断开实时连接并保留当前本地媒体预览。
5574
+ */
4829
5575
  async disconnect() {
4830
5576
  this.launchTimer.cancel();
4831
5577
  this.clearVideoStatistics();
@@ -4866,9 +5612,17 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4866
5612
  token.signal.addEventListener("abort", abortExposure, { once: true });
4867
5613
  if (token.signal.aborted) abortExposure();
4868
5614
  try {
4869
- const cameraReady = this.cameraController.waitUntilExposureReady(exposureController.signal);
4870
- void cameraReady.catch(() => {
4871
- });
5615
+ let beforePublish;
5616
+ if (this.cameraController.isFrameValidationEnabled) {
5617
+ const completeFrameValidation = this.launchTimer.startFrameValidation();
5618
+ const cameraReady = this.cameraController.waitForValidCameraFrame(exposureController.signal).then(() => {
5619
+ token.ensureCurrent();
5620
+ completeFrameValidation();
5621
+ });
5622
+ void cameraReady.catch(() => {
5623
+ });
5624
+ beforePublish = () => cameraReady;
5625
+ }
4872
5626
  const remote = await this.connectionManager.connect({
4873
5627
  localTrack,
4874
5628
  model: this.options.model,
@@ -4877,7 +5631,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4877
5631
  onPublished: () => {
4878
5632
  this.acceptsVideoStatistics = true;
4879
5633
  },
4880
- beforePublish: () => cameraReady
5634
+ beforePublish
4881
5635
  });
4882
5636
  await this.coordinator.commit(
4883
5637
  new RealtimeState({
@@ -4892,7 +5646,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4892
5646
  abortExposure();
4893
5647
  }
4894
5648
  }
4895
- /** 编排插帧、首帧计时和生成状态,任务与确认由生成管理器负责。 */
5649
+ /**
5650
+ * 编排插帧、首帧计时和生成状态,任务与确认由生成管理器负责。
5651
+ */
4896
5652
  async performStartGeneration(token, videoFormat, context) {
4897
5653
  token.setFailureScope(0 /* connection */);
4898
5654
  await this.prepareFrameInterpolation(videoFormat, token);
@@ -4902,7 +5658,6 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4902
5658
  };
4903
5659
  const taskID = await this.generationManager.start({
4904
5660
  videoFormat,
4905
- targetSize: this.connectionManager.currentTargetSize,
4906
5661
  context,
4907
5662
  signal: token.signal,
4908
5663
  ensureCurrent: () => token.ensureCurrent(),
@@ -4921,7 +5676,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4921
5676
  );
4922
5677
  return this.connectionManager.makeRemoteStream();
4923
5678
  }
4924
- /** 心跳失败或会话失效:结束当前连接生命周期并通过最终状态给出原因。 */
5679
+ /**
5680
+ * 心跳失败或会话失效:结束当前连接生命周期并通过最终状态给出原因。
5681
+ */
4925
5682
  async handleHeartbeatFailure(sessionID, error) {
4926
5683
  await this.coordinator.terminateWithError(
4927
5684
  error,
@@ -4929,7 +5686,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4929
5686
  () => this.connectionManager.currentSessionID === sessionID
4930
5687
  );
4931
5688
  }
4932
- /** 统一清理顺序:停止心跳与生成,再断开连接;all 额外释放本地媒体。 */
5689
+ /**
5690
+ * 统一清理顺序:停止心跳与生成,再断开连接;all 额外释放本地媒体。
5691
+ */
4933
5692
  async performCleanup(scope, taskID) {
4934
5693
  this.launchTimer.cancel();
4935
5694
  this.remoteFrameDisplayHandler = void 0;
@@ -4955,7 +5714,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
4955
5714
  hasLocalMedia: this.cameraController.currentTrack !== void 0
4956
5715
  };
4957
5716
  }
4958
- /** 校验音量取值范围为 `0...1`。 */
5717
+ /**
5718
+ * 校验音量取值范围为 `0...1`。
5719
+ */
4959
5720
  static validateVolume(volume) {
4960
5721
  if (!Number.isFinite(volume) || volume < 0 || volume > 1) {
4961
5722
  throw new XmaxError(
@@ -4976,11 +5737,23 @@ var XmaxConfiguration = class {
4976
5737
  * @param init.loggerOptions SDK 输出的日志类型;默认为空。
4977
5738
  */
4978
5739
  constructor(init) {
4979
- /** 调用 Xmax 服务使用的 API Key。 */
5740
+ /**
5741
+ * 服务身份与环境
5742
+ */
5743
+ /**
5744
+ * 调用 Xmax 服务使用的 API Key。
5745
+ */
4980
5746
  __publicField(this, "apiKey");
4981
- /** SDK 连接的服务环境,同时决定日志细项语言:国内为中文,海外为英文。 */
5747
+ /**
5748
+ * SDK 连接的服务环境,同时决定日志细项语言:国内为中文,海外为英文。
5749
+ */
4982
5750
  __publicField(this, "environment");
4983
- /** SDK 输出的日志类型;默认为不输出日志。 */
5751
+ /**
5752
+ * 日志配置
5753
+ */
5754
+ /**
5755
+ * SDK 输出的日志类型;默认为不输出日志。
5756
+ */
4984
5757
  __publicField(this, "loggerOptions");
4985
5758
  this.apiKey = init.apiKey.trim();
4986
5759
  this.environment = _nullishCoalesce(init.environment, () => ( "china")) /* china */;
@@ -5009,9 +5782,16 @@ var XmaxClient = class {
5009
5782
  * 在实际调用时校验 API Key。
5010
5783
  */
5011
5784
  constructor(configuration) {
5012
- /** 客户端使用的全局配置。 */
5785
+ /**
5786
+ * 客户端配置
5787
+ */
5788
+ /**
5789
+ * 客户端使用的全局配置。
5790
+ */
5013
5791
  __publicField(this, "configuration");
5014
- // 服务层组件
5792
+ /**
5793
+ * 服务层组件
5794
+ */
5015
5795
  __publicField(this, "apiService");
5016
5796
  this.configuration = configuration;
5017
5797
  XmaxLogger.configure(
@@ -5057,19 +5837,33 @@ var RealtimeConfiguration = class {
5057
5837
  *
5058
5838
  * @param init.model 实时生成业务使用的模型。
5059
5839
  * @param init.isFrameInterpolationEnabled 是否默认开启远端生成画面的插帧。
5840
+ * @param init.frameInterpolation 插帧开关和显示帧率上限的详细配置。
5060
5841
  */
5061
5842
  constructor(init) {
5062
- /** 实时生成业务使用的模型。 */
5843
+ /**
5844
+ * 模型配置
5845
+ */
5846
+ /**
5847
+ * 实时生成业务使用的模型。
5848
+ */
5063
5849
  __publicField(this, "model");
5064
- /** 是否默认请求开启远端生成画面的插帧。 */
5850
+ /**
5851
+ * 远端插帧配置
5852
+ */
5853
+ /**
5854
+ * 是否默认请求开启远端生成画面的插帧。
5855
+ */
5065
5856
  __publicField(this, "isFrameInterpolationEnabled");
5857
+ /**
5858
+ * 已补全默认值的只读插帧配置。
5859
+ */
5066
5860
  __publicField(this, "frameInterpolation");
5067
5861
  this.model = init.model;
5068
- const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access', _191 => _191.frameInterpolation, 'optionalAccess', _192 => _192.targetFrameRate]), () => ( 60));
5862
+ const targetFrameRate = _nullishCoalesce(_optionalChain([init, 'access', _186 => _186.frameInterpolation, 'optionalAccess', _187 => _187.targetFrameRate]), () => ( 60));
5069
5863
  if (!Number.isFinite(targetFrameRate) || targetFrameRate < 1 || targetFrameRate > 60) {
5070
5864
  throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Interpolation targetFrameRate must be between 1 and 60");
5071
5865
  }
5072
- this.isFrameInterpolationEnabled = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'access', _193 => _193.frameInterpolation, 'optionalAccess', _194 => _194.enabled]), () => ( init.isFrameInterpolationEnabled)), () => ( true));
5866
+ this.isFrameInterpolationEnabled = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'access', _188 => _188.frameInterpolation, 'optionalAccess', _189 => _189.enabled]), () => ( init.isFrameInterpolationEnabled)), () => ( false));
5073
5867
  this.frameInterpolation = Object.freeze({ enabled: this.isFrameInterpolationEnabled, targetFrameRate });
5074
5868
  }
5075
5869
  };
@@ -5083,15 +5877,24 @@ var VideoContentMode = /* @__PURE__ */ ((VideoContentMode2) => {
5083
5877
 
5084
5878
  // src/Service/Realtime/RealtimeContext.ts
5085
5879
  var RealtimeContext = class {
5086
- /** 创建实时生成条件并规范化文本和参考路径。 */
5880
+ /**
5881
+ * 创建实时生成条件并规范化文本和参考路径。
5882
+ */
5087
5883
  constructor(init) {
5088
- /** 实时生成使用的文本条件。 */
5884
+ /**
5885
+ * 生成条件
5886
+ */
5887
+ /**
5888
+ * 实时生成使用的文本条件。
5889
+ */
5089
5890
  __publicField(this, "prompt");
5090
- /** 已上传参考图片的可选远端路径。 */
5891
+ /**
5892
+ * 已上传参考图片的可选远端路径。
5893
+ */
5091
5894
  __publicField(this, "referencePath");
5092
5895
  this.prompt = init.prompt.trim();
5093
- const normalizedReferencePath = _optionalChain([init, 'access', _195 => _195.referencePath, 'optionalAccess', _196 => _196.trim, 'call', _197 => _197()]);
5094
- this.referencePath = normalizedReferencePath && normalizedReferencePath.length > 0 ? normalizedReferencePath : void 0;
5896
+ const normalizedReferencePath = _optionalChain([init, 'access', _190 => _190.referencePath, 'optionalAccess', _191 => _191.trim, 'call', _192 => _192()]);
5897
+ this.referencePath = normalizedReferencePath || void 0;
5095
5898
  }
5096
5899
  };
5097
5900
 
@@ -7067,7 +7870,7 @@ struct Output { @builtin(position) position: vec4f, @location(0) uv: vec2f }
7067
7870
  out.uv = vec2f((pos[i].x + 1) * 0.5, (1 - pos[i].y) * 0.5);
7068
7871
  return out;
7069
7872
  }`;
7070
- var FrameInterpolationManager = class _FrameInterpolationManager {
7873
+ var _FrameInterpolationManager = class _FrameInterpolationManager {
7071
7874
  constructor(device, canvas, size, onFailure) {
7072
7875
  __publicField(this, "device", device);
7073
7876
  __publicField(this, "canvas", canvas);
@@ -7075,7 +7878,7 @@ var FrameInterpolationManager = class _FrameInterpolationManager {
7075
7878
  __publicField(this, "onFailure", onFailure);
7076
7879
  __publicField(this, "runtime");
7077
7880
  __publicField(this, "textures", []);
7078
- __publicField(this, "current", 0);
7881
+ __publicField(this, "nextOriginal", 0);
7079
7882
  __publicField(this, "capturePipeline");
7080
7883
  __publicField(this, "displayPipeline");
7081
7884
  __publicField(this, "sampler");
@@ -7140,7 +7943,7 @@ var FrameInterpolationManager = class _FrameInterpolationManager {
7140
7943
  throw new Error("Interpolation initialization cancelled");
7141
7944
  }
7142
7945
  this.runtime = runtime;
7143
- for (let i = 0; i < 3; i++) {
7946
+ for (let i = 0; i < _FrameInterpolationManager.originalSlots + 1; i++) {
7144
7947
  this.textures.push(device.createTexture({
7145
7948
  size: [w, h],
7146
7949
  format: "rgba8unorm",
@@ -7183,21 +7986,21 @@ var FrameInterpolationManager = class _FrameInterpolationManager {
7183
7986
  }
7184
7987
  }
7185
7988
  capture(video) {
7186
- this.current = 1 - this.current;
7187
- this.draw(this.capturePipeline, this.device.importExternalTexture({ source: video }), this.textures[this.current].createView());
7188
- }
7189
- presentPrevious() {
7190
- this.present(this.textures[1 - this.current]);
7191
- }
7192
- async interpolate() {
7193
- this.runtime.prepPair(this.textures[1 - this.current], this.textures[this.current]);
7194
- this.runtime.runT(0.5, this.textures[2]);
7989
+ const slot = this.nextOriginal;
7990
+ this.nextOriginal = (this.nextOriginal + 1) % _FrameInterpolationManager.originalSlots;
7991
+ this.draw(this.capturePipeline, this.device.importExternalTexture({ source: video }), this.textures[slot].createView());
7992
+ return slot;
7993
+ }
7994
+ async interpolate(previous, current) {
7995
+ this.runtime.prepPair(this.textures[previous], this.textures[current]);
7996
+ this.runtime.runT(0.5, this.textures[_FrameInterpolationManager.originalSlots]);
7195
7997
  await this.device.queue.onSubmittedWorkDone();
7998
+ return _FrameInterpolationManager.originalSlots;
7196
7999
  }
7197
- presentInterpolated() {
7198
- this.present(this.textures[2]);
8000
+ present(slot) {
8001
+ this.presentTexture(this.textures[slot]);
7199
8002
  }
7200
- present(texture) {
8003
+ presentTexture(texture) {
7201
8004
  this.draw(this.displayPipeline, texture.createView(), this.context.getCurrentTexture().createView());
7202
8005
  }
7203
8006
  draw(pipeline, source, target) {
@@ -7217,14 +8020,17 @@ var FrameInterpolationManager = class _FrameInterpolationManager {
7217
8020
  if (this.destroyed) return;
7218
8021
  this.destroyed = true;
7219
8022
  this.device.removeEventListener("uncapturederror", this.onGPUError);
7220
- _optionalChain([this, 'access', _198 => _198.runtime, 'optionalAccess', _199 => _199.destroy, 'call', _200 => _200()]);
8023
+ _optionalChain([this, 'access', _193 => _193.runtime, 'optionalAccess', _194 => _194.destroy, 'call', _195 => _195()]);
7221
8024
  this.runtime = void 0;
7222
8025
  this.textures.forEach((texture) => texture.destroy());
7223
8026
  this.textures = [];
7224
- _optionalChain([this, 'access', _201 => _201.context, 'optionalAccess', _202 => _202.unconfigure, 'call', _203 => _203()]);
8027
+ _optionalChain([this, 'access', _196 => _196.context, 'optionalAccess', _197 => _197.unconfigure, 'call', _198 => _198()]);
7225
8028
  this.device.destroy();
7226
8029
  }
7227
8030
  };
8031
+ /** 原帧环形缓冲的槽位数;插值结果固定在最后一个槽位。 */
8032
+ __publicField(_FrameInterpolationManager, "originalSlots", 3);
8033
+ var FrameInterpolationManager = _FrameInterpolationManager;
7228
8034
 
7229
8035
  // src/Render/Video/RemoteVideoFramePipeline.ts
7230
8036
  var RemoteVideoFramePipeline = class {
@@ -7236,18 +8042,35 @@ var RemoteVideoFramePipeline = class {
7236
8042
  __publicField(this, "processor");
7237
8043
  __publicField(this, "abort", new AbortController());
7238
8044
  __publicField(this, "callback");
7239
- __publicField(this, "midpointTimer");
8045
+ __publicField(this, "raf");
7240
8046
  __publicField(this, "stallTimer");
7241
8047
  __publicField(this, "initializationTimer");
7242
- __publicField(this, "animation");
7243
8048
  __publicField(this, "loading", false);
7244
8049
  __publicField(this, "busy", false);
7245
8050
  __publicField(this, "stopped", false);
7246
- __publicField(this, "pair", 0);
8051
+ __publicField(this, "generation", 0);
8052
+ /** 播放时钟锚点:最近一次输入帧的媒体时间与对应的 vsync 时刻。 */
8053
+ __publicField(this, "anchor");
8054
+ /** 输出延迟,取最近一次有效源帧间隔,为中间帧留出计算窗口。 */
8055
+ __publicField(this, "delay", 0);
8056
+ __publicField(this, "queue", []);
8057
+ __publicField(this, "displayedTime");
7247
8058
  __publicField(this, "previousTime");
8059
+ __publicField(this, "previousSlot");
7248
8060
  __publicField(this, "previousPresented");
7249
8061
  __publicField(this, "slowPairs", 0);
7250
8062
  __publicField(this, "active", false);
8063
+ /** vsync 显示节拍:弹出到点的帧并显示最新的一张。 */
8064
+ __publicField(this, "tick", (now) => {
8065
+ if (this.stopped) return;
8066
+ this.raf = requestAnimationFrame(this.tick);
8067
+ const position = this.position(now);
8068
+ let frame;
8069
+ while (this.queue.length > 0 && this.queue[0].time <= position) {
8070
+ frame = this.queue.shift();
8071
+ }
8072
+ if (frame) this.present(frame);
8073
+ });
7251
8074
  }
7252
8075
  start() {
7253
8076
  if (this.stopped || this.callback !== void 0) return;
@@ -7259,78 +8082,101 @@ var RemoteVideoFramePipeline = class {
7259
8082
  }
7260
8083
  observe() {
7261
8084
  if (this.stopped) return;
7262
- this.callback = this.video.requestVideoFrameCallback((_now, metadata) => {
8085
+ this.callback = this.video.requestVideoFrameCallback((now, metadata) => {
7263
8086
  this.callback = void 0;
7264
8087
  if (this.stopped) return;
7265
8088
  try {
7266
- this.frame(metadata);
8089
+ this.frame(now, metadata);
7267
8090
  } catch (error) {
7268
8091
  this.fail(error);
7269
8092
  }
7270
8093
  this.observe();
7271
8094
  });
7272
8095
  }
7273
- frame(metadata) {
8096
+ frame(now, metadata) {
7274
8097
  if (typeof document !== "undefined" && document.hidden) {
7275
- this.resetPair();
8098
+ this.resetTimeline();
7276
8099
  return;
7277
8100
  }
7278
8101
  if (metadata.width !== this.options.size.width || metadata.height !== this.options.size.height) {
7279
- this.resetPair();
8102
+ this.resetTimeline();
7280
8103
  return;
7281
8104
  }
7282
8105
  if (!this.processor) {
7283
8106
  if (!this.loading) void this.initialize();
7284
8107
  return;
7285
8108
  }
7286
- if (this.busy) return;
7287
- const interval = this.previousTime === void 0 ? 0 : (metadata.mediaTime - this.previousTime) * 1e3;
8109
+ const time = metadata.mediaTime * 1e3;
8110
+ if (!Number.isFinite(time) || this.previousTime !== void 0 && time <= this.previousTime) return;
8111
+ const previous = this.previousTime;
8112
+ const interval = previous === void 0 ? 0 : time - previous;
7288
8113
  const consecutive = this.previousPresented === void 0 || metadata.presentedFrames === this.previousPresented + 1;
7289
- this.clearPresentation();
7290
- const pair = ++this.pair;
7291
- this.processor.capture(this.video);
7292
- this.previousTime = metadata.mediaTime;
8114
+ const previousSlot = this.previousSlot;
8115
+ this.anchor = { media: time, at: now };
8116
+ this.previousTime = time;
7293
8117
  this.previousPresented = metadata.presentedFrames;
7294
- if (!consecutive || interval <= 0 || interval > 250 || interval < 2e3 / this.options.targetFrameRate - 1) {
7295
- this.setActive(false);
7296
- this.canvas.style.visibility = "hidden";
8118
+ const slot = this.processor.capture(this.video);
8119
+ this.previousSlot = slot;
8120
+ if (previous === void 0 || interval > 250) {
8121
+ this.queue = [];
8122
+ this.delay = 0;
8123
+ this.present({ slot, time });
8124
+ this.startTick();
7297
8125
  return;
7298
8126
  }
8127
+ this.delay = interval;
8128
+ this.enqueue({ slot, time });
8129
+ this.startTick();
8130
+ if (!consecutive || interval < 2e3 / this.options.targetFrameRate - 1 || previousSlot === void 0 || this.busy) return;
8131
+ this.interpolate(previousSlot, slot, previous, time, interval);
8132
+ }
8133
+ /** 帧按显示时间升序入队;同一时间的内容后到先出。 */
8134
+ enqueue(frame) {
8135
+ const index = this.queue.findIndex((queued) => queued.time >= frame.time);
8136
+ if (index < 0) this.queue.push(frame);
8137
+ else this.queue.splice(index, 0, frame);
8138
+ }
8139
+ interpolate(previousSlot, currentSlot, previousTime, currentTime, interval) {
8140
+ const generation = this.generation;
8141
+ const midpoint = (previousTime + currentTime) / 2;
7299
8142
  const startedAt = performance.now();
7300
- this.processor.presentPrevious();
7301
- this.canvas.style.visibility = "visible";
7302
8143
  this.busy = true;
7303
8144
  this.stallTimer = setTimeout(() => {
7304
8145
  if (this.busy) this.fail(new Error("Interpolation GPU submission timed out"));
7305
- else this.resetPair();
7306
8146
  }, Math.max(100, interval * 3));
7307
- void this.processor.interpolate().then(() => {
8147
+ void this.processor.interpolate(previousSlot, currentSlot).then((slot) => {
7308
8148
  if (this.stopped) return;
7309
8149
  this.busy = false;
7310
- if (pair !== this.pair) return;
8150
+ clearTimeout(this.stallTimer);
8151
+ this.stallTimer = void 0;
8152
+ if (generation !== this.generation) return;
7311
8153
  const elapsed = performance.now() - startedAt;
7312
8154
  this.slowPairs = elapsed > interval / 2 ? this.slowPairs + 1 : 0;
7313
8155
  if (this.slowPairs >= 5) {
7314
8156
  this.fail(new Error("Interpolation exceeded the GPU frame budget for 5 consecutive pairs"));
7315
8157
  return;
7316
8158
  }
7317
- if (elapsed >= interval) return;
7318
- this.midpointTimer = setTimeout(() => {
7319
- this.animation = requestAnimationFrame(() => {
7320
- this.animation = void 0;
7321
- if (this.stopped || pair !== this.pair || performance.now() - startedAt >= interval) return;
7322
- try {
7323
- this.processor.presentInterpolated();
7324
- this.setActive(true);
7325
- } catch (error) {
7326
- this.fail(error);
7327
- }
7328
- });
7329
- }, Math.max(0, interval / 2 - elapsed));
8159
+ if (this.position(performance.now()) >= midpoint) return;
8160
+ this.enqueue({ slot, time: midpoint });
7330
8161
  }).catch((error) => {
7331
8162
  if (!this.stopped) this.fail(error);
7332
8163
  });
7333
8164
  }
8165
+ /** 显示时钟位置:锚点媒体时间随墙钟推进,整体后移一个源帧间隔。 */
8166
+ position(now) {
8167
+ if (!this.anchor) return -Infinity;
8168
+ return this.anchor.media + (now - this.anchor.at) - this.delay;
8169
+ }
8170
+ startTick() {
8171
+ if (this.raf === void 0) this.raf = requestAnimationFrame(this.tick);
8172
+ }
8173
+ present(frame) {
8174
+ if (this.displayedTime === frame.time) return;
8175
+ this.processor.present(frame.slot);
8176
+ this.displayedTime = frame.time;
8177
+ this.canvas.style.visibility = "visible";
8178
+ this.setActive(true);
8179
+ }
7334
8180
  async initialize() {
7335
8181
  this.loading = true;
7336
8182
  this.initializationTimer = setTimeout(() => this.fail(new Error("Interpolation initialization timed out")), 15e3);
@@ -7357,18 +8203,20 @@ var RemoteVideoFramePipeline = class {
7357
8203
  setActive(active) {
7358
8204
  if (active === this.active) return;
7359
8205
  this.active = active;
7360
- _optionalChain([this, 'access', _204 => _204.options, 'access', _205 => _205.onActiveChange, 'optionalCall', _206 => _206(active)]);
8206
+ _optionalChain([this, 'access', _199 => _199.options, 'access', _200 => _200.onActiveChange, 'optionalCall', _201 => _201(active)]);
7361
8207
  }
7362
- clearPresentation() {
7363
- clearTimeout(this.midpointTimer);
8208
+ resetTimeline() {
8209
+ this.generation++;
8210
+ this.queue = [];
7364
8211
  clearTimeout(this.stallTimer);
7365
- if (this.animation !== void 0) cancelAnimationFrame(this.animation);
7366
- this.animation = void 0;
7367
- }
7368
- resetPair() {
7369
- this.pair++;
7370
- this.clearPresentation();
8212
+ this.stallTimer = void 0;
8213
+ if (this.raf !== void 0) cancelAnimationFrame(this.raf);
8214
+ this.raf = void 0;
8215
+ this.anchor = void 0;
8216
+ this.delay = 0;
8217
+ this.displayedTime = void 0;
7371
8218
  this.previousTime = void 0;
8219
+ this.previousSlot = void 0;
7372
8220
  this.previousPresented = void 0;
7373
8221
  this.canvas.style.visibility = "hidden";
7374
8222
  this.setActive(false);
@@ -7385,8 +8233,8 @@ var RemoteVideoFramePipeline = class {
7385
8233
  if (this.callback !== void 0) this.video.cancelVideoFrameCallback(this.callback);
7386
8234
  this.callback = void 0;
7387
8235
  clearTimeout(this.initializationTimer);
7388
- this.resetPair();
7389
- _optionalChain([this, 'access', _207 => _207.processor, 'optionalAccess', _208 => _208.destroy, 'call', _209 => _209()]);
8236
+ this.resetTimeline();
8237
+ _optionalChain([this, 'access', _202 => _202.processor, 'optionalAccess', _203 => _203.destroy, 'call', _204 => _204()]);
7390
8238
  this.processor = void 0;
7391
8239
  }
7392
8240
  };
@@ -7403,27 +8251,48 @@ var XmaxVideoView = class {
7403
8251
  * @param options.videoContentMode 视频内容显示模式,默认 fill。
7404
8252
  */
7405
8253
  constructor(options) {
7406
- // 视图元素
7407
- /** 视图根元素(div,内含一个 video 元素)。 */
8254
+ /**
8255
+ * 视图元素
8256
+ */
8257
+ /**
8258
+ * 视图根元素(div,内含一个 video 元素)。
8259
+ */
7408
8260
  __publicField(this, "element");
7409
- /** @internal 渲染视频帧的元素,供绑定管线使用。 */
8261
+ /**
8262
+ * @internal 渲染视频帧的元素,供绑定管线使用。
8263
+ */
7410
8264
  __publicField(this, "videoElement");
7411
- // 公共配置
7412
- /** 首帧实际提交显示时调用(一次性;换轨后重新武装)。 */
8265
+ /**
8266
+ * 公共配置
8267
+ */
8268
+ /**
8269
+ * 首帧实际提交显示时调用(一次性;换轨后重新武装)。
8270
+ */
7413
8271
  __publicField(this, "frameDisplayHandler");
7414
- // 渲染状态
8272
+ /**
8273
+ * 渲染状态
8274
+ */
7415
8275
  __publicField(this, "currentTrack");
7416
8276
  __publicField(this, "contentMode");
7417
8277
  __publicField(this, "mirrored", false);
8278
+ /**
8279
+ * 首帧显示通知与异步回调版本
8280
+ */
7418
8281
  __publicField(this, "hasNotifiedFrameDisplay", false);
7419
8282
  __publicField(this, "onPlaying");
7420
8283
  __publicField(this, "videoFrameCallbackID");
7421
8284
  __publicField(this, "frameNotificationSequence", 0);
8285
+ /**
8286
+ * 远端插帧配置与渲染资源
8287
+ */
7422
8288
  __publicField(this, "interpolationOptions");
7423
8289
  __publicField(this, "interpolationPipeline");
7424
8290
  __publicField(this, "interpolationCanvas");
8291
+ /**
8292
+ * DOM 挂载状态
8293
+ */
7425
8294
  __publicField(this, "detached", false);
7426
- this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _210 => _210.videoContentMode]), () => ( "fill")) /* fill */;
8295
+ this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _205 => _205.videoContentMode]), () => ( "fill")) /* fill */;
7427
8296
  this.element = document.createElement("div");
7428
8297
  this.element.style.position = "relative";
7429
8298
  this.element.style.overflow = "hidden";
@@ -7439,10 +8308,15 @@ var XmaxVideoView = class {
7439
8308
  this.applyContentMode();
7440
8309
  this.element.appendChild(this.videoElement);
7441
8310
  }
7442
- /** 当前显示的视频轨道;切换时自动解绑旧轨道。 */
8311
+ /**
8312
+ * 当前显示的视频轨道;切换时自动解绑旧轨道。
8313
+ */
7443
8314
  get track() {
7444
8315
  return this.currentTrack;
7445
8316
  }
8317
+ /**
8318
+ * 解绑旧轨道后接入新轨道,并为新内容重新启用一次性首帧通知。
8319
+ */
7446
8320
  set track(track) {
7447
8321
  if (this.currentTrack === track) {
7448
8322
  return;
@@ -7454,10 +8328,15 @@ var XmaxVideoView = class {
7454
8328
  this.attachTrack(track);
7455
8329
  }
7456
8330
  }
7457
- /** 视频内容在容器中的显示模式。 */
8331
+ /**
8332
+ * 视频内容在容器中的显示模式。
8333
+ */
7458
8334
  get videoContentMode() {
7459
8335
  return this.contentMode;
7460
8336
  }
8337
+ /**
8338
+ * 更新视频及插帧画布的内容缩放方式;相同配置不重复应用。
8339
+ */
7461
8340
  set videoContentMode(mode) {
7462
8341
  if (this.contentMode === mode) {
7463
8342
  return;
@@ -7465,10 +8344,15 @@ var XmaxVideoView = class {
7465
8344
  this.contentMode = mode;
7466
8345
  this.applyContentMode();
7467
8346
  }
7468
- /** 本地预览是否镜像显示(仅影响显示,不影响发布流)。 */
8347
+ /**
8348
+ * 本地预览是否镜像显示(仅影响显示,不影响发布流)。
8349
+ */
7469
8350
  get isMirrored() {
7470
8351
  return this.mirrored;
7471
8352
  }
8353
+ /**
8354
+ * 更新视图镜像变换,仅改变呈现方式,不改动媒体流。
8355
+ */
7472
8356
  set isMirrored(mirrored) {
7473
8357
  if (this.mirrored === mirrored) {
7474
8358
  return;
@@ -7476,7 +8360,9 @@ var XmaxVideoView = class {
7476
8360
  this.mirrored = mirrored;
7477
8361
  this.applyContentMode();
7478
8362
  }
7479
- /** 挂载到容器元素。 */
8363
+ /**
8364
+ * 挂载到容器元素。
8365
+ */
7480
8366
  attach(to) {
7481
8367
  this.detached = false;
7482
8368
  to.appendChild(this.element);
@@ -7491,14 +8377,18 @@ var XmaxVideoView = class {
7491
8377
  this.armFrameDisplayNotification();
7492
8378
  }
7493
8379
  }
7494
- /** 从容器元素移除。 */
8380
+ /**
8381
+ * 从容器元素移除。
8382
+ */
7495
8383
  detach() {
7496
8384
  this.detached = true;
7497
8385
  this.stopInterpolation();
7498
8386
  this.cancelFrameDisplayNotification();
7499
8387
  this.element.remove();
7500
8388
  }
7501
- /** 直接设置渲染用的媒体流(绑定管线和直接渲染共用)。 @internal */
8389
+ /**
8390
+ * 直接设置渲染用的媒体流(绑定管线和直接渲染共用)。 @internal
8391
+ */
7502
8392
  setMediaStream(stream) {
7503
8393
  if (this.videoElement.srcObject === stream) {
7504
8394
  return;
@@ -7512,13 +8402,18 @@ var XmaxVideoView = class {
7512
8402
  this.startInterpolation();
7513
8403
  }
7514
8404
  }
7515
- /** 由远端绑定注入配置;本地预览不走此管线。 @internal */
8405
+ /**
8406
+ * 由远端绑定注入配置;本地预览不走此管线。 @internal
8407
+ */
7516
8408
  setFrameInterpolation(options) {
7517
8409
  if (options === this.interpolationOptions) return;
7518
8410
  this.stopInterpolation();
7519
8411
  this.interpolationOptions = options;
7520
8412
  this.startInterpolation();
7521
8413
  }
8414
+ /**
8415
+ * 视图已挂载且媒体与配置就绪时创建插帧画布和管线,避免重复启动。
8416
+ */
7522
8417
  startInterpolation() {
7523
8418
  if (this.detached || this.interpolationPipeline || !this.interpolationOptions || !this.videoElement.srcObject) return;
7524
8419
  const canvas = document.createElement("canvas");
@@ -7538,14 +8433,19 @@ var XmaxVideoView = class {
7538
8433
  this.interpolationPipeline = pipeline;
7539
8434
  pipeline.start();
7540
8435
  }
8436
+ /**
8437
+ * 停止并释放插帧管线,移除辅助画布,保留原始视频元素。
8438
+ */
7541
8439
  stopInterpolation() {
7542
8440
  const pipeline = this.interpolationPipeline;
7543
8441
  this.interpolationPipeline = void 0;
7544
- _optionalChain([pipeline, 'optionalAccess', _211 => _211.stop, 'call', _212 => _212()]);
7545
- _optionalChain([this, 'access', _213 => _213.interpolationCanvas, 'optionalAccess', _214 => _214.remove, 'call', _215 => _215()]);
8442
+ _optionalChain([pipeline, 'optionalAccess', _206 => _206.stop, 'call', _207 => _207()]);
8443
+ _optionalChain([this, 'access', _208 => _208.interpolationCanvas, 'optionalAccess', _209 => _209.remove, 'call', _210 => _210()]);
7546
8444
  this.interpolationCanvas = void 0;
7547
8445
  }
7548
- /** 接入轨道画面:优先走注册的渲染绑定,否则按媒体轨直接渲染。 */
8446
+ /**
8447
+ * 接入轨道画面:优先走注册的渲染绑定,否则按媒体轨直接渲染。
8448
+ */
7549
8449
  attachTrack(track) {
7550
8450
  const binding = VideoRenderRegistry.binding(track);
7551
8451
  if (binding) {
@@ -7560,17 +8460,21 @@ var XmaxVideoView = class {
7560
8460
  () => `\u8F68\u9053 ${track.id} \u65E2\u6CA1\u6709\u6E32\u67D3\u7ED1\u5B9A\u4E5F\u6CA1\u6709\u5A92\u4F53\u8F68\uFF0C\u65E0\u6CD5\u663E\u793A`
7561
8461
  );
7562
8462
  }
7563
- /** 解绑当前轨道并清空渲染内容。 */
8463
+ /**
8464
+ * 解绑当前轨道并清空渲染内容。
8465
+ */
7564
8466
  detachCurrentTrack() {
7565
8467
  const track = this.currentTrack;
7566
8468
  if (track) {
7567
- _optionalChain([VideoRenderRegistry, 'access', _216 => _216.binding, 'call', _217 => _217(track), 'optionalAccess', _218 => _218.detachHandler, 'call', _219 => _219(this)]);
8469
+ _optionalChain([VideoRenderRegistry, 'access', _211 => _211.binding, 'call', _212 => _212(track), 'optionalAccess', _213 => _213.detachHandler, 'call', _214 => _214(this)]);
7568
8470
  }
7569
8471
  this.setFrameInterpolation(void 0);
7570
8472
  this.cancelFrameDisplayNotification();
7571
8473
  this.videoElement.srcObject = null;
7572
8474
  }
7573
- /** 首帧提交合成器时通知;旧浏览器回退到 playing 近似判断。 */
8475
+ /**
8476
+ * 首帧提交合成器时通知;旧浏览器回退到 playing 近似判断。
8477
+ */
7574
8478
  armFrameDisplayNotification() {
7575
8479
  this.cancelFrameDisplayNotification();
7576
8480
  const sequence = this.frameNotificationSequence;
@@ -7582,8 +8486,8 @@ var XmaxVideoView = class {
7582
8486
  }
7583
8487
  this.hasNotifiedFrameDisplay = true;
7584
8488
  this.cancelFrameDisplayNotification();
7585
- _optionalChain([binding, 'optionalAccess', _220 => _220.frameDisplayHandler, 'optionalCall', _221 => _221()]);
7586
- _optionalChain([this, 'access', _222 => _222.frameDisplayHandler, 'optionalCall', _223 => _223()]);
8489
+ _optionalChain([binding, 'optionalAccess', _215 => _215.frameDisplayHandler, 'optionalCall', _216 => _216()]);
8490
+ _optionalChain([this, 'access', _217 => _217.frameDisplayHandler, 'optionalCall', _218 => _218()]);
7587
8491
  };
7588
8492
  if (typeof this.videoElement.requestVideoFrameCallback === "function") {
7589
8493
  this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
@@ -7597,7 +8501,9 @@ var XmaxVideoView = class {
7597
8501
  queueMicrotask(notify);
7598
8502
  }
7599
8503
  }
7600
- /** 换流、解绑或卸载时取消观察,防止迟到的首帧归入下一条流。 */
8504
+ /**
8505
+ * 换流、解绑或卸载时取消观察,防止迟到的首帧归入下一条流。
8506
+ */
7601
8507
  cancelFrameDisplayNotification() {
7602
8508
  this.frameNotificationSequence += 1;
7603
8509
  if (this.videoFrameCallbackID !== void 0) {
@@ -7609,7 +8515,9 @@ var XmaxVideoView = class {
7609
8515
  this.onPlaying = void 0;
7610
8516
  }
7611
8517
  }
7612
- /** 应用显示模式与镜像样式。 */
8518
+ /**
8519
+ * 应用显示模式与镜像样式。
8520
+ */
7613
8521
  applyContentMode() {
7614
8522
  this.videoElement.style.objectFit = OBJECT_FIT[this.contentMode];
7615
8523
  this.videoElement.style.transform = this.mirrored ? "scaleX(-1)" : "";
@@ -7631,19 +8539,27 @@ var XmaxRealtimeVideoView = class {
7631
8539
  * @param options.videoContentMode 本地与远端视频的内容显示模式,默认 fill。
7632
8540
  */
7633
8541
  constructor(options) {
7634
- // 视图元素
7635
- /** 视图根元素。 */
8542
+ /**
8543
+ * 视图元素
8544
+ */
8545
+ /**
8546
+ * 视图根元素。
8547
+ */
7636
8548
  __publicField(this, "element");
7637
- // 视频视图
8549
+ /**
8550
+ * 视频视图
8551
+ */
7638
8552
  __publicField(this, "localVideoView");
7639
8553
  __publicField(this, "remoteVideoView");
7640
- // 公共配置
8554
+ /**
8555
+ * 公共配置
8556
+ */
7641
8557
  __publicField(this, "currentLocalTrack");
7642
8558
  __publicField(this, "currentRemoteTrack");
7643
8559
  __publicField(this, "contentMode");
7644
- this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _224 => _224.videoContentMode]), () => ( "fill")) /* fill */;
7645
- this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _225 => _225.localTrack]);
7646
- this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _226 => _226.remoteTrack]);
8560
+ this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _219 => _219.videoContentMode]), () => ( "fill")) /* fill */;
8561
+ this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _220 => _220.localTrack]);
8562
+ this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _221 => _221.remoteTrack]);
7647
8563
  this.element = document.createElement("div");
7648
8564
  this.element.style.position = "relative";
7649
8565
  this.element.style.overflow = "hidden";
@@ -7658,10 +8574,15 @@ var XmaxRealtimeVideoView = class {
7658
8574
  this.localVideoView.track = this.currentLocalTrack;
7659
8575
  this.updateRemoteTrack();
7660
8576
  }
7661
- /** 当前显示的本地视频轨道。 */
8577
+ /**
8578
+ * 当前显示的本地视频轨道。
8579
+ */
7662
8580
  get localTrack() {
7663
8581
  return this.currentLocalTrack;
7664
8582
  }
8583
+ /**
8584
+ * 替换本地预览轨道;轨道未变化时保留当前绑定。
8585
+ */
7665
8586
  set localTrack(track) {
7666
8587
  if (this.currentLocalTrack === track) {
7667
8588
  return;
@@ -7676,6 +8597,9 @@ var XmaxRealtimeVideoView = class {
7676
8597
  get remoteTrack() {
7677
8598
  return this.currentRemoteTrack;
7678
8599
  }
8600
+ /**
8601
+ * 替换远端轨道并重新等待首帧渐入;清空轨道时恢复本地预览。
8602
+ */
7679
8603
  set remoteTrack(track) {
7680
8604
  if (this.currentRemoteTrack === track) {
7681
8605
  return;
@@ -7683,10 +8607,15 @@ var XmaxRealtimeVideoView = class {
7683
8607
  this.currentRemoteTrack = track;
7684
8608
  this.updateRemoteTrack();
7685
8609
  }
7686
- /** 视频内容在容器中的显示模式。 */
8610
+ /**
8611
+ * 视频内容在容器中的显示模式。
8612
+ */
7687
8613
  get videoContentMode() {
7688
8614
  return this.contentMode;
7689
8615
  }
8616
+ /**
8617
+ * 同步调整本地与远端视频在容器中的缩放和裁剪方式。
8618
+ */
7690
8619
  set videoContentMode(mode) {
7691
8620
  if (this.contentMode === mode) {
7692
8621
  return;
@@ -7695,26 +8624,37 @@ var XmaxRealtimeVideoView = class {
7695
8624
  this.localVideoView.videoContentMode = mode;
7696
8625
  this.remoteVideoView.videoContentMode = mode;
7697
8626
  }
7698
- /** 本地预览是否镜像显示(前置摄像头)。 */
8627
+ /**
8628
+ * 本地预览是否镜像显示(前置摄像头)。
8629
+ */
7699
8630
  get isLocalMirrored() {
7700
8631
  return this.localVideoView.isMirrored;
7701
8632
  }
8633
+ /**
8634
+ * 更新本地预览镜像;不修改采集帧或远端画面。
8635
+ */
7702
8636
  set isLocalMirrored(mirrored) {
7703
8637
  this.localVideoView.isMirrored = mirrored;
7704
8638
  }
7705
- /** 挂载到容器元素。 */
8639
+ /**
8640
+ * 挂载到容器元素。
8641
+ */
7706
8642
  attach(to) {
7707
8643
  to.appendChild(this.element);
7708
8644
  this.localVideoView.attach(this.element);
7709
8645
  this.remoteVideoView.attach(this.element);
7710
8646
  }
7711
- /** 从容器元素移除。 */
8647
+ /**
8648
+ * 从容器元素移除。
8649
+ */
7712
8650
  detach() {
7713
8651
  this.localVideoView.detach();
7714
8652
  this.remoteVideoView.detach();
7715
8653
  this.element.remove();
7716
8654
  }
7717
- /** 更新远端轨道绑定:重置渐入状态,等待首帧提交后再显示远端画面。 */
8655
+ /**
8656
+ * 更新远端轨道绑定:重置渐入状态,等待首帧提交后再显示远端画面。
8657
+ */
7718
8658
  updateRemoteTrack() {
7719
8659
  const remoteTrack = this.currentRemoteTrack;
7720
8660
  this.remoteVideoView.frameDisplayHandler = void 0;
@@ -7733,7 +8673,9 @@ var XmaxRealtimeVideoView = class {
7733
8673
  };
7734
8674
  this.remoteVideoView.track = remoteTrack;
7735
8675
  }
7736
- /** 远端首帧已提交:渐入远端画面。 */
8676
+ /**
8677
+ * 远端首帧已提交:渐入远端画面。
8678
+ */
7737
8679
  showRemoteVideo() {
7738
8680
  const element = this.remoteVideoView.element;
7739
8681
  if (element.style.visibility === "visible" && element.style.opacity === "1") {
@@ -7776,4 +8718,4 @@ var XmaxRealtimeVideoView = class {
7776
8718
 
7777
8719
 
7778
8720
  exports.XmaxEnvironment = XmaxEnvironment; exports.apiBaseURL = apiBaseURL; exports.XmaxLoggerOption = XmaxLoggerOption; exports.XmaxLogger = XmaxLogger; exports.XmaxErrorCode = XmaxErrorCode; exports.XmaxError = XmaxError; exports.RealtimeVideoEncoderPreference = RealtimeVideoEncoderPreference; exports.RealtimeVideoFormat = RealtimeVideoFormat; exports.RealtimeModel = RealtimeModel; exports.defaultFrameRate = defaultFrameRate; exports.defaultCameraVideoFormat = defaultCameraVideoFormat; exports.MediaService = MediaService; exports.StoredFile = StoredFile; exports.StorageService = StorageService; exports.CameraPosition = CameraPosition; exports.RealtimeVideoTrack = RealtimeVideoTrack; exports.RealtimeMediaStream = RealtimeMediaStream; exports.RealtimeConnectionState = RealtimeConnectionState; exports.RealtimeReason = RealtimeReason; exports.RealtimeState = RealtimeState; exports.XmaxConfiguration = XmaxConfiguration; exports.XmaxClient = XmaxClient; exports.RealtimeConfiguration = RealtimeConfiguration; exports.VideoContentMode = VideoContentMode; exports.RealtimeContext = RealtimeContext; exports.XmaxVideoView = XmaxVideoView; exports.XmaxRealtimeVideoView = XmaxRealtimeVideoView;
7779
- //# sourceMappingURL=chunk-JJWUZ3AW.cjs.map
8721
+ //# sourceMappingURL=chunk-FH3OPC6F.cjs.map