@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
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
// src/i18n/api-error-codes.ts
|
|
2
|
-
var SYSTEM_OVERLOADED = {
|
|
3
|
-
"zh-CN": "\u5F53\u524D\u4F7F\u7528\u4EBA\u6570\u8FC7\u591A\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",
|
|
4
|
-
"en-US": "The system is currently overloaded. Please retry after some time."
|
|
5
|
-
};
|
|
6
|
-
var API_ERROR_MESSAGES = {
|
|
7
|
-
"46001": { "zh-CN": "X-Api-Key \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "X-Api-Key cannot be empty" },
|
|
8
|
-
"46002": { "zh-CN": "\u65E0\u6548\u7684\u7528\u6237 API Key", "en-US": "Invalid user API Key" },
|
|
9
|
-
"46003": { "zh-CN": "model \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "model cannot be empty" },
|
|
10
|
-
"46004": { "zh-CN": "sessionUid \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "sessionUid cannot be empty" },
|
|
11
|
-
"46005": { "zh-CN": "\u6A21\u578B\u7C7B\u578B\u4E0D\u5B58\u5728", "en-US": "Model type does not exist" },
|
|
12
|
-
"46006": SYSTEM_OVERLOADED,
|
|
13
|
-
"46007": SYSTEM_OVERLOADED,
|
|
14
|
-
"46008": SYSTEM_OVERLOADED,
|
|
15
|
-
"46009": SYSTEM_OVERLOADED,
|
|
16
|
-
"46010": SYSTEM_OVERLOADED,
|
|
17
|
-
"46012": { "zh-CN": "\u4F1A\u8BDD\u4E0D\u5B58\u5728", "en-US": "Session does not exist" },
|
|
18
|
-
"46013": { "zh-CN": "\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u5F53\u524D\u7528\u6237", "en-US": "Session does not belong to the current user" },
|
|
19
|
-
"46014": { "zh-CN": "\u4F1A\u8BDD\u5DF2\u5173\u95ED", "en-US": "Session has been closed" },
|
|
20
|
-
"46015": { "zh-CN": "\u4F1A\u8BDD\u5DF2\u8D85\u65F6", "en-US": "Session has timed out" },
|
|
21
|
-
"46018": { "zh-CN": "\u4E34\u65F6 API Key \u5DF2\u8FC7\u671F", "en-US": "Temporary API Key has expired" },
|
|
22
|
-
"46019": {
|
|
23
|
-
"zh-CN": "\u4E34\u65F6 API Key \u5DF2\u8FBE\u5230\u79EF\u5206\u4E0A\u9650",
|
|
24
|
-
"en-US": "Temporary API Key has reached its points limit"
|
|
25
|
-
},
|
|
26
|
-
"46021": {
|
|
27
|
-
"zh-CN": "\u4E34\u65F6 API Key \u4E0D\u5141\u8BB8\u518D\u521B\u5EFA\u4E34\u65F6 API Key",
|
|
28
|
-
"en-US": "A temporary API Key cannot create another temporary API Key"
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
function resolveApiErrorMessage(code, locale) {
|
|
32
|
-
if (code === null || code === void 0) return void 0;
|
|
33
|
-
const entry = API_ERROR_MESSAGES[String(code)];
|
|
34
|
-
if (!entry) return void 0;
|
|
35
|
-
return entry[locale] ?? entry["en-US"];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
1
|
// src/i18n/en-US.ts
|
|
39
2
|
var enUS = {
|
|
40
3
|
"errors.apiKeyEmpty": "apiKey cannot be empty",
|
|
@@ -147,6 +110,43 @@ var zhCN = {
|
|
|
147
110
|
"rtc.getCodecsFailed": "\u83B7\u53D6\u6D4F\u89C8\u5668\u7F16\u89E3\u7801\u652F\u6301\u5931\u8D25\uFF0CSEI gate \u5C06\u4E0D\u4F1A\u751F\u6548\uFF0Coutput \u5C06\u4E0D\u518D\u88AB\u62E6\u622A"
|
|
148
111
|
};
|
|
149
112
|
|
|
113
|
+
// src/i18n/api-error-codes.ts
|
|
114
|
+
var SYSTEM_OVERLOADED = {
|
|
115
|
+
"zh-CN": "\u5F53\u524D\u4F7F\u7528\u4EBA\u6570\u8FC7\u591A\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",
|
|
116
|
+
"en-US": "The system is currently overloaded. Please retry after some time."
|
|
117
|
+
};
|
|
118
|
+
var API_ERROR_MESSAGES = {
|
|
119
|
+
"46001": { "zh-CN": "X-Api-Key \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "X-Api-Key cannot be empty" },
|
|
120
|
+
"46002": { "zh-CN": "\u65E0\u6548\u7684\u7528\u6237 API Key", "en-US": "Invalid user API Key" },
|
|
121
|
+
"46003": { "zh-CN": "model \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "model cannot be empty" },
|
|
122
|
+
"46004": { "zh-CN": "sessionUid \u4E0D\u80FD\u4E3A\u7A7A", "en-US": "sessionUid cannot be empty" },
|
|
123
|
+
"46005": { "zh-CN": "\u6A21\u578B\u7C7B\u578B\u4E0D\u5B58\u5728", "en-US": "Model type does not exist" },
|
|
124
|
+
"46006": SYSTEM_OVERLOADED,
|
|
125
|
+
"46007": SYSTEM_OVERLOADED,
|
|
126
|
+
"46008": SYSTEM_OVERLOADED,
|
|
127
|
+
"46009": SYSTEM_OVERLOADED,
|
|
128
|
+
"46010": SYSTEM_OVERLOADED,
|
|
129
|
+
"46012": { "zh-CN": "\u4F1A\u8BDD\u4E0D\u5B58\u5728", "en-US": "Session does not exist" },
|
|
130
|
+
"46013": { "zh-CN": "\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u5F53\u524D\u7528\u6237", "en-US": "Session does not belong to the current user" },
|
|
131
|
+
"46014": { "zh-CN": "\u4F1A\u8BDD\u5DF2\u5173\u95ED", "en-US": "Session has been closed" },
|
|
132
|
+
"46015": { "zh-CN": "\u4F1A\u8BDD\u5DF2\u8D85\u65F6", "en-US": "Session has timed out" },
|
|
133
|
+
"46018": { "zh-CN": "\u4E34\u65F6 API Key \u5DF2\u8FC7\u671F", "en-US": "Temporary API Key has expired" },
|
|
134
|
+
"46019": {
|
|
135
|
+
"zh-CN": "\u4E34\u65F6 API Key \u5DF2\u8FBE\u5230\u79EF\u5206\u4E0A\u9650",
|
|
136
|
+
"en-US": "Temporary API Key has reached its points limit"
|
|
137
|
+
},
|
|
138
|
+
"46021": {
|
|
139
|
+
"zh-CN": "\u4E34\u65F6 API Key \u4E0D\u5141\u8BB8\u518D\u521B\u5EFA\u4E34\u65F6 API Key",
|
|
140
|
+
"en-US": "A temporary API Key cannot create another temporary API Key"
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
function resolveApiErrorMessage(code, locale) {
|
|
144
|
+
if (code === null || code === void 0) return void 0;
|
|
145
|
+
const entry = API_ERROR_MESSAGES[String(code)];
|
|
146
|
+
if (!entry) return void 0;
|
|
147
|
+
return entry[locale] ?? entry["en-US"];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
150
|
// src/i18n/index.ts
|
|
151
151
|
function formatTemplate(template, params) {
|
|
152
152
|
if (!params) return template;
|
|
@@ -174,6 +174,167 @@ function createSDKI18n(input) {
|
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
// src/rtc/publish-fps.ts
|
|
178
|
+
var MOBILE_PUBLISH_MAX_WIDTH_PX = 768;
|
|
179
|
+
var RTC_PUBLISH_FPS_WEB = 30;
|
|
180
|
+
var RTC_PUBLISH_FPS_MOBILE = 24;
|
|
181
|
+
function isMobilePublishEnvironment() {
|
|
182
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
return window.matchMedia(`(max-width: ${MOBILE_PUBLISH_MAX_WIDTH_PX}px)`).matches;
|
|
186
|
+
}
|
|
187
|
+
function resolveRtcPublishFps(options = {}) {
|
|
188
|
+
if (typeof options.fps === "number" && Number.isFinite(options.fps) && options.fps > 0) {
|
|
189
|
+
return options.fps;
|
|
190
|
+
}
|
|
191
|
+
const mobile = options.mobile ?? isMobilePublishEnvironment();
|
|
192
|
+
return mobile ? RTC_PUBLISH_FPS_MOBILE : RTC_PUBLISH_FPS_WEB;
|
|
193
|
+
}
|
|
194
|
+
function resolveRtcPublishFrameIntervalS(options) {
|
|
195
|
+
return 1 / resolveRtcPublishFps(options);
|
|
196
|
+
}
|
|
197
|
+
var RTC_PUBLISH_FRAME_INTERVAL_S = 1 / RTC_PUBLISH_FPS_WEB;
|
|
198
|
+
var RTC_PUBLISH_FRAME_INTERVAL_MS = 1e3 / RTC_PUBLISH_FPS_WEB;
|
|
199
|
+
var MEDIA_TIME_EPSILON_S = 1e-3;
|
|
200
|
+
var MEDIA_TIME_LOOP_JUMP_S = 0.05;
|
|
201
|
+
|
|
202
|
+
// src/shared/reference-video-size.ts
|
|
203
|
+
var PREVIEW_CONTAINER_ASPECT_RATIO = 16 / 9;
|
|
204
|
+
function resolvePreviewAspectRatio(size) {
|
|
205
|
+
return `${size[0]} / ${size[1]}`;
|
|
206
|
+
}
|
|
207
|
+
var DEFAULT_SESSION_TARGET_SIZE = [1472, 832];
|
|
208
|
+
var UPLOAD_VIDEO_BASE = 832;
|
|
209
|
+
var UPLOAD_SIZE_ALIGN = 32;
|
|
210
|
+
var MAX_LANDSCAPE_ASPECT = 16 / 9;
|
|
211
|
+
var MAX_PORTRAIT_HEIGHT_RATIO = 16 / 9;
|
|
212
|
+
function alignToSizeMultiple(value) {
|
|
213
|
+
return Math.max(UPLOAD_SIZE_ALIGN, Math.round(value / UPLOAD_SIZE_ALIGN) * UPLOAD_SIZE_ALIGN);
|
|
214
|
+
}
|
|
215
|
+
function makeEven(value) {
|
|
216
|
+
const rounded = Math.max(2, Math.round(value));
|
|
217
|
+
return rounded % 2 === 0 ? rounded : rounded - 1;
|
|
218
|
+
}
|
|
219
|
+
function resolveUploadPublishSize(sourceWidth, sourceHeight) {
|
|
220
|
+
if (sourceWidth <= 0 || sourceHeight <= 0) {
|
|
221
|
+
return DEFAULT_SESSION_TARGET_SIZE;
|
|
222
|
+
}
|
|
223
|
+
return [makeEven(sourceWidth), makeEven(sourceHeight)];
|
|
224
|
+
}
|
|
225
|
+
function resolveAdaptiveRtcVideoSize(sourceWidth, sourceHeight, baseSize = DEFAULT_SESSION_TARGET_SIZE) {
|
|
226
|
+
if (sourceWidth <= 0 || sourceHeight <= 0) {
|
|
227
|
+
return baseSize;
|
|
228
|
+
}
|
|
229
|
+
const [baseWidth, baseHeight] = baseSize;
|
|
230
|
+
const sourceAspectRatio = sourceHeight / sourceWidth;
|
|
231
|
+
const baseAspectRatio = baseHeight / baseWidth;
|
|
232
|
+
if (sourceAspectRatio >= baseAspectRatio) {
|
|
233
|
+
return [baseWidth, baseHeight];
|
|
234
|
+
}
|
|
235
|
+
const adaptiveHeight = Math.max(
|
|
236
|
+
UPLOAD_SIZE_ALIGN,
|
|
237
|
+
Math.round(baseWidth * sourceAspectRatio)
|
|
238
|
+
);
|
|
239
|
+
return [baseWidth, makeEven(adaptiveHeight)];
|
|
240
|
+
}
|
|
241
|
+
function resolveUploadVideoSize(sourceWidth, sourceHeight) {
|
|
242
|
+
if (sourceWidth <= 0 || sourceHeight <= 0) {
|
|
243
|
+
return DEFAULT_SESSION_TARGET_SIZE;
|
|
244
|
+
}
|
|
245
|
+
if (sourceWidth === sourceHeight) {
|
|
246
|
+
return [UPLOAD_VIDEO_BASE, UPLOAD_VIDEO_BASE];
|
|
247
|
+
}
|
|
248
|
+
const aspect = sourceWidth / sourceHeight;
|
|
249
|
+
if (sourceHeight > sourceWidth) {
|
|
250
|
+
const width2 = UPLOAD_VIDEO_BASE;
|
|
251
|
+
let height2 = alignToSizeMultiple(width2 / aspect);
|
|
252
|
+
const maxHeight = alignToSizeMultiple(width2 * MAX_PORTRAIT_HEIGHT_RATIO);
|
|
253
|
+
if (height2 > maxHeight) {
|
|
254
|
+
height2 = maxHeight;
|
|
255
|
+
}
|
|
256
|
+
return [width2, height2];
|
|
257
|
+
}
|
|
258
|
+
const height = UPLOAD_VIDEO_BASE;
|
|
259
|
+
let width = alignToSizeMultiple(height * aspect);
|
|
260
|
+
const maxWidth = alignToSizeMultiple(height * MAX_LANDSCAPE_ASPECT);
|
|
261
|
+
if (width > maxWidth) {
|
|
262
|
+
width = maxWidth;
|
|
263
|
+
}
|
|
264
|
+
return [width, height];
|
|
265
|
+
}
|
|
266
|
+
function resolveSessionTargetSize(input) {
|
|
267
|
+
if (input.overrideSize) {
|
|
268
|
+
return input.overrideSize;
|
|
269
|
+
}
|
|
270
|
+
if (input.localVideoSize?.width && input.localVideoSize?.height) {
|
|
271
|
+
return [input.localVideoSize.width, input.localVideoSize.height];
|
|
272
|
+
}
|
|
273
|
+
return DEFAULT_SESSION_TARGET_SIZE;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/rtc/capture-crop.ts
|
|
277
|
+
function computeCenterCropRect(sourceWidth, sourceHeight, targetAspect) {
|
|
278
|
+
const sourceAspect = sourceWidth / sourceHeight;
|
|
279
|
+
if (sourceAspect > targetAspect) {
|
|
280
|
+
const height2 = sourceHeight;
|
|
281
|
+
const width2 = sourceHeight * targetAspect;
|
|
282
|
+
return {
|
|
283
|
+
x: (sourceWidth - width2) / 2,
|
|
284
|
+
y: 0,
|
|
285
|
+
width: width2,
|
|
286
|
+
height: height2
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const width = sourceWidth;
|
|
290
|
+
const height = sourceWidth / targetAspect;
|
|
291
|
+
return {
|
|
292
|
+
x: 0,
|
|
293
|
+
y: (sourceHeight - height) / 2,
|
|
294
|
+
width,
|
|
295
|
+
height
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/rtc/canvas-frame-draw.ts
|
|
300
|
+
function drawSourceCenterCrop(ctx, source, outputWidth, outputHeight, sourceWidth, sourceHeight) {
|
|
301
|
+
ctx.imageSmoothingEnabled = true;
|
|
302
|
+
ctx.imageSmoothingQuality = "high";
|
|
303
|
+
ctx.clearRect(0, 0, outputWidth, outputHeight);
|
|
304
|
+
const crop = computeCenterCropRect(
|
|
305
|
+
sourceWidth,
|
|
306
|
+
sourceHeight,
|
|
307
|
+
outputWidth / outputHeight
|
|
308
|
+
);
|
|
309
|
+
ctx.drawImage(
|
|
310
|
+
source,
|
|
311
|
+
crop.x,
|
|
312
|
+
crop.y,
|
|
313
|
+
crop.width,
|
|
314
|
+
crop.height,
|
|
315
|
+
0,
|
|
316
|
+
0,
|
|
317
|
+
outputWidth,
|
|
318
|
+
outputHeight
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/rtc/capture-host.ts
|
|
323
|
+
var captureHostRoot = null;
|
|
324
|
+
var CAPTURE_VIDEO_STYLE = "position:fixed;left:-10000px;top:0;width:640px;height:480px;opacity:1;pointer-events:none;z-index:-1;";
|
|
325
|
+
function mountCaptureVideo(videoEl) {
|
|
326
|
+
if (!captureHostRoot) {
|
|
327
|
+
captureHostRoot = document.createElement("div");
|
|
328
|
+
captureHostRoot.setAttribute("data-xmax-capture-host", "true");
|
|
329
|
+
captureHostRoot.style.cssText = "position:fixed;left:0;top:0;width:0;height:0;overflow:hidden;pointer-events:none;z-index:-1;";
|
|
330
|
+
document.body.appendChild(captureHostRoot);
|
|
331
|
+
}
|
|
332
|
+
videoEl.setAttribute("playsinline", "true");
|
|
333
|
+
videoEl.setAttribute("webkit-playsinline", "true");
|
|
334
|
+
videoEl.style.cssText = CAPTURE_VIDEO_STYLE;
|
|
335
|
+
captureHostRoot.appendChild(videoEl);
|
|
336
|
+
}
|
|
337
|
+
|
|
177
338
|
// src/rtc/video-frame-rate.ts
|
|
178
339
|
var COMMON_VIDEO_FPS = [24, 25, 30, 48, 50, 60];
|
|
179
340
|
function median(values) {
|
|
@@ -293,122 +454,318 @@ function resolvePlaybackDrivenEncoderFps(track, fallback = 24) {
|
|
|
293
454
|
return resolveTrackFrameRate(track, fallback);
|
|
294
455
|
}
|
|
295
456
|
|
|
296
|
-
// src/rtc/
|
|
297
|
-
var
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
var RTC_PUBLISH_FPS = RTC_PUBLISH_FPS_WEB;
|
|
301
|
-
function isMobilePublishEnvironment() {
|
|
302
|
-
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
457
|
+
// src/rtc/video-file-stream.ts
|
|
458
|
+
var STALL_CATCHUP_MS = 1500;
|
|
459
|
+
function shouldSampleAtMediaTime(lastMediaTimeS, mediaTimeS) {
|
|
460
|
+
if (!Number.isFinite(mediaTimeS) || mediaTimeS < 0) {
|
|
303
461
|
return false;
|
|
304
462
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
function resolveRtcPublishFps(options = {}) {
|
|
308
|
-
if (typeof options.fps === "number" && Number.isFinite(options.fps) && options.fps > 0) {
|
|
309
|
-
return options.fps;
|
|
463
|
+
if (lastMediaTimeS < 0) {
|
|
464
|
+
return true;
|
|
310
465
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
function resolveRtcPublishFrameIntervalS(options) {
|
|
315
|
-
return 1 / resolveRtcPublishFps(options);
|
|
316
|
-
}
|
|
317
|
-
var RTC_PUBLISH_FRAME_INTERVAL_S = 1 / RTC_PUBLISH_FPS_WEB;
|
|
318
|
-
var RTC_PUBLISH_FRAME_INTERVAL_MS = 1e3 / RTC_PUBLISH_FPS_WEB;
|
|
319
|
-
var MEDIA_TIME_EPSILON_S = 1e-3;
|
|
320
|
-
var MEDIA_TIME_LOOP_JUMP_S = 0.05;
|
|
321
|
-
|
|
322
|
-
// src/shared/reference-video-size.ts
|
|
323
|
-
var PREVIEW_CONTAINER_ASPECT_RATIO = 16 / 9;
|
|
324
|
-
function resolvePreviewAspectRatio(size) {
|
|
325
|
-
return `${size[0]} / ${size[1]}`;
|
|
326
|
-
}
|
|
327
|
-
var DEFAULT_SESSION_TARGET_SIZE = [1472, 832];
|
|
328
|
-
var UPLOAD_VIDEO_BASE = 832;
|
|
329
|
-
var UPLOAD_SIZE_ALIGN = 32;
|
|
330
|
-
var MAX_LANDSCAPE_ASPECT = 16 / 9;
|
|
331
|
-
var MAX_PORTRAIT_HEIGHT_RATIO = 16 / 9;
|
|
332
|
-
function alignToSizeMultiple(value) {
|
|
333
|
-
return Math.max(UPLOAD_SIZE_ALIGN, Math.round(value / UPLOAD_SIZE_ALIGN) * UPLOAD_SIZE_ALIGN);
|
|
334
|
-
}
|
|
335
|
-
function makeEven(value) {
|
|
336
|
-
const rounded = Math.max(2, Math.round(value));
|
|
337
|
-
return rounded % 2 === 0 ? rounded : rounded - 1;
|
|
338
|
-
}
|
|
339
|
-
function resolveUploadPublishSize(sourceWidth, sourceHeight) {
|
|
340
|
-
if (sourceWidth <= 0 || sourceHeight <= 0) {
|
|
341
|
-
return DEFAULT_SESSION_TARGET_SIZE;
|
|
466
|
+
if (mediaTimeS + MEDIA_TIME_LOOP_JUMP_S < lastMediaTimeS) {
|
|
467
|
+
return true;
|
|
342
468
|
}
|
|
343
|
-
return
|
|
469
|
+
return mediaTimeS > lastMediaTimeS + MEDIA_TIME_EPSILON_S;
|
|
344
470
|
}
|
|
345
|
-
function
|
|
346
|
-
if (
|
|
347
|
-
return
|
|
471
|
+
async function applyPublishTrackConstraints(track, width, height) {
|
|
472
|
+
if (typeof track.applyConstraints !== "function") {
|
|
473
|
+
return;
|
|
348
474
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
475
|
+
try {
|
|
476
|
+
await track.applyConstraints({
|
|
477
|
+
width: { ideal: width, max: width },
|
|
478
|
+
height: { ideal: height, max: height }
|
|
479
|
+
});
|
|
480
|
+
} catch {
|
|
354
481
|
}
|
|
355
|
-
const adaptiveHeight = Math.max(
|
|
356
|
-
UPLOAD_SIZE_ALIGN,
|
|
357
|
-
Math.round(baseWidth * sourceAspectRatio)
|
|
358
|
-
);
|
|
359
|
-
return [baseWidth, makeEven(adaptiveHeight)];
|
|
360
482
|
}
|
|
361
|
-
function
|
|
362
|
-
|
|
363
|
-
|
|
483
|
+
async function createVideoFileStream(fileOrUrl, options = {}) {
|
|
484
|
+
const i18n = options.i18n ?? createSDKI18n();
|
|
485
|
+
const isUrl = typeof fileOrUrl === "string";
|
|
486
|
+
const url = isUrl ? fileOrUrl : URL.createObjectURL(fileOrUrl);
|
|
487
|
+
const videoEl = document.createElement("video");
|
|
488
|
+
videoEl.muted = options.muted ?? true;
|
|
489
|
+
videoEl.playsInline = true;
|
|
490
|
+
if (isUrl) {
|
|
491
|
+
videoEl.crossOrigin = "anonymous";
|
|
364
492
|
}
|
|
365
|
-
|
|
366
|
-
|
|
493
|
+
videoEl.src = url;
|
|
494
|
+
videoEl.loop = options.loop ?? true;
|
|
495
|
+
videoEl.autoplay = true;
|
|
496
|
+
mountCaptureVideo(videoEl);
|
|
497
|
+
try {
|
|
498
|
+
videoEl.load();
|
|
499
|
+
await waitForEvent(videoEl, "loadedmetadata");
|
|
500
|
+
await waitForCanPlay(videoEl);
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
503
|
+
throw error;
|
|
367
504
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
505
|
+
if (typeof options.playbackRate === "number") {
|
|
506
|
+
videoEl.playbackRate = options.playbackRate;
|
|
507
|
+
}
|
|
508
|
+
await startVideoPlayback(videoEl, i18n);
|
|
509
|
+
const sourceWidth = videoEl.videoWidth || 0;
|
|
510
|
+
const sourceHeight = videoEl.videoHeight || 0;
|
|
511
|
+
if (!sourceWidth || !sourceHeight) {
|
|
512
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
513
|
+
throw new Error(i18n.t("errors.videoTrackMissing"));
|
|
514
|
+
}
|
|
515
|
+
const measuredFps = typeof options.fps === "number" && options.fps > 0 ? options.fps : await estimateVideoFrameRate(videoEl);
|
|
516
|
+
const [outputWidth, outputHeight] = options.targetSize ?? resolveUploadVideoSize(sourceWidth, sourceHeight);
|
|
517
|
+
const canvas = document.createElement("canvas");
|
|
518
|
+
canvas.width = outputWidth;
|
|
519
|
+
canvas.height = outputHeight;
|
|
520
|
+
const ctx = canvas.getContext("2d");
|
|
521
|
+
if (!ctx) {
|
|
522
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
523
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
524
|
+
}
|
|
525
|
+
const captureStreamFn = canvas.captureStream ?? canvas.mozCaptureStream;
|
|
526
|
+
if (!captureStreamFn) {
|
|
527
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
528
|
+
throw new Error(i18n.t("errors.captureStreamUnsupported"));
|
|
529
|
+
}
|
|
530
|
+
const previewStream = captureStreamFn.call(canvas);
|
|
531
|
+
const videoTrack = previewStream.getVideoTracks()[0];
|
|
532
|
+
if (!videoTrack) {
|
|
533
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
534
|
+
throw new Error(i18n.t("errors.videoTrackMissing"));
|
|
535
|
+
}
|
|
536
|
+
const publishFps = resolvePlaybackDrivenEncoderFps(videoTrack, measuredFps);
|
|
537
|
+
await applyPublishTrackConstraints(videoTrack, outputWidth, outputHeight);
|
|
538
|
+
let destroyed = false;
|
|
539
|
+
let lastAdvanceAt = Date.now();
|
|
540
|
+
let lastDrawMediaTimeS = -1;
|
|
541
|
+
let videoFrameCallbackId = null;
|
|
542
|
+
let rafId = null;
|
|
543
|
+
const drawFrame = () => {
|
|
544
|
+
if (destroyed) {
|
|
545
|
+
return;
|
|
375
546
|
}
|
|
376
|
-
|
|
547
|
+
drawSourceCenterCrop(
|
|
548
|
+
ctx,
|
|
549
|
+
videoEl,
|
|
550
|
+
outputWidth,
|
|
551
|
+
outputHeight,
|
|
552
|
+
sourceWidth,
|
|
553
|
+
sourceHeight
|
|
554
|
+
);
|
|
555
|
+
};
|
|
556
|
+
const onPlaybackSample = (mediaTimeS) => {
|
|
557
|
+
if (destroyed || !shouldSampleAtMediaTime(lastDrawMediaTimeS, mediaTimeS)) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
lastDrawMediaTimeS = mediaTimeS;
|
|
561
|
+
lastAdvanceAt = Date.now();
|
|
562
|
+
drawFrame();
|
|
563
|
+
};
|
|
564
|
+
const schedulePlaybackWatch = () => {
|
|
565
|
+
if (destroyed) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const video = videoEl;
|
|
569
|
+
if (video.requestVideoFrameCallback) {
|
|
570
|
+
videoFrameCallbackId = video.requestVideoFrameCallback((_now, metadata) => {
|
|
571
|
+
onPlaybackSample(metadata.mediaTime);
|
|
572
|
+
schedulePlaybackWatch();
|
|
573
|
+
});
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
rafId = window.requestAnimationFrame(() => {
|
|
577
|
+
onPlaybackSample(videoEl.currentTime);
|
|
578
|
+
schedulePlaybackWatch();
|
|
579
|
+
});
|
|
580
|
+
};
|
|
581
|
+
drawFrame();
|
|
582
|
+
schedulePlaybackWatch();
|
|
583
|
+
const ensurePlaying = () => {
|
|
584
|
+
if (destroyed) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (videoEl.ended && videoEl.loop) {
|
|
588
|
+
videoEl.currentTime = 0;
|
|
589
|
+
lastDrawMediaTimeS = -1;
|
|
590
|
+
}
|
|
591
|
+
if (videoEl.paused) {
|
|
592
|
+
void videoEl.play().catch(() => void 0);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
const markAdvance = () => {
|
|
596
|
+
lastAdvanceAt = Date.now();
|
|
597
|
+
};
|
|
598
|
+
videoEl.addEventListener("timeupdate", markAdvance);
|
|
599
|
+
videoEl.addEventListener("pause", ensurePlaying);
|
|
600
|
+
videoEl.addEventListener("ended", ensurePlaying);
|
|
601
|
+
videoEl.addEventListener("stalled", ensurePlaying);
|
|
602
|
+
videoEl.addEventListener("waiting", ensurePlaying);
|
|
603
|
+
const healthIntervalMs = options.healthIntervalMs ?? 3e3;
|
|
604
|
+
let healthTimer = null;
|
|
605
|
+
if (options.onHealthReport) {
|
|
606
|
+
const reportHealth = options.onHealthReport;
|
|
607
|
+
healthTimer = setInterval(() => {
|
|
608
|
+
ensurePlaying();
|
|
609
|
+
const now = Date.now();
|
|
610
|
+
const currentTime = videoEl.currentTime;
|
|
611
|
+
const duration = videoEl.duration;
|
|
612
|
+
const nearEnd = duration > 0 && currentTime >= duration - 0.2;
|
|
613
|
+
const stalled = !videoEl.paused && !videoEl.ended && !nearEnd && now - lastAdvanceAt >= healthIntervalMs;
|
|
614
|
+
if (stalled && now - lastAdvanceAt >= STALL_CATCHUP_MS) {
|
|
615
|
+
void videoEl.play().catch(() => void 0);
|
|
616
|
+
}
|
|
617
|
+
reportHealth({
|
|
618
|
+
currentTime,
|
|
619
|
+
duration,
|
|
620
|
+
paused: videoEl.paused,
|
|
621
|
+
ended: videoEl.ended,
|
|
622
|
+
readyState: videoEl.readyState,
|
|
623
|
+
trackReadyState: videoTrack.readyState,
|
|
624
|
+
trackMuted: videoTrack.muted,
|
|
625
|
+
stalled,
|
|
626
|
+
timeSinceAdvanceMs: now - lastAdvanceAt
|
|
627
|
+
});
|
|
628
|
+
}, healthIntervalMs);
|
|
377
629
|
}
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
630
|
+
const destroy = () => {
|
|
631
|
+
destroyed = true;
|
|
632
|
+
videoEl.removeEventListener("timeupdate", markAdvance);
|
|
633
|
+
videoEl.removeEventListener("pause", ensurePlaying);
|
|
634
|
+
videoEl.removeEventListener("ended", ensurePlaying);
|
|
635
|
+
videoEl.removeEventListener("stalled", ensurePlaying);
|
|
636
|
+
videoEl.removeEventListener("waiting", ensurePlaying);
|
|
637
|
+
const video = videoEl;
|
|
638
|
+
if (videoFrameCallbackId !== null) {
|
|
639
|
+
video.cancelVideoFrameCallback?.(videoFrameCallbackId);
|
|
640
|
+
videoFrameCallbackId = null;
|
|
641
|
+
}
|
|
642
|
+
if (rafId !== null) {
|
|
643
|
+
window.cancelAnimationFrame(rafId);
|
|
644
|
+
rafId = null;
|
|
645
|
+
}
|
|
646
|
+
if (healthTimer !== null) {
|
|
647
|
+
clearInterval(healthTimer);
|
|
648
|
+
healthTimer = null;
|
|
649
|
+
}
|
|
650
|
+
try {
|
|
651
|
+
videoEl.pause();
|
|
652
|
+
} catch {
|
|
653
|
+
}
|
|
654
|
+
try {
|
|
655
|
+
videoTrack.stop();
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
try {
|
|
659
|
+
previewStream.getTracks().forEach((track) => {
|
|
660
|
+
if (track.readyState !== "ended") {
|
|
661
|
+
track.stop();
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
} catch {
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
videoEl.remove();
|
|
668
|
+
} catch {
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
videoEl.src = "";
|
|
672
|
+
videoEl.load();
|
|
673
|
+
} catch {
|
|
674
|
+
}
|
|
675
|
+
if (!isUrl) URL.revokeObjectURL(url);
|
|
676
|
+
};
|
|
677
|
+
return {
|
|
678
|
+
url,
|
|
679
|
+
previewStream,
|
|
680
|
+
videoEl,
|
|
681
|
+
videoTrack,
|
|
682
|
+
fps: publishFps,
|
|
683
|
+
width: outputWidth,
|
|
684
|
+
height: outputHeight,
|
|
685
|
+
sourceWidth,
|
|
686
|
+
sourceHeight,
|
|
687
|
+
destroy
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
function waitForEvent(el, eventName) {
|
|
691
|
+
return new Promise((resolve, reject) => {
|
|
692
|
+
const onOk = () => {
|
|
693
|
+
cleanup();
|
|
694
|
+
resolve();
|
|
695
|
+
};
|
|
696
|
+
const onErr = (e) => {
|
|
697
|
+
cleanup();
|
|
698
|
+
const mediaEl = el;
|
|
699
|
+
const code = mediaEl.error ? mediaEl.error.code : "unknown";
|
|
700
|
+
const message = mediaEl.error ? mediaEl.error.message : "no message";
|
|
701
|
+
const src = mediaEl.src || "unknown src";
|
|
702
|
+
reject(new Error(`failed to load video metadata: ${String(eventName)} (code: ${code}, message: ${message}, src: ${src})`));
|
|
703
|
+
};
|
|
704
|
+
const cleanup = () => {
|
|
705
|
+
el.removeEventListener(eventName, onOk);
|
|
706
|
+
el.removeEventListener("error", onErr);
|
|
707
|
+
};
|
|
708
|
+
el.addEventListener(eventName, onOk, { once: true });
|
|
709
|
+
el.addEventListener("error", onErr, { once: true });
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
function waitForCanPlay(videoEl) {
|
|
713
|
+
if (videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
714
|
+
return Promise.resolve();
|
|
383
715
|
}
|
|
384
|
-
return
|
|
716
|
+
return new Promise((resolve) => {
|
|
717
|
+
const onReady = () => {
|
|
718
|
+
cleanup();
|
|
719
|
+
resolve();
|
|
720
|
+
};
|
|
721
|
+
const cleanup = () => {
|
|
722
|
+
videoEl.removeEventListener("canplay", onReady);
|
|
723
|
+
videoEl.removeEventListener("loadeddata", onReady);
|
|
724
|
+
};
|
|
725
|
+
videoEl.addEventListener("canplay", onReady, { once: true });
|
|
726
|
+
videoEl.addEventListener("loadeddata", onReady, { once: true });
|
|
727
|
+
});
|
|
385
728
|
}
|
|
386
|
-
function
|
|
387
|
-
|
|
388
|
-
|
|
729
|
+
async function startVideoPlayback(videoEl, i18n) {
|
|
730
|
+
try {
|
|
731
|
+
const playResult = videoEl.play();
|
|
732
|
+
if (playResult && typeof playResult.then === "function") {
|
|
733
|
+
await playResult;
|
|
734
|
+
}
|
|
735
|
+
} catch {
|
|
736
|
+
throw new Error(i18n.t("errors.videoPlaybackFailed"));
|
|
389
737
|
}
|
|
390
|
-
|
|
391
|
-
|
|
738
|
+
try {
|
|
739
|
+
await waitForPlaying(videoEl);
|
|
740
|
+
} catch {
|
|
741
|
+
throw new Error(i18n.t("errors.videoPlaybackFailed"));
|
|
742
|
+
}
|
|
743
|
+
if (videoEl.paused || videoEl.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
744
|
+
throw new Error(i18n.t("errors.videoPlaybackFailed"));
|
|
392
745
|
}
|
|
393
|
-
return DEFAULT_SESSION_TARGET_SIZE;
|
|
394
746
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
var CAPTURE_VIDEO_STYLE = "position:fixed;left:-10000px;top:0;width:640px;height:480px;opacity:1;pointer-events:none;z-index:-1;";
|
|
399
|
-
function mountCaptureVideo(videoEl) {
|
|
400
|
-
if (!captureHostRoot) {
|
|
401
|
-
captureHostRoot = document.createElement("div");
|
|
402
|
-
captureHostRoot.setAttribute("data-xmax-capture-host", "true");
|
|
403
|
-
captureHostRoot.style.cssText = "position:fixed;left:0;top:0;width:0;height:0;overflow:hidden;pointer-events:none;z-index:-1;";
|
|
404
|
-
document.body.appendChild(captureHostRoot);
|
|
747
|
+
function waitForPlaying(videoEl) {
|
|
748
|
+
if (!videoEl.paused && videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
749
|
+
return Promise.resolve();
|
|
405
750
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
751
|
+
return new Promise((resolve, reject) => {
|
|
752
|
+
const onPlaying = () => {
|
|
753
|
+
cleanup();
|
|
754
|
+
resolve();
|
|
755
|
+
};
|
|
756
|
+
const onErr = () => {
|
|
757
|
+
cleanup();
|
|
758
|
+
reject(new Error("video playback failed"));
|
|
759
|
+
};
|
|
760
|
+
const cleanup = () => {
|
|
761
|
+
videoEl.removeEventListener("playing", onPlaying);
|
|
762
|
+
videoEl.removeEventListener("error", onErr);
|
|
763
|
+
};
|
|
764
|
+
videoEl.addEventListener("playing", onPlaying, { once: true });
|
|
765
|
+
videoEl.addEventListener("error", onErr, { once: true });
|
|
766
|
+
});
|
|
410
767
|
}
|
|
411
768
|
|
|
412
|
-
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,
|
|
413
|
-
//# sourceMappingURL=chunk-
|
|
414
|
-
//# sourceMappingURL=chunk-
|
|
769
|
+
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_MOBILE, RTC_PUBLISH_FPS_WEB, RTC_PUBLISH_FRAME_INTERVAL_MS, RTC_PUBLISH_FRAME_INTERVAL_S, computeCenterCropRect, createSDKI18n, createVideoFileStream, drawSourceCenterCrop, getDefaultMessages, isMobilePublishEnvironment, mountCaptureVideo, resolveAdaptiveRtcVideoSize, resolveApiErrorMessage, resolvePlaybackDrivenEncoderFps, resolvePreviewAspectRatio, resolveRtcPublishFps, resolveRtcPublishFrameIntervalS, resolveSessionTargetSize, resolveUploadPublishSize, resolveUploadVideoSize };
|
|
770
|
+
//# sourceMappingURL=chunk-TFGYBN3Q.js.map
|
|
771
|
+
//# sourceMappingURL=chunk-TFGYBN3Q.js.map
|