@xmaxai/sdk 0.1.0
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 +40 -0
- package/LICENSE +21 -0
- package/README.md +201 -0
- package/dist/chunk-67XSD3QJ.js +2673 -0
- package/dist/chunk-67XSD3QJ.js.map +1 -0
- package/dist/chunk-74ZZWUPI.js +992 -0
- package/dist/chunk-74ZZWUPI.js.map +1 -0
- package/dist/chunk-EGNRAZ5U.js +432 -0
- package/dist/chunk-EGNRAZ5U.js.map +1 -0
- package/dist/chunk-PLU2YVAS.js +414 -0
- package/dist/chunk-PLU2YVAS.js.map +1 -0
- package/dist/experimental/index.cjs +3897 -0
- package/dist/experimental/index.cjs.map +1 -0
- package/dist/experimental/index.d.cts +2 -0
- package/dist/experimental/index.d.ts +2 -0
- package/dist/experimental/index.js +5 -0
- package/dist/experimental/index.js.map +1 -0
- package/dist/index-BIUk_kvb.d.ts +350 -0
- package/dist/index-Dai62Sos.d.cts +350 -0
- package/dist/index.cjs +5109 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +235 -0
- package/dist/index.d.ts +235 -0
- package/dist/index.js +359 -0
- package/dist/index.js.map +1 -0
- package/dist/local-publish-diagnostics-ABLL56IT.js +79 -0
- package/dist/local-publish-diagnostics-ABLL56IT.js.map +1 -0
- package/dist/react/index.cjs +4304 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +112 -0
- package/dist/react/index.d.ts +112 -0
- package/dist/react/index.js +817 -0
- package/dist/react/index.js.map +1 -0
- package/dist/rtc-manager-gYDkADGw.d.cts +412 -0
- package/dist/rtc-manager-gYDkADGw.d.ts +412 -0
- package/dist/video-file-stream-UXJ6TNIB.js +4 -0
- package/dist/video-file-stream-UXJ6TNIB.js.map +1 -0
- package/package.json +82 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
export { RealtimePrewarmHandle, RealtimeSession, createRemoteViewHost, createXmaxClient, observeDragSurfaceVideoSync, resolveRefImageUrl, syncDragSurfaceToVideo } from './chunk-74ZZWUPI.js';
|
|
2
|
+
import { requestCameraMediaStream } from './chunk-67XSD3QJ.js';
|
|
3
|
+
export { ACTIVE_STATUS, PREVIEW_CONTAIN_ATTR, PREVIEW_COVER_ATTR, PREVIEW_OUTPUT_LAYOUT_ATTR, PREVIEW_UPLOAD_FIT_ATTR, PREVIEW_UPLOAD_LAYOUT_ATTR, PUBLISH_COLD_FRAME_TIMEOUT_MS, PUBLISH_COLD_MIN_FRAMES, PUBLISH_COLD_WARMUP_MS, PUBLISH_START_FRAME_TIMEOUT_MS, PUBLISH_START_MIN_FRAMES, PUBLISH_WARM_SKIP_MS, RtcManager, XMAX_OPEN_API_BASE_URLS, XMAX_OPEN_API_PRODUCTION_BASE_URL, XmaxOpenClient, applyUploadPreviewMediaLayout, classifyCameraAccessError, createDragTrackController, createNativeCameraStream, createStartRtcRoomEvent, createStopRtcRoomEvent, createTaskUid, createTracksRtcRoomEvent, getCameraEnvironmentIssue, getContentRect, isCameraAccessError, mapTargetPointToCanvas, mapViewportPointToCoordinateSpace, models, observeUploadPreviewMediaLayout, openNativeCameraStream, requestCameraMediaStream, stabilizeCameraVideoTrack } from './chunk-67XSD3QJ.js';
|
|
4
|
+
import { computeCenterCropRect, drawSourceCenterCrop } from './chunk-EGNRAZ5U.js';
|
|
5
|
+
export { createVideoFileStream } from './chunk-EGNRAZ5U.js';
|
|
6
|
+
import { createSDKI18n, resolveUploadVideoSize, resolveRtcPublishFps, mountCaptureVideo } from './chunk-PLU2YVAS.js';
|
|
7
|
+
export { API_ERROR_MESSAGES, DEFAULT_SESSION_TARGET_SIZE, MEDIA_TIME_EPSILON_S, MEDIA_TIME_LOOP_JUMP_S, MOBILE_PUBLISH_MAX_WIDTH_PX, PREVIEW_CONTAINER_ASPECT_RATIO, RTC_PUBLISH_FPS, RTC_PUBLISH_FPS_MOBILE, RTC_PUBLISH_FPS_WEB, RTC_PUBLISH_FRAME_INTERVAL_MS, RTC_PUBLISH_FRAME_INTERVAL_S, createSDKI18n, getDefaultMessages, isMobilePublishEnvironment, resolveAdaptiveRtcVideoSize, resolveApiErrorMessage, resolvePreviewAspectRatio, resolveRtcPublishFps, resolveRtcPublishFrameIntervalS, resolveSessionTargetSize, resolveUploadPublishSize, resolveUploadVideoSize } from './chunk-PLU2YVAS.js';
|
|
8
|
+
|
|
9
|
+
// src/rtc/image-file-stream.ts
|
|
10
|
+
function loadImageElement(url, crossOrigin) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const image = new Image();
|
|
13
|
+
if (crossOrigin) {
|
|
14
|
+
image.crossOrigin = "anonymous";
|
|
15
|
+
}
|
|
16
|
+
image.onload = () => resolve(image);
|
|
17
|
+
image.onerror = () => reject(new Error("failed to load image"));
|
|
18
|
+
image.src = url;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function createImageFileStream(fileOrUrl, options = {}) {
|
|
22
|
+
const i18n = options.i18n ?? createSDKI18n();
|
|
23
|
+
const isUrl = typeof fileOrUrl === "string";
|
|
24
|
+
const url = isUrl ? fileOrUrl : URL.createObjectURL(fileOrUrl);
|
|
25
|
+
let imageEl;
|
|
26
|
+
try {
|
|
27
|
+
imageEl = await loadImageElement(url, isUrl);
|
|
28
|
+
} catch {
|
|
29
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
30
|
+
throw new Error(i18n.t("errors.imageLoadFailed"));
|
|
31
|
+
}
|
|
32
|
+
const sourceWidth = imageEl.naturalWidth || imageEl.width || 0;
|
|
33
|
+
const sourceHeight = imageEl.naturalHeight || imageEl.height || 0;
|
|
34
|
+
if (!sourceWidth || !sourceHeight) {
|
|
35
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
36
|
+
throw new Error(i18n.t("errors.imageTrackMissing"));
|
|
37
|
+
}
|
|
38
|
+
const [outputWidth, outputHeight] = options.targetSize ?? resolveUploadVideoSize(sourceWidth, sourceHeight);
|
|
39
|
+
const canvas = document.createElement("canvas");
|
|
40
|
+
canvas.width = outputWidth;
|
|
41
|
+
canvas.height = outputHeight;
|
|
42
|
+
const ctx = canvas.getContext("2d");
|
|
43
|
+
if (!ctx) {
|
|
44
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
45
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
46
|
+
}
|
|
47
|
+
const fps = resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps });
|
|
48
|
+
const frameIntervalMs = Math.max(1, Math.round(1e3 / fps));
|
|
49
|
+
const captureStreamFn = canvas.captureStream ?? canvas.mozCaptureStream;
|
|
50
|
+
if (!captureStreamFn) {
|
|
51
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
52
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
53
|
+
}
|
|
54
|
+
const previewStream = captureStreamFn.call(canvas, fps);
|
|
55
|
+
const videoTrack = previewStream.getVideoTracks()[0];
|
|
56
|
+
if (!videoTrack) {
|
|
57
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
58
|
+
throw new Error(i18n.t("errors.imageTrackMissing"));
|
|
59
|
+
}
|
|
60
|
+
let intervalId = null;
|
|
61
|
+
let destroyed = false;
|
|
62
|
+
const drawFrame = () => {
|
|
63
|
+
if (destroyed) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
drawSourceCenterCrop(
|
|
67
|
+
ctx,
|
|
68
|
+
imageEl,
|
|
69
|
+
outputWidth,
|
|
70
|
+
outputHeight,
|
|
71
|
+
sourceWidth,
|
|
72
|
+
sourceHeight
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
drawFrame();
|
|
76
|
+
intervalId = setInterval(drawFrame, frameIntervalMs);
|
|
77
|
+
const videoEl = document.createElement("video");
|
|
78
|
+
videoEl.muted = true;
|
|
79
|
+
videoEl.playsInline = true;
|
|
80
|
+
const destroy = () => {
|
|
81
|
+
destroyed = true;
|
|
82
|
+
if (intervalId !== null) {
|
|
83
|
+
clearInterval(intervalId);
|
|
84
|
+
intervalId = null;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
videoTrack.stop();
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
previewStream.getTracks().forEach((track) => {
|
|
92
|
+
if (track.readyState !== "ended") {
|
|
93
|
+
track.stop();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
imageEl.src = "";
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
videoEl.remove();
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
url,
|
|
110
|
+
previewStream,
|
|
111
|
+
videoEl,
|
|
112
|
+
videoTrack,
|
|
113
|
+
fps,
|
|
114
|
+
width: outputWidth,
|
|
115
|
+
height: outputHeight,
|
|
116
|
+
sourceWidth,
|
|
117
|
+
sourceHeight,
|
|
118
|
+
destroy
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function isImageMediaFile(file) {
|
|
122
|
+
if (typeof file === "string") {
|
|
123
|
+
return /\.(png|jpe?g|webp|gif|bmp|heic|heif)$/i.test(file.split("?")[0]);
|
|
124
|
+
}
|
|
125
|
+
if (file.type.startsWith("image/")) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
const name = file.name.toLowerCase();
|
|
129
|
+
return /\.(png|jpe?g|webp|gif|bmp|heic|heif)$/.test(name);
|
|
130
|
+
}
|
|
131
|
+
function isVideoMediaFile(file) {
|
|
132
|
+
if (typeof file === "string") {
|
|
133
|
+
return /\.(mp4|mov|webm|m4v|avi|mkv)$/i.test(file.split("?")[0]);
|
|
134
|
+
}
|
|
135
|
+
if (file.type.startsWith("video/")) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
const name = file.name.toLowerCase();
|
|
139
|
+
return /\.(mp4|mov|webm|m4v|avi|mkv)$/.test(name);
|
|
140
|
+
}
|
|
141
|
+
async function createMediaFileStream(fileOrUrl, options = {}) {
|
|
142
|
+
if (isImageMediaFile(fileOrUrl)) {
|
|
143
|
+
return createImageFileStream(fileOrUrl, options);
|
|
144
|
+
}
|
|
145
|
+
if (isVideoMediaFile(fileOrUrl)) {
|
|
146
|
+
const { createVideoFileStream: createVideoFileStream2 } = await import('./video-file-stream-UXJ6TNIB.js');
|
|
147
|
+
return createVideoFileStream2(fileOrUrl, options);
|
|
148
|
+
}
|
|
149
|
+
const i18n = options.i18n ?? createSDKI18n();
|
|
150
|
+
const typeStr = typeof fileOrUrl === "string" ? "url" : fileOrUrl.type || "unknown";
|
|
151
|
+
throw new Error(i18n.t("errors.invalidMediaFileType", { type: typeStr }));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/rtc/mirror-camera-stream.ts
|
|
155
|
+
async function openMirroredCameraStream(options = {}) {
|
|
156
|
+
const i18n = options.i18n ?? createSDKI18n();
|
|
157
|
+
const stream = await requestCameraMediaStream({
|
|
158
|
+
width: options.width ?? 1280,
|
|
159
|
+
height: options.height ?? 960,
|
|
160
|
+
frameRate: options.frameRate ?? 30,
|
|
161
|
+
facingMode: options.facingMode ?? "user"
|
|
162
|
+
});
|
|
163
|
+
return createPublishCameraStream(stream, {
|
|
164
|
+
fps: resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps ?? options.frameRate }),
|
|
165
|
+
i18n,
|
|
166
|
+
mirror: true
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async function createPublishCameraStream(sourceStream, options = {}) {
|
|
170
|
+
const i18n = options.i18n ?? createSDKI18n();
|
|
171
|
+
const mirror = options.mirror ?? false;
|
|
172
|
+
const sourceTrack = sourceStream.getVideoTracks()[0];
|
|
173
|
+
if (!sourceTrack) {
|
|
174
|
+
throw new Error(i18n.t("errors.videoTrackMissing"));
|
|
175
|
+
}
|
|
176
|
+
const videoEl = document.createElement("video");
|
|
177
|
+
videoEl.playsInline = true;
|
|
178
|
+
videoEl.muted = true;
|
|
179
|
+
videoEl.autoplay = true;
|
|
180
|
+
videoEl.srcObject = sourceStream;
|
|
181
|
+
mountCaptureVideo(videoEl);
|
|
182
|
+
await waitForEvent(videoEl, "loadedmetadata");
|
|
183
|
+
const playResult = videoEl.play();
|
|
184
|
+
if (playResult && typeof playResult.then === "function") {
|
|
185
|
+
await playResult;
|
|
186
|
+
}
|
|
187
|
+
const sourceWidth = videoEl.videoWidth || 0;
|
|
188
|
+
const sourceHeight = videoEl.videoHeight || 0;
|
|
189
|
+
if (!sourceWidth || !sourceHeight) {
|
|
190
|
+
throw new Error(i18n.t("errors.videoTrackMissing"));
|
|
191
|
+
}
|
|
192
|
+
const targetSize = options.targetSize;
|
|
193
|
+
const hasTargetSize = !!targetSize && targetSize[0] > 0 && targetSize[1] > 0;
|
|
194
|
+
if (!mirror && !hasTargetSize) {
|
|
195
|
+
return {
|
|
196
|
+
sourceStream,
|
|
197
|
+
previewStream: sourceStream,
|
|
198
|
+
videoTrack: sourceTrack,
|
|
199
|
+
videoEl,
|
|
200
|
+
width: sourceWidth,
|
|
201
|
+
height: sourceHeight,
|
|
202
|
+
destroy: () => {
|
|
203
|
+
try {
|
|
204
|
+
videoEl.pause();
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
videoEl.srcObject = null;
|
|
209
|
+
videoEl.remove();
|
|
210
|
+
} catch {
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
let outputWidth = sourceWidth;
|
|
216
|
+
let outputHeight = sourceHeight;
|
|
217
|
+
let cropRect = {
|
|
218
|
+
x: 0,
|
|
219
|
+
y: 0,
|
|
220
|
+
width: sourceWidth,
|
|
221
|
+
height: sourceHeight
|
|
222
|
+
};
|
|
223
|
+
if (hasTargetSize) {
|
|
224
|
+
outputWidth = targetSize[0];
|
|
225
|
+
outputHeight = targetSize[1];
|
|
226
|
+
cropRect = computeCenterCropRect(sourceWidth, sourceHeight, outputWidth / outputHeight);
|
|
227
|
+
}
|
|
228
|
+
const canvas = document.createElement("canvas");
|
|
229
|
+
canvas.width = outputWidth;
|
|
230
|
+
canvas.height = outputHeight;
|
|
231
|
+
const ctx = canvas.getContext("2d");
|
|
232
|
+
if (!ctx) {
|
|
233
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
234
|
+
}
|
|
235
|
+
const fps = resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps });
|
|
236
|
+
const captureStreamFn = canvas.captureStream ?? canvas.mozCaptureStream;
|
|
237
|
+
if (!captureStreamFn) {
|
|
238
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
239
|
+
}
|
|
240
|
+
const previewStream = captureStreamFn.call(canvas, fps);
|
|
241
|
+
const videoTrack = previewStream.getVideoTracks()[0];
|
|
242
|
+
if (!videoTrack) {
|
|
243
|
+
throw new Error(i18n.t("errors.videoTrackMissing"));
|
|
244
|
+
}
|
|
245
|
+
let rafId = null;
|
|
246
|
+
let videoFrameCallbackId = null;
|
|
247
|
+
let destroyed = false;
|
|
248
|
+
const drawFrame = () => {
|
|
249
|
+
if (destroyed) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
ctx.imageSmoothingEnabled = true;
|
|
253
|
+
ctx.imageSmoothingQuality = "high";
|
|
254
|
+
ctx.clearRect(0, 0, outputWidth, outputHeight);
|
|
255
|
+
ctx.save();
|
|
256
|
+
if (mirror) {
|
|
257
|
+
ctx.translate(outputWidth, 0);
|
|
258
|
+
ctx.scale(-1, 1);
|
|
259
|
+
}
|
|
260
|
+
ctx.drawImage(
|
|
261
|
+
videoEl,
|
|
262
|
+
cropRect.x,
|
|
263
|
+
cropRect.y,
|
|
264
|
+
cropRect.width,
|
|
265
|
+
cropRect.height,
|
|
266
|
+
0,
|
|
267
|
+
0,
|
|
268
|
+
outputWidth,
|
|
269
|
+
outputHeight
|
|
270
|
+
);
|
|
271
|
+
ctx.restore();
|
|
272
|
+
};
|
|
273
|
+
const scheduleNextFrame = () => {
|
|
274
|
+
if (destroyed) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const video = videoEl;
|
|
278
|
+
if (video.requestVideoFrameCallback) {
|
|
279
|
+
videoFrameCallbackId = video.requestVideoFrameCallback(() => {
|
|
280
|
+
drawFrame();
|
|
281
|
+
scheduleNextFrame();
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
rafId = window.requestAnimationFrame(() => {
|
|
286
|
+
drawFrame();
|
|
287
|
+
scheduleNextFrame();
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
drawFrame();
|
|
291
|
+
scheduleNextFrame();
|
|
292
|
+
const destroy = () => {
|
|
293
|
+
destroyed = true;
|
|
294
|
+
const video = videoEl;
|
|
295
|
+
if (videoFrameCallbackId !== null && video.cancelVideoFrameCallback) {
|
|
296
|
+
video.cancelVideoFrameCallback(videoFrameCallbackId);
|
|
297
|
+
videoFrameCallbackId = null;
|
|
298
|
+
}
|
|
299
|
+
if (rafId !== null) {
|
|
300
|
+
window.cancelAnimationFrame(rafId);
|
|
301
|
+
rafId = null;
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
videoEl.pause();
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
videoTrack.stop();
|
|
309
|
+
} catch {
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
previewStream.getTracks().forEach((track) => {
|
|
313
|
+
if (track.readyState !== "ended") {
|
|
314
|
+
track.stop();
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
videoEl.srcObject = null;
|
|
321
|
+
videoEl.remove();
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
return {
|
|
326
|
+
sourceStream,
|
|
327
|
+
previewStream,
|
|
328
|
+
videoTrack,
|
|
329
|
+
videoEl,
|
|
330
|
+
width: outputWidth,
|
|
331
|
+
height: outputHeight,
|
|
332
|
+
destroy
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
async function createMirroredCameraStreamFromMediaStream(sourceStream, options = {}) {
|
|
336
|
+
return createPublishCameraStream(sourceStream, { ...options, mirror: options.mirror ?? true });
|
|
337
|
+
}
|
|
338
|
+
function waitForEvent(el, eventName) {
|
|
339
|
+
return new Promise((resolve, reject) => {
|
|
340
|
+
const onOk = () => {
|
|
341
|
+
cleanup();
|
|
342
|
+
resolve();
|
|
343
|
+
};
|
|
344
|
+
const onErr = () => {
|
|
345
|
+
cleanup();
|
|
346
|
+
reject(new Error(`failed to load video metadata: ${String(eventName)}`));
|
|
347
|
+
};
|
|
348
|
+
const cleanup = () => {
|
|
349
|
+
el.removeEventListener(eventName, onOk);
|
|
350
|
+
el.removeEventListener("error", onErr);
|
|
351
|
+
};
|
|
352
|
+
el.addEventListener(eventName, onOk, { once: true });
|
|
353
|
+
el.addEventListener("error", onErr, { once: true });
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export { createImageFileStream, createMediaFileStream, createMirroredCameraStreamFromMediaStream, createPublishCameraStream, isImageMediaFile, isVideoMediaFile, openMirroredCameraStream };
|
|
358
|
+
//# sourceMappingURL=index.js.map
|
|
359
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rtc/image-file-stream.ts","../src/rtc/mirror-camera-stream.ts"],"names":["createVideoFileStream"],"mappings":";;;;;;;;;AASA,SAAS,gBAAA,CAAiB,KAAa,WAAA,EAAiD;AACtF,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,EAAM;AACxB,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,CAAM,WAAA,GAAc,WAAA;AAAA,IACtB;AACA,IAAA,KAAA,CAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,KAAK,CAAA;AAClC,IAAA,KAAA,CAAM,UAAU,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,sBAAsB,CAAC,CAAA;AAC9D,IAAA,KAAA,CAAM,GAAA,GAAM,GAAA;AAAA,EACd,CAAC,CAAA;AACH;AAEA,eAAsB,qBAAA,CACpB,SAAA,EACA,OAAA,GAAkC,EAAC,EACT;AAC1B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,aAAA,EAAc;AAC3C,EAAA,MAAM,KAAA,GAAQ,OAAO,SAAA,KAAc,QAAA;AACnC,EAAA,MAAM,GAAA,GAAM,KAAA,GAAQ,SAAA,GAAY,GAAA,CAAI,gBAAgB,SAAS,CAAA;AAE7D,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,MAAM,gBAAA,CAAiB,GAAA,EAAK,KAAK,CAAA;AAAA,EAC7C,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,wBAAwB,CAAC,CAAA;AAAA,EAClD;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,YAAA,IAAgB,OAAA,CAAQ,KAAA,IAAS,CAAA;AAC7D,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,aAAA,IAAiB,OAAA,CAAQ,MAAA,IAAU,CAAA;AAChE,EAAA,IAAI,CAAC,WAAA,IAAe,CAAC,YAAA,EAAc;AACjC,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,0BAA0B,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,CAAC,aAAa,YAAY,CAAA,GAAI,QAAQ,UAAA,IACvC,sBAAA,CAAuB,aAAa,YAAY,CAAA;AAErD,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,KAAA,GAAQ,WAAA;AACf,EAAA,MAAA,CAAO,MAAA,GAAS,YAAA;AAChB,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,iCAAiC,CAAC,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,GAAA,GAAM,qBAAqB,EAAE,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAA;AAC7E,EAAA,MAAM,eAAA,GAAkB,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,GAAA,GAAO,GAAG,CAAC,CAAA;AAC1D,EAAA,MAAM,eAAA,GACH,MAAA,CAAuF,aAAA,IACvF,MAAA,CAA0F,gBAAA;AAE7F,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,iCAAiC,CAAC,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,aAAA,GAAgB,eAAA,CAAgB,IAAA,CAAK,MAAA,EAAQ,GAAG,CAAA;AACtD,EAAA,MAAM,UAAA,GAAa,aAAA,CAAc,cAAA,EAAe,CAAE,CAAC,CAAA;AAEnD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,0BAA0B,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,IAAI,UAAA,GAAoD,IAAA;AACxD,EAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,IAAI,SAAA,EAAW;AACb,MAAA;AAAA,IACF;AACA,IAAA,oBAAA;AAAA,MACE,GAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAA;AAAA,MACA,YAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA;AAEA,EAAA,SAAA,EAAU;AACV,EAAA,UAAA,GAAa,WAAA,CAAY,WAAW,eAAe,CAAA;AAEnD,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC9C,EAAA,OAAA,CAAQ,KAAA,GAAQ,IAAA;AAChB,EAAA,OAAA,CAAQ,WAAA,GAAc,IAAA;AAEtB,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,SAAA,GAAY,IAAA;AAEZ,IAAA,IAAI,eAAe,IAAA,EAAM;AACvB,MAAA,aAAA,CAAc,UAAU,CAAA;AACxB,MAAA,UAAA,GAAa,IAAA;AAAA,IACf;AAEA,IAAA,IAAI;AACF,MAAA,UAAA,CAAW,IAAA,EAAK;AAAA,IAClB,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,aAAA,CAAc,SAAA,EAAU,CAAE,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC3C,QAAA,IAAI,KAAA,CAAM,eAAe,OAAA,EAAS;AAChC,UAAA,KAAA,CAAM,IAAA,EAAK;AAAA,QACb;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,GAAA,GAAM,EAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,IACjB,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AAAA,EACrC,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,aAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,GAAA;AAAA,IACA,KAAA,EAAO,WAAA;AAAA,IACP,MAAA,EAAQ,YAAA;AAAA,IACR,WAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,iBAAiB,IAAA,EAA8B;AAC7D,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,yCAAyC,IAAA,CAAK,IAAA,CAAK,MAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,EACzE;AACA,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,EAAA,OAAO,uCAAA,CAAwC,KAAK,IAAI,CAAA;AAC1D;AAEO,SAAS,iBAAiB,IAAA,EAA8B;AAC7D,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,iCAAiC,IAAA,CAAK,IAAA,CAAK,MAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,EAAA,OAAO,+BAAA,CAAgC,KAAK,IAAI,CAAA;AAClD;AAEA,eAAsB,qBAAA,CACpB,SAAA,EACA,OAAA,GAAkC,EAAC,EACT;AAC1B,EAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,IAAA,OAAO,qBAAA,CAAsB,WAAW,OAAO,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,IAAA,MAAM,EAAE,qBAAA,EAAAA,sBAAAA,EAAsB,GAAI,MAAM,OAAO,iCAAqB,CAAA;AACpE,IAAA,OAAOA,sBAAAA,CAAsB,WAAW,OAAO,CAAA;AAAA,EACjD;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,aAAA,EAAc;AAC3C,EAAA,MAAM,UAAU,OAAO,SAAA,KAAc,QAAA,GAAW,KAAA,GAAS,UAAU,IAAA,IAAQ,SAAA;AAC3E,EAAA,MAAM,IAAI,MAAM,IAAA,CAAK,CAAA,CAAE,+BAA+B,EAAE,IAAA,EAAM,OAAA,EAAS,CAAC,CAAA;AAC1E;;;ACtIA,eAAsB,wBAAA,CACpB,OAAA,GAA2C,EAAC,EACb;AAC/B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,aAAA,EAAc;AAE3C,EAAA,MAAM,MAAA,GAAS,MAAM,wBAAA,CAAyB;AAAA,IAC5C,KAAA,EAAO,QAAQ,KAAA,IAAS,IAAA;AAAA,IACxB,MAAA,EAAQ,QAAQ,MAAA,IAAU,GAAA;AAAA,IAC1B,SAAA,EAAW,QAAQ,SAAA,IAAa,EAAA;AAAA,IAChC,UAAA,EAAY,QAAQ,UAAA,IAAc;AAAA,GACnC,CAAA;AAED,EAAA,OAAO,0BAA0B,MAAA,EAAQ;AAAA,IACvC,GAAA,EAAK,oBAAA,CAAqB,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,GAAA,EAAK,OAAA,CAAQ,GAAA,IAAO,OAAA,CAAQ,SAAA,EAAW,CAAA;AAAA,IAC3F,IAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACT,CAAA;AACH;AAGA,eAAsB,yBAAA,CACpB,YAAA,EACA,OAAA,GAAuC,EAAC,EACT;AAC/B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,aAAA,EAAc;AAC3C,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,KAAA;AACjC,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,cAAA,EAAe,CAAE,CAAC,CAAA;AACnD,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,0BAA0B,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC9C,EAAA,OAAA,CAAQ,WAAA,GAAc,IAAA;AACtB,EAAA,OAAA,CAAQ,KAAA,GAAQ,IAAA;AAChB,EAAA,OAAA,CAAQ,QAAA,GAAW,IAAA;AACnB,EAAA,OAAA,CAAQ,SAAA,GAAY,YAAA;AACpB,EAAA,iBAAA,CAAkB,OAAO,CAAA;AAEzB,EAAA,MAAM,YAAA,CAAa,SAAS,gBAAgB,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAa,QAAQ,IAAA,EAAK;AAChC,EAAA,IAAI,UAAA,IAAc,OAAQ,UAAA,CAA6B,IAAA,KAAS,UAAA,EAAY;AAC1E,IAAA,MAAM,UAAA;AAAA,EACR;AAEA,EAAA,MAAM,WAAA,GAAc,QAAQ,UAAA,IAAc,CAAA;AAC1C,EAAA,MAAM,YAAA,GAAe,QAAQ,WAAA,IAAe,CAAA;AAC5C,EAAA,IAAI,CAAC,WAAA,IAAe,CAAC,YAAA,EAAc;AACjC,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,0BAA0B,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAC3B,EAAA,MAAM,aAAA,GACJ,CAAC,CAAC,UAAA,IAAc,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,IAAK,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA;AAEvD,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,aAAA,EAAe;AAC7B,IAAA,OAAO;AAAA,MACL,YAAA;AAAA,MACA,aAAA,EAAe,YAAA;AAAA,MACf,UAAA,EAAY,WAAA;AAAA,MACZ,OAAA;AAAA,MACA,KAAA,EAAO,WAAA;AAAA,MACP,MAAA,EAAQ,YAAA;AAAA,MACR,SAAS,MAAM;AACb,QAAA,IAAI;AACF,UAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,QAChB,CAAA,CAAA,MAAQ;AAAA,QACR;AACA,QAAA,IAAI;AACF,UAAA,OAAA,CAAQ,SAAA,GAAY,IAAA;AACpB,UAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,QACjB,CAAA,CAAA,MAAQ;AAAA,QACR;AAAA,MACF;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,GAAc,WAAA;AAClB,EAAA,IAAI,YAAA,GAAe,YAAA;AACnB,EAAA,IAAI,QAAA,GAAqB;AAAA,IACvB,CAAA,EAAG,CAAA;AAAA,IACH,CAAA,EAAG,CAAA;AAAA,IACH,KAAA,EAAO,WAAA;AAAA,IACP,MAAA,EAAQ;AAAA,GACV;AAEA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,WAAA,GAAc,WAAY,CAAC,CAAA;AAC3B,IAAA,YAAA,GAAe,WAAY,CAAC,CAAA;AAC5B,IAAA,QAAA,GAAW,qBAAA,CAAsB,WAAA,EAAa,YAAA,EAAc,WAAA,GAAc,YAAY,CAAA;AAAA,EACxF;AAEA,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,KAAA,GAAQ,WAAA;AACf,EAAA,MAAA,CAAO,MAAA,GAAS,YAAA;AAChB,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,iCAAiC,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,MAAM,GAAA,GAAM,qBAAqB,EAAE,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAA;AAC7E,EAAA,MAAM,eAAA,GACH,MAAA,CAAuF,aAAA,IACvF,MAAA,CAA0F,gBAAA;AAE7F,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,iCAAiC,CAAC,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,aAAA,GAAgB,eAAA,CAAgB,IAAA,CAAK,MAAA,EAAQ,GAAG,CAAA;AACtD,EAAA,MAAM,UAAA,GAAa,aAAA,CAAc,cAAA,EAAe,CAAE,CAAC,CAAA;AACnD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,CAAE,0BAA0B,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,IAAI,KAAA,GAAuB,IAAA;AAC3B,EAAA,IAAI,oBAAA,GAAsC,IAAA;AAC1C,EAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,IAAI,SAAA,EAAW;AACb,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,qBAAA,GAAwB,IAAA;AAC5B,IAAA,GAAA,CAAI,qBAAA,GAAwB,MAAA;AAC5B,IAAA,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,CAAA,EAAG,WAAA,EAAa,YAAY,CAAA;AAC7C,IAAA,GAAA,CAAI,IAAA,EAAK;AACT,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,GAAA,CAAI,SAAA,CAAU,aAAa,CAAC,CAAA;AAC5B,MAAA,GAAA,CAAI,KAAA,CAAM,IAAI,CAAC,CAAA;AAAA,IACjB;AACA,IAAA,GAAA,CAAI,SAAA;AAAA,MACF,OAAA;AAAA,MACA,QAAA,CAAS,CAAA;AAAA,MACT,QAAA,CAAS,CAAA;AAAA,MACT,QAAA,CAAS,KAAA;AAAA,MACT,QAAA,CAAS,MAAA;AAAA,MACT,CAAA;AAAA,MACA,CAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,GAAA,CAAI,OAAA,EAAQ;AAAA,EACd,CAAA;AAEA,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,IAAI,SAAA,EAAW;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,OAAA;AACd,IAAA,IAAI,MAAM,yBAAA,EAA2B;AACnC,MAAA,oBAAA,GAAuB,KAAA,CAAM,0BAA0B,MAAM;AAC3D,QAAA,SAAA,EAAU;AACV,QAAA,iBAAA,EAAkB;AAAA,MACpB,CAAC,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,GAAQ,MAAA,CAAO,sBAAsB,MAAM;AACzC,MAAA,SAAA,EAAU;AACV,MAAA,iBAAA,EAAkB;AAAA,IACpB,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,SAAA,EAAU;AACV,EAAA,iBAAA,EAAkB;AAElB,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,SAAA,GAAY,IAAA;AAEZ,IAAA,MAAM,KAAA,GAAQ,OAAA;AACd,IAAA,IAAI,oBAAA,KAAyB,IAAA,IAAQ,KAAA,CAAM,wBAAA,EAA0B;AACnE,MAAA,KAAA,CAAM,yBAAyB,oBAAoB,CAAA;AACnD,MAAA,oBAAA,GAAuB,IAAA;AAAA,IACzB;AAEA,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,MAAA,CAAO,qBAAqB,KAAK,CAAA;AACjC,MAAA,KAAA,GAAQ,IAAA;AAAA,IACV;AAEA,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,IAChB,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,UAAA,CAAW,IAAA,EAAK;AAAA,IAClB,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,aAAA,CAAc,SAAA,EAAU,CAAE,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC3C,QAAA,IAAI,KAAA,CAAM,eAAe,OAAA,EAAS;AAChC,UAAA,KAAA,CAAM,IAAA,EAAK;AAAA,QACb;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,SAAA,GAAY,IAAA;AACpB,MAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,IACjB,CAAA,CAAA,MAAQ;AAAA,IACR;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA,EAAO,WAAA;AAAA,IACP,MAAA,EAAQ,YAAA;AAAA,IACR;AAAA,GACF;AACF;AAEA,eAAsB,yCAAA,CACpB,YAAA,EACA,OAAA,GAAuC,EAAC,EACT;AAC/B,EAAA,OAAO,yBAAA,CAA0B,cAAc,EAAE,GAAG,SAAS,MAAA,EAAQ,OAAA,CAAQ,MAAA,IAAU,IAAA,EAAM,CAAA;AAC/F;AAEA,SAAS,YAAA,CACP,IACA,SAAA,EACe;AACf,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,OAAA,EAAQ;AACR,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAEA,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,OAAA,EAAQ;AACR,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,OAAO,SAAS,CAAC,EAAE,CAAC,CAAA;AAAA,IACzE,CAAA;AAEA,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,EAAA,CAAG,mBAAA,CAAoB,WAAW,IAAqB,CAAA;AACvD,MAAA,EAAA,CAAG,mBAAA,CAAoB,SAAS,KAAsB,CAAA;AAAA,IACxD,CAAA;AAEA,IAAA,EAAA,CAAG,iBAAiB,SAAA,EAAW,IAAA,EAAuB,EAAE,IAAA,EAAM,MAAM,CAAA;AACpE,IAAA,EAAA,CAAG,iBAAiB,OAAA,EAAS,KAAA,EAAwB,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACrE,CAAC,CAAA;AACH","file":"index.js","sourcesContent":["import { createSDKI18n, type SDKI18n } from '../i18n'\nimport { resolveUploadVideoSize } from '../shared/reference-video-size'\nimport type { VideoFileStream, VideoFileStreamOptions } from './video-file-stream'\nimport { drawSourceCenterCrop } from './canvas-frame-draw'\n\nimport { resolveRtcPublishFps } from './publish-fps'\n\nexport type ImageFileStreamOptions = VideoFileStreamOptions\n\nfunction loadImageElement(url: string, crossOrigin: boolean): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const image = new Image()\n if (crossOrigin) {\n image.crossOrigin = 'anonymous'\n }\n image.onload = () => resolve(image)\n image.onerror = () => reject(new Error('failed to load image'))\n image.src = url\n })\n}\n\nexport async function createImageFileStream(\n fileOrUrl: File | string,\n options: ImageFileStreamOptions = {},\n): Promise<VideoFileStream> {\n const i18n = options.i18n ?? createSDKI18n()\n const isUrl = typeof fileOrUrl === 'string'\n const url = isUrl ? fileOrUrl : URL.createObjectURL(fileOrUrl)\n\n let imageEl: HTMLImageElement\n try {\n imageEl = await loadImageElement(url, isUrl)\n } catch {\n if (!isUrl) URL.revokeObjectURL(url)\n throw new Error(i18n.t('errors.imageLoadFailed'))\n }\n\n const sourceWidth = imageEl.naturalWidth || imageEl.width || 0\n const sourceHeight = imageEl.naturalHeight || imageEl.height || 0\n if (!sourceWidth || !sourceHeight) {\n if (!isUrl) URL.revokeObjectURL(url)\n throw new Error(i18n.t('errors.imageTrackMissing'))\n }\n\n const [outputWidth, outputHeight] = options.targetSize\n ?? resolveUploadVideoSize(sourceWidth, sourceHeight)\n\n const canvas = document.createElement('canvas')\n canvas.width = outputWidth\n canvas.height = outputHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n if (!isUrl) URL.revokeObjectURL(url)\n throw new Error(i18n.t('errors.captureStreamUnsupported'))\n }\n\n const fps = resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps })\n const frameIntervalMs = Math.max(1, Math.round(1000 / fps))\n const captureStreamFn =\n (canvas as HTMLCanvasElement & { captureStream?: (frameRate?: number) => MediaStream }).captureStream ??\n (canvas as HTMLCanvasElement & { mozCaptureStream?: (frameRate?: number) => MediaStream }).mozCaptureStream\n\n if (!captureStreamFn) {\n if (!isUrl) URL.revokeObjectURL(url)\n throw new Error(i18n.t('errors.captureStreamUnsupported'))\n }\n\n const previewStream = captureStreamFn.call(canvas, fps)\n const videoTrack = previewStream.getVideoTracks()[0]\n\n if (!videoTrack) {\n if (!isUrl) URL.revokeObjectURL(url)\n throw new Error(i18n.t('errors.imageTrackMissing'))\n }\n\n let intervalId: ReturnType<typeof setInterval> | null = null\n let destroyed = false\n\n const drawFrame = () => {\n if (destroyed) {\n return\n }\n drawSourceCenterCrop(\n ctx,\n imageEl,\n outputWidth,\n outputHeight,\n sourceWidth,\n sourceHeight,\n )\n }\n\n drawFrame()\n intervalId = setInterval(drawFrame, frameIntervalMs)\n\n const videoEl = document.createElement('video')\n videoEl.muted = true\n videoEl.playsInline = true\n\n const destroy = () => {\n destroyed = true\n\n if (intervalId !== null) {\n clearInterval(intervalId)\n intervalId = null\n }\n\n try {\n videoTrack.stop()\n } catch {\n }\n\n try {\n previewStream.getTracks().forEach((track) => {\n if (track.readyState !== 'ended') {\n track.stop()\n }\n })\n } catch {\n }\n\n try {\n imageEl.src = ''\n } catch {\n }\n\n try {\n videoEl.remove()\n } catch {\n }\n\n if (!isUrl) URL.revokeObjectURL(url)\n }\n\n return {\n url,\n previewStream,\n videoEl,\n videoTrack,\n fps,\n width: outputWidth,\n height: outputHeight,\n sourceWidth,\n sourceHeight,\n destroy,\n }\n}\n\nexport function isImageMediaFile(file: File | string): boolean {\n if (typeof file === 'string') {\n return /\\.(png|jpe?g|webp|gif|bmp|heic|heif)$/i.test(file.split('?')[0])\n }\n if (file.type.startsWith('image/')) {\n return true\n }\n const name = file.name.toLowerCase()\n return /\\.(png|jpe?g|webp|gif|bmp|heic|heif)$/.test(name)\n}\n\nexport function isVideoMediaFile(file: File | string): boolean {\n if (typeof file === 'string') {\n return /\\.(mp4|mov|webm|m4v|avi|mkv)$/i.test(file.split('?')[0])\n }\n if (file.type.startsWith('video/')) {\n return true\n }\n const name = file.name.toLowerCase()\n return /\\.(mp4|mov|webm|m4v|avi|mkv)$/.test(name)\n}\n\nexport async function createMediaFileStream(\n fileOrUrl: File | string,\n options: ImageFileStreamOptions = {},\n): Promise<VideoFileStream> {\n if (isImageMediaFile(fileOrUrl)) {\n return createImageFileStream(fileOrUrl, options)\n }\n if (isVideoMediaFile(fileOrUrl)) {\n const { createVideoFileStream } = await import('./video-file-stream')\n return createVideoFileStream(fileOrUrl, options)\n }\n\n const i18n = options.i18n ?? createSDKI18n()\n const typeStr = typeof fileOrUrl === 'string' ? 'url' : (fileOrUrl.type || 'unknown')\n throw new Error(i18n.t('errors.invalidMediaFileType', { type: typeStr }))\n}\n","import { createSDKI18n, type SDKI18n } from '../i18n'\nimport { requestCameraMediaStream } from '../shared/camera-stream'\nimport { computeCenterCropRect, type CropRect } from './capture-crop'\nimport { mountCaptureVideo } from './capture-host'\n\nimport { resolveRtcPublishFps } from './publish-fps'\n\ntype VideoFrameCallbackMetadata = {\n mediaTime: number\n presentedFrames: number\n width: number\n height: number\n}\n\ntype VideoWithFrameCallback = HTMLVideoElement & {\n requestVideoFrameCallback?: (\n cb: (now: DOMHighResTimeStamp, metadata: VideoFrameCallbackMetadata) => void,\n ) => number\n cancelVideoFrameCallback?: (handle: number) => void\n}\n\nexport type MirroredCameraStream = {\n /** Original camera stream from getUserMedia. */\n sourceStream: MediaStream\n /** Horizontally flipped stream for RTC publish and local preview. */\n previewStream: MediaStream\n videoTrack: MediaStreamTrack\n videoEl: HTMLVideoElement\n width: number\n height: number\n destroy: () => void\n}\n\nexport type MirroredCameraStreamOptions = {\n fps?: number\n /** Mobile H5 uses 24fps publish; web uses 30fps. Auto-detected from viewport when omitted. */\n mobile?: boolean\n i18n?: SDKI18n\n /** Session target size — center-crop + scale before publish (WYSIWYG with preview). */\n targetSize?: [number, number]\n /** Horizontal flip before crop/scale. Defaults to true for legacy mirror helper. */\n mirror?: boolean\n}\n\nexport type OpenMirroredCameraStreamOptions = MirroredCameraStreamOptions & {\n width?: number\n height?: number\n frameRate?: number\n facingMode?: ConstrainDOMString\n}\n\nexport async function openMirroredCameraStream(\n options: OpenMirroredCameraStreamOptions = {},\n): Promise<MirroredCameraStream> {\n const i18n = options.i18n ?? createSDKI18n()\n\n const stream = await requestCameraMediaStream({\n width: options.width ?? 1280,\n height: options.height ?? 960,\n frameRate: options.frameRate ?? 30,\n facingMode: options.facingMode ?? 'user',\n })\n\n return createPublishCameraStream(stream, {\n fps: resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps ?? options.frameRate }),\n i18n,\n mirror: true,\n })\n}\n\n/** Canvas pipeline: optional mirror + center-crop/scale to session size for WYSIWYG publish. */\nexport async function createPublishCameraStream(\n sourceStream: MediaStream,\n options: MirroredCameraStreamOptions = {},\n): Promise<MirroredCameraStream> {\n const i18n = options.i18n ?? createSDKI18n()\n const mirror = options.mirror ?? false\n const sourceTrack = sourceStream.getVideoTracks()[0]\n if (!sourceTrack) {\n throw new Error(i18n.t('errors.videoTrackMissing'))\n }\n\n const videoEl = document.createElement('video')\n videoEl.playsInline = true\n videoEl.muted = true\n videoEl.autoplay = true\n videoEl.srcObject = sourceStream\n mountCaptureVideo(videoEl)\n\n await waitForEvent(videoEl, 'loadedmetadata')\n const playResult = videoEl.play()\n if (playResult && typeof (playResult as Promise<void>).then === 'function') {\n await playResult\n }\n\n const sourceWidth = videoEl.videoWidth || 0\n const sourceHeight = videoEl.videoHeight || 0\n if (!sourceWidth || !sourceHeight) {\n throw new Error(i18n.t('errors.videoTrackMissing'))\n }\n\n const targetSize = options.targetSize\n const hasTargetSize =\n !!targetSize && targetSize[0] > 0 && targetSize[1] > 0\n\n if (!mirror && !hasTargetSize) {\n return {\n sourceStream,\n previewStream: sourceStream,\n videoTrack: sourceTrack,\n videoEl,\n width: sourceWidth,\n height: sourceHeight,\n destroy: () => {\n try {\n videoEl.pause()\n } catch {\n }\n try {\n videoEl.srcObject = null\n videoEl.remove()\n } catch {\n }\n },\n }\n }\n\n let outputWidth = sourceWidth\n let outputHeight = sourceHeight\n let cropRect: CropRect = {\n x: 0,\n y: 0,\n width: sourceWidth,\n height: sourceHeight,\n }\n\n if (hasTargetSize) {\n outputWidth = targetSize![0]\n outputHeight = targetSize![1]\n cropRect = computeCenterCropRect(sourceWidth, sourceHeight, outputWidth / outputHeight)\n }\n\n const canvas = document.createElement('canvas')\n canvas.width = outputWidth\n canvas.height = outputHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n throw new Error(i18n.t('errors.captureStreamUnsupported'))\n }\n const fps = resolveRtcPublishFps({ mobile: options.mobile, fps: options.fps })\n const captureStreamFn =\n (canvas as HTMLCanvasElement & { captureStream?: (frameRate?: number) => MediaStream }).captureStream ??\n (canvas as HTMLCanvasElement & { mozCaptureStream?: (frameRate?: number) => MediaStream }).mozCaptureStream\n\n if (!captureStreamFn) {\n throw new Error(i18n.t('errors.captureStreamUnsupported'))\n }\n\n const previewStream = captureStreamFn.call(canvas, fps)\n const videoTrack = previewStream.getVideoTracks()[0]\n if (!videoTrack) {\n throw new Error(i18n.t('errors.videoTrackMissing'))\n }\n\n let rafId: number | null = null\n let videoFrameCallbackId: number | null = null\n let destroyed = false\n\n const drawFrame = () => {\n if (destroyed) {\n return\n }\n ctx.imageSmoothingEnabled = true\n ctx.imageSmoothingQuality = 'high'\n ctx.clearRect(0, 0, outputWidth, outputHeight)\n ctx.save()\n if (mirror) {\n ctx.translate(outputWidth, 0)\n ctx.scale(-1, 1)\n }\n ctx.drawImage(\n videoEl,\n cropRect.x,\n cropRect.y,\n cropRect.width,\n cropRect.height,\n 0,\n 0,\n outputWidth,\n outputHeight,\n )\n ctx.restore()\n }\n\n const scheduleNextFrame = () => {\n if (destroyed) {\n return\n }\n\n const video = videoEl as VideoWithFrameCallback\n if (video.requestVideoFrameCallback) {\n videoFrameCallbackId = video.requestVideoFrameCallback(() => {\n drawFrame()\n scheduleNextFrame()\n })\n return\n }\n\n rafId = window.requestAnimationFrame(() => {\n drawFrame()\n scheduleNextFrame()\n })\n }\n\n drawFrame()\n scheduleNextFrame()\n\n const destroy = () => {\n destroyed = true\n\n const video = videoEl as VideoWithFrameCallback\n if (videoFrameCallbackId !== null && video.cancelVideoFrameCallback) {\n video.cancelVideoFrameCallback(videoFrameCallbackId)\n videoFrameCallbackId = null\n }\n\n if (rafId !== null) {\n window.cancelAnimationFrame(rafId)\n rafId = null\n }\n\n try {\n videoEl.pause()\n } catch {\n }\n\n try {\n videoTrack.stop()\n } catch {\n }\n\n try {\n previewStream.getTracks().forEach((track) => {\n if (track.readyState !== 'ended') {\n track.stop()\n }\n })\n } catch {\n }\n\n try {\n videoEl.srcObject = null\n videoEl.remove()\n } catch {\n }\n }\n\n return {\n sourceStream,\n previewStream,\n videoTrack,\n videoEl,\n width: outputWidth,\n height: outputHeight,\n destroy,\n }\n}\n\nexport async function createMirroredCameraStreamFromMediaStream(\n sourceStream: MediaStream,\n options: MirroredCameraStreamOptions = {},\n): Promise<MirroredCameraStream> {\n return createPublishCameraStream(sourceStream, { ...options, mirror: options.mirror ?? true })\n}\n\nfunction waitForEvent<T extends HTMLElement>(\n el: T,\n eventName: keyof HTMLElementEventMap,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const onOk = () => {\n cleanup()\n resolve()\n }\n\n const onErr = () => {\n cleanup()\n reject(new Error(`failed to load video metadata: ${String(eventName)}`))\n }\n\n const cleanup = () => {\n el.removeEventListener(eventName, onOk as EventListener)\n el.removeEventListener('error', onErr as EventListener)\n }\n\n el.addEventListener(eventName, onOk as EventListener, { once: true })\n el.addEventListener('error', onErr as EventListener, { once: true })\n })\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/rtc/local-publish-diagnostics.ts
|
|
2
|
+
async function waitForMediaStreamTrackFrames(track, options = {}) {
|
|
3
|
+
const minFrames = options.minFrames ?? 3;
|
|
4
|
+
const timeoutMs = options.timeoutMs ?? 3e3;
|
|
5
|
+
const startedAtMs = performance.now();
|
|
6
|
+
if (track.readyState === "ended") {
|
|
7
|
+
return { ready: false, frameCount: 0, elapsedMs: 0 };
|
|
8
|
+
}
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
let frameCount = 0;
|
|
11
|
+
let settled = false;
|
|
12
|
+
let rvfcHandle = null;
|
|
13
|
+
let rafId = null;
|
|
14
|
+
const finish = (ready) => {
|
|
15
|
+
if (settled) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
settled = true;
|
|
19
|
+
clearTimeout(timeoutTimer);
|
|
20
|
+
const video = videoEl;
|
|
21
|
+
if (rvfcHandle !== null) {
|
|
22
|
+
video.cancelVideoFrameCallback?.(rvfcHandle);
|
|
23
|
+
}
|
|
24
|
+
if (rafId !== null) {
|
|
25
|
+
window.cancelAnimationFrame(rafId);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
videoEl.pause();
|
|
29
|
+
videoEl.srcObject = null;
|
|
30
|
+
videoEl.remove();
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
resolve({
|
|
34
|
+
ready,
|
|
35
|
+
frameCount,
|
|
36
|
+
elapsedMs: Number((performance.now() - startedAtMs).toFixed(1))
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
const onFrame = () => {
|
|
40
|
+
frameCount += 1;
|
|
41
|
+
if (frameCount >= minFrames) {
|
|
42
|
+
finish(true);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const videoEl = document.createElement("video");
|
|
46
|
+
videoEl.muted = true;
|
|
47
|
+
videoEl.playsInline = true;
|
|
48
|
+
videoEl.autoplay = true;
|
|
49
|
+
videoEl.srcObject = new MediaStream([track]);
|
|
50
|
+
videoEl.style.cssText = "position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none";
|
|
51
|
+
const schedule = () => {
|
|
52
|
+
if (settled) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const video = videoEl;
|
|
56
|
+
if (video.requestVideoFrameCallback) {
|
|
57
|
+
rvfcHandle = video.requestVideoFrameCallback(() => {
|
|
58
|
+
onFrame();
|
|
59
|
+
schedule();
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
rafId = window.requestAnimationFrame(() => {
|
|
64
|
+
onFrame();
|
|
65
|
+
schedule();
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
const timeoutTimer = setTimeout(() => finish(frameCount >= minFrames), timeoutMs);
|
|
69
|
+
void videoEl.play().then(() => {
|
|
70
|
+
if (!settled) {
|
|
71
|
+
schedule();
|
|
72
|
+
}
|
|
73
|
+
}).catch(() => finish(false));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { waitForMediaStreamTrackFrames };
|
|
78
|
+
//# sourceMappingURL=local-publish-diagnostics-ABLL56IT.js.map
|
|
79
|
+
//# sourceMappingURL=local-publish-diagnostics-ABLL56IT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rtc/local-publish-diagnostics.ts"],"names":[],"mappings":"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","file":"local-publish-diagnostics-ABLL56IT.js","sourcesContent":["type VideoWithFrameCallback = HTMLVideoElement & {\n requestVideoFrameCallback?: (\n cb: (now: DOMHighResTimeStamp, metadata: { mediaTime: number; presentedFrames?: number }) => void,\n ) => number\n cancelVideoFrameCallback?: (handle: number) => void\n}\n\nexport async function waitForMediaStreamTrackFrames(\n track: MediaStreamTrack,\n options: { minFrames?: number; timeoutMs?: number } = {},\n): Promise<{ ready: boolean; frameCount: number; elapsedMs: number }> {\n const minFrames = options.minFrames ?? 3\n const timeoutMs = options.timeoutMs ?? 3000\n const startedAtMs = performance.now()\n\n if (track.readyState === 'ended') {\n return { ready: false, frameCount: 0, elapsedMs: 0 }\n }\n\n return new Promise((resolve) => {\n let frameCount = 0\n let settled = false\n let rvfcHandle: number | null = null\n let rafId: number | null = null\n\n const finish = (ready: boolean) => {\n if (settled) {\n return\n }\n settled = true\n clearTimeout(timeoutTimer)\n const video = videoEl as VideoWithFrameCallback\n if (rvfcHandle !== null) {\n video.cancelVideoFrameCallback?.(rvfcHandle)\n }\n if (rafId !== null) {\n window.cancelAnimationFrame(rafId)\n }\n try {\n videoEl.pause()\n videoEl.srcObject = null\n videoEl.remove()\n } catch {\n }\n resolve({\n ready,\n frameCount,\n elapsedMs: Number((performance.now() - startedAtMs).toFixed(1)),\n })\n }\n\n const onFrame = () => {\n frameCount += 1\n if (frameCount >= minFrames) {\n finish(true)\n }\n }\n\n const videoEl = document.createElement('video')\n videoEl.muted = true\n videoEl.playsInline = true\n videoEl.autoplay = true\n videoEl.srcObject = new MediaStream([track])\n videoEl.style.cssText = 'position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none'\n\n const schedule = () => {\n if (settled) {\n return\n }\n\n const video = videoEl as VideoWithFrameCallback\n if (video.requestVideoFrameCallback) {\n rvfcHandle = video.requestVideoFrameCallback!(() => {\n onFrame()\n schedule()\n })\n return\n }\n\n rafId = window.requestAnimationFrame(() => {\n onFrame()\n schedule()\n })\n }\n\n const timeoutTimer = setTimeout(() => finish(frameCount >= minFrames), timeoutMs)\n\n void videoEl.play()\n .then(() => {\n if (!settled) {\n schedule()\n }\n })\n .catch(() => finish(false))\n })\n}\n"]}
|