@xmaxai/sdk 1.0.0 → 1.0.2
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/CHANGELOG.md +10 -2
- package/README.md +9 -5
- package/dist/{chunk-M5QA6LWS.js → chunk-F567ONBH.js} +32 -190
- package/dist/chunk-F567ONBH.js.map +1 -0
- package/dist/{chunk-PLU2YVAS.js → chunk-TFGYBN3Q.js} +493 -136
- package/dist/chunk-TFGYBN3Q.js.map +1 -0
- package/dist/index.cjs +76 -294
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +376 -10
- package/dist/index.d.ts +376 -10
- package/dist/index.js +1003 -9
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +34 -277
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -3
- package/dist/react/index.d.ts +1 -3
- package/dist/react/index.js +6 -26
- package/dist/react/index.js.map +1 -1
- package/dist/{rtc-manager-gYDkADGw.d.cts → rtc-manager-DnQoznIg.d.cts} +2 -17
- package/dist/{rtc-manager-gYDkADGw.d.ts → rtc-manager-DnQoznIg.d.ts} +2 -17
- package/dist/video-file-stream-4TAGKL2Q.js +3 -0
- package/dist/{video-file-stream-UXJ6TNIB.js.map → video-file-stream-4TAGKL2Q.js.map} +1 -1
- package/package.json +1 -6
- package/dist/chunk-7X7QCO3O.js +0 -992
- package/dist/chunk-7X7QCO3O.js.map +0 -1
- package/dist/chunk-EGNRAZ5U.js +0 -432
- package/dist/chunk-EGNRAZ5U.js.map +0 -1
- package/dist/chunk-M5QA6LWS.js.map +0 -1
- package/dist/chunk-PLU2YVAS.js.map +0 -1
- package/dist/experimental/index.cjs +0 -3873
- package/dist/experimental/index.cjs.map +0 -1
- package/dist/experimental/index.d.cts +0 -2
- package/dist/experimental/index.d.ts +0 -2
- package/dist/experimental/index.js +0 -5
- package/dist/experimental/index.js.map +0 -1
- package/dist/index-BEgtCLkJ.d.cts +0 -346
- package/dist/index-D9wwNTfP.d.ts +0 -346
- package/dist/video-file-stream-UXJ6TNIB.js +0 -4
package/dist/index.cjs
CHANGED
|
@@ -441,13 +441,12 @@ function resolveRtcPublishFps(options = {}) {
|
|
|
441
441
|
function resolveRtcPublishFrameIntervalS(options) {
|
|
442
442
|
return 1 / resolveRtcPublishFps(options);
|
|
443
443
|
}
|
|
444
|
-
exports.MOBILE_PUBLISH_MAX_WIDTH_PX = void 0; exports.RTC_PUBLISH_FPS_WEB = void 0; exports.RTC_PUBLISH_FPS_MOBILE = void 0; exports.
|
|
444
|
+
exports.MOBILE_PUBLISH_MAX_WIDTH_PX = void 0; exports.RTC_PUBLISH_FPS_WEB = void 0; exports.RTC_PUBLISH_FPS_MOBILE = void 0; exports.RTC_PUBLISH_FRAME_INTERVAL_S = void 0; exports.RTC_PUBLISH_FRAME_INTERVAL_MS = void 0; exports.MEDIA_TIME_EPSILON_S = void 0; exports.MEDIA_TIME_LOOP_JUMP_S = void 0;
|
|
445
445
|
var init_publish_fps = __esm({
|
|
446
446
|
"src/rtc/publish-fps.ts"() {
|
|
447
447
|
exports.MOBILE_PUBLISH_MAX_WIDTH_PX = 768;
|
|
448
448
|
exports.RTC_PUBLISH_FPS_WEB = 30;
|
|
449
449
|
exports.RTC_PUBLISH_FPS_MOBILE = 24;
|
|
450
|
-
exports.RTC_PUBLISH_FPS = exports.RTC_PUBLISH_FPS_WEB;
|
|
451
450
|
exports.RTC_PUBLISH_FRAME_INTERVAL_S = 1 / exports.RTC_PUBLISH_FPS_WEB;
|
|
452
451
|
exports.RTC_PUBLISH_FRAME_INTERVAL_MS = 1e3 / exports.RTC_PUBLISH_FPS_WEB;
|
|
453
452
|
exports.MEDIA_TIME_EPSILON_S = 1e-3;
|
|
@@ -627,17 +626,6 @@ function shouldSampleAtMediaTime(lastMediaTimeS, mediaTimeS) {
|
|
|
627
626
|
}
|
|
628
627
|
return mediaTimeS > lastMediaTimeS + exports.MEDIA_TIME_EPSILON_S;
|
|
629
628
|
}
|
|
630
|
-
function sampleCanvasFingerprint(ctx, width, height) {
|
|
631
|
-
const points = [
|
|
632
|
-
[0, 0],
|
|
633
|
-
[Math.max(0, (width >> 1) - 1), Math.max(0, (height >> 1) - 1)],
|
|
634
|
-
[Math.max(0, width - 1), Math.max(0, height - 1)]
|
|
635
|
-
];
|
|
636
|
-
return points.map(([x, y]) => {
|
|
637
|
-
const data = ctx.getImageData(x, y, 1, 1).data;
|
|
638
|
-
return `${data[0]},${data[1]},${data[2]}`;
|
|
639
|
-
}).join("|");
|
|
640
|
-
}
|
|
641
629
|
async function applyPublishTrackConstraints(track, width, height) {
|
|
642
630
|
if (typeof track.applyConstraints !== "function") {
|
|
643
631
|
return;
|
|
@@ -710,12 +698,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
|
710
698
|
let lastDrawMediaTimeS = -1;
|
|
711
699
|
let videoFrameCallbackId = null;
|
|
712
700
|
let rafId = null;
|
|
713
|
-
const logPublishFrames = options.logPublishFrames ?? false;
|
|
714
|
-
let publishFrameIndex = 0;
|
|
715
|
-
let lastPublishWallMs = 0;
|
|
716
|
-
let lastPublishMediaTimeS = -1;
|
|
717
|
-
let publishFramesInWindow = 0;
|
|
718
|
-
let publishWindowStartMs = 0;
|
|
719
701
|
const drawFrame = () => {
|
|
720
702
|
if (destroyed) {
|
|
721
703
|
return;
|
|
@@ -729,52 +711,13 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
|
729
711
|
sourceHeight
|
|
730
712
|
);
|
|
731
713
|
};
|
|
732
|
-
const
|
|
733
|
-
if (!logPublishFrames) {
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
publishFrameIndex += 1;
|
|
737
|
-
const wallNowMs = performance.now();
|
|
738
|
-
const wallDeltaMs = lastPublishWallMs > 0 ? wallNowMs - lastPublishWallMs : 0;
|
|
739
|
-
const mediaDeltaS = lastPublishMediaTimeS >= 0 ? mediaTimeS - lastPublishMediaTimeS : 0;
|
|
740
|
-
lastPublishWallMs = wallNowMs;
|
|
741
|
-
lastPublishMediaTimeS = mediaTimeS;
|
|
742
|
-
publishFramesInWindow += 1;
|
|
743
|
-
if (publishWindowStartMs === 0) {
|
|
744
|
-
publishWindowStartMs = wallNowMs;
|
|
745
|
-
}
|
|
746
|
-
const fingerprint = sampleCanvasFingerprint(ctx, outputWidth, outputHeight);
|
|
747
|
-
console.warn("[upload-video \u2192 publishFrame]", {
|
|
748
|
-
frameIndex: publishFrameIndex,
|
|
749
|
-
mediaTimeS: Number(mediaTimeS.toFixed(4)),
|
|
750
|
-
mediaDeltaS: Number(mediaDeltaS.toFixed(4)),
|
|
751
|
-
wallDeltaMs: Number(wallDeltaMs.toFixed(1)),
|
|
752
|
-
effectiveFps: wallDeltaMs > 0 ? Number((1e3 / wallDeltaMs).toFixed(1)) : null,
|
|
753
|
-
presentedFrames,
|
|
754
|
-
size: `${outputWidth}\xD7${outputHeight}`,
|
|
755
|
-
fingerprint
|
|
756
|
-
});
|
|
757
|
-
const windowElapsedMs = wallNowMs - publishWindowStartMs;
|
|
758
|
-
if (windowElapsedMs >= 1e3) {
|
|
759
|
-
console.warn("[upload-video \u2192 publishFps]", {
|
|
760
|
-
framesInLast1s: publishFramesInWindow,
|
|
761
|
-
avgFps: Number((publishFramesInWindow / (windowElapsedMs / 1e3)).toFixed(2)),
|
|
762
|
-
videoCurrentTime: Number(videoEl.currentTime.toFixed(4)),
|
|
763
|
-
videoPaused: videoEl.paused,
|
|
764
|
-
videoReadyState: videoEl.readyState
|
|
765
|
-
});
|
|
766
|
-
publishFramesInWindow = 0;
|
|
767
|
-
publishWindowStartMs = wallNowMs;
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
const onPlaybackSample = (mediaTimeS, presentedFrames) => {
|
|
714
|
+
const onPlaybackSample = (mediaTimeS) => {
|
|
771
715
|
if (destroyed || !shouldSampleAtMediaTime(lastDrawMediaTimeS, mediaTimeS)) {
|
|
772
716
|
return;
|
|
773
717
|
}
|
|
774
718
|
lastDrawMediaTimeS = mediaTimeS;
|
|
775
719
|
lastAdvanceAt = Date.now();
|
|
776
720
|
drawFrame();
|
|
777
|
-
logPublishedFrame(mediaTimeS, presentedFrames);
|
|
778
721
|
};
|
|
779
722
|
const schedulePlaybackWatch = () => {
|
|
780
723
|
if (destroyed) {
|
|
@@ -783,7 +726,7 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
|
783
726
|
const video = videoEl;
|
|
784
727
|
if (video.requestVideoFrameCallback) {
|
|
785
728
|
videoFrameCallbackId = video.requestVideoFrameCallback((_now, metadata) => {
|
|
786
|
-
onPlaybackSample(metadata.mediaTime
|
|
729
|
+
onPlaybackSample(metadata.mediaTime);
|
|
787
730
|
schedulePlaybackWatch();
|
|
788
731
|
});
|
|
789
732
|
return;
|
|
@@ -794,7 +737,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
|
794
737
|
});
|
|
795
738
|
};
|
|
796
739
|
drawFrame();
|
|
797
|
-
logPublishedFrame(videoEl.currentTime);
|
|
798
740
|
schedulePlaybackWatch();
|
|
799
741
|
const ensurePlaying = () => {
|
|
800
742
|
if (destroyed) {
|
|
@@ -816,18 +758,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
|
816
758
|
videoEl.addEventListener("ended", ensurePlaying);
|
|
817
759
|
videoEl.addEventListener("stalled", ensurePlaying);
|
|
818
760
|
videoEl.addEventListener("waiting", ensurePlaying);
|
|
819
|
-
if (logPublishFrames) {
|
|
820
|
-
const logPlaybackEvent = (eventName) => {
|
|
821
|
-
console.warn("[upload-video \u2192 playbackEvent]", {
|
|
822
|
-
event: eventName,
|
|
823
|
-
currentTime: Number(videoEl.currentTime.toFixed(4)),
|
|
824
|
-
readyState: videoEl.readyState,
|
|
825
|
-
paused: videoEl.paused
|
|
826
|
-
});
|
|
827
|
-
};
|
|
828
|
-
videoEl.addEventListener("waiting", () => logPlaybackEvent("waiting"));
|
|
829
|
-
videoEl.addEventListener("stalled", () => logPlaybackEvent("stalled"));
|
|
830
|
-
}
|
|
831
761
|
const healthIntervalMs = options.healthIntervalMs ?? 3e3;
|
|
832
762
|
let healthTimer = null;
|
|
833
763
|
if (options.onHealthReport) {
|
|
@@ -1009,148 +939,13 @@ var init_video_file_stream = __esm({
|
|
|
1009
939
|
// src/sdk/client.ts
|
|
1010
940
|
init_i18n();
|
|
1011
941
|
|
|
1012
|
-
// src/shared/browser-toast.ts
|
|
1013
|
-
var TOAST_ROOT_ID = "Xmax-sdk-toast-root";
|
|
1014
|
-
var TOAST_DURATION_MS = 3e3;
|
|
1015
|
-
var toastSeed = 0;
|
|
1016
|
-
var timeoutMap = /* @__PURE__ */ new Map();
|
|
1017
|
-
var elementMap = /* @__PURE__ */ new Map();
|
|
1018
|
-
function ensureToastRoot() {
|
|
1019
|
-
if (typeof document === "undefined") {
|
|
1020
|
-
return null;
|
|
1021
|
-
}
|
|
1022
|
-
let root = document.getElementById(TOAST_ROOT_ID);
|
|
1023
|
-
if (root) {
|
|
1024
|
-
return root;
|
|
1025
|
-
}
|
|
1026
|
-
root = document.createElement("div");
|
|
1027
|
-
root.id = TOAST_ROOT_ID;
|
|
1028
|
-
root.setAttribute("aria-live", "polite");
|
|
1029
|
-
Object.assign(root.style, {
|
|
1030
|
-
position: "fixed",
|
|
1031
|
-
left: "50%",
|
|
1032
|
-
top: "24px",
|
|
1033
|
-
transform: "translateX(-50%)",
|
|
1034
|
-
zIndex: "3000",
|
|
1035
|
-
display: "flex",
|
|
1036
|
-
flexDirection: "column",
|
|
1037
|
-
alignItems: "center",
|
|
1038
|
-
gap: "12px",
|
|
1039
|
-
pointerEvents: "none"
|
|
1040
|
-
});
|
|
1041
|
-
document.body.appendChild(root);
|
|
1042
|
-
return root;
|
|
1043
|
-
}
|
|
1044
|
-
function createIcon(type) {
|
|
1045
|
-
const icon = document.createElement("span");
|
|
1046
|
-
icon.setAttribute("aria-hidden", "true");
|
|
1047
|
-
icon.innerHTML = type === "success" ? '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M10 3L4.5 8.5 2 6" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>' : '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none"><circle cx="6" cy="6" r="5" stroke="#f87171" stroke-width="1.5"/><path d="M4 4l4 4M8 4L4 8" stroke="#f87171" stroke-width="1.5" stroke-linecap="round"/></svg>';
|
|
1048
|
-
Object.assign(icon.style, {
|
|
1049
|
-
display: "inline-flex",
|
|
1050
|
-
width: "12px",
|
|
1051
|
-
height: "12px",
|
|
1052
|
-
flexShrink: "0"
|
|
1053
|
-
});
|
|
1054
|
-
return icon;
|
|
1055
|
-
}
|
|
1056
|
-
function clearToastTimer(id) {
|
|
1057
|
-
const timer = timeoutMap.get(id);
|
|
1058
|
-
if (timer) {
|
|
1059
|
-
window.clearTimeout(timer);
|
|
1060
|
-
timeoutMap.delete(id);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
function destroyToast(id) {
|
|
1064
|
-
if (!id) {
|
|
1065
|
-
timeoutMap.forEach((timer) => window.clearTimeout(timer));
|
|
1066
|
-
timeoutMap.clear();
|
|
1067
|
-
elementMap.forEach((element2) => element2.remove());
|
|
1068
|
-
elementMap.clear();
|
|
1069
|
-
const root2 = typeof document !== "undefined" ? document.getElementById(TOAST_ROOT_ID) : null;
|
|
1070
|
-
root2?.remove();
|
|
1071
|
-
return;
|
|
1072
|
-
}
|
|
1073
|
-
clearToastTimer(id);
|
|
1074
|
-
const element = elementMap.get(id);
|
|
1075
|
-
element?.remove();
|
|
1076
|
-
elementMap.delete(id);
|
|
1077
|
-
const root = typeof document !== "undefined" ? document.getElementById(TOAST_ROOT_ID) : null;
|
|
1078
|
-
if (root && !root.childElementCount) {
|
|
1079
|
-
root.remove();
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
function showToast(type, message, options) {
|
|
1083
|
-
const root = ensureToastRoot();
|
|
1084
|
-
if (!root) {
|
|
1085
|
-
return "";
|
|
1086
|
-
}
|
|
1087
|
-
const id = options?.key || `toast-${Date.now()}-${++toastSeed}`;
|
|
1088
|
-
clearToastTimer(id);
|
|
1089
|
-
elementMap.get(id)?.remove();
|
|
1090
|
-
const isMobile = typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches;
|
|
1091
|
-
const textSize = isMobile ? "12px" : "14px";
|
|
1092
|
-
const toast = document.createElement("div");
|
|
1093
|
-
toast.setAttribute("role", "status");
|
|
1094
|
-
Object.assign(toast.style, {
|
|
1095
|
-
pointerEvents: "auto",
|
|
1096
|
-
display: "flex",
|
|
1097
|
-
alignItems: "center",
|
|
1098
|
-
gap: "12px",
|
|
1099
|
-
minWidth: "240px",
|
|
1100
|
-
padding: "16px",
|
|
1101
|
-
borderRadius: "12px",
|
|
1102
|
-
border: "1px solid rgba(255, 255, 255, 0.20)",
|
|
1103
|
-
background: "rgba(0, 0, 0, 0.80)",
|
|
1104
|
-
boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
1105
|
-
fontFamily: "Rubik, ui-sans-serif, system-ui, sans-serif",
|
|
1106
|
-
fontSize: textSize,
|
|
1107
|
-
fontWeight: "400",
|
|
1108
|
-
lineHeight: "14px"
|
|
1109
|
-
});
|
|
1110
|
-
const content = document.createElement("span");
|
|
1111
|
-
content.textContent = message;
|
|
1112
|
-
Object.assign(content.style, {
|
|
1113
|
-
paddingRight: "0px",
|
|
1114
|
-
textAlign: "center",
|
|
1115
|
-
color: "#ffffff",
|
|
1116
|
-
fontFamily: "Rubik, ui-sans-serif, system-ui, sans-serif",
|
|
1117
|
-
fontSize: textSize,
|
|
1118
|
-
fontWeight: "400",
|
|
1119
|
-
lineHeight: "14px"
|
|
1120
|
-
});
|
|
1121
|
-
toast.appendChild(createIcon(type));
|
|
1122
|
-
toast.appendChild(content);
|
|
1123
|
-
root.appendChild(toast);
|
|
1124
|
-
elementMap.set(id, toast);
|
|
1125
|
-
const timer = window.setTimeout(() => {
|
|
1126
|
-
destroyToast(id);
|
|
1127
|
-
}, options?.duration ?? TOAST_DURATION_MS);
|
|
1128
|
-
timeoutMap.set(id, timer);
|
|
1129
|
-
return id;
|
|
1130
|
-
}
|
|
1131
|
-
var browserToast = {
|
|
1132
|
-
success(message, options) {
|
|
1133
|
-
return showToast("success", message, options);
|
|
1134
|
-
},
|
|
1135
|
-
error(message, options) {
|
|
1136
|
-
return showToast("error", message, options);
|
|
1137
|
-
},
|
|
1138
|
-
destroy(id) {
|
|
1139
|
-
destroyToast(id);
|
|
1140
|
-
}
|
|
1141
|
-
};
|
|
1142
|
-
|
|
1143
942
|
// src/shared/error-utils.ts
|
|
1144
943
|
function notifyError(error, notifier, fallbackMessage) {
|
|
1145
944
|
const resolved = error instanceof Error ? error : Object.assign(new Error(fallbackMessage), { cause: error });
|
|
1146
|
-
if (!resolved.__XmaxNotified) {
|
|
945
|
+
if (!resolved.__XmaxNotified && notifier) {
|
|
1147
946
|
resolved.__XmaxNotified = true;
|
|
1148
947
|
const message = resolved.message || fallbackMessage;
|
|
1149
|
-
|
|
1150
|
-
notifier(message, error);
|
|
1151
|
-
} else if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
1152
|
-
browserToast.error(message);
|
|
1153
|
-
}
|
|
948
|
+
notifier(message, error);
|
|
1154
949
|
}
|
|
1155
950
|
return resolved;
|
|
1156
951
|
}
|
|
@@ -1222,7 +1017,7 @@ var XmaxOpenClient = class {
|
|
|
1222
1017
|
}
|
|
1223
1018
|
throw notifyError(error, this.onError, message);
|
|
1224
1019
|
}
|
|
1225
|
-
/** Stop heartbeat, abort in-flight API requests, and suppress error
|
|
1020
|
+
/** Stop heartbeat, abort in-flight API requests, and suppress error notifications during teardown. */
|
|
1226
1021
|
beginTeardown() {
|
|
1227
1022
|
this.suppressErrorNotification = true;
|
|
1228
1023
|
this.stopHeartbeat();
|
|
@@ -1278,7 +1073,8 @@ var XmaxOpenClient = class {
|
|
|
1278
1073
|
return p.data;
|
|
1279
1074
|
}
|
|
1280
1075
|
const mappedMessage = resolveApiErrorMessage(p.code, this.i18n.locale);
|
|
1281
|
-
const
|
|
1076
|
+
const backendMessage = typeof p.message === "string" && p.message.trim() ? p.message.trim() : void 0;
|
|
1077
|
+
const errorMessage = mappedMessage ?? backendMessage ?? this.i18n.t("errors.requestRetry");
|
|
1282
1078
|
throw new Error(errorMessage);
|
|
1283
1079
|
} catch (error) {
|
|
1284
1080
|
if (this.isAbortError(error)) {
|
|
@@ -1430,6 +1226,7 @@ function createStartRtcRoomEvent(input) {
|
|
|
1430
1226
|
const resolvedPrompt = input.prompt?.trim() ?? "";
|
|
1431
1227
|
const refImagePath = input.refImagePath?.trim() || input.refImage?.trim() || void 0;
|
|
1432
1228
|
const useRefImage = !!refImagePath;
|
|
1229
|
+
const staticImagePath = input.staticImagePath?.trim() || void 0;
|
|
1433
1230
|
return {
|
|
1434
1231
|
event: "start",
|
|
1435
1232
|
user_id: input.userId?.trim() || void 0,
|
|
@@ -1441,7 +1238,9 @@ function createStartRtcRoomEvent(input) {
|
|
|
1441
1238
|
prompt: resolvedPrompt,
|
|
1442
1239
|
ref_image_path: useRefImage ? refImagePath : void 0,
|
|
1443
1240
|
ref_image: useRefImage ? refImagePath : void 0,
|
|
1444
|
-
|
|
1241
|
+
// Instant-only — omit when false/undefined so non-instant starts never carry leftover flags.
|
|
1242
|
+
static_generate: input.staticGenerate === true ? true : void 0,
|
|
1243
|
+
static_image_path: staticImagePath,
|
|
1445
1244
|
...input.extraParams ?? {}
|
|
1446
1245
|
}
|
|
1447
1246
|
};
|
|
@@ -1727,7 +1526,7 @@ var _RtcManager = class _RtcManager {
|
|
|
1727
1526
|
this.lastRemoteSei = null;
|
|
1728
1527
|
this.lastRemoteSeiUserId = null;
|
|
1729
1528
|
this.hasLoggedSeiSendFailure = false;
|
|
1730
|
-
if (previousExpectedRemoteSei !== this.expectedRemoteSei && this.remoteVideoUserId) {
|
|
1529
|
+
if (previousExpectedRemoteSei !== this.expectedRemoteSei && this.remoteVideoUserId && !this.preserveRemoteDom) {
|
|
1731
1530
|
this.pendingRemoteVideoUserId = this.remoteVideoUserId;
|
|
1732
1531
|
this.remoteVideoUserId = null;
|
|
1733
1532
|
}
|
|
@@ -2075,45 +1874,6 @@ var _RtcManager = class _RtcManager {
|
|
|
2075
1874
|
sentFrameRate: this.lastObservedSentFrameRate
|
|
2076
1875
|
});
|
|
2077
1876
|
}
|
|
2078
|
-
/** @deprecated Use {@link ensurePublishedInputBeforeStart}. */
|
|
2079
|
-
async waitForRtcOutboundBeforeStart(options) {
|
|
2080
|
-
const timeoutMs = options?.timeoutMs ?? PUBLISH_READY_TIMEOUT_MS;
|
|
2081
|
-
const publishAgeMs = this.publishStartedAtMs > 0 ? performance.now() - this.publishStartedAtMs : 0;
|
|
2082
|
-
const localFramesPromise = publishAgeMs >= PUBLISH_WARM_SKIP_MS ? Promise.resolve({ ready: true, frameCount: 0, elapsedMs: 0 }) : this.waitForPublishedInputFrames({
|
|
2083
|
-
minFrames: PUBLISH_START_MIN_FRAMES,
|
|
2084
|
-
timeoutMs: PUBLISH_START_FRAME_TIMEOUT_MS
|
|
2085
|
-
});
|
|
2086
|
-
const [, rtcReady] = await Promise.all([
|
|
2087
|
-
localFramesPromise,
|
|
2088
|
-
this.waitForLocalPublishReady({ timeoutMs })
|
|
2089
|
-
]);
|
|
2090
|
-
return rtcReady;
|
|
2091
|
-
}
|
|
2092
|
-
/** @deprecated Use {@link waitForRtcOutboundBeforeStart}. */
|
|
2093
|
-
async waitForPublishedInputFramesBeforeStart() {
|
|
2094
|
-
const waitOptions = this.resolveInputFrameWaitOptions();
|
|
2095
|
-
const waitTasks = [
|
|
2096
|
-
this.waitForLocalPublishReady({ timeoutMs: PUBLISH_READY_TIMEOUT_MS })
|
|
2097
|
-
];
|
|
2098
|
-
if (waitOptions) {
|
|
2099
|
-
waitTasks.push(
|
|
2100
|
-
this.waitForMinPublishDuration(waitOptions.minPublishMs),
|
|
2101
|
-
this.waitForPublishedInputFrames({
|
|
2102
|
-
minFrames: waitOptions.minFrames,
|
|
2103
|
-
timeoutMs: waitOptions.timeoutMs
|
|
2104
|
-
})
|
|
2105
|
-
);
|
|
2106
|
-
}
|
|
2107
|
-
const [rtcResult, ...rest] = await Promise.all(waitTasks);
|
|
2108
|
-
const rtcSend = rtcResult;
|
|
2109
|
-
const frameResult = waitOptions ? rest[1] : { ready: true, frameCount: 0, elapsedMs: 0 };
|
|
2110
|
-
return {
|
|
2111
|
-
...frameResult,
|
|
2112
|
-
rtcSendReady: rtcSend.ready,
|
|
2113
|
-
rtcSendReason: rtcSend.reason,
|
|
2114
|
-
rtcSendElapsedMs: rtcSend.elapsedSincePublishMs
|
|
2115
|
-
};
|
|
2116
|
-
}
|
|
2117
1877
|
async waitForMinPublishDuration(minMs) {
|
|
2118
1878
|
if (minMs <= 0 || this.publishStartedAtMs <= 0) {
|
|
2119
1879
|
return;
|
|
@@ -3608,9 +3368,6 @@ function getFitContentRect(rect, targetSize, fitMode = "contain") {
|
|
|
3608
3368
|
height
|
|
3609
3369
|
};
|
|
3610
3370
|
}
|
|
3611
|
-
function getContentRect(rect, targetSize) {
|
|
3612
|
-
return getFitContentRect(rect, targetSize, "contain");
|
|
3613
|
-
}
|
|
3614
3371
|
function findDragMediaElement(dragSurface) {
|
|
3615
3372
|
const root = dragSurface.parentElement ?? dragSurface;
|
|
3616
3373
|
if (typeof root.querySelector !== "function") {
|
|
@@ -3776,6 +3533,7 @@ function drawNeon(ctx, segs, container, targetSize, dpr, fitMode, mirrored) {
|
|
|
3776
3533
|
}
|
|
3777
3534
|
var DragTrackController = class {
|
|
3778
3535
|
constructor(container, options) {
|
|
3536
|
+
this.strokeActive = false;
|
|
3779
3537
|
this.activePointers = /* @__PURE__ */ new Map();
|
|
3780
3538
|
this.lastTargetPoints = /* @__PURE__ */ new Map();
|
|
3781
3539
|
this.segQueue = [];
|
|
@@ -3785,6 +3543,8 @@ var DragTrackController = class {
|
|
|
3785
3543
|
this.resizeObserver = null;
|
|
3786
3544
|
this.container = container;
|
|
3787
3545
|
this.onTracks = options.onTracks;
|
|
3546
|
+
this.onStrokeStart = options.onStrokeStart;
|
|
3547
|
+
this.onStrokeEnd = options.onStrokeEnd;
|
|
3788
3548
|
this.targetSize = options.targetSize;
|
|
3789
3549
|
this.fitMode = options.fitMode ?? "cover";
|
|
3790
3550
|
this.mirrored = options.mirrored ?? false;
|
|
@@ -3955,11 +3715,17 @@ var DragTrackController = class {
|
|
|
3955
3715
|
this.flushTracks();
|
|
3956
3716
|
}, 30);
|
|
3957
3717
|
}
|
|
3958
|
-
finishStroke() {
|
|
3718
|
+
finishStroke(emitEnd = false) {
|
|
3719
|
+
const wasActive = this.strokeActive;
|
|
3720
|
+
this.strokeActive = false;
|
|
3959
3721
|
this.stopSampling();
|
|
3960
3722
|
this.stopDrawLoop();
|
|
3961
3723
|
this.segQueue.length = 0;
|
|
3962
3724
|
this.clearCanvas();
|
|
3725
|
+
if (emitEnd && wasActive && this.onStrokeEnd) {
|
|
3726
|
+
Promise.resolve(this.onStrokeEnd()).catch(() => {
|
|
3727
|
+
});
|
|
3728
|
+
}
|
|
3963
3729
|
}
|
|
3964
3730
|
handlePointerDown(e) {
|
|
3965
3731
|
if (!this.enabled) {
|
|
@@ -3983,6 +3749,12 @@ var DragTrackController = class {
|
|
|
3983
3749
|
if (targetPoint) {
|
|
3984
3750
|
this.lastTargetPoints.set(e.pointerId, targetPoint);
|
|
3985
3751
|
}
|
|
3752
|
+
const strokeWasActive = this.strokeActive;
|
|
3753
|
+
this.strokeActive = true;
|
|
3754
|
+
if (!strokeWasActive && this.onStrokeStart) {
|
|
3755
|
+
Promise.resolve(this.onStrokeStart()).catch(() => {
|
|
3756
|
+
});
|
|
3757
|
+
}
|
|
3986
3758
|
this.startDrawLoop();
|
|
3987
3759
|
this.startSampling();
|
|
3988
3760
|
}
|
|
@@ -4015,7 +3787,7 @@ var DragTrackController = class {
|
|
|
4015
3787
|
} catch {
|
|
4016
3788
|
}
|
|
4017
3789
|
if (this.activePointers.size === 0) {
|
|
4018
|
-
this.finishStroke();
|
|
3790
|
+
this.finishStroke(true);
|
|
4019
3791
|
}
|
|
4020
3792
|
}
|
|
4021
3793
|
handlePointerCancel(e) {
|
|
@@ -4025,7 +3797,7 @@ var DragTrackController = class {
|
|
|
4025
3797
|
this.activePointers.delete(e.pointerId);
|
|
4026
3798
|
this.lastTargetPoints.delete(e.pointerId);
|
|
4027
3799
|
if (this.activePointers.size === 0) {
|
|
4028
|
-
this.finishStroke();
|
|
3800
|
+
this.finishStroke(true);
|
|
4029
3801
|
}
|
|
4030
3802
|
}
|
|
4031
3803
|
};
|
|
@@ -4199,8 +3971,11 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4199
3971
|
this.localVideoSize = null;
|
|
4200
3972
|
this.currentPrompt = "";
|
|
4201
3973
|
this.currentGenerationModel = "";
|
|
4202
|
-
this.currentStaticGenerate = void 0;
|
|
4203
3974
|
this.disconnected = false;
|
|
3975
|
+
/** True only after `connect()` bootstrap succeeds — gates `onDisconnect`. */
|
|
3976
|
+
this.sessionEstablished = false;
|
|
3977
|
+
this.disconnectNotified = false;
|
|
3978
|
+
this.pendingDisconnectReason = "client";
|
|
4204
3979
|
this.remoteViewHost = null;
|
|
4205
3980
|
this.dragController = null;
|
|
4206
3981
|
this.dragTrackFitMode = "cover";
|
|
@@ -4214,6 +3989,7 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4214
3989
|
this.rtc = rtc;
|
|
4215
3990
|
this.reportError = reportError;
|
|
4216
3991
|
this.onRemoteStream = options.onRemoteStream;
|
|
3992
|
+
this.onDisconnect = options.onDisconnect;
|
|
4217
3993
|
this.onPublishPipelineWaitChange = clientOptions?.onPublishPipelineWaitChange;
|
|
4218
3994
|
if (options.remoteElement) {
|
|
4219
3995
|
this.remoteElement = options.remoteElement;
|
|
@@ -4242,7 +4018,7 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4242
4018
|
}
|
|
4243
4019
|
static async connect(stream, options, clientOptions) {
|
|
4244
4020
|
const sdkI18n = createSDKI18n({});
|
|
4245
|
-
const notifyUserError = clientOptions.onError;
|
|
4021
|
+
const notifyUserError = options.onError ?? clientOptions.onError;
|
|
4246
4022
|
const reportError = (error, fallbackMessage) => {
|
|
4247
4023
|
throw notifyError(error, notifyUserError, fallbackMessage ?? sdkI18n.t("errors.requestFailed"));
|
|
4248
4024
|
};
|
|
@@ -4263,6 +4039,7 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4263
4039
|
const session = new _RealtimeSession(client, rtc, reportError, options, clientOptions);
|
|
4264
4040
|
try {
|
|
4265
4041
|
await session.bootstrap(stream, options, clientOptions.heartbeatIntervalMs ?? 1e4, prewarmed);
|
|
4042
|
+
session.sessionEstablished = true;
|
|
4266
4043
|
return session;
|
|
4267
4044
|
} catch (error) {
|
|
4268
4045
|
await session.safeDisconnect();
|
|
@@ -4288,11 +4065,11 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4288
4065
|
heartbeatIntervalMs,
|
|
4289
4066
|
(heartbeatSession) => {
|
|
4290
4067
|
if (heartbeatSession.status !== ACTIVE_STATUS) {
|
|
4291
|
-
void this.safeDisconnect();
|
|
4068
|
+
void this.safeDisconnect({ reason: "session_inactive" });
|
|
4292
4069
|
}
|
|
4293
4070
|
},
|
|
4294
4071
|
() => {
|
|
4295
|
-
void this.safeDisconnect();
|
|
4072
|
+
void this.safeDisconnect({ reason: "heartbeat_error" });
|
|
4296
4073
|
}
|
|
4297
4074
|
);
|
|
4298
4075
|
const joinInfo = this.client.getRtcJoinInfo(createdSession);
|
|
@@ -4335,7 +4112,6 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4335
4112
|
const initialState = options.initialState;
|
|
4336
4113
|
this.currentPrompt = resolvePromptText(initialState?.prompt);
|
|
4337
4114
|
this.currentGenerationModel = resolveGenerationModel(initialState?.model);
|
|
4338
|
-
this.currentStaticGenerate = initialState?.staticGenerate;
|
|
4339
4115
|
const publishFpsOptions = {
|
|
4340
4116
|
mobile: options.mobile,
|
|
4341
4117
|
highQuality: true,
|
|
@@ -4362,7 +4138,8 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4362
4138
|
model: this.currentGenerationModel || void 0,
|
|
4363
4139
|
size: options.size,
|
|
4364
4140
|
refImage: initialRefImageUrl,
|
|
4365
|
-
staticGenerate:
|
|
4141
|
+
staticGenerate: initialState?.staticGenerate,
|
|
4142
|
+
staticImagePath: initialState?.staticImagePath?.trim() || void 0
|
|
4366
4143
|
});
|
|
4367
4144
|
}
|
|
4368
4145
|
}
|
|
@@ -4441,23 +4218,19 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4441
4218
|
if (options?.model !== void 0) {
|
|
4442
4219
|
this.currentGenerationModel = resolveGenerationModel(options.model);
|
|
4443
4220
|
}
|
|
4444
|
-
if (options?.staticGenerate !== void 0) {
|
|
4445
|
-
this.currentStaticGenerate = options.staticGenerate;
|
|
4446
|
-
}
|
|
4447
4221
|
await this.runStart({
|
|
4448
4222
|
prompt: this.currentPrompt || void 0,
|
|
4449
4223
|
model: this.currentGenerationModel || void 0,
|
|
4450
4224
|
size: options?.size,
|
|
4451
4225
|
refImage: resolvedRefImage,
|
|
4452
|
-
staticGenerate:
|
|
4226
|
+
staticGenerate: options?.staticGenerate === true ? true : void 0,
|
|
4227
|
+
staticImagePath: options?.staticImagePath?.trim() || void 0,
|
|
4228
|
+
preserveRemoteOutput: options?.preserveRemoteOutput
|
|
4453
4229
|
});
|
|
4454
4230
|
} catch (error) {
|
|
4455
4231
|
this.reportError(error);
|
|
4456
4232
|
}
|
|
4457
4233
|
}
|
|
4458
|
-
async setMode(options) {
|
|
4459
|
-
return this.restart(options);
|
|
4460
|
-
}
|
|
4461
4234
|
async refreshRemoteOutput(options) {
|
|
4462
4235
|
if (!this.remoteVideoContainer) {
|
|
4463
4236
|
return;
|
|
@@ -4531,7 +4304,7 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4531
4304
|
return;
|
|
4532
4305
|
}
|
|
4533
4306
|
this.disconnected = true;
|
|
4534
|
-
await this.safeDisconnect(options);
|
|
4307
|
+
await this.safeDisconnect({ ...options, reason: "client" });
|
|
4535
4308
|
}
|
|
4536
4309
|
getSessionUid() {
|
|
4537
4310
|
return this.sessionUid;
|
|
@@ -4540,17 +4313,20 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4540
4313
|
if (!this.rtc.snapshot.joined) {
|
|
4541
4314
|
return;
|
|
4542
4315
|
}
|
|
4316
|
+
const preserveRemoteOutput = options.preserveRemoteOutput ?? false;
|
|
4317
|
+
if (preserveRemoteOutput) {
|
|
4318
|
+
this.rtc.setPreserveRemoteDom(true);
|
|
4319
|
+
}
|
|
4543
4320
|
const startPrompt = options.prompt?.trim() ?? this.currentPrompt;
|
|
4544
4321
|
if (options.model !== void 0) {
|
|
4545
4322
|
this.currentGenerationModel = resolveGenerationModel(options.model);
|
|
4546
4323
|
}
|
|
4547
|
-
if (options.staticGenerate !== void 0) {
|
|
4548
|
-
this.currentStaticGenerate = options.staticGenerate;
|
|
4549
|
-
}
|
|
4550
4324
|
const modelLabel = resolveGenerationModel(this.currentGenerationModel);
|
|
4551
4325
|
await this.rtc.ensurePublishedInputBeforeStart();
|
|
4552
|
-
|
|
4553
|
-
|
|
4326
|
+
if (!preserveRemoteOutput) {
|
|
4327
|
+
this.rtc.setRemoteVideoContainer(null);
|
|
4328
|
+
this.rtc.clearRemoteVideo();
|
|
4329
|
+
}
|
|
4554
4330
|
const size = resolveSessionTargetSize({
|
|
4555
4331
|
localVideoSize: this.localVideoSize,
|
|
4556
4332
|
overrideSize: options.size ?? this.sessionSizeOverride
|
|
@@ -4571,16 +4347,21 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4571
4347
|
size,
|
|
4572
4348
|
prompt: startPrompt,
|
|
4573
4349
|
refImagePath: resolveRefImagePath(options.refImage),
|
|
4574
|
-
|
|
4350
|
+
// Never reuse prior start — caller must pass Instant fields each time.
|
|
4351
|
+
staticGenerate: options.staticGenerate === true ? true : void 0,
|
|
4352
|
+
staticImagePath: options.staticImagePath?.trim() || void 0
|
|
4575
4353
|
});
|
|
4576
|
-
console.log("[Xmax SDK] \u771F\u5B9E\u53D1\u9001 start ->", startRoomEvent);
|
|
4577
4354
|
await this.rtc.sendRoomEvent(startRoomEvent);
|
|
4578
|
-
await this.rtc.refreshRemoteVideoBinding({ force:
|
|
4355
|
+
await this.rtc.refreshRemoteVideoBinding({ force: !preserveRemoteOutput });
|
|
4579
4356
|
this.updateDragController(true);
|
|
4580
4357
|
this.scheduleNotifyRemoteStream();
|
|
4581
4358
|
} catch (error) {
|
|
4582
4359
|
this.rtc.configureSessionSei(null);
|
|
4583
4360
|
throw error;
|
|
4361
|
+
} finally {
|
|
4362
|
+
if (preserveRemoteOutput) {
|
|
4363
|
+
this.rtc.setPreserveRemoteDom(false);
|
|
4364
|
+
}
|
|
4584
4365
|
}
|
|
4585
4366
|
}
|
|
4586
4367
|
isDragEnabled() {
|
|
@@ -4606,17 +4387,6 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4606
4387
|
mirrored: false,
|
|
4607
4388
|
enabled: true,
|
|
4608
4389
|
onTracks: (tracks) => {
|
|
4609
|
-
const media = this.remoteViewHost?.videoHost?.querySelector("video, canvas");
|
|
4610
|
-
const mediaRect = media?.getBoundingClientRect();
|
|
4611
|
-
const dragRect = dragHost.getBoundingClientRect();
|
|
4612
|
-
console.log("[Xmax] sendTracks", {
|
|
4613
|
-
taskUid: this.taskUid,
|
|
4614
|
-
targetSize: this.sessionTargetSize,
|
|
4615
|
-
fitMode: this.dragTrackFitMode,
|
|
4616
|
-
tracks,
|
|
4617
|
-
dragRect: dragRect ? { w: dragRect.width, h: dragRect.height } : null,
|
|
4618
|
-
mediaRect: mediaRect ? { w: mediaRect.width, h: mediaRect.height, l: mediaRect.left, t: mediaRect.top } : null
|
|
4619
|
-
});
|
|
4620
4390
|
void this.sendTracks(tracks);
|
|
4621
4391
|
}
|
|
4622
4392
|
});
|
|
@@ -4665,7 +4435,20 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4665
4435
|
this.remoteStreamNotifyTimer = null;
|
|
4666
4436
|
}
|
|
4667
4437
|
}
|
|
4438
|
+
emitDisconnect(reason) {
|
|
4439
|
+
if (!this.sessionEstablished || this.disconnectNotified) {
|
|
4440
|
+
return;
|
|
4441
|
+
}
|
|
4442
|
+
this.disconnectNotified = true;
|
|
4443
|
+
try {
|
|
4444
|
+
this.onDisconnect?.(reason);
|
|
4445
|
+
} catch {
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4668
4448
|
async safeDisconnect(options) {
|
|
4449
|
+
const reason = options?.reason ?? this.pendingDisconnectReason;
|
|
4450
|
+
this.pendingDisconnectReason = reason;
|
|
4451
|
+
this.disconnected = true;
|
|
4669
4452
|
this.clearRemoteStreamNotifyTimer();
|
|
4670
4453
|
this.lastNotifiedRemoteStream = null;
|
|
4671
4454
|
const activeSessionUid = this.sessionUid;
|
|
@@ -4707,7 +4490,6 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4707
4490
|
this.taskUid = null;
|
|
4708
4491
|
this.currentPrompt = "";
|
|
4709
4492
|
this.currentGenerationModel = "";
|
|
4710
|
-
this.currentStaticGenerate = void 0;
|
|
4711
4493
|
this.sessionTargetSize = null;
|
|
4712
4494
|
this.dragController?.destroy();
|
|
4713
4495
|
this.dragController = null;
|
|
@@ -4717,6 +4499,7 @@ var RealtimeSession = class _RealtimeSession {
|
|
|
4717
4499
|
this.hiddenRemoteElement.remove();
|
|
4718
4500
|
this.hiddenRemoteElement = null;
|
|
4719
4501
|
}
|
|
4502
|
+
this.emitDisconnect(reason);
|
|
4720
4503
|
}
|
|
4721
4504
|
};
|
|
4722
4505
|
|
|
@@ -5056,7 +4839,6 @@ exports.createTracksRtcRoomEvent = createTracksRtcRoomEvent;
|
|
|
5056
4839
|
exports.createVideoFileStream = createVideoFileStream;
|
|
5057
4840
|
exports.createXmaxClient = createXmaxClient;
|
|
5058
4841
|
exports.getCameraEnvironmentIssue = getCameraEnvironmentIssue;
|
|
5059
|
-
exports.getContentRect = getContentRect;
|
|
5060
4842
|
exports.getDefaultMessages = getDefaultMessages;
|
|
5061
4843
|
exports.isCameraAccessError = isCameraAccessError;
|
|
5062
4844
|
exports.isImageMediaFile = isImageMediaFile;
|