@xmaxai/web-sdk 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -12
- package/dist/{chunk-FEL5MJMJ.cjs → chunk-JN6HURTT.cjs} +1770 -376
- package/dist/chunk-JN6HURTT.cjs.map +1 -0
- package/dist/{chunk-FMAQXPTE.js → chunk-VMJXIVUF.js} +1578 -184
- package/dist/chunk-VMJXIVUF.js.map +1 -0
- package/dist/index.cjs +14 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +350 -92
- package/dist/index.d.ts +350 -92
- package/dist/index.js +15 -3
- package/dist/react/index.cjs +3 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +9 -7
- package/dist/chunk-FEL5MJMJ.cjs.map +0 -1
- package/dist/chunk-FMAQXPTE.js.map +0 -1
|
@@ -12,9 +12,16 @@ var API_BASE_URLS = {
|
|
|
12
12
|
["china" /* china */]: "https://cloud.xmax.22duck.cn/open/api/v1",
|
|
13
13
|
["global" /* global */]: "https://api.xmax.cloud/open/api/v1"
|
|
14
14
|
};
|
|
15
|
+
var NON_REALTIME_API_BASE_URLS = {
|
|
16
|
+
["china" /* china */]: "https://api.xmaxai.com/open/api/v1",
|
|
17
|
+
["global" /* global */]: "https://api.xmax.ai/open/api/v1"
|
|
18
|
+
};
|
|
15
19
|
function apiBaseURL(environment) {
|
|
16
20
|
return API_BASE_URLS[environment];
|
|
17
21
|
}
|
|
22
|
+
function nonRealtimeApiBaseURL(environment) {
|
|
23
|
+
return NON_REALTIME_API_BASE_URLS[environment];
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
// src/Foundation/Logging/XmaxLogger.ts
|
|
20
27
|
var XmaxLoggerOption = /* @__PURE__ */ ((XmaxLoggerOption2) => {
|
|
@@ -198,7 +205,7 @@ var XmaxError = class _XmaxError extends Error {
|
|
|
198
205
|
};
|
|
199
206
|
|
|
200
207
|
// src/Foundation/Runtime/RuntimeInfo.ts
|
|
201
|
-
var XMAX_SDK_VERSION = "1.0.
|
|
208
|
+
var XMAX_SDK_VERSION = "1.0.5";
|
|
202
209
|
var _RuntimeInfo = class _RuntimeInfo {
|
|
203
210
|
/**
|
|
204
211
|
* 序列化为接口传输使用的 snake_case 字段。
|
|
@@ -268,8 +275,24 @@ var _ApiService = class _ApiService {
|
|
|
268
275
|
*/
|
|
269
276
|
async request(method, path, body, options) {
|
|
270
277
|
this.validateConfiguration();
|
|
278
|
+
if (_optionalChain([options, 'optionalAccess', _4 => _4.signal, 'optionalAccess', _5 => _5.aborted])) {
|
|
279
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "API request was cancelled");
|
|
280
|
+
}
|
|
271
281
|
const request = this.makeRequest(method, path, body, options);
|
|
272
282
|
const startedAt = Date.now();
|
|
283
|
+
const timeoutSignal = request.init.signal;
|
|
284
|
+
const controller = new AbortController();
|
|
285
|
+
const abortTimeout = () => controller.abort(timeoutSignal.reason);
|
|
286
|
+
const abortCaller = () => controller.abort(new DOMException("Cancelled", "AbortError"));
|
|
287
|
+
timeoutSignal.addEventListener("abort", abortTimeout, { once: true });
|
|
288
|
+
_optionalChain([options, 'optionalAccess', _6 => _6.signal, 'optionalAccess', _7 => _7.addEventListener, 'call', _8 => _8("abort", abortCaller, { once: true })]);
|
|
289
|
+
request.init.signal = controller.signal;
|
|
290
|
+
if (timeoutSignal.aborted) {
|
|
291
|
+
abortTimeout();
|
|
292
|
+
}
|
|
293
|
+
if (_optionalChain([options, 'optionalAccess', _9 => _9.signal, 'optionalAccess', _10 => _10.aborted])) {
|
|
294
|
+
abortCaller();
|
|
295
|
+
}
|
|
273
296
|
let status;
|
|
274
297
|
let text;
|
|
275
298
|
try {
|
|
@@ -280,6 +303,9 @@ var _ApiService = class _ApiService {
|
|
|
280
303
|
const mapped = _ApiService.transportError(error);
|
|
281
304
|
this.logFailure(method, path, mapped, startedAt);
|
|
282
305
|
throw mapped;
|
|
306
|
+
} finally {
|
|
307
|
+
timeoutSignal.removeEventListener("abort", abortTimeout);
|
|
308
|
+
_optionalChain([options, 'optionalAccess', _11 => _11.signal, 'optionalAccess', _12 => _12.removeEventListener, 'call', _13 => _13("abort", abortCaller)]);
|
|
283
309
|
}
|
|
284
310
|
try {
|
|
285
311
|
const value = _ApiService.parseResponse(text, status);
|
|
@@ -297,8 +323,8 @@ var _ApiService = class _ApiService {
|
|
|
297
323
|
/**
|
|
298
324
|
* 发送 GET 请求。
|
|
299
325
|
*/
|
|
300
|
-
get(path) {
|
|
301
|
-
return this.request("GET" /* get */, path);
|
|
326
|
+
get(path, options) {
|
|
327
|
+
return this.request("GET" /* get */, path, void 0, options);
|
|
302
328
|
}
|
|
303
329
|
/**
|
|
304
330
|
* 发送 POST 请求。
|
|
@@ -388,7 +414,7 @@ var _ApiService = class _ApiService {
|
|
|
388
414
|
},
|
|
389
415
|
body: encodedBody,
|
|
390
416
|
signal: AbortSignal.timeout(this.timeoutMs),
|
|
391
|
-
..._optionalChain([options, 'optionalAccess',
|
|
417
|
+
..._optionalChain([options, 'optionalAccess', _14 => _14.keepalive]) ? { keepalive: true } : {}
|
|
392
418
|
}
|
|
393
419
|
};
|
|
394
420
|
}
|
|
@@ -405,8 +431,9 @@ var _ApiService = class _ApiService {
|
|
|
405
431
|
});
|
|
406
432
|
}
|
|
407
433
|
const ok = status >= 200 && status < 300;
|
|
408
|
-
|
|
409
|
-
|
|
434
|
+
const succeeded = envelope.success === true || envelope.success === void 0 && envelope.code === 200;
|
|
435
|
+
if (!ok || !succeeded) {
|
|
436
|
+
const message = _optionalChain([envelope, 'access', _15 => _15.message, 'optionalAccess', _16 => _16.trim, 'call', _17 => _17()]);
|
|
410
437
|
throw new XmaxError(
|
|
411
438
|
"API_ERROR" /* apiError */,
|
|
412
439
|
message || "Xmax API request failed",
|
|
@@ -561,6 +588,14 @@ var RealtimeVideoFormat = class _RealtimeVideoFormat {
|
|
|
561
588
|
}
|
|
562
589
|
};
|
|
563
590
|
|
|
591
|
+
// src/Foundation/RTC/RtcProvider.ts
|
|
592
|
+
var RtcProvider = /* @__PURE__ */ ((RtcProvider2) => {
|
|
593
|
+
RtcProvider2["trtc"] = "trtc";
|
|
594
|
+
RtcProvider2["agora"] = "agora";
|
|
595
|
+
RtcProvider2["vertc"] = "vertc";
|
|
596
|
+
return RtcProvider2;
|
|
597
|
+
})(RtcProvider || {});
|
|
598
|
+
|
|
564
599
|
// src/Service/Realtime/RealtimeModel.ts
|
|
565
600
|
var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
|
|
566
601
|
RealtimeModel2["x2_0"] = "x2.0";
|
|
@@ -569,12 +604,28 @@ var RealtimeModel = /* @__PURE__ */ ((RealtimeModel2) => {
|
|
|
569
604
|
RealtimeModel2["x2_1_preview"] = "x2.1-preview";
|
|
570
605
|
return RealtimeModel2;
|
|
571
606
|
})(RealtimeModel || {});
|
|
607
|
+
function isKnownModel(model) {
|
|
608
|
+
if (typeof model !== "string" || !model.trim()) {
|
|
609
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Realtime model must be a non-empty string");
|
|
610
|
+
}
|
|
611
|
+
return Object.values(RealtimeModel).includes(model);
|
|
612
|
+
}
|
|
613
|
+
function modelDefaults(model) {
|
|
614
|
+
return isKnownModel(model) ? model : "x2.1-preview" /* x2_1_preview */;
|
|
615
|
+
}
|
|
616
|
+
var MODEL_DISPLAY_NAMES = {
|
|
617
|
+
["x2.0" /* x2_0 */]: "X2.0",
|
|
618
|
+
["x2.0-trtc" /* x2_0_trtc */]: "X2.1-preview-trtc",
|
|
619
|
+
["x2.0-agora" /* x2_0_agora */]: "X2.1-preview-agora",
|
|
620
|
+
["x2.1-preview" /* x2_1_preview */]: "X2.1-preview-vertc"
|
|
621
|
+
};
|
|
572
622
|
var MODEL_BASE_URLS = {
|
|
573
623
|
["x2.0-agora" /* x2_0_agora */]: "https://dev.xmaxai.com/open/api/v1",
|
|
574
624
|
["x2.1-preview" /* x2_1_preview */]: "https://dev.xmaxai.com/open/api/v1"
|
|
575
625
|
};
|
|
576
626
|
var RESOLUTION_BUCKETS = {
|
|
577
|
-
["x2.
|
|
627
|
+
["x2.0" /* x2_0 */]: [],
|
|
628
|
+
["x2.0-trtc" /* x2_0_trtc */]: [
|
|
578
629
|
{ width: 1024, height: 1920 },
|
|
579
630
|
{ width: 1920, height: 1024 }
|
|
580
631
|
],
|
|
@@ -582,29 +633,31 @@ var RESOLUTION_BUCKETS = {
|
|
|
582
633
|
{ width: 1024, height: 1920 },
|
|
583
634
|
{ width: 1920, height: 1024 }
|
|
584
635
|
],
|
|
585
|
-
["x2.
|
|
586
|
-
["x2.0-trtc" /* x2_0_trtc */]: [
|
|
636
|
+
["x2.1-preview" /* x2_1_preview */]: [
|
|
587
637
|
{ width: 1024, height: 1920 },
|
|
588
638
|
{ width: 1920, height: 1024 }
|
|
589
639
|
]
|
|
590
640
|
};
|
|
591
641
|
var MAXIMUM_INPUT_PIXELS = {
|
|
592
|
-
["x2.1-preview" /* x2_1_preview */]: 21e5,
|
|
593
|
-
["x2.0-agora" /* x2_0_agora */]: 21e5,
|
|
594
642
|
["x2.0" /* x2_0 */]: 128e4,
|
|
595
|
-
["x2.0-trtc" /* x2_0_trtc */]: 21e5
|
|
643
|
+
["x2.0-trtc" /* x2_0_trtc */]: 21e5,
|
|
644
|
+
["x2.0-agora" /* x2_0_agora */]: 21e5,
|
|
645
|
+
["x2.1-preview" /* x2_1_preview */]: 21e5
|
|
596
646
|
};
|
|
647
|
+
function modelDisplayName(model) {
|
|
648
|
+
return isKnownModel(model) ? MODEL_DISPLAY_NAMES[model] : model;
|
|
649
|
+
}
|
|
597
650
|
function modelBaseURL(model) {
|
|
598
|
-
return MODEL_BASE_URLS[model];
|
|
651
|
+
return MODEL_BASE_URLS[modelDefaults(model)];
|
|
599
652
|
}
|
|
600
653
|
function resolutionBuckets(model) {
|
|
601
|
-
return RESOLUTION_BUCKETS[model];
|
|
654
|
+
return RESOLUTION_BUCKETS[modelDefaults(model)];
|
|
602
655
|
}
|
|
603
656
|
function minimumInputPixels(_model) {
|
|
604
657
|
return 6e5;
|
|
605
658
|
}
|
|
606
659
|
function maximumInputPixels(model) {
|
|
607
|
-
return MAXIMUM_INPUT_PIXELS[model];
|
|
660
|
+
return MAXIMUM_INPUT_PIXELS[modelDefaults(model)];
|
|
608
661
|
}
|
|
609
662
|
function inputSizeAlignment(_model) {
|
|
610
663
|
return 32;
|
|
@@ -613,11 +666,24 @@ function defaultFrameRate(_model) {
|
|
|
613
666
|
return 30;
|
|
614
667
|
}
|
|
615
668
|
function defaultCameraVideoFormat(model) {
|
|
616
|
-
if (model === "x2.0" /* x2_0 */) {
|
|
669
|
+
if (modelDefaults(model) === "x2.0" /* x2_0 */) {
|
|
617
670
|
return new RealtimeVideoFormat({ width: 832, height: 1472, fps: 30 });
|
|
618
671
|
}
|
|
619
672
|
return new RealtimeVideoFormat({ width: 1024, height: 1920, fps: 30 });
|
|
620
673
|
}
|
|
674
|
+
var MODEL_RTC_PROVIDERS = {
|
|
675
|
+
["x2.0" /* x2_0 */]: Object.freeze(["vertc" /* vertc */]),
|
|
676
|
+
["x2.0-trtc" /* x2_0_trtc */]: Object.freeze(["trtc" /* trtc */]),
|
|
677
|
+
["x2.0-agora" /* x2_0_agora */]: Object.freeze(["agora" /* agora */]),
|
|
678
|
+
["x2.1-preview" /* x2_1_preview */]: Object.freeze(["vertc" /* vertc */])
|
|
679
|
+
};
|
|
680
|
+
function supportedRtcProviders(model) {
|
|
681
|
+
return isKnownModel(model) ? MODEL_RTC_PROVIDERS[model] : CUSTOM_MODEL_RTC_PROVIDERS;
|
|
682
|
+
}
|
|
683
|
+
var CUSTOM_MODEL_RTC_PROVIDERS = Object.freeze([
|
|
684
|
+
...MODEL_RTC_PROVIDERS["x2.1-preview" /* x2_1_preview */],
|
|
685
|
+
...Object.values(RtcProvider).filter((provider) => !MODEL_RTC_PROVIDERS["x2.1-preview" /* x2_1_preview */].includes(provider))
|
|
686
|
+
]);
|
|
621
687
|
|
|
622
688
|
// src/Foundation/Media/Video/FrameInterpolationSupport.ts
|
|
623
689
|
async function frameInterpolationAdapter(size) {
|
|
@@ -625,7 +691,7 @@ async function frameInterpolationAdapter(size) {
|
|
|
625
691
|
if (size && (!Number.isSafeInteger(size.width) || !Number.isSafeInteger(size.height) || size.width <= 0 || size.height <= 0)) return null;
|
|
626
692
|
try {
|
|
627
693
|
const adapter = await navigator.gpu.requestAdapter();
|
|
628
|
-
if (!_optionalChain([adapter, 'optionalAccess',
|
|
694
|
+
if (!_optionalChain([adapter, 'optionalAccess', _18 => _18.features, 'access', _19 => _19.has, 'call', _20 => _20("shader-f16")])) return null;
|
|
629
695
|
if (size && (Math.ceil(size.width / 16) * 16 > adapter.limits.maxTextureDimension2D || Math.ceil(size.height / 16) * 16 > adapter.limits.maxTextureDimension2D)) return null;
|
|
630
696
|
return adapter;
|
|
631
697
|
} catch (e5) {
|
|
@@ -802,7 +868,14 @@ var CONTENT_TYPES = {
|
|
|
802
868
|
gif: "image/gif",
|
|
803
869
|
bmp: "image/bmp",
|
|
804
870
|
heic: "image/heic",
|
|
805
|
-
heif: "image/heif"
|
|
871
|
+
heif: "image/heif",
|
|
872
|
+
mp4: "video/mp4",
|
|
873
|
+
m4v: "video/mp4",
|
|
874
|
+
mov: "video/quicktime",
|
|
875
|
+
webm: "video/webm",
|
|
876
|
+
avi: "video/x-msvideo",
|
|
877
|
+
mkv: "video/x-matroska",
|
|
878
|
+
ogv: "video/ogg"
|
|
806
879
|
};
|
|
807
880
|
var StorageService = class _StorageService {
|
|
808
881
|
/**
|
|
@@ -836,15 +909,90 @@ var StorageService = class _StorageService {
|
|
|
836
909
|
* 上传图片并返回访问地址。
|
|
837
910
|
*/
|
|
838
911
|
async uploadImage(options) {
|
|
912
|
+
return this.upload(options, "Image");
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* 普通上传原始视频并返回访问地址,不进行转码、压缩或分片。
|
|
916
|
+
*/
|
|
917
|
+
async uploadVideo(options) {
|
|
918
|
+
return this.upload(options, "Video");
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* 下载原始视频文件并交给浏览器保存,支持取消网络下载。
|
|
922
|
+
*/
|
|
923
|
+
async downloadVideo(options) {
|
|
924
|
+
const fileName = _StorageService.validateFileName(options.fileName);
|
|
925
|
+
let url;
|
|
926
|
+
try {
|
|
927
|
+
url = new URL(options.url.trim());
|
|
928
|
+
} catch (e6) {
|
|
929
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Invalid video download URL");
|
|
930
|
+
}
|
|
931
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) {
|
|
932
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Video download requires an HTTP(S) URL without embedded credentials");
|
|
933
|
+
}
|
|
934
|
+
if (typeof document === "undefined" || !document.body) {
|
|
935
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Video saving requires a browser document");
|
|
936
|
+
}
|
|
937
|
+
let objectURL;
|
|
938
|
+
let link;
|
|
939
|
+
let saveRequested = false;
|
|
940
|
+
try {
|
|
941
|
+
if (_optionalChain([options, 'access', _21 => _21.signal, 'optionalAccess', _22 => _22.aborted])) {
|
|
942
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Video download was cancelled");
|
|
943
|
+
}
|
|
944
|
+
const response = await fetch(options.url.trim(), { credentials: "omit", signal: options.signal });
|
|
945
|
+
if (!response.ok) {
|
|
946
|
+
throw new XmaxError("DOWNLOAD_ERROR" /* downloadError */, "Video download failed", { httpStatus: response.status });
|
|
947
|
+
}
|
|
948
|
+
const data = await response.blob();
|
|
949
|
+
if (_optionalChain([options, 'access', _23 => _23.signal, 'optionalAccess', _24 => _24.aborted])) {
|
|
950
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Video download was cancelled");
|
|
951
|
+
}
|
|
952
|
+
if (data.size === 0) {
|
|
953
|
+
throw new XmaxError("DOWNLOAD_ERROR" /* downloadError */, "Downloaded video is empty");
|
|
954
|
+
}
|
|
955
|
+
objectURL = URL.createObjectURL(data);
|
|
956
|
+
link = document.createElement("a");
|
|
957
|
+
link.href = objectURL;
|
|
958
|
+
link.download = fileName;
|
|
959
|
+
link.hidden = true;
|
|
960
|
+
document.body.appendChild(link);
|
|
961
|
+
link.click();
|
|
962
|
+
saveRequested = true;
|
|
963
|
+
} catch (error) {
|
|
964
|
+
if (_optionalChain([options, 'access', _25 => _25.signal, 'optionalAccess', _26 => _26.aborted])) {
|
|
965
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Video download was cancelled");
|
|
966
|
+
}
|
|
967
|
+
if (error instanceof XmaxError) {
|
|
968
|
+
throw error;
|
|
969
|
+
}
|
|
970
|
+
throw new XmaxError("DOWNLOAD_ERROR" /* downloadError */, error instanceof Error ? error.message : String(error));
|
|
971
|
+
} finally {
|
|
972
|
+
_optionalChain([link, 'optionalAccess', _27 => _27.remove, 'call', _28 => _28()]);
|
|
973
|
+
if (objectURL) {
|
|
974
|
+
const resourceURL = objectURL;
|
|
975
|
+
if (saveRequested) {
|
|
976
|
+
setTimeout(() => URL.revokeObjectURL(resourceURL), 6e4);
|
|
977
|
+
} else {
|
|
978
|
+
URL.revokeObjectURL(resourceURL);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* 获取临时凭证并通过 COS putObject 上传文件,统一处理进度、结果和错误。
|
|
985
|
+
*/
|
|
986
|
+
async upload(options, mediaType) {
|
|
839
987
|
const startedAt = Date.now();
|
|
840
988
|
try {
|
|
841
989
|
const safeName = _StorageService.validateFileName(options.fileName);
|
|
842
|
-
const contentType = _optionalChain([options, 'access',
|
|
990
|
+
const contentType = _optionalChain([options, 'access', _29 => _29.contentType, 'optionalAccess', _30 => _30.trim, 'call', _31 => _31()]) || _StorageService.inferContentType(safeName);
|
|
843
991
|
const body = _StorageService.makeBody(options.data, contentType);
|
|
844
992
|
if (body.size === 0) {
|
|
845
993
|
throw new XmaxError(
|
|
846
994
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
847
|
-
|
|
995
|
+
`${mediaType} data cannot be empty`
|
|
848
996
|
);
|
|
849
997
|
}
|
|
850
998
|
const temporary = await this.fetchStorageConfiguration();
|
|
@@ -861,7 +1009,7 @@ var StorageService = class _StorageService {
|
|
|
861
1009
|
Key: objectKey,
|
|
862
1010
|
Body: body,
|
|
863
1011
|
ContentType: contentType,
|
|
864
|
-
onProgress: options.onProgress ? (info) => _optionalChain([options, 'access',
|
|
1012
|
+
onProgress: options.onProgress ? (info) => _optionalChain([options, 'access', _32 => _32.onProgress, 'optionalCall', _33 => _33(info.loaded, info.total)]) : void 0
|
|
865
1013
|
});
|
|
866
1014
|
const url = _StorageService.resolveObjectURL(
|
|
867
1015
|
uploaded.Location,
|
|
@@ -893,9 +1041,9 @@ var StorageService = class _StorageService {
|
|
|
893
1041
|
const bucket = _StorageService.nonEmpty(payload.bucket);
|
|
894
1042
|
const region = _StorageService.nonEmpty(payload.region);
|
|
895
1043
|
const prefix = _StorageService.nonEmpty(payload.prefix);
|
|
896
|
-
const accessKeyID = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
897
|
-
const secretAccessKey = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
898
|
-
const sessionToken = _StorageService.nonEmpty(_optionalChain([payload, 'access',
|
|
1044
|
+
const accessKeyID = _StorageService.nonEmpty(_optionalChain([payload, 'access', _34 => _34.credentials, 'optionalAccess', _35 => _35.accessKeyId]));
|
|
1045
|
+
const secretAccessKey = _StorageService.nonEmpty(_optionalChain([payload, 'access', _36 => _36.credentials, 'optionalAccess', _37 => _37.secretAccessKey]));
|
|
1046
|
+
const sessionToken = _StorageService.nonEmpty(_optionalChain([payload, 'access', _38 => _38.credentials, 'optionalAccess', _39 => _39.sessionToken]));
|
|
899
1047
|
if (!bucket || !region || !prefix || !accessKeyID || !secretAccessKey || !sessionToken) {
|
|
900
1048
|
throw new XmaxError("API_ERROR" /* apiError */, message);
|
|
901
1049
|
}
|
|
@@ -936,7 +1084,7 @@ var StorageService = class _StorageService {
|
|
|
936
1084
|
reject(
|
|
937
1085
|
new XmaxError(
|
|
938
1086
|
"UPLOAD_ERROR" /* uploadError */,
|
|
939
|
-
_optionalChain([error, 'access',
|
|
1087
|
+
_optionalChain([error, 'access', _40 => _40.message, 'optionalAccess', _41 => _41.trim, 'call', _42 => _42()]) || "Storage upload failed"
|
|
940
1088
|
)
|
|
941
1089
|
);
|
|
942
1090
|
return;
|
|
@@ -950,14 +1098,14 @@ var StorageService = class _StorageService {
|
|
|
950
1098
|
* 其次拼接自定义 endpoint,最后回退到默认 COS 域名。
|
|
951
1099
|
*/
|
|
952
1100
|
static resolveObjectURL(location, configuration, objectKey) {
|
|
953
|
-
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess',
|
|
1101
|
+
const candidate = _nullishCoalesce(_optionalChain([location, 'optionalAccess', _43 => _43.trim, 'call', _44 => _44()]), () => ( ""));
|
|
954
1102
|
if (candidate.startsWith("//")) {
|
|
955
1103
|
return `https:${candidate}`;
|
|
956
1104
|
}
|
|
957
1105
|
if (/^https?:\/\//i.test(candidate)) {
|
|
958
1106
|
return candidate;
|
|
959
1107
|
}
|
|
960
|
-
const endpoint = _optionalChain([configuration, 'access',
|
|
1108
|
+
const endpoint = _optionalChain([configuration, 'access', _45 => _45.endpoint, 'optionalAccess', _46 => _46.trim, 'call', _47 => _47()]);
|
|
961
1109
|
if (endpoint) {
|
|
962
1110
|
const normalized = /^https?:\/\//i.test(endpoint) ? endpoint : `https://${endpoint}`;
|
|
963
1111
|
return `${normalized.replace(/\/+$/, "")}/${objectKey}`;
|
|
@@ -982,7 +1130,7 @@ var StorageService = class _StorageService {
|
|
|
982
1130
|
if (!safeName || safeName.includes("/") || safeName.includes("\\")) {
|
|
983
1131
|
throw new XmaxError(
|
|
984
1132
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
985
|
-
"Invalid file name for storage
|
|
1133
|
+
"Invalid file name for storage operation"
|
|
986
1134
|
);
|
|
987
1135
|
}
|
|
988
1136
|
return safeName;
|
|
@@ -991,7 +1139,7 @@ var StorageService = class _StorageService {
|
|
|
991
1139
|
* 按文件名后缀推断内容类型。
|
|
992
1140
|
*/
|
|
993
1141
|
static inferContentType(fileName) {
|
|
994
|
-
const extension = _nullishCoalesce(_optionalChain([fileName, 'access',
|
|
1142
|
+
const extension = _nullishCoalesce(_optionalChain([fileName, 'access', _48 => _48.split, 'call', _49 => _49("."), 'access', _50 => _50.pop, 'call', _51 => _51(), 'optionalAccess', _52 => _52.toLowerCase, 'call', _53 => _53()]), () => ( ""));
|
|
995
1143
|
return _nullishCoalesce(CONTENT_TYPES[extension], () => ( "application/octet-stream"));
|
|
996
1144
|
}
|
|
997
1145
|
/**
|
|
@@ -1010,7 +1158,7 @@ var StorageService = class _StorageService {
|
|
|
1010
1158
|
* 归一化可选字符串:去除首尾空白后为空时返回 `undefined`。
|
|
1011
1159
|
*/
|
|
1012
1160
|
static nonEmpty(value) {
|
|
1013
|
-
const normalized = _optionalChain([value, 'optionalAccess',
|
|
1161
|
+
const normalized = _optionalChain([value, 'optionalAccess', _54 => _54.trim, 'call', _55 => _55()]);
|
|
1014
1162
|
return normalized || void 0;
|
|
1015
1163
|
}
|
|
1016
1164
|
};
|
|
@@ -1025,7 +1173,7 @@ var CameraPosition = /* @__PURE__ */ ((CameraPosition3) => {
|
|
|
1025
1173
|
// src/Foundation/Permissions/MediaPermissionWatch.ts
|
|
1026
1174
|
var PERMISSION_POLL_INTERVAL_MS = 100;
|
|
1027
1175
|
async function watchMediaPermissionPrompt(includeMicrophone) {
|
|
1028
|
-
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access',
|
|
1176
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _56 => _56.permissions, 'optionalAccess', _57 => _57.query])) {
|
|
1029
1177
|
return void 0;
|
|
1030
1178
|
}
|
|
1031
1179
|
const names = ["camera", ...includeMicrophone ? ["microphone"] : []];
|
|
@@ -1044,7 +1192,7 @@ async function watchMediaPermissionPrompt(includeMicrophone) {
|
|
|
1044
1192
|
name
|
|
1045
1193
|
});
|
|
1046
1194
|
return status.state;
|
|
1047
|
-
} catch (
|
|
1195
|
+
} catch (e7) {
|
|
1048
1196
|
return "prompt";
|
|
1049
1197
|
}
|
|
1050
1198
|
})
|
|
@@ -1052,7 +1200,7 @@ async function watchMediaPermissionPrompt(includeMicrophone) {
|
|
|
1052
1200
|
let states;
|
|
1053
1201
|
try {
|
|
1054
1202
|
states = await queryOnce();
|
|
1055
|
-
} catch (
|
|
1203
|
+
} catch (e8) {
|
|
1056
1204
|
return void 0;
|
|
1057
1205
|
}
|
|
1058
1206
|
if (states.every((state2) => state2 === "granted")) {
|
|
@@ -1108,12 +1256,12 @@ var AgoraRtcStatistics = class _AgoraRtcStatistics {
|
|
|
1108
1256
|
frameRate: valid(stats.receiveFrameRate),
|
|
1109
1257
|
bitrateKbps: valid(stats.receiveBitrate / 1e3),
|
|
1110
1258
|
rttMs: valid(rtc.RTT),
|
|
1111
|
-
uplinkLossPercent: _optionalChain([localVideo, 'optionalAccess',
|
|
1259
|
+
uplinkLossPercent: _optionalChain([localVideo, 'optionalAccess', _58 => _58.uplinkLossPercent]),
|
|
1112
1260
|
downlinkLossPercent: loss(stats.currentPacketLossRate),
|
|
1113
1261
|
endToEndDelayMs: valid(stats.end2EndDelay)
|
|
1114
1262
|
}));
|
|
1115
|
-
_optionalChain([listener, 'optionalAccess',
|
|
1116
|
-
_optionalChain([listener, 'optionalAccess',
|
|
1263
|
+
_optionalChain([listener, 'optionalAccess', _59 => _59.onLocalVideoStatistics, 'optionalCall', _60 => _60(localVideo && Object.freeze(localVideo))]);
|
|
1264
|
+
_optionalChain([listener, 'optionalAccess', _61 => _61.onRemoteVideoStatistics, 'optionalCall', _62 => _62(Object.freeze(remote.map((item) => Object.freeze(item))))]);
|
|
1117
1265
|
XmaxLogger.rtc.info(() => `Agora \u8FD0\u884C\u7EDF\u8BA1 (Agora RTC Statistics)
|
|
1118
1266
|
${JSON.stringify({
|
|
1119
1267
|
rttMs: valid(rtc.RTT),
|
|
@@ -1131,7 +1279,7 @@ ${JSON.stringify({
|
|
|
1131
1279
|
static network(stats, listener) {
|
|
1132
1280
|
const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
|
|
1133
1281
|
const result = Object.freeze({ uplinkQuality: quality(stats.uplinkNetworkQuality), downlinkQuality: quality(stats.downlinkNetworkQuality) });
|
|
1134
|
-
_optionalChain([listener, 'optionalAccess',
|
|
1282
|
+
_optionalChain([listener, 'optionalAccess', _63 => _63.onNetworkStatistics, 'optionalCall', _64 => _64(result)]);
|
|
1135
1283
|
XmaxLogger.rtc.info(() => `Agora \u7F51\u7EDC\u8D28\u91CF (Agora Network Quality)
|
|
1136
1284
|
${JSON.stringify(result, null, 2)}`, 2 /* performance */);
|
|
1137
1285
|
}
|
|
@@ -1151,17 +1299,17 @@ ${JSON.stringify(result, null, 2)}`, 2 /* performance */);
|
|
|
1151
1299
|
|
|
1152
1300
|
// src/Foundation/RTC/RtcVideoOrientation.ts
|
|
1153
1301
|
function shouldTransposeRtcVideoSize(environment) {
|
|
1154
|
-
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
1155
|
-
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
1302
|
+
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _65 => _65.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
|
|
1303
|
+
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _66 => _66.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
|
|
1156
1304
|
const mobile = /Android|webOS|iPhone|iPad|iPod|Mobile/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
|
|
1157
1305
|
if (!mobile) {
|
|
1158
1306
|
return false;
|
|
1159
1307
|
}
|
|
1160
|
-
const orientationType = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
1308
|
+
const orientationType = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _67 => _67.orientationType]), () => ( (typeof window === "undefined" ? void 0 : _optionalChain([window, 'access', _68 => _68.screen, 'optionalAccess', _69 => _69.orientation, 'optionalAccess', _70 => _70.type]))));
|
|
1161
1309
|
if (orientationType !== void 0) {
|
|
1162
1310
|
return orientationType.includes("portrait");
|
|
1163
1311
|
}
|
|
1164
|
-
const degrees = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
1312
|
+
const degrees = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _71 => _71.orientationDegrees]), () => ( (typeof window === "undefined" ? void 0 : window.orientation)));
|
|
1165
1313
|
return degrees === 0 || degrees === 180;
|
|
1166
1314
|
}
|
|
1167
1315
|
function rtcOrientedVideoSize(size, environment) {
|
|
@@ -1185,6 +1333,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1185
1333
|
__publicField(this, "lifecycle", 0);
|
|
1186
1334
|
__publicField(this, "camera");
|
|
1187
1335
|
__publicField(this, "microphone");
|
|
1336
|
+
__publicField(this, "externalVideo");
|
|
1337
|
+
__publicField(this, "externalAudio");
|
|
1188
1338
|
__publicField(this, "connection");
|
|
1189
1339
|
__publicField(this, "roomVersion", 0);
|
|
1190
1340
|
/**
|
|
@@ -1256,7 +1406,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1256
1406
|
if (typeof client.sendStreamMessage !== "function") {
|
|
1257
1407
|
throw new XmaxError("RTC_ERROR" /* rtcError */, "Agora DataStream is unavailable in this SDK version");
|
|
1258
1408
|
}
|
|
1259
|
-
_AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess',
|
|
1409
|
+
_AgoraRtcManager.regions.set(sdk, { environment: this.environment, count: (_nullishCoalesce(_optionalChain([region, 'optionalAccess', _72 => _72.count]), () => ( 0))) + 1 });
|
|
1260
1410
|
this.sdk = sdk;
|
|
1261
1411
|
this.client = client;
|
|
1262
1412
|
this.registerEvents(client);
|
|
@@ -1267,19 +1417,22 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1267
1417
|
async destroy() {
|
|
1268
1418
|
this.lifecycle++;
|
|
1269
1419
|
const client = this.client;
|
|
1270
|
-
this.listener = void 0;
|
|
1271
1420
|
this.clearRoom();
|
|
1272
1421
|
this.client = void 0;
|
|
1273
|
-
_optionalChain([client, 'optionalAccess',
|
|
1274
|
-
_optionalChain([this, 'access',
|
|
1275
|
-
_optionalChain([this, 'access',
|
|
1422
|
+
_optionalChain([client, 'optionalAccess', _73 => _73.removeAllListeners, 'call', _74 => _74()]);
|
|
1423
|
+
_optionalChain([this, 'access', _75 => _75.camera, 'optionalAccess', _76 => _76.close, 'call', _77 => _77()]);
|
|
1424
|
+
_optionalChain([this, 'access', _78 => _78.microphone, 'optionalAccess', _79 => _79.close, 'call', _80 => _80()]);
|
|
1425
|
+
_optionalChain([this, 'access', _81 => _81.externalVideo, 'optionalAccess', _82 => _82.close, 'call', _83 => _83()]);
|
|
1426
|
+
_optionalChain([this, 'access', _84 => _84.externalAudio, 'optionalAccess', _85 => _85.close, 'call', _86 => _86()]);
|
|
1427
|
+
this.externalVideo = void 0;
|
|
1428
|
+
this.externalAudio = void 0;
|
|
1276
1429
|
this.camera = void 0;
|
|
1277
1430
|
this.microphone = void 0;
|
|
1278
1431
|
const sdk = this.sdk;
|
|
1279
1432
|
this.sdk = void 0;
|
|
1280
1433
|
try {
|
|
1281
|
-
await _optionalChain([client, 'optionalAccess',
|
|
1282
|
-
} catch (
|
|
1434
|
+
await _optionalChain([client, 'optionalAccess', _87 => _87.leave, 'call', _88 => _88()]);
|
|
1435
|
+
} catch (e9) {
|
|
1283
1436
|
XmaxLogger.rtc.warning(() => "Agora \u9000\u623F\u5931\u8D25\uFF0C\u5DF2\u91CA\u653E\u672C\u5730\u8D44\u6E90 (Agora Leave Failed)");
|
|
1284
1437
|
} finally {
|
|
1285
1438
|
const region = sdk && _AgoraRtcManager.regions.get(sdk);
|
|
@@ -1291,7 +1444,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1291
1444
|
*/
|
|
1292
1445
|
async startCameraCapture(options) {
|
|
1293
1446
|
const client = this.requireClient();
|
|
1294
|
-
if (this.camera
|
|
1447
|
+
if (this.camera || this.externalVideo) {
|
|
1448
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "A local video source is already active");
|
|
1449
|
+
}
|
|
1295
1450
|
try {
|
|
1296
1451
|
const captureSize = rtcOrientedVideoSize(options);
|
|
1297
1452
|
const camera = await this.sdk.createCameraVideoTrack({
|
|
@@ -1323,14 +1478,45 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1323
1478
|
async stopCameraCapture() {
|
|
1324
1479
|
const camera = this.camera;
|
|
1325
1480
|
this.camera = void 0;
|
|
1326
|
-
_optionalChain([camera, 'optionalAccess',
|
|
1481
|
+
_optionalChain([camera, 'optionalAccess', _89 => _89.close, 'call', _90 => _90()]);
|
|
1327
1482
|
}
|
|
1328
1483
|
/**
|
|
1329
|
-
*
|
|
1484
|
+
* 将外部原生轨包装为 Agora 本地轨,不申请设备权限;失败时释放本次克隆。
|
|
1485
|
+
*/
|
|
1486
|
+
async setExternalMediaTracks(tracks) {
|
|
1487
|
+
this.requireClient();
|
|
1488
|
+
if (this.camera || this.microphone || this.externalVideo) {
|
|
1489
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
|
|
1490
|
+
}
|
|
1491
|
+
if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
|
|
1492
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External media requires live video and optional audio tracks");
|
|
1493
|
+
}
|
|
1494
|
+
const video = tracks.videoTrack.clone();
|
|
1495
|
+
let audio;
|
|
1496
|
+
let wrappedVideo;
|
|
1497
|
+
let wrappedAudio;
|
|
1498
|
+
try {
|
|
1499
|
+
audio = _optionalChain([tracks, 'access', _91 => _91.audioTrack, 'optionalAccess', _92 => _92.clone, 'call', _93 => _93()]);
|
|
1500
|
+
wrappedVideo = this.sdk.createCustomVideoTrack({ mediaStreamTrack: video });
|
|
1501
|
+
if (audio) {
|
|
1502
|
+
wrappedAudio = this.sdk.createCustomAudioTrack({ mediaStreamTrack: audio, encoderConfig: "music_standard" });
|
|
1503
|
+
}
|
|
1504
|
+
this.externalVideo = wrappedVideo;
|
|
1505
|
+
this.externalAudio = wrappedAudio;
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
_optionalChain([wrappedVideo, 'optionalAccess', _94 => _94.close, 'call', _95 => _95()]);
|
|
1508
|
+
_optionalChain([wrappedAudio, 'optionalAccess', _96 => _96.close, 'call', _97 => _97()]);
|
|
1509
|
+
video.stop();
|
|
1510
|
+
_optionalChain([audio, 'optionalAccess', _98 => _98.stop, 'call', _99 => _99()]);
|
|
1511
|
+
throw this.mapError(error);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* 应用公共编码配置;仅相机源补偿移动端转置,Canvas 外部源使用原始方向。
|
|
1330
1516
|
*/
|
|
1331
1517
|
async configureVideoEncoding(config) {
|
|
1332
|
-
const camera = this.
|
|
1333
|
-
const encodingSize = rtcOrientedVideoSize(config);
|
|
1518
|
+
const camera = this.requireLocalVideo();
|
|
1519
|
+
const encodingSize = this.externalVideo ? config : rtcOrientedVideoSize(config);
|
|
1334
1520
|
await this.run(async () => {
|
|
1335
1521
|
await camera.setEncoderConfiguration({
|
|
1336
1522
|
width: encodingSize.width,
|
|
@@ -1346,10 +1532,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1346
1532
|
* 使用会话下发的字符串频道与 UID 入房;不采信后端区域覆盖。
|
|
1347
1533
|
*/
|
|
1348
1534
|
async joinRoom(configuration) {
|
|
1349
|
-
await _optionalChain([this, 'access',
|
|
1535
|
+
await _optionalChain([this, 'access', _100 => _100.rejoinTask, 'optionalAccess', _101 => _101.catch, 'call', _102 => _102(() => {
|
|
1350
1536
|
})]);
|
|
1351
1537
|
const client = this.requireClient();
|
|
1352
|
-
if (configuration.provider !== "agora" || this.connection) {
|
|
1538
|
+
if (configuration.provider !== "agora" /* agora */ || this.connection) {
|
|
1353
1539
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Agora credentials and an idle room are required");
|
|
1354
1540
|
}
|
|
1355
1541
|
const version = ++this.roomVersion;
|
|
@@ -1360,13 +1546,13 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1360
1546
|
}
|
|
1361
1547
|
this.connection = configuration;
|
|
1362
1548
|
for (const user of client.remoteUsers) {
|
|
1363
|
-
if (user.hasVideo) _optionalChain([this, 'access',
|
|
1549
|
+
if (user.hasVideo) _optionalChain([this, 'access', _103 => _103.listener, 'optionalAccess', _104 => _104.onRemoteVideoPublished, 'call', _105 => _105(String(user.uid), true)]);
|
|
1364
1550
|
}
|
|
1365
1551
|
this.statisticsTimer = setInterval(() => {
|
|
1366
1552
|
if (this.client !== client || !this.connection || this.tokenExpired || this.rejoinOperation) return;
|
|
1367
1553
|
try {
|
|
1368
1554
|
AgoraRtcStatistics.collect(client, this.listener);
|
|
1369
|
-
} catch (
|
|
1555
|
+
} catch (e10) {
|
|
1370
1556
|
XmaxLogger.rtc.warning(() => "Agora \u7EDF\u8BA1\u91C7\u6837\u5931\u8D25 (Agora Statistics Failed)");
|
|
1371
1557
|
}
|
|
1372
1558
|
}, 2e3);
|
|
@@ -1382,10 +1568,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1382
1568
|
* 应用同一频道的新 Token;即将过期时续签,已经过期时重新进房并恢复媒体。
|
|
1383
1569
|
*/
|
|
1384
1570
|
async updateCredentials(config, signal) {
|
|
1385
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1571
|
+
if (_optionalChain([signal, 'optionalAccess', _106 => _106.aborted])) throw this.cancelled();
|
|
1386
1572
|
const current = this.connection;
|
|
1387
1573
|
const client = this.requireClient();
|
|
1388
|
-
if (!current || config.provider !== "agora" || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
1574
|
+
if (!current || config.provider !== "agora" /* agora */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
1389
1575
|
throw new XmaxError("SESSION_ERROR" /* sessionError */, "Agora session binding changed");
|
|
1390
1576
|
}
|
|
1391
1577
|
const version = this.roomVersion;
|
|
@@ -1398,7 +1584,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1398
1584
|
}
|
|
1399
1585
|
}
|
|
1400
1586
|
this.ensureRoomCurrent(client, version);
|
|
1401
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1587
|
+
if (_optionalChain([signal, 'optionalAccess', _107 => _107.aborted])) throw this.cancelled();
|
|
1402
1588
|
if (this.tokenExpired) await this.rejoinRoom(client, config, signal);
|
|
1403
1589
|
else this.connection = config;
|
|
1404
1590
|
}
|
|
@@ -1421,21 +1607,21 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1421
1607
|
reject(this.cancelled());
|
|
1422
1608
|
};
|
|
1423
1609
|
this.cancelRejoin = cancel;
|
|
1424
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1610
|
+
_optionalChain([signal, 'optionalAccess', _108 => _108.addEventListener, 'call', _109 => _109("abort", cancel, { once: true })]);
|
|
1425
1611
|
task.then(resolve, reject);
|
|
1426
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1612
|
+
if (_optionalChain([signal, 'optionalAccess', _110 => _110.aborted])) cancel();
|
|
1427
1613
|
});
|
|
1428
1614
|
this.rejoinOperation = operation;
|
|
1429
1615
|
try {
|
|
1430
1616
|
await operation;
|
|
1431
1617
|
} finally {
|
|
1432
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1618
|
+
_optionalChain([signal, 'optionalAccess', _111 => _111.removeEventListener, 'call', _112 => _112("abort", cancel)]);
|
|
1433
1619
|
if (this.cancelRejoin === cancel) this.cancelRejoin = void 0;
|
|
1434
1620
|
if (this.rejoinOperation === operation) this.rejoinOperation = void 0;
|
|
1435
1621
|
}
|
|
1436
1622
|
this.ensureRoomCurrent(client, version);
|
|
1437
1623
|
for (const user of client.remoteUsers) {
|
|
1438
|
-
if (user.hasVideo) _optionalChain([this, 'access',
|
|
1624
|
+
if (user.hasVideo) _optionalChain([this, 'access', _113 => _113.listener, 'optionalAccess', _114 => _114.onRemoteVideoPublished, 'call', _115 => _115(String(user.uid), true)]);
|
|
1439
1625
|
}
|
|
1440
1626
|
}
|
|
1441
1627
|
/**
|
|
@@ -1443,10 +1629,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1443
1629
|
*/
|
|
1444
1630
|
async performRejoin(client, config, version) {
|
|
1445
1631
|
this.ensureRoomCurrent(client, version);
|
|
1446
|
-
_optionalChain([this, 'access',
|
|
1447
|
-
_optionalChain([this, 'access',
|
|
1448
|
-
_optionalChain([this, 'access',
|
|
1449
|
-
for (const user of client.remoteUsers) _optionalChain([user, 'access',
|
|
1632
|
+
_optionalChain([this, 'access', _116 => _116.cancelSendDelay, 'optionalCall', _117 => _117()]);
|
|
1633
|
+
_optionalChain([this, 'access', _118 => _118.cancelActiveSend, 'optionalCall', _119 => _119()]);
|
|
1634
|
+
_optionalChain([this, 'access', _120 => _120.listener, 'optionalAccess', _121 => _121.onRoomRejoining, 'optionalCall', _122 => _122()]);
|
|
1635
|
+
for (const user of client.remoteUsers) _optionalChain([user, 'access', _123 => _123.audioTrack, 'optionalAccess', _124 => _124.stop, 'call', _125 => _125()]);
|
|
1450
1636
|
await this.run(() => client.leave());
|
|
1451
1637
|
this.ensureRoomCurrent(client, version);
|
|
1452
1638
|
await this.run(() => client.join(config.appID, config.roomID, config.roomToken, config.userID));
|
|
@@ -1454,12 +1640,14 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1454
1640
|
await this.run(() => client.leave());
|
|
1455
1641
|
throw this.cancelled();
|
|
1456
1642
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1643
|
+
const video = _nullishCoalesce(this.externalVideo, () => ( this.camera));
|
|
1644
|
+
const audio = this.externalVideo ? this.externalAudio : this.microphone;
|
|
1645
|
+
if (this.videoPublishRequested && video) {
|
|
1646
|
+
await this.run(() => client.publish(video));
|
|
1459
1647
|
this.ensureRoomCurrent(client, version);
|
|
1460
1648
|
}
|
|
1461
|
-
if (this.audioPublishRequested &&
|
|
1462
|
-
await this.run(() => client.publish(
|
|
1649
|
+
if (this.audioPublishRequested && audio) {
|
|
1650
|
+
await this.run(() => client.publish(audio));
|
|
1463
1651
|
this.ensureRoomCurrent(client, version);
|
|
1464
1652
|
}
|
|
1465
1653
|
for (const user of client.remoteUsers) {
|
|
@@ -1480,7 +1668,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1480
1668
|
*/
|
|
1481
1669
|
async publishLocalVideo() {
|
|
1482
1670
|
const client = this.requireClient();
|
|
1483
|
-
const camera = this.
|
|
1671
|
+
const camera = this.requireLocalVideo();
|
|
1484
1672
|
this.videoPublishRequested = true;
|
|
1485
1673
|
await this.rejoinOperation;
|
|
1486
1674
|
if (client !== this.client || !this.videoPublishRequested) throw this.cancelled();
|
|
@@ -1493,10 +1681,13 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1493
1681
|
async unpublishLocalVideo() {
|
|
1494
1682
|
this.videoPublishRequested = false;
|
|
1495
1683
|
if (this.rejoinTask || this.tokenExpired) return;
|
|
1496
|
-
|
|
1684
|
+
const video = _nullishCoalesce(this.externalVideo, () => ( this.camera));
|
|
1685
|
+
if (this.client && video) {
|
|
1686
|
+
await this.run(() => this.client.unpublish(video));
|
|
1687
|
+
}
|
|
1497
1688
|
}
|
|
1498
1689
|
/**
|
|
1499
|
-
*
|
|
1690
|
+
* 外部源只发布提供的音轨;相机源首次发布时申请麦克风,迟到采集立即释放。
|
|
1500
1691
|
*/
|
|
1501
1692
|
async publishLocalAudio() {
|
|
1502
1693
|
const client = this.requireClient();
|
|
@@ -1504,6 +1695,13 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1504
1695
|
await this.rejoinOperation;
|
|
1505
1696
|
const version = this.roomVersion;
|
|
1506
1697
|
if (client !== this.client || !this.audioPublishRequested) throw this.cancelled();
|
|
1698
|
+
if (this.externalVideo) {
|
|
1699
|
+
const audio = this.externalAudio;
|
|
1700
|
+
if (audio && !client.localTracks.includes(audio)) {
|
|
1701
|
+
await this.run(() => client.publish(audio));
|
|
1702
|
+
}
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1507
1705
|
try {
|
|
1508
1706
|
if (!this.microphone) {
|
|
1509
1707
|
const track = await this.sdk.createMicrophoneAudioTrack();
|
|
@@ -1524,7 +1722,10 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1524
1722
|
async unpublishLocalAudio() {
|
|
1525
1723
|
this.audioPublishRequested = false;
|
|
1526
1724
|
if (this.rejoinTask || this.tokenExpired) return;
|
|
1527
|
-
|
|
1725
|
+
const audio = this.externalVideo ? this.externalAudio : this.microphone;
|
|
1726
|
+
if (this.client && audio) {
|
|
1727
|
+
await this.run(() => this.client.unpublish(audio));
|
|
1728
|
+
}
|
|
1528
1729
|
}
|
|
1529
1730
|
/**
|
|
1530
1731
|
* 订阅远端主视频并返回原生轨道,不创建额外播放视图。
|
|
@@ -1553,8 +1754,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1553
1754
|
const user = client.remoteUsers.find((user2) => String(user2.uid) === userID);
|
|
1554
1755
|
if (!subscribe) {
|
|
1555
1756
|
this.requestedAudio.delete(userID);
|
|
1556
|
-
_optionalChain([user, 'optionalAccess',
|
|
1557
|
-
if (_optionalChain([user, 'optionalAccess',
|
|
1757
|
+
_optionalChain([user, 'optionalAccess', _126 => _126.audioTrack, 'optionalAccess', _127 => _127.stop, 'call', _128 => _128()]);
|
|
1758
|
+
if (_optionalChain([user, 'optionalAccess', _129 => _129.audioTrack]) && !this.rejoinTask) await this.run(() => client.unsubscribe(user, "audio"));
|
|
1558
1759
|
return;
|
|
1559
1760
|
}
|
|
1560
1761
|
this.requestedAudio.add(userID);
|
|
@@ -1565,7 +1766,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1565
1766
|
if (this.requestedAudio.has(userID)) await this.subscribeRemoteAudio(userID, true);
|
|
1566
1767
|
return;
|
|
1567
1768
|
}
|
|
1568
|
-
if (!_optionalChain([user, 'optionalAccess',
|
|
1769
|
+
if (!_optionalChain([user, 'optionalAccess', _130 => _130.hasAudio])) return;
|
|
1569
1770
|
const version = this.roomVersion;
|
|
1570
1771
|
const track = await this.run(() => client.subscribe(user, "audio"));
|
|
1571
1772
|
if (client !== this.client || version !== this.roomVersion || !this.requestedAudio.has(userID)) {
|
|
@@ -1579,9 +1780,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1579
1780
|
*/
|
|
1580
1781
|
setRemoteAudioVolume(volume, userID) {
|
|
1581
1782
|
this.audioVolumes.set(userID, Math.max(0, Math.min(100, Number.isFinite(volume) ? Math.round(volume) : 0)));
|
|
1582
|
-
const user = _optionalChain([this, 'access',
|
|
1783
|
+
const user = _optionalChain([this, 'access', _131 => _131.client, 'optionalAccess', _132 => _132.remoteUsers, 'access', _133 => _133.find, 'call', _134 => _134((user2) => String(user2.uid) === userID)]);
|
|
1583
1784
|
if (this.rejoinTask || this.tokenExpired) {
|
|
1584
|
-
_optionalChain([user, 'optionalAccess',
|
|
1785
|
+
_optionalChain([user, 'optionalAccess', _135 => _135.audioTrack, 'optionalAccess', _136 => _136.stop, 'call', _137 => _137()]);
|
|
1585
1786
|
return;
|
|
1586
1787
|
}
|
|
1587
1788
|
if (user) this.applyAudioVolume(user);
|
|
@@ -1670,33 +1871,33 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1670
1871
|
const handleExpired = () => {
|
|
1671
1872
|
if (!active() || this.tokenExpired) return;
|
|
1672
1873
|
this.tokenExpired = true;
|
|
1673
|
-
_optionalChain([this, 'access',
|
|
1874
|
+
_optionalChain([this, 'access', _138 => _138.listener, 'optionalAccess', _139 => _139.onTokenExpired, 'optionalCall', _140 => _140()]);
|
|
1674
1875
|
};
|
|
1675
1876
|
client.on("user-published", (user, kind) => {
|
|
1676
1877
|
if (!mediaActive()) return;
|
|
1677
|
-
if (kind === "video") _optionalChain([this, 'access',
|
|
1878
|
+
if (kind === "video") _optionalChain([this, 'access', _141 => _141.listener, 'optionalAccess', _142 => _142.onRemoteVideoPublished, 'call', _143 => _143(String(user.uid), true)]);
|
|
1678
1879
|
if (kind === "audio" && this.requestedAudio.has(String(user.uid))) {
|
|
1679
1880
|
void this.subscribeRemoteAudio(String(user.uid), true).catch((error) => {
|
|
1680
|
-
if (active()) _optionalChain([this, 'access',
|
|
1881
|
+
if (active()) _optionalChain([this, 'access', _144 => _144.listener, 'optionalAccess', _145 => _145.onError, 'optionalCall', _146 => _146(this.mapError(error))]);
|
|
1681
1882
|
});
|
|
1682
1883
|
}
|
|
1683
1884
|
});
|
|
1684
1885
|
client.on("user-unpublished", (user, kind) => {
|
|
1685
1886
|
if (!mediaActive()) return;
|
|
1686
|
-
if (kind === "video") _optionalChain([this, 'access',
|
|
1687
|
-
if (kind === "audio") _optionalChain([user, 'access',
|
|
1887
|
+
if (kind === "video") _optionalChain([this, 'access', _147 => _147.listener, 'optionalAccess', _148 => _148.onRemoteVideoPublished, 'call', _149 => _149(String(user.uid), false)]);
|
|
1888
|
+
if (kind === "audio") _optionalChain([user, 'access', _150 => _150.audioTrack, 'optionalAccess', _151 => _151.stop, 'call', _152 => _152()]);
|
|
1688
1889
|
});
|
|
1689
1890
|
client.on("user-left", (user) => {
|
|
1690
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
1891
|
+
if (mediaActive()) _optionalChain([this, 'access', _153 => _153.listener, 'optionalAccess', _154 => _154.onRemoteVideoPublished, 'call', _155 => _155(String(user.uid), false)]);
|
|
1691
1892
|
});
|
|
1692
1893
|
client.on("stream-message", (uid, data) => {
|
|
1693
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
1894
|
+
if (mediaActive()) _optionalChain([this, 'access', _156 => _156.listener, 'optionalAccess', _157 => _157.onCustomMessageReceived, 'call', _158 => _158(String(uid), typeof data === "string" ? data : new TextDecoder().decode(data))]);
|
|
1694
1895
|
});
|
|
1695
1896
|
client.on("network-quality", (quality) => {
|
|
1696
1897
|
if (mediaActive()) AgoraRtcStatistics.network(quality, this.listener);
|
|
1697
1898
|
});
|
|
1698
1899
|
client.on("token-privilege-will-expire", () => {
|
|
1699
|
-
if (active() && !this.tokenExpired) _optionalChain([this, 'access',
|
|
1900
|
+
if (active() && !this.tokenExpired) _optionalChain([this, 'access', _159 => _159.listener, 'optionalAccess', _160 => _160.onTokenWillExpire, 'optionalCall', _161 => _161()]);
|
|
1700
1901
|
});
|
|
1701
1902
|
client.on("token-privilege-did-expire", handleExpired);
|
|
1702
1903
|
client.on("connection-state-change", (state2, previous, reason) => {
|
|
@@ -1705,7 +1906,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1705
1906
|
return;
|
|
1706
1907
|
}
|
|
1707
1908
|
if (active() && !this.tokenExpired && state2 === "DISCONNECTED" && previous !== "DISCONNECTED") {
|
|
1708
|
-
_optionalChain([this, 'access',
|
|
1909
|
+
_optionalChain([this, 'access', _162 => _162.listener, 'optionalAccess', _163 => _163.onError, 'optionalCall', _164 => _164(new XmaxError("RTC_ERROR" /* rtcError */, `Agora connection disconnected: ${_nullishCoalesce(reason, () => ( "unknown"))}`))]);
|
|
1709
1910
|
}
|
|
1710
1911
|
});
|
|
1711
1912
|
}
|
|
@@ -1714,20 +1915,20 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1714
1915
|
*/
|
|
1715
1916
|
clearRoom() {
|
|
1716
1917
|
this.roomVersion++;
|
|
1717
|
-
_optionalChain([this, 'access',
|
|
1918
|
+
_optionalChain([this, 'access', _165 => _165.cancelRejoin, 'optionalCall', _166 => _166()]);
|
|
1718
1919
|
this.connection = void 0;
|
|
1719
1920
|
this.tokenExpired = false;
|
|
1720
1921
|
this.videoPublishRequested = false;
|
|
1721
1922
|
this.audioPublishRequested = false;
|
|
1722
1923
|
clearInterval(this.statisticsTimer);
|
|
1723
1924
|
this.statisticsTimer = void 0;
|
|
1724
|
-
_optionalChain([this, 'access',
|
|
1725
|
-
_optionalChain([this, 'access',
|
|
1925
|
+
_optionalChain([this, 'access', _167 => _167.cancelSendDelay, 'optionalCall', _168 => _168()]);
|
|
1926
|
+
_optionalChain([this, 'access', _169 => _169.cancelActiveSend, 'optionalCall', _170 => _170()]);
|
|
1726
1927
|
this.sentPackets = [];
|
|
1727
1928
|
this.sendTail = Promise.resolve();
|
|
1728
1929
|
this.requestedAudio.clear();
|
|
1729
1930
|
this.audioVolumes.clear();
|
|
1730
|
-
for (const user of _nullishCoalesce(_optionalChain([this, 'access',
|
|
1931
|
+
for (const user of _nullishCoalesce(_optionalChain([this, 'access', _171 => _171.client, 'optionalAccess', _172 => _172.remoteUsers]), () => ( []))) _optionalChain([user, 'access', _173 => _173.audioTrack, 'optionalAccess', _174 => _174.stop, 'call', _175 => _175()]);
|
|
1731
1932
|
}
|
|
1732
1933
|
/**
|
|
1733
1934
|
* 判断异步恢复工作是否仍属于当前房间生命周期。
|
|
@@ -1755,6 +1956,16 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1755
1956
|
if (!this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
1756
1957
|
return this.camera;
|
|
1757
1958
|
}
|
|
1959
|
+
/**
|
|
1960
|
+
* 获取当前可编码、发布的视频轨,不要求来源为摄像头。
|
|
1961
|
+
*/
|
|
1962
|
+
requireLocalVideo() {
|
|
1963
|
+
const video = _nullishCoalesce(this.externalVideo, () => ( this.camera));
|
|
1964
|
+
if (!video) {
|
|
1965
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video source is not prepared");
|
|
1966
|
+
}
|
|
1967
|
+
return video;
|
|
1968
|
+
}
|
|
1758
1969
|
/**
|
|
1759
1970
|
* 执行声网操作并统一错误类型。
|
|
1760
1971
|
*/
|
|
@@ -1787,14 +1998,6 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1787
1998
|
__publicField(_AgoraRtcManager, "regions", /* @__PURE__ */ new Map());
|
|
1788
1999
|
var AgoraRtcManager = _AgoraRtcManager;
|
|
1789
2000
|
|
|
1790
|
-
// src/Foundation/RTC/RtcProvider.ts
|
|
1791
|
-
var RtcProvider = /* @__PURE__ */ ((RtcProvider2) => {
|
|
1792
|
-
RtcProvider2["trtc"] = "trtc";
|
|
1793
|
-
RtcProvider2["agora"] = "agora";
|
|
1794
|
-
RtcProvider2["vertc"] = "vertc";
|
|
1795
|
-
return RtcProvider2;
|
|
1796
|
-
})(RtcProvider || {});
|
|
1797
|
-
|
|
1798
2001
|
// src/Foundation/RTC/TRTC/RtcEngineManager.ts
|
|
1799
2002
|
var RtcEngineLease = class {
|
|
1800
2003
|
/**
|
|
@@ -1863,13 +2066,13 @@ var _RtcEngineManager = class _RtcEngineManager {
|
|
|
1863
2066
|
* 释放有效租约、销毁 Engine,并把独占权交给下一个等待者。
|
|
1864
2067
|
*/
|
|
1865
2068
|
release(lease) {
|
|
1866
|
-
if (_optionalChain([this, 'access',
|
|
2069
|
+
if (_optionalChain([this, 'access', _176 => _176.activeLease, 'optionalAccess', _177 => _177.id]) !== lease.id) {
|
|
1867
2070
|
return;
|
|
1868
2071
|
}
|
|
1869
2072
|
this.activeLease = void 0;
|
|
1870
2073
|
try {
|
|
1871
2074
|
lease.engine.destroy();
|
|
1872
|
-
} catch (
|
|
2075
|
+
} catch (e11) {
|
|
1873
2076
|
}
|
|
1874
2077
|
void this.fulfillNextRequest();
|
|
1875
2078
|
}
|
|
@@ -1937,10 +2140,10 @@ var RtcStatsLogger = class {
|
|
|
1937
2140
|
`${XmaxLogger.localized("\u7D2F\u8BA1\u63A5\u6536\uFF1A", "Bytes Received: ")}${this.value(stats.bytesReceived, "bytes")}`
|
|
1938
2141
|
])];
|
|
1939
2142
|
const local = stats.localStatistics;
|
|
1940
|
-
if (_optionalChain([local, 'optionalAccess',
|
|
2143
|
+
if (_optionalChain([local, 'optionalAccess', _178 => _178.audio])) {
|
|
1941
2144
|
blocks.push(this.audioBlock("\u672C\u5730\u97F3\u9891\u53D1\u9001 (Local Audio Uplink)", local.audio, false));
|
|
1942
2145
|
}
|
|
1943
|
-
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess',
|
|
2146
|
+
for (const video of _nullishCoalesce(_optionalChain([local, 'optionalAccess', _179 => _179.video]), () => ( []))) {
|
|
1944
2147
|
blocks.push(this.videoBlock("\u672C\u5730\u89C6\u9891\u53D1\u9001 (Local Video Uplink)", video, false));
|
|
1945
2148
|
}
|
|
1946
2149
|
for (const remote of _nullishCoalesce(stats.remoteStatistics, () => ( []))) {
|
|
@@ -2030,8 +2233,8 @@ var RtcStatsLogger = class {
|
|
|
2030
2233
|
|
|
2031
2234
|
// src/Foundation/RTC/TRTC/TrtcAudioVolumeSupport.ts
|
|
2032
2235
|
function canControlTrtcRemoteAudioVolume(environment) {
|
|
2033
|
-
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
2034
|
-
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess',
|
|
2236
|
+
const userAgent = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _180 => _180.userAgent]), () => ( (typeof navigator === "undefined" ? "" : navigator.userAgent)));
|
|
2237
|
+
const maxTouchPoints = _nullishCoalesce(_optionalChain([environment, 'optionalAccess', _181 => _181.maxTouchPoints]), () => ( (typeof navigator === "undefined" ? 0 : _nullishCoalesce(navigator.maxTouchPoints, () => ( 0)))));
|
|
2035
2238
|
const ios = /iPhone|iPad|iPod/i.test(userAgent) || /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
|
|
2036
2239
|
return !ios;
|
|
2037
2240
|
}
|
|
@@ -2072,6 +2275,11 @@ var TrtcRtcManager = class {
|
|
|
2072
2275
|
*/
|
|
2073
2276
|
__publicField(this, "isCapturing", false);
|
|
2074
2277
|
__publicField(this, "isAudioCapturing", false);
|
|
2278
|
+
/**
|
|
2279
|
+
* 外部媒体的克隆轨;原始轨道由媒体源管理。
|
|
2280
|
+
*/
|
|
2281
|
+
__publicField(this, "externalVideo");
|
|
2282
|
+
__publicField(this, "externalAudio");
|
|
2075
2283
|
/**
|
|
2076
2284
|
* 房间状态
|
|
2077
2285
|
*/
|
|
@@ -2106,25 +2314,78 @@ var TrtcRtcManager = class {
|
|
|
2106
2314
|
async destroy() {
|
|
2107
2315
|
const lease = this.lease;
|
|
2108
2316
|
this.lease = void 0;
|
|
2109
|
-
|
|
2317
|
+
const externalVideo = this.externalVideo;
|
|
2318
|
+
const externalAudio = this.externalAudio;
|
|
2319
|
+
this.externalVideo = void 0;
|
|
2320
|
+
this.externalAudio = void 0;
|
|
2110
2321
|
this.isCapturing = false;
|
|
2111
2322
|
this.isAudioCapturing = false;
|
|
2112
2323
|
this.isInRoom = false;
|
|
2113
|
-
_optionalChain([this, 'access',
|
|
2324
|
+
_optionalChain([this, 'access', _182 => _182.removeStatsListeners, 'optionalCall', _183 => _183()]);
|
|
2114
2325
|
this.removeStatsListeners = void 0;
|
|
2115
2326
|
if (!lease) {
|
|
2327
|
+
_optionalChain([externalVideo, 'optionalAccess', _184 => _184.stop, 'call', _185 => _185()]);
|
|
2328
|
+
_optionalChain([externalAudio, 'optionalAccess', _186 => _186.stop, 'call', _187 => _187()]);
|
|
2116
2329
|
return;
|
|
2117
2330
|
}
|
|
2118
2331
|
try {
|
|
2119
2332
|
await lease.engine.stopLocalAudio();
|
|
2120
|
-
} catch (
|
|
2333
|
+
} catch (e12) {
|
|
2121
2334
|
}
|
|
2122
2335
|
try {
|
|
2123
2336
|
await lease.engine.stopLocalVideo();
|
|
2124
|
-
} catch (
|
|
2337
|
+
} catch (e13) {
|
|
2125
2338
|
}
|
|
2339
|
+
_optionalChain([externalVideo, 'optionalAccess', _188 => _188.stop, 'call', _189 => _189()]);
|
|
2340
|
+
_optionalChain([externalAudio, 'optionalAccess', _190 => _190.stop, 'call', _191 => _191()]);
|
|
2126
2341
|
this.engineManager.release(lease);
|
|
2127
2342
|
}
|
|
2343
|
+
/**
|
|
2344
|
+
* 准备外部音视频轨但不发布;失败时释放克隆轨,不影响原始媒体源。
|
|
2345
|
+
*/
|
|
2346
|
+
async setExternalMediaTracks(tracks) {
|
|
2347
|
+
const engine = this.requireEngine();
|
|
2348
|
+
if (this.isCapturing || this.isAudioCapturing || this.externalVideo) {
|
|
2349
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
|
|
2350
|
+
}
|
|
2351
|
+
if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
|
|
2352
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External media tracks must be live video/audio tracks");
|
|
2353
|
+
}
|
|
2354
|
+
const video = tracks.videoTrack.clone();
|
|
2355
|
+
this.externalVideo = video;
|
|
2356
|
+
let audio;
|
|
2357
|
+
try {
|
|
2358
|
+
audio = _optionalChain([tracks, 'access', _192 => _192.audioTrack, 'optionalAccess', _193 => _193.clone, 'call', _194 => _194()]);
|
|
2359
|
+
this.externalAudio = audio;
|
|
2360
|
+
await engine.startLocalVideo({ publish: false, option: { videoTrack: video } });
|
|
2361
|
+
if (_optionalChain([this, 'access', _195 => _195.lease, 'optionalAccess', _196 => _196.engine]) !== engine) {
|
|
2362
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
|
|
2363
|
+
}
|
|
2364
|
+
if (audio) {
|
|
2365
|
+
await engine.startLocalAudio({
|
|
2366
|
+
publish: false,
|
|
2367
|
+
option: { audioTrack: audio, echoCancellation: false, autoGainControl: false, noiseSuppression: false }
|
|
2368
|
+
});
|
|
2369
|
+
if (_optionalChain([this, 'access', _197 => _197.lease, 'optionalAccess', _198 => _198.engine]) !== engine) {
|
|
2370
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "External media preparation was cancelled");
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
} catch (error) {
|
|
2374
|
+
if (_optionalChain([this, 'access', _199 => _199.lease, 'optionalAccess', _200 => _200.engine]) === engine) {
|
|
2375
|
+
await engine.stopLocalAudio().catch(() => {
|
|
2376
|
+
});
|
|
2377
|
+
await engine.stopLocalVideo().catch(() => {
|
|
2378
|
+
});
|
|
2379
|
+
}
|
|
2380
|
+
if (this.externalVideo === video) {
|
|
2381
|
+
this.externalVideo = void 0;
|
|
2382
|
+
this.externalAudio = void 0;
|
|
2383
|
+
}
|
|
2384
|
+
video.stop();
|
|
2385
|
+
_optionalChain([audio, 'optionalAccess', _201 => _201.stop, 'call', _202 => _202()]);
|
|
2386
|
+
throw this.mapError(error);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2128
2389
|
/**
|
|
2129
2390
|
* 启动摄像头采集(不发布)。
|
|
2130
2391
|
*
|
|
@@ -2133,7 +2394,7 @@ var TrtcRtcManager = class {
|
|
|
2133
2394
|
*/
|
|
2134
2395
|
async startCameraCapture(options) {
|
|
2135
2396
|
const engine = this.requireEngine();
|
|
2136
|
-
if (this.isCapturing) {
|
|
2397
|
+
if (this.isCapturing || this.externalVideo) {
|
|
2137
2398
|
throw new XmaxError(
|
|
2138
2399
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
2139
2400
|
"Camera capture is already running"
|
|
@@ -2203,7 +2464,10 @@ var TrtcRtcManager = class {
|
|
|
2203
2464
|
* 停止摄像头采集;引擎未初始化或采集未启动时不产生效果。
|
|
2204
2465
|
*/
|
|
2205
2466
|
async stopCameraCapture() {
|
|
2206
|
-
|
|
2467
|
+
if (this.externalVideo) {
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
const engine = _optionalChain([this, 'access', _203 => _203.lease, 'optionalAccess', _204 => _204.engine]);
|
|
2207
2471
|
this.isCapturing = false;
|
|
2208
2472
|
if (!engine) {
|
|
2209
2473
|
return;
|
|
@@ -2220,7 +2484,7 @@ var TrtcRtcManager = class {
|
|
|
2220
2484
|
* @throws 引擎未初始化、进房参数无效或进房失败时抛出错误。
|
|
2221
2485
|
*/
|
|
2222
2486
|
async joinRoom(configuration) {
|
|
2223
|
-
if (configuration.provider !== "trtc") {
|
|
2487
|
+
if (configuration.provider !== "trtc" /* trtc */) {
|
|
2224
2488
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "TRTC credentials required");
|
|
2225
2489
|
}
|
|
2226
2490
|
const engine = this.requireEngine();
|
|
@@ -2256,7 +2520,7 @@ var TrtcRtcManager = class {
|
|
|
2256
2520
|
* 离开当前 RTC 房间;未在房间中或引擎未初始化时不产生效果,退房失败仅记录日志。
|
|
2257
2521
|
*/
|
|
2258
2522
|
async leaveRoom() {
|
|
2259
|
-
const engine = _optionalChain([this, 'access',
|
|
2523
|
+
const engine = _optionalChain([this, 'access', _205 => _205.lease, 'optionalAccess', _206 => _206.engine]);
|
|
2260
2524
|
if (!engine || !this.isInRoom) {
|
|
2261
2525
|
return;
|
|
2262
2526
|
}
|
|
@@ -2276,18 +2540,18 @@ var TrtcRtcManager = class {
|
|
|
2276
2540
|
* TRTC 只接受单一目标码率,以 `minimumBitrate`(流畅优先档)作为目标码率;
|
|
2277
2541
|
* 编码策略偏好映射为 TRTC 弱网偏好。
|
|
2278
2542
|
*
|
|
2279
|
-
* @throws
|
|
2543
|
+
* @throws 本地视频未准备或编码参数配置失败时抛出错误。
|
|
2280
2544
|
*/
|
|
2281
2545
|
async configureVideoEncoding(configuration) {
|
|
2282
2546
|
const engine = this.requireEngine();
|
|
2283
|
-
if (!this.isCapturing) {
|
|
2547
|
+
if (!this.isCapturing && !this.externalVideo) {
|
|
2284
2548
|
throw new XmaxError(
|
|
2285
2549
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
2286
|
-
"
|
|
2550
|
+
"Local video is not prepared"
|
|
2287
2551
|
);
|
|
2288
2552
|
}
|
|
2289
2553
|
try {
|
|
2290
|
-
const encodingSize = rtcOrientedVideoSize({
|
|
2554
|
+
const encodingSize = this.externalVideo ? configuration : rtcOrientedVideoSize({
|
|
2291
2555
|
width: configuration.width,
|
|
2292
2556
|
height: configuration.height
|
|
2293
2557
|
});
|
|
@@ -2309,14 +2573,14 @@ var TrtcRtcManager = class {
|
|
|
2309
2573
|
/**
|
|
2310
2574
|
* 发布本地视频流。
|
|
2311
2575
|
*
|
|
2312
|
-
* @throws
|
|
2576
|
+
* @throws 本地视频未准备或发布失败时抛出错误。
|
|
2313
2577
|
*/
|
|
2314
2578
|
async publishLocalVideo() {
|
|
2315
2579
|
const engine = this.requireEngine();
|
|
2316
|
-
if (!this.isCapturing) {
|
|
2580
|
+
if (!this.isCapturing && !this.externalVideo) {
|
|
2317
2581
|
throw new XmaxError(
|
|
2318
2582
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
2319
|
-
"
|
|
2583
|
+
"Local video is not prepared"
|
|
2320
2584
|
);
|
|
2321
2585
|
}
|
|
2322
2586
|
try {
|
|
@@ -2329,8 +2593,8 @@ var TrtcRtcManager = class {
|
|
|
2329
2593
|
* 停止发布本地视频流;采集保持运行,本地预览不受影响。
|
|
2330
2594
|
*/
|
|
2331
2595
|
async unpublishLocalVideo() {
|
|
2332
|
-
const engine = _optionalChain([this, 'access',
|
|
2333
|
-
if (!engine || !this.isCapturing) {
|
|
2596
|
+
const engine = _optionalChain([this, 'access', _207 => _207.lease, 'optionalAccess', _208 => _208.engine]);
|
|
2597
|
+
if (!engine || !this.isCapturing && !this.externalVideo) {
|
|
2334
2598
|
return;
|
|
2335
2599
|
}
|
|
2336
2600
|
try {
|
|
@@ -2340,14 +2604,18 @@ var TrtcRtcManager = class {
|
|
|
2340
2604
|
}
|
|
2341
2605
|
}
|
|
2342
2606
|
/**
|
|
2343
|
-
*
|
|
2607
|
+
* 发布文件音频或麦克风;无文件音轨时不启动麦克风。
|
|
2344
2608
|
*
|
|
2345
2609
|
* @throws 引擎未初始化、麦克风权限被拒绝或发布失败时抛出错误。
|
|
2346
2610
|
*/
|
|
2347
2611
|
async publishLocalAudio() {
|
|
2348
2612
|
const engine = this.requireEngine();
|
|
2349
2613
|
try {
|
|
2350
|
-
if (
|
|
2614
|
+
if (this.externalVideo) {
|
|
2615
|
+
if (this.externalAudio) {
|
|
2616
|
+
await engine.updateLocalAudio({ publish: true });
|
|
2617
|
+
}
|
|
2618
|
+
} else if (!this.isAudioCapturing) {
|
|
2351
2619
|
await engine.startLocalAudio();
|
|
2352
2620
|
this.isAudioCapturing = true;
|
|
2353
2621
|
} else {
|
|
@@ -2361,8 +2629,8 @@ var TrtcRtcManager = class {
|
|
|
2361
2629
|
* 停止发布本地音频流;麦克风采集保持运行。
|
|
2362
2630
|
*/
|
|
2363
2631
|
async unpublishLocalAudio() {
|
|
2364
|
-
const engine = _optionalChain([this, 'access',
|
|
2365
|
-
if (!engine || !this.isAudioCapturing) {
|
|
2632
|
+
const engine = _optionalChain([this, 'access', _209 => _209.lease, 'optionalAccess', _210 => _210.engine]);
|
|
2633
|
+
if (!engine || !this.isAudioCapturing && !this.externalAudio) {
|
|
2366
2634
|
return;
|
|
2367
2635
|
}
|
|
2368
2636
|
try {
|
|
@@ -2487,19 +2755,19 @@ var TrtcRtcManager = class {
|
|
|
2487
2755
|
registerEventBridge(engine) {
|
|
2488
2756
|
const source = engine;
|
|
2489
2757
|
const onStatistics = (stats) => {
|
|
2490
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
2758
|
+
if (this.isInRoom && _optionalChain([this, 'access', _211 => _211.lease, 'optionalAccess', _212 => _212.engine]) === engine) {
|
|
2491
2759
|
RtcStatsLogger.logStatistics(stats);
|
|
2492
|
-
const video = _optionalChain([stats, 'access',
|
|
2760
|
+
const video = _optionalChain([stats, 'access', _213 => _213.localStatistics, 'optionalAccess', _214 => _214.video, 'optionalAccess', _215 => _215.find, 'call', _216 => _216((item) => item.videoType === "big")]);
|
|
2493
2761
|
const valid = (value, minimum) => typeof value === "number" && Number.isFinite(value) && value >= minimum ? value : void 0;
|
|
2494
|
-
_optionalChain([this, 'access',
|
|
2762
|
+
_optionalChain([this, 'access', _217 => _217.eventListener, 'optionalAccess', _218 => _218.onLocalVideoStatistics, 'optionalCall', _219 => _219(video ? Object.freeze({
|
|
2495
2763
|
width: valid(video.width, 1),
|
|
2496
2764
|
height: valid(video.height, 1),
|
|
2497
2765
|
frameRate: valid(video.frameRate, 0),
|
|
2498
2766
|
bitrateKbps: valid(video.bitrate, 0)
|
|
2499
2767
|
}) : void 0)]);
|
|
2500
|
-
_optionalChain([this, 'access',
|
|
2768
|
+
_optionalChain([this, 'access', _220 => _220.eventListener, 'optionalAccess', _221 => _221.onRemoteVideoStatistics, 'optionalCall', _222 => _222(Object.freeze(
|
|
2501
2769
|
(_nullishCoalesce(stats.remoteStatistics, () => ( []))).flatMap((remote) => {
|
|
2502
|
-
const video2 = _optionalChain([remote, 'access',
|
|
2770
|
+
const video2 = _optionalChain([remote, 'access', _223 => _223.video, 'optionalAccess', _224 => _224.find, 'call', _225 => _225((item) => item.videoType === "big")]);
|
|
2503
2771
|
if (!video2) {
|
|
2504
2772
|
return [];
|
|
2505
2773
|
}
|
|
@@ -2521,11 +2789,11 @@ var TrtcRtcManager = class {
|
|
|
2521
2789
|
}
|
|
2522
2790
|
};
|
|
2523
2791
|
const onNetworkQuality = (stats) => {
|
|
2524
|
-
if (this.isInRoom && _optionalChain([this, 'access',
|
|
2792
|
+
if (this.isInRoom && _optionalChain([this, 'access', _226 => _226.lease, 'optionalAccess', _227 => _227.engine]) === engine) {
|
|
2525
2793
|
RtcStatsLogger.logNetworkQuality(stats);
|
|
2526
2794
|
const quality = (value) => Number.isInteger(value) && value >= 0 && value <= 6 ? value : void 0;
|
|
2527
2795
|
const rtt = (value) => Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
2528
|
-
_optionalChain([this, 'access',
|
|
2796
|
+
_optionalChain([this, 'access', _228 => _228.eventListener, 'optionalAccess', _229 => _229.onNetworkStatistics, 'optionalCall', _230 => _230(Object.freeze({
|
|
2529
2797
|
uplinkQuality: quality(stats.uplinkNetworkQuality),
|
|
2530
2798
|
downlinkQuality: quality(stats.downlinkNetworkQuality),
|
|
2531
2799
|
uplinkRttMs: rtt(stats.uplinkRTT),
|
|
@@ -2540,36 +2808,36 @@ var TrtcRtcManager = class {
|
|
|
2540
2808
|
source.off(RTC_EVENT.networkQuality, onNetworkQuality);
|
|
2541
2809
|
};
|
|
2542
2810
|
source.on(RTC_EVENT.remoteVideoAvailable, (event) => {
|
|
2543
|
-
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
2811
|
+
if (_optionalChain([this, 'access', _231 => _231.lease, 'optionalAccess', _232 => _232.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
|
|
2544
2812
|
return;
|
|
2545
2813
|
}
|
|
2546
|
-
_optionalChain([this, 'access',
|
|
2814
|
+
_optionalChain([this, 'access', _233 => _233.eventListener, 'optionalAccess', _234 => _234.onRemoteVideoPublished, 'call', _235 => _235(event.userId, true)]);
|
|
2547
2815
|
});
|
|
2548
2816
|
source.on(RTC_EVENT.remoteVideoUnavailable, (event) => {
|
|
2549
|
-
if (event.streamType !== STREAM_TYPE_MAIN) {
|
|
2817
|
+
if (_optionalChain([this, 'access', _236 => _236.lease, 'optionalAccess', _237 => _237.engine]) !== engine || event.streamType !== STREAM_TYPE_MAIN) {
|
|
2550
2818
|
return;
|
|
2551
2819
|
}
|
|
2552
|
-
_optionalChain([this, 'access',
|
|
2820
|
+
_optionalChain([this, 'access', _238 => _238.eventListener, 'optionalAccess', _239 => _239.onRemoteVideoPublished, 'call', _240 => _240(event.userId, false)]);
|
|
2553
2821
|
});
|
|
2554
2822
|
source.on(RTC_EVENT.customMessage, (event) => {
|
|
2555
|
-
if (event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
|
|
2823
|
+
if (_optionalChain([this, 'access', _241 => _241.lease, 'optionalAccess', _242 => _242.engine]) !== engine || event.cmdId !== CUSTOM_MESSAGE_CMD_ID) {
|
|
2556
2824
|
return;
|
|
2557
2825
|
}
|
|
2558
2826
|
let message;
|
|
2559
2827
|
try {
|
|
2560
2828
|
message = new TextDecoder().decode(event.data);
|
|
2561
|
-
} catch (
|
|
2829
|
+
} catch (e14) {
|
|
2562
2830
|
XmaxLogger.rtc.warning(() => "\u81EA\u5B9A\u4E49\u6D88\u606F\u89E3\u7801\u5931\u8D25 (Failed to Decode Custom Message)");
|
|
2563
2831
|
return;
|
|
2564
2832
|
}
|
|
2565
|
-
_optionalChain([this, 'access',
|
|
2833
|
+
_optionalChain([this, 'access', _243 => _243.eventListener, 'optionalAccess', _244 => _244.onCustomMessageReceived, 'call', _245 => _245(event.userId, message)]);
|
|
2566
2834
|
});
|
|
2567
2835
|
}
|
|
2568
2836
|
/**
|
|
2569
2837
|
* 返回当前引擎实例;未初始化时抛出错误。
|
|
2570
2838
|
*/
|
|
2571
2839
|
requireEngine() {
|
|
2572
|
-
const engine = _optionalChain([this, 'access',
|
|
2840
|
+
const engine = _optionalChain([this, 'access', _246 => _246.lease, 'optionalAccess', _247 => _247.engine]);
|
|
2573
2841
|
if (!engine) {
|
|
2574
2842
|
throw new XmaxError(
|
|
2575
2843
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -2586,8 +2854,8 @@ var TrtcRtcManager = class {
|
|
|
2586
2854
|
return error;
|
|
2587
2855
|
}
|
|
2588
2856
|
const rtcError = error;
|
|
2589
|
-
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess',
|
|
2590
|
-
const message = typeof _optionalChain([rtcError, 'optionalAccess',
|
|
2857
|
+
const originName = _nullishCoalesce(_optionalChain([rtcError, 'optionalAccess', _248 => _248.originError, 'optionalAccess', _249 => _249.name]), () => ( ""));
|
|
2858
|
+
const message = typeof _optionalChain([rtcError, 'optionalAccess', _250 => _250.message]) === "string" && rtcError.message.trim().length > 0 ? rtcError.message.trim() : String(error);
|
|
2591
2859
|
if (originName === "NotAllowedError" || originName === "SecurityError" || /NotAllowed/i.test(message)) {
|
|
2592
2860
|
return new XmaxError("CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */, message);
|
|
2593
2861
|
}
|
|
@@ -2645,6 +2913,11 @@ var VeRtcManager = class {
|
|
|
2645
2913
|
__publicField(this, "captureVersion", 0);
|
|
2646
2914
|
__publicField(this, "camera");
|
|
2647
2915
|
__publicField(this, "microphone", false);
|
|
2916
|
+
/**
|
|
2917
|
+
* 外部媒体的克隆轨;原始轨道由媒体源管理。
|
|
2918
|
+
*/
|
|
2919
|
+
__publicField(this, "externalVideo");
|
|
2920
|
+
__publicField(this, "externalAudio");
|
|
2648
2921
|
__publicField(this, "connection");
|
|
2649
2922
|
__publicField(this, "joined", false);
|
|
2650
2923
|
__publicField(this, "roomVersion", 0);
|
|
@@ -2700,18 +2973,76 @@ var VeRtcManager = class {
|
|
|
2700
2973
|
this.captureVersion++;
|
|
2701
2974
|
const engine = this.engine;
|
|
2702
2975
|
const sdk = this.sdk;
|
|
2703
|
-
this.listener = void 0;
|
|
2704
2976
|
this.clearRoom();
|
|
2705
2977
|
this.engine = void 0;
|
|
2706
2978
|
this.sdk = void 0;
|
|
2707
2979
|
this.camera = void 0;
|
|
2708
2980
|
this.microphone = false;
|
|
2709
|
-
_optionalChain([engine, 'optionalAccess',
|
|
2710
|
-
|
|
2981
|
+
_optionalChain([engine, 'optionalAccess', _251 => _251.removeAllListeners, 'call', _252 => _252()]);
|
|
2982
|
+
try {
|
|
2983
|
+
if (engine && sdk) sdk.default.destroyEngine(engine);
|
|
2984
|
+
} finally {
|
|
2985
|
+
_optionalChain([this, 'access', _253 => _253.externalVideo, 'optionalAccess', _254 => _254.stop, 'call', _255 => _255()]);
|
|
2986
|
+
_optionalChain([this, 'access', _256 => _256.externalAudio, 'optionalAccess', _257 => _257.stop, 'call', _258 => _258()]);
|
|
2987
|
+
this.externalVideo = void 0;
|
|
2988
|
+
this.externalAudio = void 0;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* 将克隆的文件音视频轨绑定到主流,不采集设备、不自动发布。
|
|
2993
|
+
*/
|
|
2994
|
+
async setExternalMediaTracks(tracks) {
|
|
2995
|
+
const engine = this.requireEngine();
|
|
2996
|
+
const sdk = this.sdk;
|
|
2997
|
+
if (this.camera || this.microphone || this.externalVideo) {
|
|
2998
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
|
|
2999
|
+
}
|
|
3000
|
+
if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
|
|
3001
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "External media tracks must be live video/audio tracks");
|
|
3002
|
+
}
|
|
3003
|
+
const video = tracks.videoTrack.clone();
|
|
3004
|
+
this.externalVideo = video;
|
|
3005
|
+
let audio;
|
|
3006
|
+
const index = sdk.StreamIndex.STREAM_INDEX_MAIN;
|
|
3007
|
+
const ensureCurrent = () => {
|
|
3008
|
+
if (this.engine !== engine || this.externalVideo !== video) {
|
|
3009
|
+
throw this.cancelled();
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
try {
|
|
3013
|
+
audio = _optionalChain([tracks, 'access', _259 => _259.audioTrack, 'optionalAccess', _260 => _260.clone, 'call', _261 => _261()]);
|
|
3014
|
+
this.externalAudio = audio;
|
|
3015
|
+
await engine.setVideoSourceType(index, sdk.VideoSourceType.VIDEO_SOURCE_TYPE_EXTERNAL);
|
|
3016
|
+
ensureCurrent();
|
|
3017
|
+
await engine.setExternalVideoTrack(index, video);
|
|
3018
|
+
ensureCurrent();
|
|
3019
|
+
if (audio) {
|
|
3020
|
+
await engine.setAudioSourceType(index, sdk.AudioSourceType.AUDIO_SOURCE_TYPE_EXTERNAL);
|
|
3021
|
+
ensureCurrent();
|
|
3022
|
+
await engine.setExternalAudioTrack(index, audio);
|
|
3023
|
+
ensureCurrent();
|
|
3024
|
+
}
|
|
3025
|
+
} catch (error) {
|
|
3026
|
+
if (this.engine === engine) {
|
|
3027
|
+
await engine.setAudioSourceType(index, sdk.AudioSourceType.AUDIO_SOURCE_TYPE_INTERNAL).catch(() => {
|
|
3028
|
+
});
|
|
3029
|
+
await engine.setVideoSourceType(index, sdk.VideoSourceType.VIDEO_SOURCE_TYPE_INTERNAL).catch(() => {
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
if (this.externalVideo === video) {
|
|
3033
|
+
this.externalVideo = void 0;
|
|
3034
|
+
this.externalAudio = void 0;
|
|
3035
|
+
}
|
|
3036
|
+
video.stop();
|
|
3037
|
+
_optionalChain([audio, 'optionalAccess', _262 => _262.stop, 'call', _263 => _263()]);
|
|
3038
|
+
throw this.mapError(error);
|
|
3039
|
+
}
|
|
2711
3040
|
}
|
|
2712
3041
|
async startCameraCapture(options) {
|
|
2713
3042
|
const engine = this.requireEngine();
|
|
2714
|
-
if (this.camera
|
|
3043
|
+
if (this.camera || this.externalVideo) {
|
|
3044
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is already prepared");
|
|
3045
|
+
}
|
|
2715
3046
|
const version = ++this.captureVersion;
|
|
2716
3047
|
await this.run(() => engine.setVideoEncoderConfig({
|
|
2717
3048
|
...rtcOrientedVideoSize({ width: options.width, height: options.height }),
|
|
@@ -2751,15 +3082,20 @@ var VeRtcManager = class {
|
|
|
2751
3082
|
return track;
|
|
2752
3083
|
}
|
|
2753
3084
|
async stopCameraCapture() {
|
|
3085
|
+
if (this.externalVideo) {
|
|
3086
|
+
return;
|
|
3087
|
+
}
|
|
2754
3088
|
this.captureVersion++;
|
|
2755
3089
|
this.camera = void 0;
|
|
2756
3090
|
if (this.engine) await this.run(() => this.engine.stopVideoCapture());
|
|
2757
3091
|
}
|
|
2758
3092
|
async configureVideoEncoding(config) {
|
|
2759
3093
|
const engine = this.requireEngine();
|
|
2760
|
-
this.
|
|
3094
|
+
this.requireLocalVideo();
|
|
3095
|
+
const size = this.externalVideo ? config : rtcOrientedVideoSize(config);
|
|
2761
3096
|
await this.run(() => engine.setVideoEncoderConfig({
|
|
2762
|
-
|
|
3097
|
+
width: size.width,
|
|
3098
|
+
height: size.height,
|
|
2763
3099
|
frameRate: config.frameRate,
|
|
2764
3100
|
maxKbps: config.maximumBitrate,
|
|
2765
3101
|
contentHint: config.encoderPreference === "maintainFramerate" /* maintainFramerate */ ? "motion" : "detail",
|
|
@@ -2767,12 +3103,12 @@ var VeRtcManager = class {
|
|
|
2767
3103
|
}));
|
|
2768
3104
|
}
|
|
2769
3105
|
async joinRoom(config) {
|
|
2770
|
-
await _optionalChain([this, 'access',
|
|
3106
|
+
await _optionalChain([this, 'access', _264 => _264.joining, 'optionalAccess', _265 => _265.catch, 'call', _266 => _266(() => {
|
|
2771
3107
|
})]);
|
|
2772
|
-
await _optionalChain([this, 'access',
|
|
3108
|
+
await _optionalChain([this, 'access', _267 => _267.recovery, 'optionalAccess', _268 => _268.catch, 'call', _269 => _269(() => {
|
|
2773
3109
|
})]);
|
|
2774
3110
|
const engine = this.requireEngine();
|
|
2775
|
-
if (config.provider !== "vertc" || config.appID !== VERTC_APP_ID || this.connection) {
|
|
3111
|
+
if (config.provider !== "vertc" /* vertc */ || config.appID !== VERTC_APP_ID || this.connection) {
|
|
2776
3112
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "VeRTC credentials for the configured AppID and an idle room are required");
|
|
2777
3113
|
}
|
|
2778
3114
|
this.clearRoom();
|
|
@@ -2818,8 +3154,8 @@ var VeRtcManager = class {
|
|
|
2818
3154
|
async updateCredentials(config, signal) {
|
|
2819
3155
|
const engine = this.requireEngine();
|
|
2820
3156
|
const current = this.connection;
|
|
2821
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
2822
|
-
if (!current || config.provider !== "vertc" || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
3157
|
+
if (_optionalChain([signal, 'optionalAccess', _270 => _270.aborted])) throw this.cancelled();
|
|
3158
|
+
if (!current || config.provider !== "vertc" /* vertc */ || config.appID !== current.appID || config.roomID !== current.roomID || config.userID !== current.userID) {
|
|
2823
3159
|
throw new XmaxError("SESSION_ERROR" /* sessionError */, "VeRTC session binding changed");
|
|
2824
3160
|
}
|
|
2825
3161
|
const version = this.roomVersion;
|
|
@@ -2846,7 +3182,7 @@ var VeRtcManager = class {
|
|
|
2846
3182
|
const restore = this.tokenExpired || this.publishPrivilegeExpired || this.subscribePrivilegeExpired;
|
|
2847
3183
|
if (restore) {
|
|
2848
3184
|
this.joined = false;
|
|
2849
|
-
_optionalChain([this, 'access',
|
|
3185
|
+
_optionalChain([this, 'access', _271 => _271.listener, 'optionalAccess', _272 => _272.onRoomRejoining, 'optionalCall', _273 => _273()]);
|
|
2850
3186
|
this.clearPlayers();
|
|
2851
3187
|
this.clearStatistics();
|
|
2852
3188
|
if (this.tokenExpired) {
|
|
@@ -2861,7 +3197,7 @@ var VeRtcManager = class {
|
|
|
2861
3197
|
throw this.cancelled();
|
|
2862
3198
|
}
|
|
2863
3199
|
}
|
|
2864
|
-
if ((this.tokenExpired || this.publishPrivilegeExpired) && this.videoRequested && this.camera) {
|
|
3200
|
+
if ((this.tokenExpired || this.publishPrivilegeExpired) && this.videoRequested && (this.camera || this.externalVideo)) {
|
|
2865
3201
|
await this.run(() => engine.publishStream(this.sdk.MediaType.VIDEO));
|
|
2866
3202
|
this.ensureCurrent(engine, version);
|
|
2867
3203
|
if (!this.videoRequested) {
|
|
@@ -2869,7 +3205,7 @@ var VeRtcManager = class {
|
|
|
2869
3205
|
this.ensureCurrent(engine, version);
|
|
2870
3206
|
}
|
|
2871
3207
|
}
|
|
2872
|
-
if ((this.tokenExpired || this.publishPrivilegeExpired) && this.audioRequested && this.microphone) {
|
|
3208
|
+
if ((this.tokenExpired || this.publishPrivilegeExpired) && this.audioRequested && (this.microphone || this.externalAudio)) {
|
|
2873
3209
|
await this.run(() => engine.publishStream(this.sdk.MediaType.AUDIO));
|
|
2874
3210
|
this.ensureCurrent(engine, version);
|
|
2875
3211
|
if (!this.audioRequested) {
|
|
@@ -2893,7 +3229,7 @@ var VeRtcManager = class {
|
|
|
2893
3229
|
}
|
|
2894
3230
|
async publishLocalVideo() {
|
|
2895
3231
|
const engine = this.requireEngine();
|
|
2896
|
-
this.
|
|
3232
|
+
this.requireLocalVideo();
|
|
2897
3233
|
this.videoRequested = true;
|
|
2898
3234
|
const version = this.roomVersion;
|
|
2899
3235
|
await this.recovery;
|
|
@@ -2907,12 +3243,15 @@ var VeRtcManager = class {
|
|
|
2907
3243
|
}
|
|
2908
3244
|
async publishLocalAudio() {
|
|
2909
3245
|
const engine = this.requireEngine();
|
|
3246
|
+
if (this.externalVideo && !this.externalAudio) {
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
2910
3249
|
this.audioRequested = true;
|
|
2911
3250
|
const version = this.roomVersion;
|
|
2912
3251
|
await this.recovery;
|
|
2913
3252
|
this.ensureCurrent(engine, version);
|
|
2914
3253
|
try {
|
|
2915
|
-
if (!this.microphone) {
|
|
3254
|
+
if (!this.externalVideo && !this.microphone) {
|
|
2916
3255
|
await engine.startAudioCapture();
|
|
2917
3256
|
if (!this.isCurrent(engine, version)) {
|
|
2918
3257
|
await engine.stopAudioCapture().catch(() => {
|
|
@@ -2924,7 +3263,7 @@ var VeRtcManager = class {
|
|
|
2924
3263
|
if (!this.audioRequested) throw this.cancelled();
|
|
2925
3264
|
await engine.publishStream(this.sdk.MediaType.AUDIO);
|
|
2926
3265
|
} catch (error) {
|
|
2927
|
-
throw this.mapError(error, "MICROPHONE_PERMISSION_DENIED" /* microphonePermissionDenied */);
|
|
3266
|
+
throw this.mapError(error, this.externalVideo ? "RTC_ERROR" /* rtcError */ : "MICROPHONE_PERMISSION_DENIED" /* microphonePermissionDenied */);
|
|
2928
3267
|
}
|
|
2929
3268
|
}
|
|
2930
3269
|
async unpublishLocalAudio() {
|
|
@@ -3014,13 +3353,13 @@ var VeRtcManager = class {
|
|
|
3014
3353
|
if (!active()) return;
|
|
3015
3354
|
if (video(mediaType)) {
|
|
3016
3355
|
this.publishedVideo.add(userId);
|
|
3017
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3356
|
+
if (mediaActive()) _optionalChain([this, 'access', _274 => _274.listener, 'optionalAccess', _275 => _275.onRemoteVideoPublished, 'call', _276 => _276(userId, true)]);
|
|
3018
3357
|
}
|
|
3019
3358
|
if (audio(mediaType)) {
|
|
3020
3359
|
this.publishedAudio.add(userId);
|
|
3021
3360
|
if (mediaActive() && this.requestedAudio.has(userId)) {
|
|
3022
3361
|
void this.subscribeRemoteAudio(userId, true).catch((error) => {
|
|
3023
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3362
|
+
if (mediaActive()) _optionalChain([this, 'access', _277 => _277.listener, 'optionalAccess', _278 => _278.onError, 'optionalCall', _279 => _279(this.mapError(error))]);
|
|
3024
3363
|
});
|
|
3025
3364
|
}
|
|
3026
3365
|
}
|
|
@@ -3040,10 +3379,10 @@ var VeRtcManager = class {
|
|
|
3040
3379
|
this.clearPlayer(userInfo.userId);
|
|
3041
3380
|
});
|
|
3042
3381
|
engine.on(events.onRoomMessageReceived, ({ userId, message }) => {
|
|
3043
|
-
if (mediaActive() && typeof message === "string") _optionalChain([this, 'access',
|
|
3382
|
+
if (mediaActive() && typeof message === "string") _optionalChain([this, 'access', _280 => _280.listener, 'optionalAccess', _281 => _281.onCustomMessageReceived, 'call', _282 => _282(userId, message)]);
|
|
3044
3383
|
});
|
|
3045
3384
|
const willExpire = () => {
|
|
3046
|
-
if (active()) _optionalChain([this, 'access',
|
|
3385
|
+
if (active()) _optionalChain([this, 'access', _283 => _283.listener, 'optionalAccess', _284 => _284.onTokenWillExpire, 'optionalCall', _285 => _285()]);
|
|
3047
3386
|
};
|
|
3048
3387
|
engine.on(events.onTokenWillExpire, willExpire);
|
|
3049
3388
|
engine.on(events.onTokenPublishPrivilegeWillExpire, willExpire);
|
|
@@ -3051,13 +3390,13 @@ var VeRtcManager = class {
|
|
|
3051
3390
|
engine.on(events.onTokenPublishPrivilegeDidExpired, () => {
|
|
3052
3391
|
if (!active() || this.publishPrivilegeExpired) return;
|
|
3053
3392
|
this.publishPrivilegeExpired = true;
|
|
3054
|
-
_optionalChain([this, 'access',
|
|
3393
|
+
_optionalChain([this, 'access', _286 => _286.listener, 'optionalAccess', _287 => _287.onTokenExpired, 'optionalCall', _288 => _288()]);
|
|
3055
3394
|
});
|
|
3056
3395
|
engine.on(events.onTokenSubscribePrivilegeDidExpired, () => {
|
|
3057
3396
|
if (!active() || this.subscribePrivilegeExpired) return;
|
|
3058
3397
|
this.subscribePrivilegeExpired = true;
|
|
3059
3398
|
this.clearPlayers();
|
|
3060
|
-
_optionalChain([this, 'access',
|
|
3399
|
+
_optionalChain([this, 'access', _289 => _289.listener, 'optionalAccess', _290 => _290.onTokenExpired, 'optionalCall', _291 => _291()]);
|
|
3061
3400
|
});
|
|
3062
3401
|
engine.on(events.onError, ({ errorCode }) => {
|
|
3063
3402
|
if (!active()) return;
|
|
@@ -3065,23 +3404,23 @@ var VeRtcManager = class {
|
|
|
3065
3404
|
if (this.tokenExpired) return;
|
|
3066
3405
|
this.tokenExpired = true;
|
|
3067
3406
|
this.clearPlayers();
|
|
3068
|
-
_optionalChain([this, 'access',
|
|
3069
|
-
} else _optionalChain([this, 'access',
|
|
3407
|
+
_optionalChain([this, 'access', _292 => _292.listener, 'optionalAccess', _293 => _293.onTokenExpired, 'optionalCall', _294 => _294()]);
|
|
3408
|
+
} else _optionalChain([this, 'access', _295 => _295.listener, 'optionalAccess', _296 => _296.onError, 'optionalCall', _297 => _297(this.mapError({ code: errorCode }))]);
|
|
3070
3409
|
});
|
|
3071
3410
|
engine.on(events.onConnectionStateChanged, ({ state: state2 }) => {
|
|
3072
3411
|
if (!mediaActive() || state2 !== this.sdk.ConnectionState.CONNECTION_STATE_RECONNECTED) return;
|
|
3073
|
-
_optionalChain([this, 'access',
|
|
3412
|
+
_optionalChain([this, 'access', _298 => _298.listener, 'optionalAccess', _299 => _299.onRoomRejoining, 'optionalCall', _300 => _300()]);
|
|
3074
3413
|
this.clearPlayers();
|
|
3075
3414
|
this.clearStatistics();
|
|
3076
3415
|
this.replayVideo();
|
|
3077
3416
|
for (const userID of this.requestedAudio) {
|
|
3078
3417
|
void this.subscribeRemoteAudio(userID, true).catch((error) => {
|
|
3079
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3418
|
+
if (mediaActive()) _optionalChain([this, 'access', _301 => _301.listener, 'optionalAccess', _302 => _302.onError, 'optionalCall', _303 => _303(this.mapError(error))]);
|
|
3080
3419
|
});
|
|
3081
3420
|
}
|
|
3082
3421
|
});
|
|
3083
3422
|
engine.on(events.onNetworkQuality, (up, down) => {
|
|
3084
|
-
if (mediaActive()) _optionalChain([this, 'access',
|
|
3423
|
+
if (mediaActive()) _optionalChain([this, 'access', _304 => _304.listener, 'optionalAccess', _305 => _305.onNetworkStatistics, 'optionalCall', _306 => _306(Object.freeze({
|
|
3085
3424
|
uplinkQuality: VeRtcStatistics.quality(up),
|
|
3086
3425
|
downlinkQuality: VeRtcStatistics.quality(down)
|
|
3087
3426
|
}))]);
|
|
@@ -3090,7 +3429,7 @@ var VeRtcManager = class {
|
|
|
3090
3429
|
if (!mediaActive() || stats.isScreen || !this.videoRequested) return;
|
|
3091
3430
|
const result = VeRtcStatistics.local(stats.videoStats);
|
|
3092
3431
|
this.uplinkLossPercent = result.uplinkLossPercent;
|
|
3093
|
-
_optionalChain([this, 'access',
|
|
3432
|
+
_optionalChain([this, 'access', _307 => _307.listener, 'optionalAccess', _308 => _308.onLocalVideoStatistics, 'optionalCall', _309 => _309(result)]);
|
|
3094
3433
|
XmaxLogger.rtc.info(() => `VeRTC local video statistics: ${JSON.stringify(result)}`, 2 /* performance */);
|
|
3095
3434
|
});
|
|
3096
3435
|
engine.on(events.onRemoteStreamStats, (stats) => {
|
|
@@ -3100,21 +3439,21 @@ var VeRtcManager = class {
|
|
|
3100
3439
|
});
|
|
3101
3440
|
}
|
|
3102
3441
|
replayVideo() {
|
|
3103
|
-
for (const userID of this.publishedVideo) _optionalChain([this, 'access',
|
|
3442
|
+
for (const userID of this.publishedVideo) _optionalChain([this, 'access', _310 => _310.listener, 'optionalAccess', _311 => _311.onRemoteVideoPublished, 'call', _312 => _312(userID, true)]);
|
|
3104
3443
|
}
|
|
3105
3444
|
removeVideo(userID) {
|
|
3106
3445
|
this.publishedVideo.delete(userID);
|
|
3107
3446
|
this.remoteStatistics.delete(userID);
|
|
3108
3447
|
this.emitRemoteStatistics();
|
|
3109
|
-
if (this.joined && !this.tokenExpired) _optionalChain([this, 'access',
|
|
3448
|
+
if (this.joined && !this.tokenExpired) _optionalChain([this, 'access', _313 => _313.listener, 'optionalAccess', _314 => _314.onRemoteVideoPublished, 'call', _315 => _315(userID, false)]);
|
|
3110
3449
|
}
|
|
3111
3450
|
emitRemoteStatistics() {
|
|
3112
|
-
_optionalChain([this, 'access',
|
|
3451
|
+
_optionalChain([this, 'access', _316 => _316.listener, 'optionalAccess', _317 => _317.onRemoteVideoStatistics, 'optionalCall', _318 => _318(Object.freeze([...this.remoteStatistics.values()]))]);
|
|
3113
3452
|
}
|
|
3114
3453
|
clearStatistics() {
|
|
3115
3454
|
this.remoteStatistics.clear();
|
|
3116
3455
|
this.uplinkLossPercent = void 0;
|
|
3117
|
-
_optionalChain([this, 'access',
|
|
3456
|
+
_optionalChain([this, 'access', _319 => _319.listener, 'optionalAccess', _320 => _320.onLocalVideoStatistics, 'optionalCall', _321 => _321(void 0)]);
|
|
3118
3457
|
this.emitRemoteStatistics();
|
|
3119
3458
|
}
|
|
3120
3459
|
clearPlayer(userID) {
|
|
@@ -3160,15 +3499,15 @@ var VeRtcManager = class {
|
|
|
3160
3499
|
const cleanup = () => {
|
|
3161
3500
|
clearTimeout(timer);
|
|
3162
3501
|
roomSignal.removeEventListener("abort", cancel);
|
|
3163
|
-
_optionalChain([signal, 'optionalAccess',
|
|
3502
|
+
_optionalChain([signal, 'optionalAccess', _322 => _322.removeEventListener, 'call', _323 => _323("abort", cancel)]);
|
|
3164
3503
|
};
|
|
3165
3504
|
const cancel = () => {
|
|
3166
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
3505
|
+
if (_optionalChain([signal, 'optionalAccess', _324 => _324.aborted]) && !roomSignal.aborted) this.roomVersion++;
|
|
3167
3506
|
cleanup();
|
|
3168
3507
|
reject(this.cancelled());
|
|
3169
3508
|
};
|
|
3170
3509
|
roomSignal.addEventListener("abort", cancel, { once: true });
|
|
3171
|
-
_optionalChain([signal, 'optionalAccess',
|
|
3510
|
+
_optionalChain([signal, 'optionalAccess', _325 => _325.addEventListener, 'call', _326 => _326("abort", cancel, { once: true })]);
|
|
3172
3511
|
task.then((value) => {
|
|
3173
3512
|
cleanup();
|
|
3174
3513
|
resolve(value);
|
|
@@ -3176,7 +3515,7 @@ var VeRtcManager = class {
|
|
|
3176
3515
|
cleanup();
|
|
3177
3516
|
reject(error);
|
|
3178
3517
|
});
|
|
3179
|
-
if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess',
|
|
3518
|
+
if (roomSignal.aborted || _optionalChain([signal, 'optionalAccess', _327 => _327.aborted])) cancel();
|
|
3180
3519
|
});
|
|
3181
3520
|
}
|
|
3182
3521
|
isCurrent(engine, version) {
|
|
@@ -3189,6 +3528,15 @@ var VeRtcManager = class {
|
|
|
3189
3528
|
if (!this.engine) throw new XmaxError("RTC_ERROR" /* rtcError */, "VeRTC is not initialized");
|
|
3190
3529
|
return this.engine;
|
|
3191
3530
|
}
|
|
3531
|
+
/**
|
|
3532
|
+
* 获取已准备的文件或摄像头视频轨。
|
|
3533
|
+
*/
|
|
3534
|
+
requireLocalVideo() {
|
|
3535
|
+
if (this.externalVideo) {
|
|
3536
|
+
return this.externalVideo;
|
|
3537
|
+
}
|
|
3538
|
+
return this.requireCamera();
|
|
3539
|
+
}
|
|
3192
3540
|
requireCamera() {
|
|
3193
3541
|
if (!this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
3194
3542
|
return this.camera;
|
|
@@ -3203,8 +3551,8 @@ var VeRtcManager = class {
|
|
|
3203
3551
|
mapError(error, permissionCode) {
|
|
3204
3552
|
if (error instanceof XmaxError) return error;
|
|
3205
3553
|
const value = error;
|
|
3206
|
-
const code = typeof _optionalChain([value, 'optionalAccess',
|
|
3207
|
-
const denied = _optionalChain([value, 'optionalAccess',
|
|
3554
|
+
const code = typeof _optionalChain([value, 'optionalAccess', _328 => _328.code]) === "string" && /^[A-Z_0-9-]{1,64}$/.test(value.code) ? value.code : "UNKNOWN";
|
|
3555
|
+
const denied = _optionalChain([value, 'optionalAccess', _329 => _329.name]) === "NotAllowedError" || code === "PERMISSION_DENIED" || code === "DEVICE_PERMISSION_DENIED";
|
|
3208
3556
|
return new XmaxError(permissionCode && denied ? permissionCode : "RTC_ERROR" /* rtcError */, `VeRTC operation failed (${code})`);
|
|
3209
3557
|
}
|
|
3210
3558
|
cancelled() {
|
|
@@ -3215,12 +3563,14 @@ var VeRtcManager = class {
|
|
|
3215
3563
|
// src/Foundation/RTC/RtcFactory.ts
|
|
3216
3564
|
function createRtcManager(provider, environment) {
|
|
3217
3565
|
switch (provider) {
|
|
3566
|
+
case "trtc" /* trtc */:
|
|
3567
|
+
return new TrtcRtcManager();
|
|
3218
3568
|
case "agora" /* agora */:
|
|
3219
3569
|
return new AgoraRtcManager({ environment });
|
|
3220
3570
|
case "vertc" /* vertc */:
|
|
3221
3571
|
return new VeRtcManager();
|
|
3222
3572
|
default:
|
|
3223
|
-
|
|
3573
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Unsupported RTC provider");
|
|
3224
3574
|
}
|
|
3225
3575
|
}
|
|
3226
3576
|
|
|
@@ -3284,7 +3634,7 @@ var PermissionManager = class {
|
|
|
3284
3634
|
* @param deniedCode 权限被拒绝时抛出的错误码。
|
|
3285
3635
|
*/
|
|
3286
3636
|
async ensurePermission(name, deniedCode) {
|
|
3287
|
-
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access',
|
|
3637
|
+
if (typeof navigator === "undefined" || !_optionalChain([navigator, 'access', _330 => _330.mediaDevices, 'optionalAccess', _331 => _331.getUserMedia])) {
|
|
3288
3638
|
throw new XmaxError(
|
|
3289
3639
|
deniedCode,
|
|
3290
3640
|
"This browser does not support media capture (getUserMedia)"
|
|
@@ -3292,7 +3642,7 @@ var PermissionManager = class {
|
|
|
3292
3642
|
}
|
|
3293
3643
|
try {
|
|
3294
3644
|
const permissions = navigator.permissions;
|
|
3295
|
-
if (!_optionalChain([permissions, 'optionalAccess',
|
|
3645
|
+
if (!_optionalChain([permissions, 'optionalAccess', _332 => _332.query])) {
|
|
3296
3646
|
return;
|
|
3297
3647
|
}
|
|
3298
3648
|
const status = await permissions.query({
|
|
@@ -3472,10 +3822,10 @@ var _CameraController = class _CameraController {
|
|
|
3472
3822
|
*/
|
|
3473
3823
|
__publicField(this, "storedUseMicrophone", false);
|
|
3474
3824
|
__publicField(this, "storedFrameValidationEnabled", true);
|
|
3475
|
-
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3476
|
-
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3477
|
-
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3478
|
-
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3825
|
+
this.permissionManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _333 => _333.permissionManager]), () => ( new PermissionManager()));
|
|
3826
|
+
this.rtcManager = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _334 => _334.rtcManager]), () => ( new TrtcRtcManager()));
|
|
3827
|
+
this.mediaService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _335 => _335.mediaService]), () => ( new MediaService()));
|
|
3828
|
+
this.errorListener = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _336 => _336.errorListener]), () => ( (() => {
|
|
3479
3829
|
})));
|
|
3480
3830
|
}
|
|
3481
3831
|
/**
|
|
@@ -3501,7 +3851,7 @@ var _CameraController = class _CameraController {
|
|
|
3501
3851
|
*/
|
|
3502
3852
|
async waitForValidCameraFrame(signal) {
|
|
3503
3853
|
const track = this.activeTrack;
|
|
3504
|
-
const mediaTrack = _optionalChain([track, 'optionalAccess',
|
|
3854
|
+
const mediaTrack = _optionalChain([track, 'optionalAccess', _337 => _337.mediaStreamTrack]);
|
|
3505
3855
|
if (!mediaTrack) throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera capture is not running");
|
|
3506
3856
|
if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Camera frame validation cancelled");
|
|
3507
3857
|
if (!this.isFrameValidationEnabled) return;
|
|
@@ -3601,7 +3951,7 @@ var _CameraController = class _CameraController {
|
|
|
3601
3951
|
*/
|
|
3602
3952
|
async switchCamera() {
|
|
3603
3953
|
const track = this.activeTrack;
|
|
3604
|
-
const position = _optionalChain([track, 'optionalAccess',
|
|
3954
|
+
const position = _optionalChain([track, 'optionalAccess', _338 => _338.position]);
|
|
3605
3955
|
if (!track || !position) {
|
|
3606
3956
|
throw new XmaxError(
|
|
3607
3957
|
"RTC_ERROR" /* rtcError */,
|
|
@@ -3619,7 +3969,7 @@ var _CameraController = class _CameraController {
|
|
|
3619
3969
|
}
|
|
3620
3970
|
this.previewStream.addTrack(mediaTrack);
|
|
3621
3971
|
}
|
|
3622
|
-
_optionalChain([this, 'access',
|
|
3972
|
+
_optionalChain([this, 'access', _339 => _339.previewMirrorApplier, 'optionalCall', _340 => _340(nextPosition === "front" /* front */)]);
|
|
3623
3973
|
this.observeMediaTrack(track, mediaTrack);
|
|
3624
3974
|
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
3625
3975
|
}
|
|
@@ -3715,6 +4065,463 @@ var _CameraController = class _CameraController {
|
|
|
3715
4065
|
__publicField(_CameraController, "localVideoTrackID", "video0");
|
|
3716
4066
|
var CameraController = _CameraController;
|
|
3717
4067
|
|
|
4068
|
+
// src/Service/Realtime/RealtimeReferenceVideo.ts
|
|
4069
|
+
var RealtimeVideoSampleMethod = /* @__PURE__ */ ((RealtimeVideoSampleMethod2) => {
|
|
4070
|
+
RealtimeVideoSampleMethod2["time"] = "time";
|
|
4071
|
+
RealtimeVideoSampleMethod2["fps"] = "fps";
|
|
4072
|
+
return RealtimeVideoSampleMethod2;
|
|
4073
|
+
})(RealtimeVideoSampleMethod || {});
|
|
4074
|
+
|
|
4075
|
+
// src/Media/Video/NetworkVideoController.ts
|
|
4076
|
+
var NetworkVideoController = class {
|
|
4077
|
+
constructor() {
|
|
4078
|
+
/**
|
|
4079
|
+
* 当前视频源与完成通知
|
|
4080
|
+
*/
|
|
4081
|
+
__publicField(this, "currentTrack");
|
|
4082
|
+
__publicField(this, "reference");
|
|
4083
|
+
__publicField(this, "onFinish");
|
|
4084
|
+
/**
|
|
4085
|
+
* 预览进度与视图资源
|
|
4086
|
+
*/
|
|
4087
|
+
__publicField(this, "position", 0);
|
|
4088
|
+
__publicField(this, "ended", false);
|
|
4089
|
+
__publicField(this, "bindings", /* @__PURE__ */ new Map());
|
|
4090
|
+
}
|
|
4091
|
+
/**
|
|
4092
|
+
* 创建网络视频源,校验地址、采样方式和模型支持的尺寸;不请求视频下载。
|
|
4093
|
+
*/
|
|
4094
|
+
create(options, mediaService) {
|
|
4095
|
+
let url;
|
|
4096
|
+
try {
|
|
4097
|
+
url = new URL(options.url);
|
|
4098
|
+
} catch (e15) {
|
|
4099
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Network video requires an absolute HTTP or HTTPS URL");
|
|
4100
|
+
}
|
|
4101
|
+
if (!["http:", "https:"].includes(url.protocol) || !url.hostname || url.username || url.password) {
|
|
4102
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Network video requires an HTTP or HTTPS URL without embedded credentials");
|
|
4103
|
+
}
|
|
4104
|
+
const sampleMethod = _nullishCoalesce(options.sampleMethod, () => ( "time")) /* time */;
|
|
4105
|
+
if (!Object.values(RealtimeVideoSampleMethod).includes(sampleMethod)) {
|
|
4106
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Unsupported video sample method");
|
|
4107
|
+
}
|
|
4108
|
+
if (this.currentTrack) {
|
|
4109
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Close the current network video stream before creating another one");
|
|
4110
|
+
}
|
|
4111
|
+
options.videoFormat.validate();
|
|
4112
|
+
const size = mediaService.resolveModelInputSize(options.videoFormat);
|
|
4113
|
+
const track = new RealtimeVideoTrack({
|
|
4114
|
+
id: "network-video",
|
|
4115
|
+
videoFormat: options.videoFormat.resized(size.width, size.height)
|
|
4116
|
+
});
|
|
4117
|
+
this.currentTrack = track;
|
|
4118
|
+
this.reference = Object.freeze({ path: options.url.trim(), sampleMethod });
|
|
4119
|
+
this.onFinish = options.onFinish;
|
|
4120
|
+
VideoRenderRegistry.register(track, {
|
|
4121
|
+
attachHandler: (view) => this.attach(view),
|
|
4122
|
+
detachHandler: (view) => this.detach(view)
|
|
4123
|
+
});
|
|
4124
|
+
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
4125
|
+
}
|
|
4126
|
+
/**
|
|
4127
|
+
* 释放全部预览绑定及源信息,不影响其他媒体源。
|
|
4128
|
+
*/
|
|
4129
|
+
stop() {
|
|
4130
|
+
for (const view of this.bindings.keys()) {
|
|
4131
|
+
this.detach(view);
|
|
4132
|
+
}
|
|
4133
|
+
if (this.currentTrack) {
|
|
4134
|
+
VideoRenderRegistry.unregister(this.currentTrack);
|
|
4135
|
+
}
|
|
4136
|
+
this.currentTrack = void 0;
|
|
4137
|
+
this.reference = void 0;
|
|
4138
|
+
this.onFinish = void 0;
|
|
4139
|
+
this.position = 0;
|
|
4140
|
+
this.ended = false;
|
|
4141
|
+
}
|
|
4142
|
+
/**
|
|
4143
|
+
* 绑定播放器,恢复预览位置;本地播放错误仅记录,不中断服务端生成。
|
|
4144
|
+
*/
|
|
4145
|
+
attach(view) {
|
|
4146
|
+
if (!this.reference || !view.videoElement || !view.setVideoURL) {
|
|
4147
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "This render target does not support network video preview");
|
|
4148
|
+
}
|
|
4149
|
+
this.detach(view);
|
|
4150
|
+
const video = view.videoElement;
|
|
4151
|
+
video.autoplay = !this.ended;
|
|
4152
|
+
const restore = () => {
|
|
4153
|
+
if (this.position > 0) {
|
|
4154
|
+
video.currentTime = Math.min(this.position, Math.max(0, video.duration - 1e-3) || this.position);
|
|
4155
|
+
}
|
|
4156
|
+
if (this.ended) {
|
|
4157
|
+
video.pause();
|
|
4158
|
+
}
|
|
4159
|
+
};
|
|
4160
|
+
const fail = () => {
|
|
4161
|
+
XmaxLogger.render.warning(() => "\u7F51\u7EDC\u89C6\u9891\u9884\u89C8\u5931\u8D25 (Network Video Preview Failed)");
|
|
4162
|
+
};
|
|
4163
|
+
video.addEventListener("loadedmetadata", restore);
|
|
4164
|
+
video.addEventListener("error", fail);
|
|
4165
|
+
this.bindings.set(view, () => {
|
|
4166
|
+
this.position = video.currentTime;
|
|
4167
|
+
this.ended = video.ended || this.ended;
|
|
4168
|
+
video.removeEventListener("loadedmetadata", restore);
|
|
4169
|
+
video.removeEventListener("error", fail);
|
|
4170
|
+
_optionalChain([view, 'access', _341 => _341.setVideoURL, 'optionalCall', _342 => _342(null)]);
|
|
4171
|
+
});
|
|
4172
|
+
view.isMirrored = false;
|
|
4173
|
+
view.setVideoURL(this.reference.path);
|
|
4174
|
+
}
|
|
4175
|
+
/**
|
|
4176
|
+
* 保存预览进度并释放该视图的地址和事件监听。
|
|
4177
|
+
*/
|
|
4178
|
+
detach(view) {
|
|
4179
|
+
_optionalChain([this, 'access', _343 => _343.bindings, 'access', _344 => _344.get, 'call', _345 => _345(view), 'optionalCall', _346 => _346()]);
|
|
4180
|
+
this.bindings.delete(view);
|
|
4181
|
+
}
|
|
4182
|
+
};
|
|
4183
|
+
|
|
4184
|
+
// src/Media/Video/LocalVideoController.ts
|
|
4185
|
+
var LocalVideoController = class {
|
|
4186
|
+
/**
|
|
4187
|
+
* 保存媒体错误处理器,不创建浏览器资源。
|
|
4188
|
+
*/
|
|
4189
|
+
constructor(onError = () => {
|
|
4190
|
+
}) {
|
|
4191
|
+
/**
|
|
4192
|
+
* 当前文件资源与运行期错误通知
|
|
4193
|
+
*/
|
|
4194
|
+
__publicField(this, "source");
|
|
4195
|
+
__publicField(this, "onError");
|
|
4196
|
+
this.onError = onError;
|
|
4197
|
+
}
|
|
4198
|
+
/**
|
|
4199
|
+
* 是否持有文件资源,包含尚未完成准备的播放器。
|
|
4200
|
+
*/
|
|
4201
|
+
get isActive() {
|
|
4202
|
+
return this.source !== void 0;
|
|
4203
|
+
}
|
|
4204
|
+
/**
|
|
4205
|
+
* 准备完成的本地视频轨。
|
|
4206
|
+
*/
|
|
4207
|
+
get currentTrack() {
|
|
4208
|
+
return _optionalChain([this, 'access', _347 => _347.source, 'optionalAccess', _348 => _348.track]);
|
|
4209
|
+
}
|
|
4210
|
+
/**
|
|
4211
|
+
* 文件音频输出;禁用音频时为空,无音轨文件的 Web Audio 输出为静音。
|
|
4212
|
+
*/
|
|
4213
|
+
get audioTrack() {
|
|
4214
|
+
return _optionalChain([this, 'access', _349 => _349.source, 'optionalAccess', _350 => _350.audioDestination, 'optionalAccess', _351 => _351.stream, 'access', _352 => _352.getAudioTracks, 'call', _353 => _353(), 'access', _354 => _354[0]]);
|
|
4215
|
+
}
|
|
4216
|
+
/**
|
|
4217
|
+
* 校验文件和格式,准备首帧与音频输出;应从用户点击事件直接调用以解锁播放。
|
|
4218
|
+
*/
|
|
4219
|
+
async create(options, mediaService, signal) {
|
|
4220
|
+
if (this.source) {
|
|
4221
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Close the current local video before creating another one");
|
|
4222
|
+
}
|
|
4223
|
+
if (!(options.file instanceof Blob) || options.file.size === 0) {
|
|
4224
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video requires a non-empty File or Blob");
|
|
4225
|
+
}
|
|
4226
|
+
const format = this.resolveVideoFormat(options.videoFormat, mediaService);
|
|
4227
|
+
if (signal.aborted) {
|
|
4228
|
+
throw this.cancelled();
|
|
4229
|
+
}
|
|
4230
|
+
if (typeof document === "undefined") {
|
|
4231
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Local video requires a browser");
|
|
4232
|
+
}
|
|
4233
|
+
const video = document.createElement("video");
|
|
4234
|
+
const canvas = document.createElement("canvas");
|
|
4235
|
+
const context = canvas.getContext("2d");
|
|
4236
|
+
if (!context || typeof canvas.captureStream !== "function") {
|
|
4237
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Canvas video capture is unavailable");
|
|
4238
|
+
}
|
|
4239
|
+
canvas.width = format.width;
|
|
4240
|
+
canvas.height = format.height;
|
|
4241
|
+
const source = {
|
|
4242
|
+
video,
|
|
4243
|
+
canvas,
|
|
4244
|
+
context,
|
|
4245
|
+
url: URL.createObjectURL(options.file),
|
|
4246
|
+
abort: new AbortController(),
|
|
4247
|
+
targets: /* @__PURE__ */ new Set()
|
|
4248
|
+
};
|
|
4249
|
+
this.source = source;
|
|
4250
|
+
try {
|
|
4251
|
+
video.playsInline = true;
|
|
4252
|
+
video.loop = _nullishCoalesce(options.loop, () => ( true));
|
|
4253
|
+
video.preload = "auto";
|
|
4254
|
+
video.volume = 1;
|
|
4255
|
+
video.muted = options.includeAudio === false;
|
|
4256
|
+
if (options.includeAudio !== false) {
|
|
4257
|
+
if (typeof AudioContext === "undefined") {
|
|
4258
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Web Audio is unavailable; disable file audio or use a supported browser");
|
|
4259
|
+
}
|
|
4260
|
+
const audio = new AudioContext();
|
|
4261
|
+
source.audioContext = audio;
|
|
4262
|
+
source.audioSource = audio.createMediaElementSource(video);
|
|
4263
|
+
source.audioDestination = audio.createMediaStreamDestination();
|
|
4264
|
+
source.audioSource.connect(source.audioDestination);
|
|
4265
|
+
}
|
|
4266
|
+
video.src = source.url;
|
|
4267
|
+
const resume = _optionalChain([source, 'access', _355 => _355.audioContext, 'optionalAccess', _356 => _356.resume, 'call', _357 => _357()]);
|
|
4268
|
+
const playing = this.play(source, signal);
|
|
4269
|
+
await this.wait(source, Promise.all([resume, playing]), signal);
|
|
4270
|
+
video.pause();
|
|
4271
|
+
if (!video.videoWidth || !video.videoHeight || !Number.isFinite(video.duration) || video.duration <= 0) {
|
|
4272
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "The file has no playable finite video stream");
|
|
4273
|
+
}
|
|
4274
|
+
await this.rewind(source, signal);
|
|
4275
|
+
this.draw(source);
|
|
4276
|
+
source.stream = canvas.captureStream(format.fps);
|
|
4277
|
+
const nativeTrack = source.stream.getVideoTracks()[0];
|
|
4278
|
+
if (!nativeTrack) {
|
|
4279
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Canvas did not provide a video track");
|
|
4280
|
+
}
|
|
4281
|
+
const track = new RealtimeVideoTrack({ id: "local-video", videoFormat: format });
|
|
4282
|
+
track.mediaStreamTrack = nativeTrack;
|
|
4283
|
+
source.track = track;
|
|
4284
|
+
this.draw(source);
|
|
4285
|
+
source.drawTimer = setInterval(() => {
|
|
4286
|
+
if (this.source !== source) {
|
|
4287
|
+
return;
|
|
4288
|
+
}
|
|
4289
|
+
try {
|
|
4290
|
+
this.draw(source);
|
|
4291
|
+
} catch (e16) {
|
|
4292
|
+
this.handleError(source);
|
|
4293
|
+
}
|
|
4294
|
+
}, 1e3 / format.fps);
|
|
4295
|
+
source.onError = () => this.handleError(source);
|
|
4296
|
+
video.addEventListener("error", source.onError);
|
|
4297
|
+
VideoRenderRegistry.register(track, {
|
|
4298
|
+
attachHandler: (view) => {
|
|
4299
|
+
view.isMirrored = false;
|
|
4300
|
+
view.setMediaStream(source.stream);
|
|
4301
|
+
source.targets.add(view);
|
|
4302
|
+
},
|
|
4303
|
+
detachHandler: (view) => {
|
|
4304
|
+
source.targets.delete(view);
|
|
4305
|
+
view.setMediaStream(null);
|
|
4306
|
+
}
|
|
4307
|
+
});
|
|
4308
|
+
return new RealtimeMediaStream({ id: "stream0" /* local */, videoTrack: track });
|
|
4309
|
+
} catch (error) {
|
|
4310
|
+
await this.stop();
|
|
4311
|
+
throw XmaxError.from(error);
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
/**
|
|
4315
|
+
* 开始信令发送成功后,从文件开头同步启动音视频;不等待远端首帧。
|
|
4316
|
+
*/
|
|
4317
|
+
async start(signal) {
|
|
4318
|
+
const source = this.source;
|
|
4319
|
+
if (!_optionalChain([source, 'optionalAccess', _358 => _358.track])) {
|
|
4320
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is not prepared");
|
|
4321
|
+
}
|
|
4322
|
+
if (signal.aborted) {
|
|
4323
|
+
throw this.cancelled();
|
|
4324
|
+
}
|
|
4325
|
+
try {
|
|
4326
|
+
await this.rewind(source, signal);
|
|
4327
|
+
await this.wait(source, Promise.all([_optionalChain([source, 'access', _359 => _359.audioContext, 'optionalAccess', _360 => _360.resume, 'call', _361 => _361()]), this.play(source, signal)]), signal);
|
|
4328
|
+
} catch (error) {
|
|
4329
|
+
source.video.pause();
|
|
4330
|
+
throw error;
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
/**
|
|
4334
|
+
* 暂停文件音视频,保留当前预览;重新开始生成时回到文件开头。
|
|
4335
|
+
*/
|
|
4336
|
+
pause() {
|
|
4337
|
+
_optionalChain([this, 'access', _362 => _362.source, 'optionalAccess', _363 => _363.video, 'access', _364 => _364.pause, 'call', _365 => _365()]);
|
|
4338
|
+
}
|
|
4339
|
+
/**
|
|
4340
|
+
* 释放播放器、预览、定时器、轨道、音频上下文和对象 URL。
|
|
4341
|
+
*/
|
|
4342
|
+
async stop() {
|
|
4343
|
+
const source = this.source;
|
|
4344
|
+
this.source = void 0;
|
|
4345
|
+
if (!source) {
|
|
4346
|
+
return;
|
|
4347
|
+
}
|
|
4348
|
+
source.abort.abort();
|
|
4349
|
+
clearInterval(source.drawTimer);
|
|
4350
|
+
if (source.onError) {
|
|
4351
|
+
source.video.removeEventListener("error", source.onError);
|
|
4352
|
+
}
|
|
4353
|
+
if (source.track) {
|
|
4354
|
+
VideoRenderRegistry.unregister(source.track);
|
|
4355
|
+
source.track.mediaStreamTrack = void 0;
|
|
4356
|
+
}
|
|
4357
|
+
for (const view of source.targets) {
|
|
4358
|
+
try {
|
|
4359
|
+
view.setMediaStream(null);
|
|
4360
|
+
} catch (e17) {
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
source.targets.clear();
|
|
4364
|
+
source.video.pause();
|
|
4365
|
+
source.video.removeAttribute("src");
|
|
4366
|
+
source.video.load();
|
|
4367
|
+
_optionalChain([source, 'access', _366 => _366.stream, 'optionalAccess', _367 => _367.getTracks, 'call', _368 => _368(), 'access', _369 => _369.forEach, 'call', _370 => _370((track) => track.stop())]);
|
|
4368
|
+
_optionalChain([source, 'access', _371 => _371.audioDestination, 'optionalAccess', _372 => _372.stream, 'access', _373 => _373.getTracks, 'call', _374 => _374(), 'access', _375 => _375.forEach, 'call', _376 => _376((track) => track.stop())]);
|
|
4369
|
+
_optionalChain([source, 'access', _377 => _377.audioSource, 'optionalAccess', _378 => _378.disconnect, 'call', _379 => _379()]);
|
|
4370
|
+
_optionalChain([source, 'access', _380 => _380.audioDestination, 'optionalAccess', _381 => _381.disconnect, 'call', _382 => _382()]);
|
|
4371
|
+
URL.revokeObjectURL(source.url);
|
|
4372
|
+
await _optionalChain([source, 'access', _383 => _383.audioContext, 'optionalAccess', _384 => _384.close, 'call', _385 => _385(), 'access', _386 => _386.catch, 'call', _387 => _387(() => {
|
|
4373
|
+
})]);
|
|
4374
|
+
}
|
|
4375
|
+
/**
|
|
4376
|
+
* 播放被浏览器拒绝时给出可操作错误;关闭后的迟到播放立即暂停。
|
|
4377
|
+
*/
|
|
4378
|
+
play(source, signal) {
|
|
4379
|
+
return source.video.play().then(() => {
|
|
4380
|
+
if (this.source !== source || source.abort.signal.aborted || signal.aborted) {
|
|
4381
|
+
source.video.pause();
|
|
4382
|
+
throw this.cancelled();
|
|
4383
|
+
}
|
|
4384
|
+
}).catch((error) => {
|
|
4385
|
+
if (error instanceof XmaxError) {
|
|
4386
|
+
throw error;
|
|
4387
|
+
}
|
|
4388
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Cannot play local video; call from a user click and use a browser-supported video codec");
|
|
4389
|
+
});
|
|
4390
|
+
}
|
|
4391
|
+
/**
|
|
4392
|
+
* 等待 seek 完成,确保重新生成从首帧开始,而非使用旧缓存画面。
|
|
4393
|
+
*/
|
|
4394
|
+
async rewind(source, signal) {
|
|
4395
|
+
if (source.video.currentTime === 0) {
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
let seeked;
|
|
4399
|
+
const ready = new Promise((resolve) => {
|
|
4400
|
+
seeked = resolve;
|
|
4401
|
+
});
|
|
4402
|
+
source.video.addEventListener("seeked", seeked, { once: true });
|
|
4403
|
+
try {
|
|
4404
|
+
source.video.currentTime = 0;
|
|
4405
|
+
await this.wait(source, ready, signal);
|
|
4406
|
+
} finally {
|
|
4407
|
+
source.video.removeEventListener("seeked", seeked);
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
/**
|
|
4411
|
+
* 给浏览器准备和播放操作设置 10 秒上限,同时响应关闭、取消和解码错误。
|
|
4412
|
+
*/
|
|
4413
|
+
wait(source, operation, signal) {
|
|
4414
|
+
return new Promise((resolve, reject) => {
|
|
4415
|
+
const finish = (error) => {
|
|
4416
|
+
clearTimeout(timer);
|
|
4417
|
+
signal.removeEventListener("abort", abort);
|
|
4418
|
+
source.abort.signal.removeEventListener("abort", abort);
|
|
4419
|
+
source.video.removeEventListener("error", failed);
|
|
4420
|
+
if (error) {
|
|
4421
|
+
reject(error);
|
|
4422
|
+
} else {
|
|
4423
|
+
resolve();
|
|
4424
|
+
}
|
|
4425
|
+
};
|
|
4426
|
+
const abort = () => finish(this.cancelled());
|
|
4427
|
+
const failed = () => finish(new XmaxError("MEDIA_ERROR" /* mediaError */, "The browser cannot decode this video file"));
|
|
4428
|
+
const timer = setTimeout(() => finish(new XmaxError("TIMEOUT" /* timeout */, "Local video preparation timed out; start from a user click and check the video codec")), 1e4);
|
|
4429
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4430
|
+
source.abort.signal.addEventListener("abort", abort, { once: true });
|
|
4431
|
+
source.video.addEventListener("error", failed, { once: true });
|
|
4432
|
+
operation.then(() => finish(), finish);
|
|
4433
|
+
if (signal.aborted || source.abort.signal.aborted) {
|
|
4434
|
+
abort();
|
|
4435
|
+
}
|
|
4436
|
+
});
|
|
4437
|
+
}
|
|
4438
|
+
/**
|
|
4439
|
+
* 等比缩放并居中补黑边,保留完整画面,不按设备方向转置文件尺寸。
|
|
4440
|
+
*/
|
|
4441
|
+
draw(source) {
|
|
4442
|
+
const { video, canvas, context } = source;
|
|
4443
|
+
if (video.readyState < 2) {
|
|
4444
|
+
return;
|
|
4445
|
+
}
|
|
4446
|
+
const scale = Math.min(canvas.width / video.videoWidth, canvas.height / video.videoHeight);
|
|
4447
|
+
const width = video.videoWidth * scale;
|
|
4448
|
+
const height = video.videoHeight * scale;
|
|
4449
|
+
context.fillStyle = "black";
|
|
4450
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
4451
|
+
context.drawImage(video, (canvas.width - width) / 2, (canvas.height - height) / 2, width, height);
|
|
4452
|
+
}
|
|
4453
|
+
/**
|
|
4454
|
+
* 仅为本地文件选择最接近宽高比的模型档位;比例距离相同时优先横屏。
|
|
4455
|
+
* 无固定档位时保留公共尺寸解析规则,帧率和显式编码配置不变。
|
|
4456
|
+
*/
|
|
4457
|
+
resolveVideoFormat(format, mediaService) {
|
|
4458
|
+
format.validate();
|
|
4459
|
+
const buckets = resolutionBuckets(mediaService.model);
|
|
4460
|
+
let target = buckets.find((size2) => size2.width === format.width && size2.height === format.height);
|
|
4461
|
+
if (!target && buckets.length > 0) {
|
|
4462
|
+
const ratio = format.width / format.height;
|
|
4463
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
4464
|
+
for (const bucket of buckets) {
|
|
4465
|
+
const distance = Math.abs(Math.log(bucket.width / bucket.height / ratio));
|
|
4466
|
+
const tied = Math.abs(distance - bestDistance) < 1e-9;
|
|
4467
|
+
if (distance < bestDistance - 1e-9 || tied && bucket.width >= bucket.height && target && target.width < target.height) {
|
|
4468
|
+
target = bucket;
|
|
4469
|
+
bestDistance = distance;
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
const size = mediaService.resolveModelInputSize(_nullishCoalesce(target, () => ( format)));
|
|
4474
|
+
return format.resized(size.width, size.height);
|
|
4475
|
+
}
|
|
4476
|
+
/**
|
|
4477
|
+
* 解码或绘制失败时停止媒体推进,并报告一次运行期错误。
|
|
4478
|
+
*/
|
|
4479
|
+
handleError(source) {
|
|
4480
|
+
if (this.source !== source || source.drawTimer === void 0) {
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
clearInterval(source.drawTimer);
|
|
4484
|
+
source.drawTimer = void 0;
|
|
4485
|
+
source.video.pause();
|
|
4486
|
+
XmaxLogger.realtime.warning(() => "\u672C\u5730\u89C6\u9891\u89E3\u7801\u5931\u8D25 (Local Video Decode Failed)");
|
|
4487
|
+
this.onError(new XmaxError("MEDIA_ERROR" /* mediaError */, "Local video decoding failed"));
|
|
4488
|
+
}
|
|
4489
|
+
/**
|
|
4490
|
+
* 构造统一的媒体操作取消错误。
|
|
4491
|
+
*/
|
|
4492
|
+
cancelled() {
|
|
4493
|
+
return new XmaxError("CANCELLED" /* cancelled */, "Local video operation was cancelled");
|
|
4494
|
+
}
|
|
4495
|
+
};
|
|
4496
|
+
|
|
4497
|
+
// src/Service/Realtime/RealtimeContext.ts
|
|
4498
|
+
var RealtimeContext = class {
|
|
4499
|
+
/**
|
|
4500
|
+
* 创建实时生成条件并规范化文本和参考路径。
|
|
4501
|
+
*/
|
|
4502
|
+
constructor(init) {
|
|
4503
|
+
/**
|
|
4504
|
+
* 服务端直接读取的网络视频。
|
|
4505
|
+
*/
|
|
4506
|
+
__publicField(this, "referenceVideo");
|
|
4507
|
+
/**
|
|
4508
|
+
* 生成条件
|
|
4509
|
+
*/
|
|
4510
|
+
/**
|
|
4511
|
+
* 实时生成使用的文本条件。
|
|
4512
|
+
*/
|
|
4513
|
+
__publicField(this, "prompt");
|
|
4514
|
+
/**
|
|
4515
|
+
* 已上传参考图片的可选远端路径。
|
|
4516
|
+
*/
|
|
4517
|
+
__publicField(this, "referencePath");
|
|
4518
|
+
this.referenceVideo = init.referenceVideo && Object.freeze({ ...init.referenceVideo });
|
|
4519
|
+
this.prompt = init.prompt.trim();
|
|
4520
|
+
const normalizedReferencePath = _optionalChain([init, 'access', _388 => _388.referencePath, 'optionalAccess', _389 => _389.trim, 'call', _390 => _390()]);
|
|
4521
|
+
this.referencePath = normalizedReferencePath || void 0;
|
|
4522
|
+
}
|
|
4523
|
+
};
|
|
4524
|
+
|
|
3718
4525
|
// src/Service/Realtime/RealtimeSession.ts
|
|
3719
4526
|
var RealtimeSession = class {
|
|
3720
4527
|
/**
|
|
@@ -3779,7 +4586,7 @@ var RoomJoinConfiguration = class {
|
|
|
3779
4586
|
/**
|
|
3780
4587
|
* RTC 提供方。
|
|
3781
4588
|
*/
|
|
3782
|
-
__publicField(this, "provider", "trtc");
|
|
4589
|
+
__publicField(this, "provider", "trtc" /* trtc */);
|
|
3783
4590
|
/**
|
|
3784
4591
|
* 进房参数
|
|
3785
4592
|
*/
|
|
@@ -3872,10 +4679,10 @@ var RealtimeSessionConnection = class {
|
|
|
3872
4679
|
}
|
|
3873
4680
|
};
|
|
3874
4681
|
function toRoomJoinConfiguration(connection) {
|
|
3875
|
-
return connection.provider === "trtc" ? new RoomJoinConfiguration(connection) : connection;
|
|
4682
|
+
return connection.provider === "trtc" /* trtc */ ? new RoomJoinConfiguration(connection) : connection;
|
|
3876
4683
|
}
|
|
3877
4684
|
function connectionAppID(connection) {
|
|
3878
|
-
return connection.provider === "trtc" ? connection.sdkAppID : connection.appID;
|
|
4685
|
+
return connection.provider === "trtc" /* trtc */ ? connection.sdkAppID : connection.appID;
|
|
3879
4686
|
}
|
|
3880
4687
|
|
|
3881
4688
|
// src/Service/Realtime/RealtimeSessionService.ts
|
|
@@ -3978,7 +4785,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
3978
4785
|
return;
|
|
3979
4786
|
}
|
|
3980
4787
|
_RealtimeSessionService.ensureSessionActive(session);
|
|
3981
|
-
await _optionalChain([handlers, 'access',
|
|
4788
|
+
await _optionalChain([handlers, 'access', _391 => _391.onRefresh, 'optionalCall', _392 => _392(session)]);
|
|
3982
4789
|
} catch (error) {
|
|
3983
4790
|
if (this.heartbeatVersion !== version) {
|
|
3984
4791
|
return;
|
|
@@ -4090,7 +4897,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
4090
4897
|
return void 0;
|
|
4091
4898
|
}
|
|
4092
4899
|
return new RealtimeSessionConnection({
|
|
4093
|
-
provider: "trtc"
|
|
4900
|
+
provider: "trtc" /* trtc */,
|
|
4094
4901
|
roomID,
|
|
4095
4902
|
sdkAppID,
|
|
4096
4903
|
userID,
|
|
@@ -4106,7 +4913,7 @@ var RealtimeSessionService = class _RealtimeSessionService {
|
|
|
4106
4913
|
if (typeof modelExtra === "string") {
|
|
4107
4914
|
try {
|
|
4108
4915
|
return _RealtimeSessionService.decodeConnectionPayload(JSON.parse(modelExtra));
|
|
4109
|
-
} catch (
|
|
4916
|
+
} catch (e18) {
|
|
4110
4917
|
return void 0;
|
|
4111
4918
|
}
|
|
4112
4919
|
}
|
|
@@ -4191,7 +4998,7 @@ var RealtimeState = class {
|
|
|
4191
4998
|
* @param other 待比较的状态。
|
|
4192
4999
|
*/
|
|
4193
5000
|
equals(other) {
|
|
4194
|
-
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access',
|
|
5001
|
+
return this.connectionState === other.connectionState && this.sessionID === other.sessionID && this.taskID === other.taskID && _optionalChain([this, 'access', _393 => _393.reason, 'optionalAccess', _394 => _394.kind]) === _optionalChain([other, 'access', _395 => _395.reason, 'optionalAccess', _396 => _396.kind]);
|
|
4195
5002
|
}
|
|
4196
5003
|
};
|
|
4197
5004
|
|
|
@@ -4234,9 +5041,20 @@ var RoomEvent = class _RoomEvent {
|
|
|
4234
5041
|
static start(options) {
|
|
4235
5042
|
return _RoomEvent.encode({
|
|
4236
5043
|
event: "start",
|
|
4237
|
-
params:
|
|
5044
|
+
params: {
|
|
5045
|
+
..._RoomEvent.generationParameters(options),
|
|
5046
|
+
...options.context.referenceVideo && {
|
|
5047
|
+
ref_video_path: options.context.referenceVideo.path,
|
|
5048
|
+
sample_method: options.context.referenceVideo.sampleMethod,
|
|
5049
|
+
target_size: [
|
|
5050
|
+
_nullishCoalesce(_optionalChain([options, 'access', _397 => _397.targetSize, 'optionalAccess', _398 => _398.width]), () => ( options.videoFormat.width)),
|
|
5051
|
+
_nullishCoalesce(_optionalChain([options, 'access', _399 => _399.targetSize, 'optionalAccess', _400 => _400.height]), () => ( options.videoFormat.height))
|
|
5052
|
+
]
|
|
5053
|
+
}
|
|
5054
|
+
},
|
|
4238
5055
|
user_id: options.userID,
|
|
4239
|
-
uid: options.taskID
|
|
5056
|
+
uid: options.taskID,
|
|
5057
|
+
...options.context.referenceVideo && { session_uid: options.taskID }
|
|
4240
5058
|
});
|
|
4241
5059
|
}
|
|
4242
5060
|
/**
|
|
@@ -4317,7 +5135,7 @@ var RoomEvent = class _RoomEvent {
|
|
|
4317
5135
|
static encode(payload) {
|
|
4318
5136
|
try {
|
|
4319
5137
|
return JSON.stringify({ ...payload, runtime: RuntimeInfo.toJSON() });
|
|
4320
|
-
} catch (
|
|
5138
|
+
} catch (e19) {
|
|
4321
5139
|
throw new XmaxError(
|
|
4322
5140
|
"INTERNAL_ERROR" /* internalError */,
|
|
4323
5141
|
"Failed to encode RTC room event"
|
|
@@ -4443,7 +5261,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
4443
5261
|
let parsed;
|
|
4444
5262
|
try {
|
|
4445
5263
|
parsed = JSON.parse(message);
|
|
4446
|
-
} catch (
|
|
5264
|
+
} catch (e20) {
|
|
4447
5265
|
XmaxLogger.room.warning(() => "\u623F\u95F4\u6D88\u606F\u4E0D\u662F\u5408\u6CD5 JSON (Room Message Is Not Valid JSON)");
|
|
4448
5266
|
return void 0;
|
|
4449
5267
|
}
|
|
@@ -4452,20 +5270,20 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
4452
5270
|
return parsed;
|
|
4453
5271
|
}
|
|
4454
5272
|
const key = `${senderUserID}:${chunk.eventId}`;
|
|
4455
|
-
let
|
|
4456
|
-
if (!
|
|
4457
|
-
|
|
4458
|
-
this.records.set(key,
|
|
5273
|
+
let record2 = this.records.get(key);
|
|
5274
|
+
if (!record2) {
|
|
5275
|
+
record2 = { count: chunk.count, parts: /* @__PURE__ */ new Map() };
|
|
5276
|
+
this.records.set(key, record2);
|
|
4459
5277
|
this.evictOverflow();
|
|
4460
5278
|
}
|
|
4461
|
-
|
|
4462
|
-
if (
|
|
5279
|
+
record2.parts.set(chunk.index, chunk.data);
|
|
5280
|
+
if (record2.parts.size < record2.count) {
|
|
4463
5281
|
return void 0;
|
|
4464
5282
|
}
|
|
4465
5283
|
this.records.delete(key);
|
|
4466
5284
|
const parts = [];
|
|
4467
|
-
for (let index = 0; index <
|
|
4468
|
-
const part =
|
|
5285
|
+
for (let index = 0; index < record2.count; index += 1) {
|
|
5286
|
+
const part = record2.parts.get(index);
|
|
4469
5287
|
if (part === void 0) {
|
|
4470
5288
|
return void 0;
|
|
4471
5289
|
}
|
|
@@ -4474,7 +5292,7 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
4474
5292
|
const joined = parts.join("");
|
|
4475
5293
|
try {
|
|
4476
5294
|
return JSON.parse(joined);
|
|
4477
|
-
} catch (
|
|
5295
|
+
} catch (e21) {
|
|
4478
5296
|
XmaxLogger.room.warning(
|
|
4479
5297
|
() => `\u623F\u95F4\u6D88\u606F\u7EC4\u5305\u540E\u4E0D\u662F\u5408\u6CD5 JSON (Reassembled Message Is Not Valid JSON)
|
|
4480
5298
|
\u2514\u2500 eventId: ${chunk.eventId}`
|
|
@@ -4495,16 +5313,16 @@ var _RoomMessageCodec = class _RoomMessageCodec {
|
|
|
4495
5313
|
if (this.chunkEvent === null || typeof parsed !== "object" || parsed === null) {
|
|
4496
5314
|
return void 0;
|
|
4497
5315
|
}
|
|
4498
|
-
const
|
|
4499
|
-
if (
|
|
5316
|
+
const record2 = parsed;
|
|
5317
|
+
if (record2.event !== this.chunkEvent || typeof record2.eventId !== "string" || record2.eventId.length === 0 || !Number.isInteger(record2.index) || !Number.isInteger(record2.count) || typeof record2.data !== "string") {
|
|
4500
5318
|
return void 0;
|
|
4501
5319
|
}
|
|
4502
|
-
const index =
|
|
4503
|
-
const count =
|
|
5320
|
+
const index = record2.index;
|
|
5321
|
+
const count = record2.count;
|
|
4504
5322
|
if (count < 1 || index < 0 || index >= count) {
|
|
4505
5323
|
return void 0;
|
|
4506
5324
|
}
|
|
4507
|
-
return { eventId:
|
|
5325
|
+
return { eventId: record2.eventId, index, count, data: record2.data };
|
|
4508
5326
|
}
|
|
4509
5327
|
/**
|
|
4510
5328
|
* 淘汰最旧的未完成记录,保持缓存不超过上限。
|
|
@@ -4616,9 +5434,9 @@ var RoomController = class {
|
|
|
4616
5434
|
*
|
|
4617
5435
|
* @throws 已有房间未离开、操作失效或进房失败时抛出错误。
|
|
4618
5436
|
*/
|
|
4619
|
-
async join(connection,
|
|
5437
|
+
async join(connection, ensureActive2) {
|
|
4620
5438
|
try {
|
|
4621
|
-
|
|
5439
|
+
ensureActive2();
|
|
4622
5440
|
} catch (error) {
|
|
4623
5441
|
throw XmaxError.from(error);
|
|
4624
5442
|
}
|
|
@@ -4633,10 +5451,10 @@ var RoomController = class {
|
|
|
4633
5451
|
this.heartbeat.stop();
|
|
4634
5452
|
try {
|
|
4635
5453
|
if (!this.customCodec) this.codec = new RoomMessageCodec(
|
|
4636
|
-
connection.provider === "vertc" ? null : connection.provider === "agora" ? "__agora_chunk__" : "__trtc_chunk__"
|
|
5454
|
+
connection.provider === "vertc" /* vertc */ ? null : connection.provider === "agora" /* agora */ ? "__agora_chunk__" : "__trtc_chunk__"
|
|
4637
5455
|
);
|
|
4638
5456
|
await this.rtcManager.joinRoom(toRoomJoinConfiguration(connection));
|
|
4639
|
-
|
|
5457
|
+
ensureActive2();
|
|
4640
5458
|
if (this.state.kind !== "joining" || this.state.operationID !== operationID || this.leaveOperation) {
|
|
4641
5459
|
throw new XmaxError("CANCELLED" /* cancelled */, "RTC room join was cancelled");
|
|
4642
5460
|
}
|
|
@@ -4774,7 +5592,7 @@ var RoomController = class {
|
|
|
4774
5592
|
if (targetUserID && ownUserID && targetUserID !== ownUserID) {
|
|
4775
5593
|
return;
|
|
4776
5594
|
}
|
|
4777
|
-
_optionalChain([this, 'access',
|
|
5595
|
+
_optionalChain([this, 'access', _401 => _401.listener, 'optionalAccess', _402 => _402.onRoomMessage, 'call', _403 => _403(senderUserID, message)]);
|
|
4778
5596
|
}
|
|
4779
5597
|
/**
|
|
4780
5598
|
* 发送房间信令并输出日志。
|
|
@@ -5019,6 +5837,7 @@ var StreamController = class {
|
|
|
5019
5837
|
* 运行状态
|
|
5020
5838
|
*/
|
|
5021
5839
|
__publicField(this, "state", makeInitialState());
|
|
5840
|
+
__publicField(this, "roomListener");
|
|
5022
5841
|
this.rtcManager = options.rtcManager;
|
|
5023
5842
|
this.roomController = _nullishCoalesce(options.roomController, () => ( new RoomController({ rtcManager: options.rtcManager })));
|
|
5024
5843
|
this.encodingController = _nullishCoalesce(options.encodingController, () => ( new EncodingController({ rtcManager: options.rtcManager })));
|
|
@@ -5027,25 +5846,31 @@ var StreamController = class {
|
|
|
5027
5846
|
this.remoteStreamListener = _nullishCoalesce(options.remoteStreamListener, () => ( (() => {
|
|
5028
5847
|
})));
|
|
5029
5848
|
this.generationTimeoutMs = _nullishCoalesce(options.generationTimeoutMs, () => ( 3e4));
|
|
5849
|
+
this.roomController.setListener({
|
|
5850
|
+
onRoomMessage: (sender, message) => {
|
|
5851
|
+
this.handleNetworkVideoCompletion(sender, message);
|
|
5852
|
+
_optionalChain([this, 'access', _404 => _404.roomListener, 'optionalAccess', _405 => _405.onRoomMessage, 'call', _406 => _406(sender, message)]);
|
|
5853
|
+
}
|
|
5854
|
+
});
|
|
5030
5855
|
this.rtcManager.setEventListener({
|
|
5031
5856
|
onTokenWillExpire: options.onCredentialsRequired,
|
|
5032
5857
|
onTokenExpired: options.onCredentialsRequired,
|
|
5033
5858
|
onRoomRejoining: () => this.handleRoomRejoining(),
|
|
5034
5859
|
onError: (error) => this.errorListener(error),
|
|
5035
5860
|
onNetworkStatistics: (statistics) => {
|
|
5036
|
-
if (this.state.
|
|
5037
|
-
_optionalChain([this, 'access',
|
|
5861
|
+
if (this.state.roomID) {
|
|
5862
|
+
_optionalChain([this, 'access', _407 => _407.networkStatisticsListener, 'optionalCall', _408 => _408(statistics)]);
|
|
5038
5863
|
}
|
|
5039
5864
|
},
|
|
5040
5865
|
onRemoteVideoStatistics: (statistics) => {
|
|
5041
|
-
const userID = _optionalChain([this, 'access',
|
|
5042
|
-
_optionalChain([this, 'access',
|
|
5866
|
+
const userID = _optionalChain([this, 'access', _409 => _409.state, 'access', _410 => _410.activeRemoteStream, 'optionalAccess', _411 => _411.userID]);
|
|
5867
|
+
_optionalChain([this, 'access', _412 => _412.remoteVideoStatisticsListener, 'optionalCall', _413 => _413(
|
|
5043
5868
|
userID ? statistics.find((item) => item.userID === userID) : void 0
|
|
5044
5869
|
)]);
|
|
5045
5870
|
},
|
|
5046
5871
|
onLocalVideoStatistics: (statistics) => {
|
|
5047
5872
|
if (this.state.localVideoPublished) {
|
|
5048
|
-
_optionalChain([this, 'access',
|
|
5873
|
+
_optionalChain([this, 'access', _414 => _414.localVideoStatisticsListener, 'optionalCall', _415 => _415(statistics)]);
|
|
5049
5874
|
}
|
|
5050
5875
|
},
|
|
5051
5876
|
onCustomMessageReceived: (senderUserID, message) => {
|
|
@@ -5109,17 +5934,19 @@ var StreamController = class {
|
|
|
5109
5934
|
*
|
|
5110
5935
|
* @throws 连接已取消,或 RTC 进房、房间配置与本地流发布失败时抛出错误。
|
|
5111
5936
|
*/
|
|
5112
|
-
async connect(connection, includeLocalAudio,
|
|
5937
|
+
async connect(connection, includeLocalAudio, ensureActive2, beforePublish, publishLocalMedia = true) {
|
|
5113
5938
|
this.configureRoom({ roomID: connection.roomID, botID: connection.botID });
|
|
5114
|
-
await this.roomController.join(connection,
|
|
5115
|
-
|
|
5939
|
+
await this.roomController.join(connection, ensureActive2);
|
|
5940
|
+
ensureActive2();
|
|
5116
5941
|
XmaxLogger.stream.info(
|
|
5117
5942
|
() => `RTC \u623F\u95F4\u5DF2\u914D\u7F6E (RTC Room Configured)
|
|
5118
5943
|
\u2514\u2500 roomID: ${connection.roomID}, botID: ${_nullishCoalesce(connection.botID, () => ( "(\u672A\u8BBE\u7F6E)"))}`
|
|
5119
5944
|
);
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5945
|
+
if (publishLocalMedia) {
|
|
5946
|
+
await _optionalChain([beforePublish, 'optionalCall', _416 => _416()]);
|
|
5947
|
+
ensureActive2();
|
|
5948
|
+
await this.publishLocalStream(includeLocalAudio);
|
|
5949
|
+
}
|
|
5123
5950
|
}
|
|
5124
5951
|
/**
|
|
5125
5952
|
* 清理生成状态、本地发布和远端订阅,并离开当前 RTC 房间。
|
|
@@ -5180,6 +6007,7 @@ var StreamController = class {
|
|
|
5180
6007
|
}, this.generationTimeoutMs)
|
|
5181
6008
|
};
|
|
5182
6009
|
this.state.generationTaskID = taskID;
|
|
6010
|
+
this.state.networkVideoCompletion = options.context.referenceVideo ? { taskID, finished: false, scheduled: false } : void 0;
|
|
5183
6011
|
this.state.generationWaiter = waiter;
|
|
5184
6012
|
void confirmation.catch(() => {
|
|
5185
6013
|
});
|
|
@@ -5191,7 +6019,9 @@ var StreamController = class {
|
|
|
5191
6019
|
context: options.context
|
|
5192
6020
|
});
|
|
5193
6021
|
const state2 = this.state;
|
|
5194
|
-
const sent = Promise.resolve(sending).then(() => {
|
|
6022
|
+
const sent = Promise.resolve(sending).then(async () => {
|
|
6023
|
+
if (this.state !== state2 || state2.generationTaskID !== taskID) return;
|
|
6024
|
+
await _optionalChain([options, 'access', _417 => _417.onStartSent, 'optionalCall', _418 => _418()]);
|
|
5195
6025
|
if (this.state !== state2 || state2.generationTaskID !== taskID) return;
|
|
5196
6026
|
for (const userID of state2.publishedRemoteUserIDs) {
|
|
5197
6027
|
void this.handleRemoteVideoPublished(userID, true);
|
|
@@ -5215,7 +6045,7 @@ var StreamController = class {
|
|
|
5215
6045
|
try {
|
|
5216
6046
|
void this.roomController.stopGeneration(taskID).catch(() => {
|
|
5217
6047
|
});
|
|
5218
|
-
} catch (
|
|
6048
|
+
} catch (e22) {
|
|
5219
6049
|
}
|
|
5220
6050
|
throw mapped;
|
|
5221
6051
|
}
|
|
@@ -5257,9 +6087,9 @@ var StreamController = class {
|
|
|
5257
6087
|
*
|
|
5258
6088
|
* @throws 操作已取消、房间未就绪或信令发送失败时抛出错误。
|
|
5259
6089
|
*/
|
|
5260
|
-
async changeTargetSize(taskID, targetSize,
|
|
6090
|
+
async changeTargetSize(taskID, targetSize, ensureActive2) {
|
|
5261
6091
|
try {
|
|
5262
|
-
await this.roomController.changeTargetSize({ taskID, targetSize, ensureActive });
|
|
6092
|
+
await this.roomController.changeTargetSize({ taskID, targetSize, ensureActive: ensureActive2 });
|
|
5263
6093
|
} catch (error) {
|
|
5264
6094
|
throw XmaxError.from(error);
|
|
5265
6095
|
}
|
|
@@ -5296,14 +6126,57 @@ var StreamController = class {
|
|
|
5296
6126
|
* 设置房间业务消息监听器,传入空值时清除监听器。
|
|
5297
6127
|
*/
|
|
5298
6128
|
setRoomListener(listener) {
|
|
5299
|
-
this.
|
|
6129
|
+
this.roomListener = listener;
|
|
6130
|
+
}
|
|
6131
|
+
/**
|
|
6132
|
+
* 生成状态已提交后登记完成通知,避免快速任务在启动返回前交付完成事件。
|
|
6133
|
+
*/
|
|
6134
|
+
activateNetworkVideoCompletion(onFinish) {
|
|
6135
|
+
const completion = this.state.networkVideoCompletion;
|
|
6136
|
+
if (completion) {
|
|
6137
|
+
completion.onFinish = onFinish;
|
|
6138
|
+
this.deliverNetworkVideoCompletion();
|
|
6139
|
+
}
|
|
6140
|
+
}
|
|
6141
|
+
/**
|
|
6142
|
+
* 仅接受当前任务和目标机器人的完成消息;不因完成事件立即退房。
|
|
6143
|
+
*/
|
|
6144
|
+
handleNetworkVideoCompletion(sender, message) {
|
|
6145
|
+
const state2 = this.state;
|
|
6146
|
+
const completion = state2.networkVideoCompletion;
|
|
6147
|
+
if (!state2.roomID || !completion || completion.taskID !== state2.generationTaskID || message.event !== "video_stopped" || message.uid !== completion.taskID || !sender || state2.botID && sender !== state2.botID) {
|
|
6148
|
+
return;
|
|
6149
|
+
}
|
|
6150
|
+
completion.finished = true;
|
|
6151
|
+
this.deliverNetworkVideoCompletion();
|
|
6152
|
+
}
|
|
6153
|
+
/**
|
|
6154
|
+
* 异步交付一次完成通知;执行前复核任务,隔离用户回调异常。
|
|
6155
|
+
*/
|
|
6156
|
+
deliverNetworkVideoCompletion() {
|
|
6157
|
+
const state2 = this.state;
|
|
6158
|
+
const completion = state2.networkVideoCompletion;
|
|
6159
|
+
if (!_optionalChain([completion, 'optionalAccess', _419 => _419.finished]) || !completion.onFinish || completion.scheduled) {
|
|
6160
|
+
return;
|
|
6161
|
+
}
|
|
6162
|
+
completion.scheduled = true;
|
|
6163
|
+
queueMicrotask(() => {
|
|
6164
|
+
if (this.state !== state2 || state2.generationTaskID !== completion.taskID) {
|
|
6165
|
+
return;
|
|
6166
|
+
}
|
|
6167
|
+
try {
|
|
6168
|
+
void Promise.resolve(_optionalChain([completion, 'access', _420 => _420.onFinish, 'optionalCall', _421 => _421()])).catch(() => {
|
|
6169
|
+
});
|
|
6170
|
+
} catch (e23) {
|
|
6171
|
+
}
|
|
6172
|
+
});
|
|
5300
6173
|
}
|
|
5301
6174
|
/**
|
|
5302
6175
|
* 配置当前房间;已有发布、订阅或生成任务时拒绝重新配置。
|
|
5303
6176
|
*/
|
|
5304
6177
|
configureRoom(options) {
|
|
5305
6178
|
const roomID = options.roomID.trim();
|
|
5306
|
-
const botID = _nullishCoalesce(_optionalChain([options, 'access',
|
|
6179
|
+
const botID = _nullishCoalesce(_optionalChain([options, 'access', _422 => _422.botID, 'optionalAccess', _423 => _423.trim, 'call', _424 => _424()]), () => ( ""));
|
|
5307
6180
|
if (!roomID) {
|
|
5308
6181
|
throw new XmaxError(
|
|
5309
6182
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
@@ -5386,7 +6259,7 @@ var StreamController = class {
|
|
|
5386
6259
|
return;
|
|
5387
6260
|
}
|
|
5388
6261
|
this.state.subscribedRemoteUserIDs.delete(trimmedUserID);
|
|
5389
|
-
if (_optionalChain([this, 'access',
|
|
6262
|
+
if (_optionalChain([this, 'access', _425 => _425.state, 'access', _426 => _426.activeRemoteStream, 'optionalAccess', _427 => _427.userID]) === trimmedUserID) {
|
|
5390
6263
|
await this.unsubscribeRemoteAudio(trimmedUserID);
|
|
5391
6264
|
this.state.activeRemoteStream = void 0;
|
|
5392
6265
|
this.clearRemoteStream();
|
|
@@ -5527,6 +6400,7 @@ var StreamController = class {
|
|
|
5527
6400
|
const remoteAudioUserIDs = [...this.state.subscribedRemoteAudioUserIDs];
|
|
5528
6401
|
this.state.generationTaskID = void 0;
|
|
5529
6402
|
this.state.generationWaiter = void 0;
|
|
6403
|
+
this.state.networkVideoCompletion = void 0;
|
|
5530
6404
|
this.state.activeRemoteStream = void 0;
|
|
5531
6405
|
this.state.subscribedRemoteAudioUserIDs.clear();
|
|
5532
6406
|
if (waiter) {
|
|
@@ -5575,7 +6449,7 @@ var StreamController = class {
|
|
|
5575
6449
|
*/
|
|
5576
6450
|
resolveGenerationStart(taskID) {
|
|
5577
6451
|
const waiter = this.state.generationWaiter;
|
|
5578
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
6452
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _428 => _428.taskID]) !== taskID) {
|
|
5579
6453
|
return;
|
|
5580
6454
|
}
|
|
5581
6455
|
this.state.generationWaiter = void 0;
|
|
@@ -5587,7 +6461,7 @@ var StreamController = class {
|
|
|
5587
6461
|
*/
|
|
5588
6462
|
rejectGenerationStart(taskID, error) {
|
|
5589
6463
|
const waiter = this.state.generationWaiter;
|
|
5590
|
-
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess',
|
|
6464
|
+
if (this.state.generationTaskID !== taskID || _optionalChain([waiter, 'optionalAccess', _429 => _429.taskID]) !== taskID) {
|
|
5591
6465
|
return;
|
|
5592
6466
|
}
|
|
5593
6467
|
this.state.generationWaiter = void 0;
|
|
@@ -5598,7 +6472,7 @@ var StreamController = class {
|
|
|
5598
6472
|
* 通知渲染层清理远端生成流;失败仅记录日志。
|
|
5599
6473
|
*/
|
|
5600
6474
|
clearRemoteStream() {
|
|
5601
|
-
_optionalChain([this, 'access',
|
|
6475
|
+
_optionalChain([this, 'access', _430 => _430.remoteVideoStatisticsListener, 'optionalCall', _431 => _431(void 0)]);
|
|
5602
6476
|
try {
|
|
5603
6477
|
this.remoteStreamListener(null);
|
|
5604
6478
|
} catch (error) {
|
|
@@ -5869,7 +6743,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
5869
6743
|
}
|
|
5870
6744
|
throw _RealtimeCoordinator.cancelledError();
|
|
5871
6745
|
}
|
|
5872
|
-
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access',
|
|
6746
|
+
const terminationTask = await _asyncNullishCoalesce(await _asyncNullishCoalesce(operation.terminationTask, async () => ( _optionalChain([this, 'access', _432 => _432.termination, 'optionalAccess', _433 => _433.task]))), async () => ( await this.requestTermination(
|
|
5873
6747
|
_nullishCoalesce(operation.lease.failureScope, () => ( 0)) /* connection */,
|
|
5874
6748
|
void 0,
|
|
5875
6749
|
RealtimeReason.normal,
|
|
@@ -5998,7 +6872,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
5998
6872
|
* 结束指定操作,释放操作准入场。
|
|
5999
6873
|
*/
|
|
6000
6874
|
finish(operation) {
|
|
6001
|
-
if (_optionalChain([this, 'access',
|
|
6875
|
+
if (_optionalChain([this, 'access', _434 => _434.activeOperation, 'optionalAccess', _435 => _435.id]) === operation.id) {
|
|
6002
6876
|
this.activeOperation = void 0;
|
|
6003
6877
|
}
|
|
6004
6878
|
}
|
|
@@ -6010,7 +6884,7 @@ var RealtimeCoordinator = class _RealtimeCoordinator {
|
|
|
6010
6884
|
return;
|
|
6011
6885
|
}
|
|
6012
6886
|
this.state = nextState;
|
|
6013
|
-
_optionalChain([this, 'access',
|
|
6887
|
+
_optionalChain([this, 'access', _436 => _436.stateListener, 'optionalCall', _437 => _437(nextState)]);
|
|
6014
6888
|
}
|
|
6015
6889
|
/**
|
|
6016
6890
|
* 构造统一的操作取消错误。
|
|
@@ -6078,13 +6952,18 @@ var RealtimeLaunchTimer = class {
|
|
|
6078
6952
|
* 开始新的启动周期并清空旧快照,返回记录相机创建完成的一次性回调。
|
|
6079
6953
|
*/
|
|
6080
6954
|
startCamera() {
|
|
6955
|
+
this.start();
|
|
6956
|
+
return this.measure("cameraMs", this.startedAt);
|
|
6957
|
+
}
|
|
6958
|
+
/**
|
|
6959
|
+
* 开始新的启动周期;非摄像头源不产生相机和发布耗时。
|
|
6960
|
+
*/
|
|
6961
|
+
start() {
|
|
6081
6962
|
this.sequence += 1;
|
|
6082
6963
|
this.active = true;
|
|
6083
6964
|
this.startedAt = performance.now();
|
|
6084
6965
|
this.snapshot = Object.freeze({});
|
|
6085
|
-
const complete = this.measure("cameraMs", this.startedAt);
|
|
6086
6966
|
this.notify();
|
|
6087
|
-
return complete;
|
|
6088
6967
|
}
|
|
6089
6968
|
/**
|
|
6090
6969
|
* 开始等待用户授权系统媒体权限,返回授权决定时调用的记录函数。
|
|
@@ -6142,9 +7021,9 @@ var RealtimeLaunchTimer = class {
|
|
|
6142
7021
|
*/
|
|
6143
7022
|
notify() {
|
|
6144
7023
|
try {
|
|
6145
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
7024
|
+
void Promise.resolve(_optionalChain([this, 'access', _438 => _438.listener, 'optionalCall', _439 => _439(this.snapshot)])).catch(() => {
|
|
6146
7025
|
});
|
|
6147
|
-
} catch (
|
|
7026
|
+
} catch (e24) {
|
|
6148
7027
|
}
|
|
6149
7028
|
}
|
|
6150
7029
|
};
|
|
@@ -6174,7 +7053,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6174
7053
|
* 当前活动会话标识;尚未连接或清理完成后为空。
|
|
6175
7054
|
*/
|
|
6176
7055
|
get currentSessionID() {
|
|
6177
|
-
return _optionalChain([this, 'access',
|
|
7056
|
+
return _optionalChain([this, 'access', _440 => _440.activeSession, 'optionalAccess', _441 => _441.id]);
|
|
6178
7057
|
}
|
|
6179
7058
|
/**
|
|
6180
7059
|
* 未配置 API 服务时在连接操作开始前报错,不影响本地预览。
|
|
@@ -6215,19 +7094,23 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6215
7094
|
"Local video stream has no video format"
|
|
6216
7095
|
);
|
|
6217
7096
|
}
|
|
6218
|
-
|
|
7097
|
+
const publishLocalMedia = _nullishCoalesce(options.publishLocalMedia, () => ( true));
|
|
7098
|
+
if (publishLocalMedia) {
|
|
7099
|
+
await streamController.setVideoEncoderConfig(videoFormat);
|
|
7100
|
+
}
|
|
6219
7101
|
options.ensureCurrent();
|
|
6220
7102
|
let completePublish;
|
|
6221
7103
|
await streamController.connect(connection, options.includeLocalAudio, () => {
|
|
6222
7104
|
options.ensureCurrent();
|
|
6223
7105
|
}, async () => {
|
|
6224
7106
|
options.ensureCurrent();
|
|
6225
|
-
await _optionalChain([options, 'access',
|
|
7107
|
+
await _optionalChain([options, 'access', _442 => _442.beforePublish, 'optionalCall', _443 => _443()]);
|
|
6226
7108
|
completeConnection();
|
|
6227
7109
|
completePublish = this.dependencies.timing.startPublish();
|
|
6228
|
-
});
|
|
7110
|
+
}, publishLocalMedia);
|
|
6229
7111
|
options.ensureCurrent();
|
|
6230
|
-
|
|
7112
|
+
completeConnection();
|
|
7113
|
+
_optionalChain([completePublish, 'optionalCall', _444 => _444()]);
|
|
6231
7114
|
options.onPublished();
|
|
6232
7115
|
sessionService.startHeartbeat(session.id, {
|
|
6233
7116
|
onFailure: (sessionID, error) => {
|
|
@@ -6250,24 +7133,24 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6250
7133
|
* 更新已绑定远端视图的插帧配置;传 undefined 停用插帧。
|
|
6251
7134
|
*/
|
|
6252
7135
|
setFrameInterpolation(options) {
|
|
6253
|
-
_optionalChain([this, 'access',
|
|
7136
|
+
_optionalChain([this, 'access', _445 => _445.remoteTarget, 'optionalAccess', _446 => _446.setFrameInterpolation, 'optionalCall', _447 => _447(options)]);
|
|
6254
7137
|
}
|
|
6255
7138
|
/**
|
|
6256
7139
|
* 清空远端视图的媒体流,保留轨道与视图绑定以供统一清理。
|
|
6257
7140
|
*/
|
|
6258
7141
|
clearRemoteMedia() {
|
|
6259
|
-
_optionalChain([this, 'access',
|
|
7142
|
+
_optionalChain([this, 'access', _448 => _448.remoteTarget, 'optionalAccess', _449 => _449.setMediaStream, 'call', _450 => _450(null)]);
|
|
6260
7143
|
}
|
|
6261
7144
|
/**
|
|
6262
7145
|
* 停止会话心跳;未配置会话服务时不执行操作。
|
|
6263
7146
|
*/
|
|
6264
7147
|
stopHeartbeat() {
|
|
6265
7148
|
this.refreshVersion++;
|
|
6266
|
-
_optionalChain([this, 'access',
|
|
7149
|
+
_optionalChain([this, 'access', _451 => _451.credentialController, 'optionalAccess', _452 => _452.abort, 'call', _453 => _453()]);
|
|
6267
7150
|
this.credentialController = void 0;
|
|
6268
7151
|
this.credentialRefresh = void 0;
|
|
6269
7152
|
this.credentialApplication = Promise.resolve();
|
|
6270
|
-
_optionalChain([this, 'access',
|
|
7153
|
+
_optionalChain([this, 'access', _454 => _454.dependencies, 'access', _455 => _455.sessionService, 'optionalAccess', _456 => _456.stopHeartbeat, 'call', _457 => _457()]);
|
|
6271
7154
|
}
|
|
6272
7155
|
/**
|
|
6273
7156
|
* RTC Token 过期时复用会话心跳获取新凭据,并合并同一实例的并发请求。
|
|
@@ -6275,14 +7158,14 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6275
7158
|
async refreshCredentials() {
|
|
6276
7159
|
if (this.credentialRefresh) return this.credentialRefresh;
|
|
6277
7160
|
const current = this.activeSession;
|
|
6278
|
-
if (!_optionalChain([current, 'optionalAccess',
|
|
7161
|
+
if (!_optionalChain([current, 'optionalAccess', _458 => _458.connection]) || current.connection.provider === "trtc" /* trtc */) return;
|
|
6279
7162
|
const version = this.refreshVersion;
|
|
6280
7163
|
const operation = (async () => {
|
|
6281
7164
|
try {
|
|
6282
7165
|
const session = await this.requireSessionService().heartbeatSession(current.id);
|
|
6283
7166
|
await this.handleSessionRefresh(session, version, true);
|
|
6284
7167
|
} catch (error) {
|
|
6285
|
-
if (version === this.refreshVersion && _optionalChain([this, 'access',
|
|
7168
|
+
if (version === this.refreshVersion && _optionalChain([this, 'access', _459 => _459.activeSession, 'optionalAccess', _460 => _460.id]) === current.id) {
|
|
6286
7169
|
this.dependencies.onHeartbeatFailure(current.id, XmaxError.from(error));
|
|
6287
7170
|
}
|
|
6288
7171
|
}
|
|
@@ -6299,7 +7182,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6299
7182
|
*/
|
|
6300
7183
|
async waitUntilRemoteTrackReady(timeoutMs, signal) {
|
|
6301
7184
|
if (signal.aborted) throw RealtimeCoordinator.cancelledError();
|
|
6302
|
-
const mediaTrack = _optionalChain([this, 'access',
|
|
7185
|
+
const mediaTrack = _optionalChain([this, 'access', _461 => _461.activeRemoteTrack, 'optionalAccess', _462 => _462.mediaStreamTrack]);
|
|
6303
7186
|
if (!mediaTrack || !mediaTrack.muted) return;
|
|
6304
7187
|
await new Promise((resolve, reject) => {
|
|
6305
7188
|
const cleanup = () => {
|
|
@@ -6336,7 +7219,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6336
7219
|
if (track) {
|
|
6337
7220
|
track.mediaStreamTrack = void 0;
|
|
6338
7221
|
}
|
|
6339
|
-
_optionalChain([this, 'access',
|
|
7222
|
+
_optionalChain([this, 'access', _463 => _463.remoteTarget, 'optionalAccess', _464 => _464.setMediaStream, 'call', _465 => _465(null)]);
|
|
6340
7223
|
return;
|
|
6341
7224
|
}
|
|
6342
7225
|
if (!track) {
|
|
@@ -6346,7 +7229,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6346
7229
|
);
|
|
6347
7230
|
}
|
|
6348
7231
|
track.mediaStreamTrack = binding.videoTrack;
|
|
6349
|
-
_optionalChain([this, 'access',
|
|
7232
|
+
_optionalChain([this, 'access', _466 => _466.remoteTarget, 'optionalAccess', _467 => _467.setMediaStream, 'call', _468 => _468(new MediaStream([binding.videoTrack]))]);
|
|
6350
7233
|
}
|
|
6351
7234
|
/**
|
|
6352
7235
|
* 为远端轨道注册渲染绑定:attach 时挂流占位,媒体轨到达后送入画面。
|
|
@@ -6359,7 +7242,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6359
7242
|
}
|
|
6360
7243
|
},
|
|
6361
7244
|
attachHandler: (view) => {
|
|
6362
|
-
_optionalChain([this, 'access',
|
|
7245
|
+
_optionalChain([this, 'access', _469 => _469.remoteTarget, 'optionalAccess', _470 => _470.setFrameInterpolation, 'optionalCall', _471 => _471(void 0)]);
|
|
6363
7246
|
view.isMirrored = this.dependencies.isMirrored();
|
|
6364
7247
|
this.remoteTarget = view;
|
|
6365
7248
|
this.dependencies.onRenderAttached();
|
|
@@ -6371,7 +7254,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6371
7254
|
this.dependencies.onRenderDetached();
|
|
6372
7255
|
this.remoteTarget = void 0;
|
|
6373
7256
|
}
|
|
6374
|
-
_optionalChain([view, 'access',
|
|
7257
|
+
_optionalChain([view, 'access', _472 => _472.setFrameInterpolation, 'optionalCall', _473 => _473(void 0)]);
|
|
6375
7258
|
view.setMediaStream(null);
|
|
6376
7259
|
}
|
|
6377
7260
|
});
|
|
@@ -6428,8 +7311,8 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6428
7311
|
);
|
|
6429
7312
|
return;
|
|
6430
7313
|
}
|
|
6431
|
-
if (next.provider !== "trtc" && (force || !previous || previous.provider === "trtc" || next.roomToken !== previous.roomToken)) {
|
|
6432
|
-
await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access',
|
|
7314
|
+
if (next.provider !== "trtc" /* trtc */ && (force || !previous || previous.provider === "trtc" /* trtc */ || next.roomToken !== previous.roomToken)) {
|
|
7315
|
+
await this.dependencies.streamController.updateCredentials(next, _optionalChain([this, 'access', _474 => _474.credentialController, 'optionalAccess', _475 => _475.signal]));
|
|
6433
7316
|
if (version !== this.refreshVersion || this.activeSession !== current) return;
|
|
6434
7317
|
}
|
|
6435
7318
|
this.activeSession = new RealtimeSession({
|
|
@@ -6444,7 +7327,7 @@ var XmaxRealtimeConnectionManager = class {
|
|
|
6444
7327
|
* 尽力清理全部连接资源,即使退房失败也关闭服务端会话。
|
|
6445
7328
|
*/
|
|
6446
7329
|
async disconnect() {
|
|
6447
|
-
const sessionID = _optionalChain([this, 'access',
|
|
7330
|
+
const sessionID = _optionalChain([this, 'access', _476 => _476.activeSession, 'optionalAccess', _477 => _477.id]);
|
|
6448
7331
|
this.stopHeartbeat();
|
|
6449
7332
|
this.clearRemoteMedia();
|
|
6450
7333
|
try {
|
|
@@ -6526,7 +7409,8 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
6526
7409
|
const confirmation = this.streamController.beginGeneration({
|
|
6527
7410
|
taskID,
|
|
6528
7411
|
videoFormat: options.videoFormat,
|
|
6529
|
-
context
|
|
7412
|
+
context,
|
|
7413
|
+
...options.onStartSent && { onStartSent: options.onStartSent }
|
|
6530
7414
|
});
|
|
6531
7415
|
await this.awaitConfirmation(confirmation, options.signal);
|
|
6532
7416
|
options.ensureCurrent();
|
|
@@ -6578,7 +7462,7 @@ var XmaxRealtimeGenerationManager = class _XmaxRealtimeGenerationManager {
|
|
|
6578
7462
|
try {
|
|
6579
7463
|
await completion;
|
|
6580
7464
|
} finally {
|
|
6581
|
-
if (_optionalChain([this, 'access',
|
|
7465
|
+
if (_optionalChain([this, 'access', _478 => _478.pendingStop, 'optionalAccess', _479 => _479.completion]) === completion) this.pendingStop = void 0;
|
|
6582
7466
|
}
|
|
6583
7467
|
}
|
|
6584
7468
|
/**
|
|
@@ -6659,6 +7543,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6659
7543
|
__publicField(this, "coordinator");
|
|
6660
7544
|
__publicField(this, "errorHandler");
|
|
6661
7545
|
__publicField(this, "cameraController");
|
|
7546
|
+
__publicField(this, "networkVideoController", new NetworkVideoController());
|
|
7547
|
+
__publicField(this, "localVideoController", new LocalVideoController((error) => {
|
|
7548
|
+
void this.coordinator.terminateWithError(error, 0 /* connection */);
|
|
7549
|
+
}));
|
|
7550
|
+
__publicField(this, "rtcManager");
|
|
6662
7551
|
/**
|
|
6663
7552
|
* 启动计时与首帧通知
|
|
6664
7553
|
*/
|
|
@@ -6692,18 +7581,19 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6692
7581
|
this.options = options;
|
|
6693
7582
|
this.mediaService = new MediaService(options.model);
|
|
6694
7583
|
this.interpolationRequested = options.isFrameInterpolationEnabled;
|
|
6695
|
-
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
7584
|
+
this.supportsInterpolation = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _480 => _480.supportsFrameInterpolation]), () => ( (async (size) => await frameInterpolationAdapter(size) !== null)));
|
|
6696
7585
|
this.errorHandler = new RealtimeErrorHandler();
|
|
6697
|
-
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
6698
|
-
this.
|
|
7586
|
+
const rtcManager = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _481 => _481.rtcManager]), () => ( createRtcManager(options.provider, _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _482 => _482.environment]), () => ( "china")) /* china */)));
|
|
7587
|
+
this.rtcManager = rtcManager;
|
|
7588
|
+
this.cameraController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _483 => _483.cameraController]), () => ( new CameraController({
|
|
6699
7589
|
rtcManager,
|
|
6700
7590
|
mediaService: this.mediaService,
|
|
6701
7591
|
errorListener: (error) => {
|
|
6702
7592
|
void this.errorHandler.report(error);
|
|
6703
7593
|
}
|
|
6704
7594
|
})));
|
|
6705
|
-
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
6706
|
-
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess',
|
|
7595
|
+
const sessionService = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _484 => _484.sessionService]), () => ( (_optionalChain([dependencies, 'optionalAccess', _485 => _485.apiService]) ? new RealtimeSessionService({ apiService: dependencies.apiService, provider: options.provider }) : void 0)));
|
|
7596
|
+
this.streamController = _nullishCoalesce(_optionalChain([dependencies, 'optionalAccess', _486 => _486.streamController]), () => ( new StreamController({
|
|
6707
7597
|
rtcManager,
|
|
6708
7598
|
onCredentialsRequired: () => {
|
|
6709
7599
|
void this.connectionManager.refreshCredentials();
|
|
@@ -6721,12 +7611,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6721
7611
|
sessionService,
|
|
6722
7612
|
streamController: this.streamController,
|
|
6723
7613
|
timing: this.launchTimer,
|
|
6724
|
-
isMirrored: () => _optionalChain([this, 'access',
|
|
7614
|
+
isMirrored: () => _optionalChain([this, 'access', _487 => _487.cameraController, 'access', _488 => _488.currentTrack, 'optionalAccess', _489 => _489.position]) === "front" /* front */,
|
|
6725
7615
|
remoteAudioVolume: () => this.storedRemoteAudioVolume,
|
|
6726
7616
|
onHeartbeatFailure: (sessionID, error) => {
|
|
6727
7617
|
void this.handleHeartbeatFailure(sessionID, error);
|
|
6728
7618
|
},
|
|
6729
|
-
onFrameDisplayed: () => _optionalChain([this, 'access',
|
|
7619
|
+
onFrameDisplayed: () => _optionalChain([this, 'access', _490 => _490.remoteFrameDisplayHandler, 'optionalCall', _491 => _491()]),
|
|
6730
7620
|
onRenderAttached: () => this.applyRemoteInterpolation(),
|
|
6731
7621
|
onRenderDetached: () => {
|
|
6732
7622
|
this.interpolationRevision++;
|
|
@@ -6773,7 +7663,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6773
7663
|
*/
|
|
6774
7664
|
async setFrameInterpolationEnabled(enabled) {
|
|
6775
7665
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
6776
|
-
const format = _nullishCoalesce(this.generationVideoFormat, () => ( _optionalChain([this, 'access',
|
|
7666
|
+
const format = _nullishCoalesce(this.generationVideoFormat, () => ( _optionalChain([this, 'access', _492 => _492.currentLocalTrack, 'optionalAccess', _493 => _493.videoFormat])));
|
|
6777
7667
|
const size = format && enabled ? this.mediaService.resolveFrameInterpolationSize(format) : void 0;
|
|
6778
7668
|
if (enabled && !await this.checkInterpolationSupport(size, token)) {
|
|
6779
7669
|
token.ensureCurrent();
|
|
@@ -6838,7 +7728,6 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6838
7728
|
const size = this.interpolationSize;
|
|
6839
7729
|
this.connectionManager.setFrameInterpolation(size ? {
|
|
6840
7730
|
size,
|
|
6841
|
-
targetFrameRate: this.options.frameInterpolation.targetFrameRate,
|
|
6842
7731
|
onFailure: (error) => {
|
|
6843
7732
|
if (revision === this.interpolationRevision) this.handleInterpolationFailure(error);
|
|
6844
7733
|
}
|
|
@@ -6899,9 +7788,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6899
7788
|
*/
|
|
6900
7789
|
notifyRemoteVideoStatistics() {
|
|
6901
7790
|
try {
|
|
6902
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
7791
|
+
void Promise.resolve(_optionalChain([this, 'access', _494 => _494.remoteVideoStatisticsListener, 'optionalCall', _495 => _495(this.remoteVideoStatistics)])).catch(() => {
|
|
6903
7792
|
});
|
|
6904
|
-
} catch (
|
|
7793
|
+
} catch (e25) {
|
|
6905
7794
|
}
|
|
6906
7795
|
}
|
|
6907
7796
|
/**
|
|
@@ -6916,9 +7805,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6916
7805
|
*/
|
|
6917
7806
|
notifyNetworkStatistics() {
|
|
6918
7807
|
try {
|
|
6919
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
7808
|
+
void Promise.resolve(_optionalChain([this, 'access', _496 => _496.networkStatisticsListener, 'optionalCall', _497 => _497(this.networkStatistics)])).catch(() => {
|
|
6920
7809
|
});
|
|
6921
|
-
} catch (
|
|
7810
|
+
} catch (e26) {
|
|
6922
7811
|
}
|
|
6923
7812
|
}
|
|
6924
7813
|
/**
|
|
@@ -6936,9 +7825,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6936
7825
|
*/
|
|
6937
7826
|
notifyLocalVideoStatistics() {
|
|
6938
7827
|
try {
|
|
6939
|
-
void Promise.resolve(_optionalChain([this, 'access',
|
|
7828
|
+
void Promise.resolve(_optionalChain([this, 'access', _498 => _498.localVideoStatisticsListener, 'optionalCall', _499 => _499(this.localVideoStatistics)])).catch(() => {
|
|
6940
7829
|
});
|
|
6941
|
-
} catch (
|
|
7830
|
+
} catch (e27) {
|
|
6942
7831
|
}
|
|
6943
7832
|
}
|
|
6944
7833
|
/**
|
|
@@ -6999,6 +7888,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
6999
7888
|
"media" /* media */,
|
|
7000
7889
|
void 0,
|
|
7001
7890
|
async (token) => {
|
|
7891
|
+
this.ensureNoLocalSource();
|
|
7002
7892
|
await this.coordinator.commit(
|
|
7003
7893
|
new RealtimeState({
|
|
7004
7894
|
connectionState: "Preparing" /* preparing */
|
|
@@ -7009,7 +7899,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7009
7899
|
const completeCamera = this.launchTimer.startCamera();
|
|
7010
7900
|
this.clearVideoStatistics();
|
|
7011
7901
|
this.disposePermissionWatch();
|
|
7012
|
-
const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
7902
|
+
const permissionWatch = await watchMediaPermissionPrompt(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _500 => _500.useMicrophone]), () => ( false)));
|
|
7013
7903
|
if (permissionWatch) {
|
|
7014
7904
|
const completePermission = this.launchTimer.startPermission();
|
|
7015
7905
|
void permissionWatch.decided.then(() => completePermission()).catch(() => {
|
|
@@ -7026,7 +7916,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7026
7916
|
throw error;
|
|
7027
7917
|
}
|
|
7028
7918
|
token.ensureCurrent();
|
|
7029
|
-
this.generationVideoFormat = _optionalChain([stream, 'access',
|
|
7919
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _501 => _501.videoTrack, 'optionalAccess', _502 => _502.videoFormat]);
|
|
7030
7920
|
completeCamera();
|
|
7031
7921
|
this.cameraController.setPreviewReadyHandler((isCurrent) => {
|
|
7032
7922
|
void this.coordinator.localPreviewDidBecomeReady(isCurrent);
|
|
@@ -7035,25 +7925,82 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7035
7925
|
}
|
|
7036
7926
|
);
|
|
7037
7927
|
}
|
|
7928
|
+
/**
|
|
7929
|
+
* 创建网络视频源并初始化接收端 RTC;预览是否加载成功不影响服务端读取视频。
|
|
7930
|
+
*/
|
|
7931
|
+
async createNetworkVideoStream(options) {
|
|
7932
|
+
return this.coordinator.run("media" /* media */, void 0, async (token) => {
|
|
7933
|
+
this.ensureNoLocalSource();
|
|
7934
|
+
const stream = this.networkVideoController.create(options, this.mediaService);
|
|
7935
|
+
token.setFailureScope(1 /* all */);
|
|
7936
|
+
this.launchTimer.start();
|
|
7937
|
+
this.clearVideoStatistics();
|
|
7938
|
+
await this.rtcManager.initialize();
|
|
7939
|
+
token.ensureCurrent();
|
|
7940
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _503 => _503.videoTrack, 'optionalAccess', _504 => _504.videoFormat]);
|
|
7941
|
+
await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
|
|
7942
|
+
return stream;
|
|
7943
|
+
});
|
|
7944
|
+
}
|
|
7945
|
+
/**
|
|
7946
|
+
* 创建文件音视频源并准备外部轨道;准备失败时统一释放本次媒体和 RTC 资源。
|
|
7947
|
+
*/
|
|
7948
|
+
async createLocalVideoStream(options) {
|
|
7949
|
+
return this.coordinator.run("media" /* media */, void 0, async (token) => {
|
|
7950
|
+
this.ensureNoLocalSource();
|
|
7951
|
+
if (!this.rtcManager.setExternalMediaTracks) {
|
|
7952
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "The RTC provider does not support local video streams");
|
|
7953
|
+
}
|
|
7954
|
+
token.setFailureScope(1 /* all */);
|
|
7955
|
+
this.launchTimer.start();
|
|
7956
|
+
this.clearVideoStatistics();
|
|
7957
|
+
const stream = await this.localVideoController.create(options, this.mediaService, token.signal);
|
|
7958
|
+
token.ensureCurrent();
|
|
7959
|
+
await this.rtcManager.initialize();
|
|
7960
|
+
token.ensureCurrent();
|
|
7961
|
+
await this.rtcManager.setExternalMediaTracks({
|
|
7962
|
+
videoTrack: stream.videoTrack.mediaStreamTrack,
|
|
7963
|
+
audioTrack: this.localVideoController.audioTrack
|
|
7964
|
+
});
|
|
7965
|
+
token.ensureCurrent();
|
|
7966
|
+
this.generationVideoFormat = _optionalChain([stream, 'access', _505 => _505.videoTrack, 'optionalAccess', _506 => _506.videoFormat]);
|
|
7967
|
+
await this.coordinator.commit(new RealtimeState({ connectionState: "Ready" /* ready */ }), token);
|
|
7968
|
+
return stream;
|
|
7969
|
+
});
|
|
7970
|
+
}
|
|
7971
|
+
/**
|
|
7972
|
+
* 当前 Manager 拥有的媒体源轨道。
|
|
7973
|
+
*/
|
|
7974
|
+
get currentLocalTrack() {
|
|
7975
|
+
return _nullishCoalesce(_nullishCoalesce(this.localVideoController.currentTrack, () => ( this.networkVideoController.currentTrack)), () => ( this.cameraController.currentTrack));
|
|
7976
|
+
}
|
|
7977
|
+
/**
|
|
7978
|
+
* 创建前拒绝覆盖活动源,避免旧预览或连接资源被静默遗留。
|
|
7979
|
+
*/
|
|
7980
|
+
ensureNoLocalSource() {
|
|
7981
|
+
if (this.currentLocalTrack || this.localVideoController.isActive) {
|
|
7982
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Close the current local stream before creating another one");
|
|
7983
|
+
}
|
|
7984
|
+
}
|
|
7038
7985
|
/**
|
|
7039
7986
|
* 移除媒体权限弹窗观察;授权决定已记录或不再需要观察时调用。
|
|
7040
7987
|
*/
|
|
7041
7988
|
disposePermissionWatch() {
|
|
7042
|
-
_optionalChain([this, 'access',
|
|
7989
|
+
_optionalChain([this, 'access', _507 => _507.permissionWatchDispose, 'optionalCall', _508 => _508()]);
|
|
7043
7990
|
this.permissionWatchDispose = void 0;
|
|
7044
7991
|
}
|
|
7045
7992
|
/**
|
|
7046
7993
|
* 应用完整的上行视频格式,成功后更新本地轨道元数据,不改变生成格式或生命周期。
|
|
7047
7994
|
* 复用配置操作准入,避免与建连、切换摄像头或其他配置更新并发。
|
|
7048
7995
|
*
|
|
7049
|
-
* @throws
|
|
7996
|
+
* @throws 无本地相机或文件视频流、参数无效、操作冲突或底层编码更新失败时抛错。
|
|
7050
7997
|
*/
|
|
7051
7998
|
async updateVideoFormat(videoFormat) {
|
|
7052
7999
|
await this.coordinator.run("configuration" /* configuration */, void 0, async (token) => {
|
|
7053
|
-
const track = this.cameraController.currentTrack;
|
|
7054
|
-
const previousFormat = _optionalChain([track, 'optionalAccess',
|
|
8000
|
+
const track = _nullishCoalesce(this.localVideoController.currentTrack, () => ( this.cameraController.currentTrack));
|
|
8001
|
+
const previousFormat = _optionalChain([track, 'optionalAccess', _509 => _509.videoFormat]);
|
|
7055
8002
|
if (!track || !previousFormat) {
|
|
7056
|
-
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local camera stream is not started");
|
|
8003
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local camera or file video stream is not started");
|
|
7057
8004
|
}
|
|
7058
8005
|
videoFormat.validate();
|
|
7059
8006
|
await this.streamController.setVideoEncoderConfig(videoFormat);
|
|
@@ -7066,6 +8013,9 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7066
8013
|
* 停止本地相机流并释放本地预览与 RTC 资源。
|
|
7067
8014
|
*/
|
|
7068
8015
|
async stopLocalCameraStream() {
|
|
8016
|
+
if (this.networkVideoController.currentTrack || this.localVideoController.isActive) {
|
|
8017
|
+
return;
|
|
8018
|
+
}
|
|
7069
8019
|
await this.coordinator.run(
|
|
7070
8020
|
"media" /* media */,
|
|
7071
8021
|
void 0,
|
|
@@ -7106,11 +8056,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7106
8056
|
/**
|
|
7107
8057
|
* 使用当前 Manager 创建的本地流建立实时连接。
|
|
7108
8058
|
*
|
|
7109
|
-
* 创建实时会话、加入 RTC
|
|
8059
|
+
* 创建实时会话、加入 RTC 房间并启动会话心跳;摄像头源发布本地流,网络视频源仅接收。
|
|
7110
8060
|
* 启用帧检测时,发布前并行等待相机预热(固定 200ms),避免把黑帧推给 RTC。
|
|
7111
8061
|
* 返回的远端媒体流在生成开始后承载远端生成画面。
|
|
7112
8062
|
*
|
|
7113
|
-
* @param localStream
|
|
8063
|
+
* @param localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
|
|
7114
8064
|
* @returns 远端生成结果占位的媒体流。
|
|
7115
8065
|
* @throws 本地流不属于当前 Manager、已有活动连接、会话创建或进房
|
|
7116
8066
|
* 发布失败时抛出错误;失败时自动释放连接资源并恢复本地预览。
|
|
@@ -7137,7 +8087,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7137
8087
|
* 尚未连接时先建立实时连接;已在生成时仅更新生成条件,不重启生成。
|
|
7138
8088
|
* 首次生成必须提供条件上下文,之后缺省时复用最近一次缓存的上下文。
|
|
7139
8089
|
*
|
|
7140
|
-
* @param options.localStream
|
|
8090
|
+
* @param options.localStream 由当前 Manager 创建的摄像头、本地文件或网络视频源。
|
|
7141
8091
|
* @param options.context 本次生成使用的条件上下文;缺省时复用缓存。
|
|
7142
8092
|
* @returns 承载远端生成画面的媒体流。
|
|
7143
8093
|
* @throws 本地流不属于当前 Manager、缺少可用的条件上下文、信令发送
|
|
@@ -7149,7 +8099,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7149
8099
|
void 0,
|
|
7150
8100
|
async (token) => {
|
|
7151
8101
|
const localTrack = options.localStream.videoTrack;
|
|
7152
|
-
if (!localTrack || localTrack !== this.
|
|
8102
|
+
if (!localTrack || localTrack !== this.currentLocalTrack) {
|
|
7153
8103
|
throw new XmaxError(
|
|
7154
8104
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
7155
8105
|
"The local stream must be created and started by this realtime manager"
|
|
@@ -7171,7 +8121,12 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7171
8121
|
token.ensureCurrent();
|
|
7172
8122
|
return this.connectionManager.makeRemoteStream();
|
|
7173
8123
|
}
|
|
7174
|
-
const
|
|
8124
|
+
const supplied = this.generationManager.validateContext(options.context);
|
|
8125
|
+
const referenceVideo = this.networkVideoController.reference;
|
|
8126
|
+
if (!referenceVideo && supplied.referenceVideo) {
|
|
8127
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Create a network video stream before using a reference video");
|
|
8128
|
+
}
|
|
8129
|
+
const context = referenceVideo ? new RealtimeContext({ ...supplied, referenceVideo }) : supplied;
|
|
7175
8130
|
if (currentState.connectionState !== "Connected" /* connected */) {
|
|
7176
8131
|
await this.performConnect(options.localStream, token);
|
|
7177
8132
|
}
|
|
@@ -7183,6 +8138,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7183
8138
|
* 断开实时连接并保留当前本地媒体预览。
|
|
7184
8139
|
*/
|
|
7185
8140
|
async disconnect() {
|
|
8141
|
+
this.localVideoController.pause();
|
|
7186
8142
|
this.launchTimer.cancel();
|
|
7187
8143
|
this.clearVideoStatistics();
|
|
7188
8144
|
await this.coordinator.disconnect();
|
|
@@ -7192,6 +8148,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7192
8148
|
* 关闭期间重复调用会等待同一个释放任务;关闭完成后仍可重新创建本地流。
|
|
7193
8149
|
*/
|
|
7194
8150
|
async close() {
|
|
8151
|
+
this.localVideoController.pause();
|
|
7195
8152
|
this.launchTimer.cancel();
|
|
7196
8153
|
this.clearVideoStatistics();
|
|
7197
8154
|
await this.coordinator.terminate(1 /* all */);
|
|
@@ -7205,7 +8162,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7205
8162
|
*/
|
|
7206
8163
|
async performConnect(localStream, token) {
|
|
7207
8164
|
const localTrack = localStream.videoTrack;
|
|
7208
|
-
if (!localTrack || localTrack !== this.
|
|
8165
|
+
if (!localTrack || localTrack !== this.currentLocalTrack) {
|
|
7209
8166
|
throw new XmaxError(
|
|
7210
8167
|
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
7211
8168
|
"The local stream must be created and started by this realtime manager"
|
|
@@ -7223,7 +8180,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7223
8180
|
if (token.signal.aborted) abortWarmup();
|
|
7224
8181
|
try {
|
|
7225
8182
|
let beforePublish;
|
|
7226
|
-
if (this.cameraController.isFrameValidationEnabled) {
|
|
8183
|
+
if (!this.localVideoController.isActive && !this.networkVideoController.currentTrack && this.cameraController.isFrameValidationEnabled) {
|
|
7227
8184
|
const cameraReady = this.cameraController.waitForValidCameraFrame(warmupController.signal).then(() => {
|
|
7228
8185
|
token.ensureCurrent();
|
|
7229
8186
|
});
|
|
@@ -7235,7 +8192,8 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7235
8192
|
localTrack,
|
|
7236
8193
|
remoteVideoFormat: this.generationVideoFormat,
|
|
7237
8194
|
model: this.options.model,
|
|
7238
|
-
includeLocalAudio: this.cameraController.useMicrophone,
|
|
8195
|
+
includeLocalAudio: this.localVideoController.isActive ? this.localVideoController.audioTrack !== void 0 : !this.networkVideoController.currentTrack && this.cameraController.useMicrophone,
|
|
8196
|
+
publishLocalMedia: !this.networkVideoController.currentTrack,
|
|
7239
8197
|
ensureCurrent: () => token.ensureCurrent(),
|
|
7240
8198
|
onPublished: () => {
|
|
7241
8199
|
this.acceptsVideoStatistics = true;
|
|
@@ -7270,6 +8228,11 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7270
8228
|
context,
|
|
7271
8229
|
signal: token.signal,
|
|
7272
8230
|
ensureCurrent: () => token.ensureCurrent(),
|
|
8231
|
+
onStartSent: this.localVideoController.isActive ? async () => {
|
|
8232
|
+
token.ensureCurrent();
|
|
8233
|
+
await this.localVideoController.start(token.signal);
|
|
8234
|
+
token.ensureCurrent();
|
|
8235
|
+
} : void 0,
|
|
7273
8236
|
waitUntilRemoteReady: () => this.connectionManager.waitUntilRemoteTrackReady(
|
|
7274
8237
|
REMOTE_FIRST_FRAME_TIMEOUT_MS,
|
|
7275
8238
|
token.signal
|
|
@@ -7283,6 +8246,14 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7283
8246
|
new RealtimeState({ connectionState: "Generating" /* generating */, sessionID, taskID }),
|
|
7284
8247
|
token
|
|
7285
8248
|
);
|
|
8249
|
+
const onFinish = this.networkVideoController.onFinish;
|
|
8250
|
+
if (this.networkVideoController.currentTrack) {
|
|
8251
|
+
this.streamController.activateNetworkVideoCompletion(onFinish && (() => {
|
|
8252
|
+
if (this.currentState.taskID === taskID && this.currentState.connectionState === "Generating" /* generating */) {
|
|
8253
|
+
return onFinish();
|
|
8254
|
+
}
|
|
8255
|
+
}));
|
|
8256
|
+
}
|
|
7286
8257
|
return this.connectionManager.makeRemoteStream();
|
|
7287
8258
|
}
|
|
7288
8259
|
/**
|
|
@@ -7299,6 +8270,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7299
8270
|
* 统一清理顺序:停止心跳与生成,再断开连接;all 额外释放本地媒体。
|
|
7300
8271
|
*/
|
|
7301
8272
|
async performCleanup(scope, taskID) {
|
|
8273
|
+
this.localVideoController.pause();
|
|
7302
8274
|
this.launchTimer.cancel();
|
|
7303
8275
|
this.remoteFrameDisplayHandler = void 0;
|
|
7304
8276
|
this.clearVideoStatistics();
|
|
@@ -7309,20 +8281,30 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
7309
8281
|
await this.generationManager.reset(taskID);
|
|
7310
8282
|
const sessionID = await this.connectionManager.disconnect();
|
|
7311
8283
|
if (scope === 1 /* all */) {
|
|
8284
|
+
const hadFileSource = this.networkVideoController.currentTrack !== void 0 || this.localVideoController.isActive;
|
|
8285
|
+
this.networkVideoController.stop();
|
|
7312
8286
|
this.generationVideoFormat = void 0;
|
|
7313
8287
|
this.disposePermissionWatch();
|
|
7314
8288
|
try {
|
|
7315
|
-
|
|
8289
|
+
if (hadFileSource) {
|
|
8290
|
+
await this.rtcManager.destroy();
|
|
8291
|
+
} else {
|
|
8292
|
+
await this.cameraController.stopLocalCameraStream();
|
|
8293
|
+
}
|
|
7316
8294
|
} catch (error) {
|
|
7317
8295
|
XmaxLogger.realtime.error(
|
|
7318
|
-
() => `\
|
|
8296
|
+
() => `\u91CA\u653E\u672C\u5730\u5A92\u4F53\u5931\u8D25 (Failed to Release Local Media)
|
|
7319
8297
|
\u2514\u2500 ${XmaxLogger.localized("\u539F\u56E0\uFF1A", "Reason: ")}${XmaxError.from(error).message}`
|
|
7320
8298
|
);
|
|
8299
|
+
} finally {
|
|
8300
|
+
if (this.localVideoController.isActive) {
|
|
8301
|
+
await this.localVideoController.stop();
|
|
8302
|
+
}
|
|
7321
8303
|
}
|
|
7322
8304
|
}
|
|
7323
8305
|
return {
|
|
7324
8306
|
sessionID,
|
|
7325
|
-
hasLocalMedia: this.
|
|
8307
|
+
hasLocalMedia: this.currentLocalTrack !== void 0
|
|
7326
8308
|
};
|
|
7327
8309
|
}
|
|
7328
8310
|
/**
|
|
@@ -7384,6 +8366,405 @@ var XmaxConfiguration = class {
|
|
|
7384
8366
|
}
|
|
7385
8367
|
};
|
|
7386
8368
|
|
|
8369
|
+
// src/Service/NonRealtime/NonRealtimeTask.ts
|
|
8370
|
+
var NonRealtimeQuality = /* @__PURE__ */ ((NonRealtimeQuality2) => {
|
|
8371
|
+
NonRealtimeQuality2["sd"] = "sd";
|
|
8372
|
+
NonRealtimeQuality2["hd"] = "hd";
|
|
8373
|
+
return NonRealtimeQuality2;
|
|
8374
|
+
})(NonRealtimeQuality || {});
|
|
8375
|
+
var NonRealtimeTaskStatus = /* @__PURE__ */ ((NonRealtimeTaskStatus2) => {
|
|
8376
|
+
NonRealtimeTaskStatus2["submitted"] = "submitted";
|
|
8377
|
+
NonRealtimeTaskStatus2["processing"] = "processing";
|
|
8378
|
+
NonRealtimeTaskStatus2["completed"] = "completed";
|
|
8379
|
+
NonRealtimeTaskStatus2["error"] = "error";
|
|
8380
|
+
return NonRealtimeTaskStatus2;
|
|
8381
|
+
})(NonRealtimeTaskStatus || {});
|
|
8382
|
+
|
|
8383
|
+
// src/Service/NonRealtime/NonRealtimeTaskService.ts
|
|
8384
|
+
var SUPPORTED_FPS = /* @__PURE__ */ new Set([8, 10, 12, 15, 16, 18, 20, 22, 24, 25, 30, 45, 48, 50, 60, 72, 90, 100, 120]);
|
|
8385
|
+
var NonRealtimeTaskService = class {
|
|
8386
|
+
/**
|
|
8387
|
+
* 注入非实时任务使用的 API 服务。
|
|
8388
|
+
*/
|
|
8389
|
+
constructor(api) {
|
|
8390
|
+
/**
|
|
8391
|
+
* 网络依赖
|
|
8392
|
+
*/
|
|
8393
|
+
__publicField(this, "api");
|
|
8394
|
+
this.api = api;
|
|
8395
|
+
}
|
|
8396
|
+
/**
|
|
8397
|
+
* 提交一次任务;请求结果不确定时也不自动重试,以免重复扣费。
|
|
8398
|
+
*/
|
|
8399
|
+
async submitTask(options) {
|
|
8400
|
+
const model = _optionalChain([options, 'access', _510 => _510.model, 'optionalAccess', _511 => _511.trim, 'call', _512 => _512()]);
|
|
8401
|
+
if (!model) {
|
|
8402
|
+
invalid("Model must not be empty");
|
|
8403
|
+
}
|
|
8404
|
+
const prompt = options.prompt.trim();
|
|
8405
|
+
if (!prompt || [...prompt].length > 1024) {
|
|
8406
|
+
invalid("Prompt must contain 1\u20131024 characters");
|
|
8407
|
+
}
|
|
8408
|
+
validateURL(options.videoPath);
|
|
8409
|
+
if (options.referencePath !== void 0) {
|
|
8410
|
+
validateURL(options.referencePath);
|
|
8411
|
+
}
|
|
8412
|
+
if (!Object.values(NonRealtimeQuality).includes(options.quality)) {
|
|
8413
|
+
invalid("Quality must be sd or hd");
|
|
8414
|
+
}
|
|
8415
|
+
if (options.fps !== void 0 && !SUPPORTED_FPS.has(options.fps)) {
|
|
8416
|
+
invalid("Unsupported processing frame rate");
|
|
8417
|
+
}
|
|
8418
|
+
const payload = await this.api.post("/offline-task", {
|
|
8419
|
+
model,
|
|
8420
|
+
prompt,
|
|
8421
|
+
refVideoPath: options.videoPath.trim(),
|
|
8422
|
+
...options.referencePath === void 0 ? {} : { refImagePath: options.referencePath.trim() },
|
|
8423
|
+
quality: options.quality,
|
|
8424
|
+
...options.fps === void 0 ? {} : { fps: options.fps }
|
|
8425
|
+
});
|
|
8426
|
+
return parseTask(payload);
|
|
8427
|
+
}
|
|
8428
|
+
/**
|
|
8429
|
+
* 查询任务,校验返回 ID;signal 只取消本次 HTTP 查询,不取消服务端任务。
|
|
8430
|
+
*/
|
|
8431
|
+
async getTask(taskUid, signal) {
|
|
8432
|
+
const uid = validateTaskUid(taskUid);
|
|
8433
|
+
const task = parseTask(await this.api.get(`/offline-task/${encodeURIComponent(uid)}`, { signal }));
|
|
8434
|
+
if (task.uid !== uid) {
|
|
8435
|
+
malformed("Task UID does not match the request");
|
|
8436
|
+
}
|
|
8437
|
+
return task;
|
|
8438
|
+
}
|
|
8439
|
+
/**
|
|
8440
|
+
* 查询最多 100 个 ID,按首次出现顺序去重;任一任务不可用时整体失败。
|
|
8441
|
+
*/
|
|
8442
|
+
async getTasks(taskUids) {
|
|
8443
|
+
if (taskUids.length < 1 || taskUids.length > 100) {
|
|
8444
|
+
invalid("Provide 1\u2013100 task UIDs");
|
|
8445
|
+
}
|
|
8446
|
+
const uids = [...new Set(taskUids.map(validateTaskUid))];
|
|
8447
|
+
const payload = record(await this.api.post("/offline-task/batch-query", { taskUids: uids }));
|
|
8448
|
+
const tasks = parseList(payload.list);
|
|
8449
|
+
if (tasks.length !== uids.length || tasks.some((task, index) => task.uid !== uids[index])) {
|
|
8450
|
+
malformed("Batch response does not match the requested task UIDs");
|
|
8451
|
+
}
|
|
8452
|
+
return tasks;
|
|
8453
|
+
}
|
|
8454
|
+
/**
|
|
8455
|
+
* 分页查询任务,不隐式加载其他页。
|
|
8456
|
+
*/
|
|
8457
|
+
async listTasks(options = {}) {
|
|
8458
|
+
const pageNumber = _nullishCoalesce(options.pageNumber, () => ( 1));
|
|
8459
|
+
const pageSize = _nullishCoalesce(options.pageSize, () => ( 10));
|
|
8460
|
+
if (!Number.isSafeInteger(pageNumber) || pageNumber < 1) {
|
|
8461
|
+
invalid("Page number must be a positive integer");
|
|
8462
|
+
}
|
|
8463
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) {
|
|
8464
|
+
invalid("Page size must be between 1 and 100");
|
|
8465
|
+
}
|
|
8466
|
+
if (options.status !== void 0 && !Object.values(NonRealtimeTaskStatus).includes(options.status)) {
|
|
8467
|
+
invalid("Invalid task status");
|
|
8468
|
+
}
|
|
8469
|
+
const query = new URLSearchParams({ pageNumber: String(pageNumber), pageSize: String(pageSize) });
|
|
8470
|
+
if (options.status !== void 0) {
|
|
8471
|
+
query.set("status", options.status);
|
|
8472
|
+
}
|
|
8473
|
+
const payload = record(await this.api.get(`/offline-task/page?${query}`));
|
|
8474
|
+
return Object.freeze({
|
|
8475
|
+
pageNumber: pageInteger(payload, "pageNumber", 1),
|
|
8476
|
+
pageSize: pageInteger(payload, "pageSize", 1),
|
|
8477
|
+
total: pageInteger(payload, "total", 0),
|
|
8478
|
+
list: parseList(payload.list)
|
|
8479
|
+
});
|
|
8480
|
+
}
|
|
8481
|
+
};
|
|
8482
|
+
function validateTaskUid(value) {
|
|
8483
|
+
const uid = value.trim();
|
|
8484
|
+
if (!uid || uid === "." || uid === "..") {
|
|
8485
|
+
invalid("Task UID must not be empty or a relative path segment");
|
|
8486
|
+
}
|
|
8487
|
+
return uid;
|
|
8488
|
+
}
|
|
8489
|
+
function validateURL(value) {
|
|
8490
|
+
let url;
|
|
8491
|
+
try {
|
|
8492
|
+
url = new URL(value.trim());
|
|
8493
|
+
} catch (e28) {
|
|
8494
|
+
return invalid("Resource must be an uploaded HTTP(S) URL");
|
|
8495
|
+
}
|
|
8496
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password) {
|
|
8497
|
+
invalid("Resource must be an uploaded HTTP(S) URL");
|
|
8498
|
+
}
|
|
8499
|
+
}
|
|
8500
|
+
function invalid(message) {
|
|
8501
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, message);
|
|
8502
|
+
}
|
|
8503
|
+
function malformed(message = "Invalid non-realtime response data") {
|
|
8504
|
+
throw new XmaxError("API_ERROR" /* apiError */, message);
|
|
8505
|
+
}
|
|
8506
|
+
function record(value) {
|
|
8507
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
8508
|
+
malformed();
|
|
8509
|
+
}
|
|
8510
|
+
return value;
|
|
8511
|
+
}
|
|
8512
|
+
function field(data, key, type) {
|
|
8513
|
+
const value = data[key];
|
|
8514
|
+
if (value === void 0 || value === null) {
|
|
8515
|
+
return void 0;
|
|
8516
|
+
}
|
|
8517
|
+
if (typeof value !== type || typeof value === "number" && (!Number.isFinite(value) || value < 0)) {
|
|
8518
|
+
malformed(`Invalid field: ${key}`);
|
|
8519
|
+
}
|
|
8520
|
+
return value;
|
|
8521
|
+
}
|
|
8522
|
+
function pageInteger(data, key, minimum) {
|
|
8523
|
+
const value = field(data, key, "number");
|
|
8524
|
+
if (value === void 0 || !Number.isSafeInteger(value) || value < minimum) {
|
|
8525
|
+
malformed(`Invalid field: ${key}`);
|
|
8526
|
+
}
|
|
8527
|
+
return value;
|
|
8528
|
+
}
|
|
8529
|
+
function parseList(value) {
|
|
8530
|
+
if (!Array.isArray(value)) {
|
|
8531
|
+
malformed("Missing task list");
|
|
8532
|
+
}
|
|
8533
|
+
return Object.freeze(value.map(parseTask));
|
|
8534
|
+
}
|
|
8535
|
+
function parseTask(value) {
|
|
8536
|
+
const data = record(value);
|
|
8537
|
+
const uid = field(data, "uid", "string");
|
|
8538
|
+
const status = field(data, "status", "string");
|
|
8539
|
+
const quality = field(data, "quality", "string");
|
|
8540
|
+
if (!_optionalChain([uid, 'optionalAccess', _513 => _513.trim, 'call', _514 => _514()]) || !Object.values(NonRealtimeTaskStatus).includes(status)) {
|
|
8541
|
+
malformed("Missing task UID or invalid status");
|
|
8542
|
+
}
|
|
8543
|
+
if (quality !== void 0 && !Object.values(NonRealtimeQuality).includes(quality)) {
|
|
8544
|
+
malformed("Invalid task quality");
|
|
8545
|
+
}
|
|
8546
|
+
return Object.freeze({
|
|
8547
|
+
uid,
|
|
8548
|
+
status,
|
|
8549
|
+
quality,
|
|
8550
|
+
userUid: field(data, "userUid", "string"),
|
|
8551
|
+
prompt: field(data, "prompt", "string"),
|
|
8552
|
+
videoPath: field(data, "refVideoPath", "string"),
|
|
8553
|
+
referencePath: field(data, "refImagePath", "string"),
|
|
8554
|
+
processorId: field(data, "processorId", "string"),
|
|
8555
|
+
requestedFps: field(data, "requestedFps", "number"),
|
|
8556
|
+
resolvedFps: field(data, "resolvedFps", "number"),
|
|
8557
|
+
retryCount: field(data, "retryCount", "number"),
|
|
8558
|
+
videoDurationSeconds: field(data, "videoDurationSeconds", "number"),
|
|
8559
|
+
billableDurationSeconds: field(data, "billableDurationSeconds", "number"),
|
|
8560
|
+
chargePoints: field(data, "chargePoints", "number"),
|
|
8561
|
+
result: data.result == null ? void 0 : parseResult(data.result),
|
|
8562
|
+
processStartTime: field(data, "processStartTime", "string"),
|
|
8563
|
+
createTimestamp: field(data, "createTimestamp", "string"),
|
|
8564
|
+
updateTimestamp: field(data, "updateTimestamp", "string")
|
|
8565
|
+
});
|
|
8566
|
+
}
|
|
8567
|
+
function parseResult(value) {
|
|
8568
|
+
const data = record(value);
|
|
8569
|
+
return Object.freeze({
|
|
8570
|
+
url: field(data, "result_url", "string"),
|
|
8571
|
+
uploadError: field(data, "upload_error", "string"),
|
|
8572
|
+
uploadStatus: field(data, "upload_status", "string"),
|
|
8573
|
+
finalizeDurationMs: field(data, "finalize_duration_ms", "number"),
|
|
8574
|
+
compressionLevel: field(data, "compression_level", "string"),
|
|
8575
|
+
frameCount: field(data, "frame_count", "number"),
|
|
8576
|
+
fps: field(data, "fps", "number"),
|
|
8577
|
+
durationMs: field(data, "result_duration_ms", "number"),
|
|
8578
|
+
fileSizeBytes: field(data, "file_size_bytes", "number"),
|
|
8579
|
+
droppedFrameCount: field(data, "dropped_frame_count", "number"),
|
|
8580
|
+
originalFileSizeBytes: field(data, "original_file_size_bytes", "number")
|
|
8581
|
+
});
|
|
8582
|
+
}
|
|
8583
|
+
|
|
8584
|
+
// src/Service/NonRealtime/NonRealtimeTaskError.ts
|
|
8585
|
+
var NonRealtimeTaskError = class extends XmaxError {
|
|
8586
|
+
/**
|
|
8587
|
+
* 使用 API 错误分类,不虚构服务端未返回的业务错误码。
|
|
8588
|
+
*/
|
|
8589
|
+
constructor(task, message) {
|
|
8590
|
+
super("API_ERROR" /* apiError */, message);
|
|
8591
|
+
/**
|
|
8592
|
+
* 失败上下文
|
|
8593
|
+
*/
|
|
8594
|
+
__publicField(this, "task");
|
|
8595
|
+
this.name = "NonRealtimeTaskError";
|
|
8596
|
+
this.task = task;
|
|
8597
|
+
}
|
|
8598
|
+
};
|
|
8599
|
+
|
|
8600
|
+
// src/Core/NonRealtime/XmaxNonRealtimeManager.ts
|
|
8601
|
+
var XmaxNonRealtimeManager = class {
|
|
8602
|
+
/**
|
|
8603
|
+
* 注入非实时任务服务。
|
|
8604
|
+
*/
|
|
8605
|
+
constructor(tasks) {
|
|
8606
|
+
/**
|
|
8607
|
+
* 服务层组件
|
|
8608
|
+
*/
|
|
8609
|
+
__publicField(this, "tasks");
|
|
8610
|
+
this.tasks = tasks;
|
|
8611
|
+
}
|
|
8612
|
+
/**
|
|
8613
|
+
* 单次提交任务,不自动重试可能已扣费的请求。
|
|
8614
|
+
*/
|
|
8615
|
+
submitTask(options) {
|
|
8616
|
+
return this.tasks.submitTask(options);
|
|
8617
|
+
}
|
|
8618
|
+
/**
|
|
8619
|
+
* 取得任务快照,不把服务端失败终态当成查询失败。
|
|
8620
|
+
*/
|
|
8621
|
+
getTask(taskUid, options) {
|
|
8622
|
+
return this.tasks.getTask(taskUid, _optionalChain([options, 'optionalAccess', _515 => _515.signal]));
|
|
8623
|
+
}
|
|
8624
|
+
/**
|
|
8625
|
+
* 批量取得任务快照。
|
|
8626
|
+
*/
|
|
8627
|
+
getTasks(taskUids) {
|
|
8628
|
+
return this.tasks.getTasks(taskUids);
|
|
8629
|
+
}
|
|
8630
|
+
/**
|
|
8631
|
+
* 分页取得任务列表。
|
|
8632
|
+
*/
|
|
8633
|
+
listTasks(options) {
|
|
8634
|
+
return this.tasks.listTasks(options);
|
|
8635
|
+
}
|
|
8636
|
+
/**
|
|
8637
|
+
* 等待任务完成;查询串行执行,瞬时错误有限退避,取消与总超时覆盖请求及等待阶段。
|
|
8638
|
+
*/
|
|
8639
|
+
async waitForCompletion(taskUid, options = {}) {
|
|
8640
|
+
const uid = validateTaskUid(taskUid);
|
|
8641
|
+
const interval = _nullishCoalesce(options.intervalMs, () => ( 2e3));
|
|
8642
|
+
const retries = _nullishCoalesce(options.maxConsecutiveRetries, () => ( 3));
|
|
8643
|
+
validateDelay(interval);
|
|
8644
|
+
if (options.timeoutMs !== void 0) {
|
|
8645
|
+
validateDelay(options.timeoutMs);
|
|
8646
|
+
}
|
|
8647
|
+
if (!Number.isSafeInteger(retries) || retries < 0) {
|
|
8648
|
+
throw new XmaxError(
|
|
8649
|
+
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
8650
|
+
"Retry count must be a non-negative integer"
|
|
8651
|
+
);
|
|
8652
|
+
}
|
|
8653
|
+
const controller = new AbortController();
|
|
8654
|
+
let timedOut = false;
|
|
8655
|
+
const abort = () => controller.abort();
|
|
8656
|
+
_optionalChain([options, 'access', _516 => _516.signal, 'optionalAccess', _517 => _517.addEventListener, 'call', _518 => _518("abort", abort, { once: true })]);
|
|
8657
|
+
if (_optionalChain([options, 'access', _519 => _519.signal, 'optionalAccess', _520 => _520.aborted])) {
|
|
8658
|
+
abort();
|
|
8659
|
+
}
|
|
8660
|
+
const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
8661
|
+
timedOut = true;
|
|
8662
|
+
abort();
|
|
8663
|
+
}, options.timeoutMs);
|
|
8664
|
+
let failures = 0;
|
|
8665
|
+
try {
|
|
8666
|
+
for (; ; ) {
|
|
8667
|
+
ensureActive(controller.signal);
|
|
8668
|
+
let task;
|
|
8669
|
+
try {
|
|
8670
|
+
task = await this.tasks.getTask(uid, controller.signal);
|
|
8671
|
+
} catch (error) {
|
|
8672
|
+
ensureActive(controller.signal);
|
|
8673
|
+
if (!isTransient(error) || failures >= retries) {
|
|
8674
|
+
throw error;
|
|
8675
|
+
}
|
|
8676
|
+
failures++;
|
|
8677
|
+
await delay(Math.min(interval * 2 ** (failures - 1), 3e4), controller.signal);
|
|
8678
|
+
continue;
|
|
8679
|
+
}
|
|
8680
|
+
ensureActive(controller.signal);
|
|
8681
|
+
failures = 0;
|
|
8682
|
+
try {
|
|
8683
|
+
void Promise.resolve(_optionalChain([options, 'access', _521 => _521.onTaskUpdated, 'optionalCall', _522 => _522(task)])).catch(() => {
|
|
8684
|
+
});
|
|
8685
|
+
} catch (e29) {
|
|
8686
|
+
}
|
|
8687
|
+
ensureActive(controller.signal);
|
|
8688
|
+
if (task.status === "error" /* error */) {
|
|
8689
|
+
throw new NonRealtimeTaskError(task, `Non-realtime task ${uid} failed`);
|
|
8690
|
+
}
|
|
8691
|
+
if (task.status === "completed" /* completed */) {
|
|
8692
|
+
if (!isResultAvailable(task)) {
|
|
8693
|
+
throw new NonRealtimeTaskError(
|
|
8694
|
+
task,
|
|
8695
|
+
`Non-realtime task ${uid} completed without a usable result`
|
|
8696
|
+
);
|
|
8697
|
+
}
|
|
8698
|
+
return task;
|
|
8699
|
+
}
|
|
8700
|
+
await delay(interval, controller.signal);
|
|
8701
|
+
}
|
|
8702
|
+
} catch (error) {
|
|
8703
|
+
if (timedOut) {
|
|
8704
|
+
throw new XmaxError(
|
|
8705
|
+
"TIMEOUT" /* timeout */,
|
|
8706
|
+
`Waiting for task ${uid} timed out; the server task was not cancelled`
|
|
8707
|
+
);
|
|
8708
|
+
}
|
|
8709
|
+
ensureActive(controller.signal);
|
|
8710
|
+
throw error;
|
|
8711
|
+
} finally {
|
|
8712
|
+
clearTimeout(timer);
|
|
8713
|
+
_optionalChain([options, 'access', _523 => _523.signal, 'optionalAccess', _524 => _524.removeEventListener, 'call', _525 => _525("abort", abort)]);
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
};
|
|
8717
|
+
function validateDelay(value) {
|
|
8718
|
+
if (!Number.isFinite(value) || value <= 0 || value > 2147483647) {
|
|
8719
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Polling durations must be positive and within the timer range");
|
|
8720
|
+
}
|
|
8721
|
+
}
|
|
8722
|
+
function ensureActive(signal) {
|
|
8723
|
+
if (signal.aborted) {
|
|
8724
|
+
throw new XmaxError(
|
|
8725
|
+
"CANCELLED" /* cancelled */,
|
|
8726
|
+
"Task wait was cancelled locally; the server task was not cancelled"
|
|
8727
|
+
);
|
|
8728
|
+
}
|
|
8729
|
+
}
|
|
8730
|
+
function delay(ms, signal) {
|
|
8731
|
+
return new Promise((resolve, reject) => {
|
|
8732
|
+
const finish = () => {
|
|
8733
|
+
clearTimeout(timer);
|
|
8734
|
+
signal.removeEventListener("abort", finish);
|
|
8735
|
+
try {
|
|
8736
|
+
ensureActive(signal);
|
|
8737
|
+
resolve();
|
|
8738
|
+
} catch (error) {
|
|
8739
|
+
reject(error);
|
|
8740
|
+
}
|
|
8741
|
+
};
|
|
8742
|
+
const timer = setTimeout(finish, ms);
|
|
8743
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
8744
|
+
if (signal.aborted) {
|
|
8745
|
+
finish();
|
|
8746
|
+
}
|
|
8747
|
+
});
|
|
8748
|
+
}
|
|
8749
|
+
function isTransient(error) {
|
|
8750
|
+
if (!(error instanceof XmaxError)) {
|
|
8751
|
+
return false;
|
|
8752
|
+
}
|
|
8753
|
+
return error.code === "NETWORK_ERROR" /* networkError */ || error.code === "TIMEOUT" /* timeout */ || error.code === "API_ERROR" /* apiError */ && (_nullishCoalesce(error.httpStatus, () => ( 0))) >= 500 && (error.apiCode === void 0 || error.apiCode === error.httpStatus);
|
|
8754
|
+
}
|
|
8755
|
+
function isResultAvailable(task) {
|
|
8756
|
+
const result = task.result;
|
|
8757
|
+
if (!_optionalChain([result, 'optionalAccess', _526 => _526.url, 'optionalAccess', _527 => _527.trim, 'call', _528 => _528()]) || _optionalChain([result, 'access', _529 => _529.uploadError, 'optionalAccess', _530 => _530.trim, 'call', _531 => _531()]) || result.uploadStatus !== void 0 && result.uploadStatus !== "success") {
|
|
8758
|
+
return false;
|
|
8759
|
+
}
|
|
8760
|
+
try {
|
|
8761
|
+
const url = new URL(result.url);
|
|
8762
|
+
return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password;
|
|
8763
|
+
} catch (e30) {
|
|
8764
|
+
return false;
|
|
8765
|
+
}
|
|
8766
|
+
}
|
|
8767
|
+
|
|
7387
8768
|
// src/Core/XmaxClient.ts
|
|
7388
8769
|
var XmaxClient = class {
|
|
7389
8770
|
/**
|
|
@@ -7429,6 +8810,17 @@ var XmaxClient = class {
|
|
|
7429
8810
|
environment: this.configuration.environment
|
|
7430
8811
|
});
|
|
7431
8812
|
}
|
|
8813
|
+
/**
|
|
8814
|
+
* 创建非实时视频任务 Manager,使用全局 API Key 和当前环境的非实时任务服务地址。
|
|
8815
|
+
* 本方法不发起网络请求或加载 RTC,任务由服务端持久化,可按 ID 恢复查询。
|
|
8816
|
+
*/
|
|
8817
|
+
createNonRealtimeManager() {
|
|
8818
|
+
const apiService = new ApiService({
|
|
8819
|
+
apiKey: this.configuration.apiKey,
|
|
8820
|
+
baseURL: nonRealtimeApiBaseURL(this.configuration.environment)
|
|
8821
|
+
});
|
|
8822
|
+
return new XmaxNonRealtimeManager(new NonRealtimeTaskService(apiService));
|
|
8823
|
+
}
|
|
7432
8824
|
/**
|
|
7433
8825
|
* 创建媒体处理与能力查询 Service。
|
|
7434
8826
|
*
|
|
@@ -7440,7 +8832,7 @@ var XmaxClient = class {
|
|
|
7440
8832
|
/**
|
|
7441
8833
|
* 创建文件存储 Service。
|
|
7442
8834
|
*
|
|
7443
|
-
* @returns
|
|
8835
|
+
* @returns 可上传图片和视频到对象存储的存储 Service。
|
|
7444
8836
|
*/
|
|
7445
8837
|
createStorageService() {
|
|
7446
8838
|
return new StorageService({ apiService: this.apiService });
|
|
@@ -7452,45 +8844,36 @@ var RealtimeConfiguration = class {
|
|
|
7452
8844
|
/**
|
|
7453
8845
|
* 创建实时业务配置。
|
|
7454
8846
|
*
|
|
7455
|
-
* @param init.model
|
|
7456
|
-
* @param init.provider RTC
|
|
7457
|
-
* @param init.isFrameInterpolationEnabled
|
|
7458
|
-
* @param init.frameInterpolation 插帧开关和显示帧率上限的详细配置。
|
|
8847
|
+
* @param init.model 实时生成业务使用的模型;未知名称原样透传,默认配置同 x2.1-preview。
|
|
8848
|
+
* @param init.provider RTC 提供方,默认按模型定义选择;必须受模型支持,创建后不可切换。
|
|
8849
|
+
* @param init.isFrameInterpolationEnabled 是否默认开启远端生成画面的插帧,默认 false。
|
|
7459
8850
|
*/
|
|
7460
8851
|
constructor(init) {
|
|
7461
|
-
/**
|
|
7462
|
-
* RTC 配置
|
|
7463
|
-
*/
|
|
7464
|
-
__publicField(this, "provider");
|
|
7465
|
-
/**
|
|
7466
|
-
* 模型配置
|
|
7467
|
-
*/
|
|
7468
8852
|
/**
|
|
7469
8853
|
* 实时生成业务使用的模型。
|
|
7470
8854
|
*/
|
|
7471
8855
|
__publicField(this, "model");
|
|
7472
8856
|
/**
|
|
7473
|
-
*
|
|
8857
|
+
* 实时连接使用的 RTC 提供方。
|
|
7474
8858
|
*/
|
|
8859
|
+
__publicField(this, "provider");
|
|
7475
8860
|
/**
|
|
7476
8861
|
* 是否默认请求开启远端生成画面的插帧。
|
|
7477
8862
|
*/
|
|
7478
8863
|
__publicField(this, "isFrameInterpolationEnabled");
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
*/
|
|
7482
|
-
__publicField(this, "frameInterpolation");
|
|
7483
|
-
this.provider = _nullishCoalesce(init.provider, () => ( "trtc")) /* trtc */;
|
|
8864
|
+
const providers = supportedRtcProviders(init.model);
|
|
8865
|
+
this.provider = _nullishCoalesce(init.provider, () => ( providers[0]));
|
|
7484
8866
|
if (!Object.values(RtcProvider).includes(this.provider)) {
|
|
7485
8867
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Unsupported RTC provider");
|
|
7486
8868
|
}
|
|
7487
|
-
this.
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
8869
|
+
if (!providers.includes(this.provider)) {
|
|
8870
|
+
throw new XmaxError(
|
|
8871
|
+
"INVALID_CONFIGURATION" /* invalidConfiguration */,
|
|
8872
|
+
`Model ${init.model} does not support RTC provider ${this.provider}`
|
|
8873
|
+
);
|
|
7491
8874
|
}
|
|
7492
|
-
this.
|
|
7493
|
-
this.
|
|
8875
|
+
this.model = init.model;
|
|
8876
|
+
this.isFrameInterpolationEnabled = _nullishCoalesce(init.isFrameInterpolationEnabled, () => ( false));
|
|
7494
8877
|
}
|
|
7495
8878
|
};
|
|
7496
8879
|
|
|
@@ -7501,29 +8884,6 @@ var VideoContentMode = /* @__PURE__ */ ((VideoContentMode2) => {
|
|
|
7501
8884
|
return VideoContentMode2;
|
|
7502
8885
|
})(VideoContentMode || {});
|
|
7503
8886
|
|
|
7504
|
-
// src/Service/Realtime/RealtimeContext.ts
|
|
7505
|
-
var RealtimeContext = class {
|
|
7506
|
-
/**
|
|
7507
|
-
* 创建实时生成条件并规范化文本和参考路径。
|
|
7508
|
-
*/
|
|
7509
|
-
constructor(init) {
|
|
7510
|
-
/**
|
|
7511
|
-
* 生成条件
|
|
7512
|
-
*/
|
|
7513
|
-
/**
|
|
7514
|
-
* 实时生成使用的文本条件。
|
|
7515
|
-
*/
|
|
7516
|
-
__publicField(this, "prompt");
|
|
7517
|
-
/**
|
|
7518
|
-
* 已上传参考图片的可选远端路径。
|
|
7519
|
-
*/
|
|
7520
|
-
__publicField(this, "referencePath");
|
|
7521
|
-
this.prompt = init.prompt.trim();
|
|
7522
|
-
const normalizedReferencePath = _optionalChain([init, 'access', _380 => _380.referencePath, 'optionalAccess', _381 => _381.trim, 'call', _382 => _382()]);
|
|
7523
|
-
this.referencePath = normalizedReferencePath || void 0;
|
|
7524
|
-
}
|
|
7525
|
-
};
|
|
7526
|
-
|
|
7527
8887
|
// ../../node_modules/.pnpm/framegen@1.4.0/node_modules/framegen/rt.js
|
|
7528
8888
|
var WG = 8;
|
|
7529
8889
|
var texBgSeq = 0;
|
|
@@ -9516,11 +10876,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
9516
10876
|
});
|
|
9517
10877
|
}
|
|
9518
10878
|
static async create(canvas, size, onFailure, signal) {
|
|
9519
|
-
const
|
|
10879
|
+
const ensureActive2 = () => {
|
|
9520
10880
|
if (signal.aborted) throw new XmaxError("CANCELLED" /* cancelled */, "Interpolation initialization cancelled");
|
|
9521
10881
|
};
|
|
9522
10882
|
const adapter = await frameInterpolationAdapter(size);
|
|
9523
|
-
|
|
10883
|
+
ensureActive2();
|
|
9524
10884
|
if (!adapter) throw new XmaxError("FRAME_INTERPOLATION_UNSUPPORTED" /* frameInterpolationUnsupported */, "WebGPU shader-f16 is unavailable");
|
|
9525
10885
|
const device = await adapter.requestDevice({ requiredFeatures: ["shader-f16"] });
|
|
9526
10886
|
const manager = new _FrameInterpolationManager(device, canvas, size, onFailure);
|
|
@@ -9531,9 +10891,9 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
9531
10891
|
if (!manager.destroyed) onFailure(new Error(`Interpolation GPU device lost: ${info.message}`));
|
|
9532
10892
|
});
|
|
9533
10893
|
try {
|
|
9534
|
-
|
|
10894
|
+
ensureActive2();
|
|
9535
10895
|
await manager.initialize();
|
|
9536
|
-
|
|
10896
|
+
ensureActive2();
|
|
9537
10897
|
return manager;
|
|
9538
10898
|
} catch (error) {
|
|
9539
10899
|
manager.destroy();
|
|
@@ -9646,11 +11006,11 @@ var _FrameInterpolationManager = class _FrameInterpolationManager {
|
|
|
9646
11006
|
if (this.destroyed) return;
|
|
9647
11007
|
this.destroyed = true;
|
|
9648
11008
|
this.device.removeEventListener("uncapturederror", this.onGPUError);
|
|
9649
|
-
_optionalChain([this, 'access',
|
|
11009
|
+
_optionalChain([this, 'access', _532 => _532.runtime, 'optionalAccess', _533 => _533.destroy, 'call', _534 => _534()]);
|
|
9650
11010
|
this.runtime = void 0;
|
|
9651
11011
|
this.textures.forEach((texture) => texture.destroy());
|
|
9652
11012
|
this.textures = [];
|
|
9653
|
-
_optionalChain([this, 'access',
|
|
11013
|
+
_optionalChain([this, 'access', _535 => _535.context, 'optionalAccess', _536 => _536.unconfigure, 'call', _537 => _537()]);
|
|
9654
11014
|
this.device.destroy();
|
|
9655
11015
|
}
|
|
9656
11016
|
};
|
|
@@ -9659,6 +11019,7 @@ __publicField(_FrameInterpolationManager, "originalSlots", 3);
|
|
|
9659
11019
|
var FrameInterpolationManager = _FrameInterpolationManager;
|
|
9660
11020
|
|
|
9661
11021
|
// src/Render/Video/RemoteVideoFramePipeline.ts
|
|
11022
|
+
var INTERPOLATION_FRAME_RATE = 60;
|
|
9662
11023
|
var RemoteVideoFramePipeline = class {
|
|
9663
11024
|
constructor(video, canvas, options, createProcessor = FrameInterpolationManager.create) {
|
|
9664
11025
|
__publicField(this, "video", video);
|
|
@@ -9753,7 +11114,9 @@ var RemoteVideoFramePipeline = class {
|
|
|
9753
11114
|
this.delay = interval;
|
|
9754
11115
|
this.enqueue({ slot, time });
|
|
9755
11116
|
this.startTick();
|
|
9756
|
-
if (!consecutive || interval < 2e3 /
|
|
11117
|
+
if (!consecutive || interval < 2e3 / INTERPOLATION_FRAME_RATE - 1 || previousSlot === void 0 || this.busy) {
|
|
11118
|
+
return;
|
|
11119
|
+
}
|
|
9757
11120
|
this.interpolate(previousSlot, slot, previous, time, interval);
|
|
9758
11121
|
}
|
|
9759
11122
|
/** 帧按显示时间升序入队;同一时间的内容后到先出。 */
|
|
@@ -9829,7 +11192,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
9829
11192
|
setActive(active) {
|
|
9830
11193
|
if (active === this.active) return;
|
|
9831
11194
|
this.active = active;
|
|
9832
|
-
_optionalChain([this, 'access',
|
|
11195
|
+
_optionalChain([this, 'access', _538 => _538.options, 'access', _539 => _539.onActiveChange, 'optionalCall', _540 => _540(active)]);
|
|
9833
11196
|
}
|
|
9834
11197
|
resetTimeline() {
|
|
9835
11198
|
this.generation++;
|
|
@@ -9860,7 +11223,7 @@ var RemoteVideoFramePipeline = class {
|
|
|
9860
11223
|
this.callback = void 0;
|
|
9861
11224
|
clearTimeout(this.initializationTimer);
|
|
9862
11225
|
this.resetTimeline();
|
|
9863
|
-
_optionalChain([this, 'access',
|
|
11226
|
+
_optionalChain([this, 'access', _541 => _541.processor, 'optionalAccess', _542 => _542.destroy, 'call', _543 => _543()]);
|
|
9864
11227
|
this.processor = void 0;
|
|
9865
11228
|
}
|
|
9866
11229
|
};
|
|
@@ -9918,7 +11281,7 @@ var XmaxVideoView = class {
|
|
|
9918
11281
|
* DOM 挂载状态
|
|
9919
11282
|
*/
|
|
9920
11283
|
__publicField(this, "detached", false);
|
|
9921
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11284
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _544 => _544.videoContentMode]), () => ( "fill")) /* fill */;
|
|
9922
11285
|
this.element = document.createElement("div");
|
|
9923
11286
|
this.element.style.position = "relative";
|
|
9924
11287
|
this.element.style.overflow = "hidden";
|
|
@@ -9992,14 +11355,14 @@ var XmaxVideoView = class {
|
|
|
9992
11355
|
attach(to) {
|
|
9993
11356
|
this.detached = false;
|
|
9994
11357
|
to.appendChild(this.element);
|
|
9995
|
-
if (this.videoElement.srcObject && this.videoElement.paused && typeof this.videoElement.play === "function") {
|
|
11358
|
+
if ((this.videoElement.srcObject || this.videoElement.getAttribute("src")) && this.videoElement.autoplay && !this.videoElement.ended && this.videoElement.paused && typeof this.videoElement.play === "function") {
|
|
9996
11359
|
void this.videoElement.play().catch((error) => {
|
|
9997
11360
|
XmaxLogger.render.warning(() => `\u6062\u590D\u89C6\u9891\u64AD\u653E\u5931\u8D25 (Failed to Resume Video Playback)
|
|
9998
11361
|
\u2514\u2500 ${String(error)}`);
|
|
9999
11362
|
});
|
|
10000
11363
|
}
|
|
10001
11364
|
this.startInterpolation();
|
|
10002
|
-
if (this.videoElement.srcObject && !this.hasNotifiedFrameDisplay) {
|
|
11365
|
+
if ((this.videoElement.srcObject || this.videoElement.getAttribute("src")) && !this.hasNotifiedFrameDisplay) {
|
|
10003
11366
|
this.armFrameDisplayNotification();
|
|
10004
11367
|
}
|
|
10005
11368
|
}
|
|
@@ -10010,8 +11373,29 @@ var XmaxVideoView = class {
|
|
|
10010
11373
|
this.detached = true;
|
|
10011
11374
|
this.stopInterpolation();
|
|
10012
11375
|
this.cancelFrameDisplayNotification();
|
|
11376
|
+
if (this.videoElement.getAttribute("src")) {
|
|
11377
|
+
this.videoElement.pause();
|
|
11378
|
+
}
|
|
10013
11379
|
this.element.remove();
|
|
10014
11380
|
}
|
|
11381
|
+
/**
|
|
11382
|
+
* 设置网络视频预览;静音播放一次,不捕获或发布媒体轨道。 @internal
|
|
11383
|
+
*/
|
|
11384
|
+
setVideoURL(url) {
|
|
11385
|
+
this.stopInterpolation();
|
|
11386
|
+
this.cancelFrameDisplayNotification();
|
|
11387
|
+
this.hasNotifiedFrameDisplay = false;
|
|
11388
|
+
this.videoElement.pause();
|
|
11389
|
+
this.videoElement.srcObject = null;
|
|
11390
|
+
this.videoElement.removeAttribute("src");
|
|
11391
|
+
this.videoElement.muted = true;
|
|
11392
|
+
this.videoElement.loop = false;
|
|
11393
|
+
if (url) {
|
|
11394
|
+
this.videoElement.src = url;
|
|
11395
|
+
this.armFrameDisplayNotification();
|
|
11396
|
+
}
|
|
11397
|
+
this.videoElement.load();
|
|
11398
|
+
}
|
|
10015
11399
|
/**
|
|
10016
11400
|
* 直接设置渲染用的媒体流(绑定管线和直接渲染共用)。 @internal
|
|
10017
11401
|
*/
|
|
@@ -10024,6 +11408,7 @@ var XmaxVideoView = class {
|
|
|
10024
11408
|
this.hasNotifiedFrameDisplay = false;
|
|
10025
11409
|
this.videoElement.srcObject = stream;
|
|
10026
11410
|
if (stream) {
|
|
11411
|
+
this.videoElement.autoplay = true;
|
|
10027
11412
|
this.armFrameDisplayNotification();
|
|
10028
11413
|
this.startInterpolation();
|
|
10029
11414
|
}
|
|
@@ -10065,8 +11450,8 @@ var XmaxVideoView = class {
|
|
|
10065
11450
|
stopInterpolation() {
|
|
10066
11451
|
const pipeline = this.interpolationPipeline;
|
|
10067
11452
|
this.interpolationPipeline = void 0;
|
|
10068
|
-
_optionalChain([pipeline, 'optionalAccess',
|
|
10069
|
-
_optionalChain([this, 'access',
|
|
11453
|
+
_optionalChain([pipeline, 'optionalAccess', _545 => _545.stop, 'call', _546 => _546()]);
|
|
11454
|
+
_optionalChain([this, 'access', _547 => _547.interpolationCanvas, 'optionalAccess', _548 => _548.remove, 'call', _549 => _549()]);
|
|
10070
11455
|
this.interpolationCanvas = void 0;
|
|
10071
11456
|
}
|
|
10072
11457
|
/**
|
|
@@ -10092,11 +11477,14 @@ var XmaxVideoView = class {
|
|
|
10092
11477
|
detachCurrentTrack() {
|
|
10093
11478
|
const track = this.currentTrack;
|
|
10094
11479
|
if (track) {
|
|
10095
|
-
_optionalChain([VideoRenderRegistry, 'access',
|
|
11480
|
+
_optionalChain([VideoRenderRegistry, 'access', _550 => _550.binding, 'call', _551 => _551(track), 'optionalAccess', _552 => _552.detachHandler, 'call', _553 => _553(this)]);
|
|
10096
11481
|
}
|
|
10097
11482
|
this.setFrameInterpolation(void 0);
|
|
10098
11483
|
this.cancelFrameDisplayNotification();
|
|
10099
11484
|
this.videoElement.srcObject = null;
|
|
11485
|
+
if (this.videoElement.getAttribute("src")) {
|
|
11486
|
+
this.setVideoURL(null);
|
|
11487
|
+
}
|
|
10100
11488
|
}
|
|
10101
11489
|
/**
|
|
10102
11490
|
* 首帧提交合成器时通知;旧浏览器回退到 playing 近似判断。
|
|
@@ -10112,8 +11500,8 @@ var XmaxVideoView = class {
|
|
|
10112
11500
|
}
|
|
10113
11501
|
this.hasNotifiedFrameDisplay = true;
|
|
10114
11502
|
this.cancelFrameDisplayNotification();
|
|
10115
|
-
_optionalChain([binding, 'optionalAccess',
|
|
10116
|
-
_optionalChain([this, 'access',
|
|
11503
|
+
_optionalChain([binding, 'optionalAccess', _554 => _554.frameDisplayHandler, 'optionalCall', _555 => _555()]);
|
|
11504
|
+
_optionalChain([this, 'access', _556 => _556.frameDisplayHandler, 'optionalCall', _557 => _557()]);
|
|
10117
11505
|
};
|
|
10118
11506
|
if (typeof this.videoElement.requestVideoFrameCallback === "function") {
|
|
10119
11507
|
this.videoFrameCallbackID = this.videoElement.requestVideoFrameCallback(notify);
|
|
@@ -10183,9 +11571,9 @@ var XmaxRealtimeVideoView = class {
|
|
|
10183
11571
|
__publicField(this, "currentLocalTrack");
|
|
10184
11572
|
__publicField(this, "currentRemoteTrack");
|
|
10185
11573
|
__publicField(this, "contentMode");
|
|
10186
|
-
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
10187
|
-
this.currentLocalTrack = _optionalChain([options, 'optionalAccess',
|
|
10188
|
-
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess',
|
|
11574
|
+
this.contentMode = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _558 => _558.videoContentMode]), () => ( "fill")) /* fill */;
|
|
11575
|
+
this.currentLocalTrack = _optionalChain([options, 'optionalAccess', _559 => _559.localTrack]);
|
|
11576
|
+
this.currentRemoteTrack = _optionalChain([options, 'optionalAccess', _560 => _560.remoteTrack]);
|
|
10189
11577
|
this.element = document.createElement("div");
|
|
10190
11578
|
this.element.style.position = "relative";
|
|
10191
11579
|
this.element.style.overflow = "hidden";
|
|
@@ -10344,5 +11732,11 @@ var XmaxRealtimeVideoView = class {
|
|
|
10344
11732
|
|
|
10345
11733
|
|
|
10346
11734
|
|
|
10347
|
-
|
|
10348
|
-
|
|
11735
|
+
|
|
11736
|
+
|
|
11737
|
+
|
|
11738
|
+
|
|
11739
|
+
|
|
11740
|
+
|
|
11741
|
+
exports.XmaxEnvironment = XmaxEnvironment; exports.apiBaseURL = apiBaseURL; exports.XmaxLoggerOption = XmaxLoggerOption; exports.XmaxLogger = XmaxLogger; exports.XmaxErrorCode = XmaxErrorCode; exports.XmaxError = XmaxError; exports.RealtimeVideoEncoderPreference = RealtimeVideoEncoderPreference; exports.RealtimeVideoFormat = RealtimeVideoFormat; exports.RtcProvider = RtcProvider; exports.RealtimeModel = RealtimeModel; exports.modelDisplayName = modelDisplayName; exports.defaultFrameRate = defaultFrameRate; exports.defaultCameraVideoFormat = defaultCameraVideoFormat; exports.supportedRtcProviders = supportedRtcProviders; exports.MediaService = MediaService; exports.StoredFile = StoredFile; exports.StorageService = StorageService; exports.CameraPosition = CameraPosition; exports.RealtimeVideoTrack = RealtimeVideoTrack; exports.RealtimeMediaStream = RealtimeMediaStream; exports.RealtimeVideoSampleMethod = RealtimeVideoSampleMethod; exports.RealtimeContext = RealtimeContext; exports.RealtimeConnectionState = RealtimeConnectionState; exports.RealtimeReason = RealtimeReason; exports.RealtimeState = RealtimeState; exports.XmaxConfiguration = XmaxConfiguration; exports.NonRealtimeQuality = NonRealtimeQuality; exports.NonRealtimeTaskStatus = NonRealtimeTaskStatus; exports.NonRealtimeTaskError = NonRealtimeTaskError; exports.XmaxClient = XmaxClient; exports.RealtimeConfiguration = RealtimeConfiguration; exports.VideoContentMode = VideoContentMode; exports.XmaxVideoView = XmaxVideoView; exports.XmaxRealtimeVideoView = XmaxRealtimeVideoView;
|
|
11742
|
+
//# sourceMappingURL=chunk-JN6HURTT.cjs.map
|