@xmaxai/sdk 1.0.1 → 1.0.3

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/README.md +19 -5
  3. package/dist/{chunk-LCPC56BK.js → chunk-B5EAQTBY.js} +497 -136
  4. package/dist/chunk-B5EAQTBY.js.map +1 -0
  5. package/dist/{chunk-V4NR6CPP.js → chunk-ZMLV7YQP.js} +24 -184
  6. package/dist/chunk-ZMLV7YQP.js.map +1 -0
  7. package/dist/index.cjs +53 -273
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +380 -8
  10. package/dist/index.d.ts +380 -8
  11. package/dist/index.js +1004 -9
  12. package/dist/index.js.map +1 -1
  13. package/dist/react/index.cjs +30 -271
  14. package/dist/react/index.cjs.map +1 -1
  15. package/dist/react/index.d.cts +1 -3
  16. package/dist/react/index.d.ts +1 -3
  17. package/dist/react/index.js +6 -26
  18. package/dist/react/index.js.map +1 -1
  19. package/dist/{rtc-manager-gYDkADGw.d.ts → rtc-manager-Bk2lIJ0d.d.cts} +7 -17
  20. package/dist/{rtc-manager-gYDkADGw.d.cts → rtc-manager-Bk2lIJ0d.d.ts} +7 -17
  21. package/dist/video-file-stream-OVPBV7IX.js +3 -0
  22. package/dist/{video-file-stream-K7GQMIJ5.js.map → video-file-stream-OVPBV7IX.js.map} +1 -1
  23. package/package.json +1 -6
  24. package/dist/chunk-4YHBCQ2C.js +0 -432
  25. package/dist/chunk-4YHBCQ2C.js.map +0 -1
  26. package/dist/chunk-LCPC56BK.js.map +0 -1
  27. package/dist/chunk-V4NR6CPP.js.map +0 -1
  28. package/dist/chunk-VLJZ56PT.js +0 -997
  29. package/dist/chunk-VLJZ56PT.js.map +0 -1
  30. package/dist/experimental/index.cjs +0 -3897
  31. package/dist/experimental/index.cjs.map +0 -1
  32. package/dist/experimental/index.d.cts +0 -2
  33. package/dist/experimental/index.d.ts +0 -2
  34. package/dist/experimental/index.js +0 -5
  35. package/dist/experimental/index.js.map +0 -1
  36. package/dist/index-Cw8C8LbO.d.ts +0 -367
  37. package/dist/index-Dg1ElHAj.d.cts +0 -367
  38. package/dist/video-file-stream-K7GQMIJ5.js +0 -4
@@ -119,6 +119,8 @@ var enUS = {
119
119
  "errors.sessionJoinInfoIncomplete": "session does not contain complete RTC join info",
120
120
  "errors.sessionUidMissing": "session does not contain sessionUid",
121
121
  "errors.refImageMissing": "missing reference image",
122
+ "errors.imageCheckMissingUrl": "image check response missing url",
123
+ "errors.imageCheckUnsafe": "image did not pass safety check",
122
124
  "errors.captureStreamUnsupported": "captureStream is not supported in this browser",
123
125
  "errors.videoTrackMissing": "failed to create video track from file",
124
126
  "errors.imageTrackMissing": "failed to create video track from image file",
@@ -175,6 +177,8 @@ var zhCN = {
175
177
  "errors.sessionJoinInfoIncomplete": "session \u7F3A\u5C11\u5B8C\u6574\u7684 RTC \u8FDB\u623F\u4FE1\u606F",
176
178
  "errors.sessionUidMissing": "session \u7F3A\u5C11 sessionUid",
177
179
  "errors.refImageMissing": "\u7F3A\u5C11\u53C2\u8003\u56FE",
180
+ "errors.imageCheckMissingUrl": "\u56FE\u7247\u68C0\u67E5\u54CD\u5E94\u7F3A\u5C11 url",
181
+ "errors.imageCheckUnsafe": "\u56FE\u7247\u672A\u901A\u8FC7\u5B89\u5168\u68C0\u67E5",
178
182
  "errors.captureStreamUnsupported": "\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 captureStream",
179
183
  "errors.videoTrackMissing": "\u672A\u80FD\u4ECE\u89C6\u9891\u6587\u4EF6\u521B\u5EFA video track",
180
184
  "errors.imageTrackMissing": "\u672A\u80FD\u4ECE\u56FE\u7247\u6587\u4EF6\u521B\u5EFA video track",
@@ -280,148 +284,13 @@ function createSDKI18n(input) {
280
284
  };
281
285
  }
282
286
 
283
- // src/shared/browser-toast.ts
284
- var TOAST_ROOT_ID = "Xmax-sdk-toast-root";
285
- var TOAST_DURATION_MS = 3e3;
286
- var toastSeed = 0;
287
- var timeoutMap = /* @__PURE__ */ new Map();
288
- var elementMap = /* @__PURE__ */ new Map();
289
- function ensureToastRoot() {
290
- if (typeof document === "undefined") {
291
- return null;
292
- }
293
- let root = document.getElementById(TOAST_ROOT_ID);
294
- if (root) {
295
- return root;
296
- }
297
- root = document.createElement("div");
298
- root.id = TOAST_ROOT_ID;
299
- root.setAttribute("aria-live", "polite");
300
- Object.assign(root.style, {
301
- position: "fixed",
302
- left: "50%",
303
- top: "24px",
304
- transform: "translateX(-50%)",
305
- zIndex: "3000",
306
- display: "flex",
307
- flexDirection: "column",
308
- alignItems: "center",
309
- gap: "12px",
310
- pointerEvents: "none"
311
- });
312
- document.body.appendChild(root);
313
- return root;
314
- }
315
- function createIcon(type) {
316
- const icon = document.createElement("span");
317
- icon.setAttribute("aria-hidden", "true");
318
- 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>';
319
- Object.assign(icon.style, {
320
- display: "inline-flex",
321
- width: "12px",
322
- height: "12px",
323
- flexShrink: "0"
324
- });
325
- return icon;
326
- }
327
- function clearToastTimer(id) {
328
- const timer = timeoutMap.get(id);
329
- if (timer) {
330
- window.clearTimeout(timer);
331
- timeoutMap.delete(id);
332
- }
333
- }
334
- function destroyToast(id) {
335
- if (!id) {
336
- timeoutMap.forEach((timer) => window.clearTimeout(timer));
337
- timeoutMap.clear();
338
- elementMap.forEach((element2) => element2.remove());
339
- elementMap.clear();
340
- const root2 = typeof document !== "undefined" ? document.getElementById(TOAST_ROOT_ID) : null;
341
- root2?.remove();
342
- return;
343
- }
344
- clearToastTimer(id);
345
- const element = elementMap.get(id);
346
- element?.remove();
347
- elementMap.delete(id);
348
- const root = typeof document !== "undefined" ? document.getElementById(TOAST_ROOT_ID) : null;
349
- if (root && !root.childElementCount) {
350
- root.remove();
351
- }
352
- }
353
- function showToast(type, message, options) {
354
- const root = ensureToastRoot();
355
- if (!root) {
356
- return "";
357
- }
358
- const id = options?.key || `toast-${Date.now()}-${++toastSeed}`;
359
- clearToastTimer(id);
360
- elementMap.get(id)?.remove();
361
- const isMobile = typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches;
362
- const textSize = isMobile ? "12px" : "14px";
363
- const toast = document.createElement("div");
364
- toast.setAttribute("role", "status");
365
- Object.assign(toast.style, {
366
- pointerEvents: "auto",
367
- display: "flex",
368
- alignItems: "center",
369
- gap: "12px",
370
- minWidth: "240px",
371
- padding: "16px",
372
- borderRadius: "12px",
373
- border: "1px solid rgba(255, 255, 255, 0.20)",
374
- background: "rgba(0, 0, 0, 0.80)",
375
- boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
376
- fontFamily: "Rubik, ui-sans-serif, system-ui, sans-serif",
377
- fontSize: textSize,
378
- fontWeight: "400",
379
- lineHeight: "14px"
380
- });
381
- const content = document.createElement("span");
382
- content.textContent = message;
383
- Object.assign(content.style, {
384
- paddingRight: "0px",
385
- textAlign: "center",
386
- color: "#ffffff",
387
- fontFamily: "Rubik, ui-sans-serif, system-ui, sans-serif",
388
- fontSize: textSize,
389
- fontWeight: "400",
390
- lineHeight: "14px"
391
- });
392
- toast.appendChild(createIcon(type));
393
- toast.appendChild(content);
394
- root.appendChild(toast);
395
- elementMap.set(id, toast);
396
- const timer = window.setTimeout(() => {
397
- destroyToast(id);
398
- }, options?.duration ?? TOAST_DURATION_MS);
399
- timeoutMap.set(id, timer);
400
- return id;
401
- }
402
- var browserToast = {
403
- success(message, options) {
404
- return showToast("success", message, options);
405
- },
406
- error(message, options) {
407
- return showToast("error", message, options);
408
- },
409
- destroy(id) {
410
- destroyToast(id);
411
- }
412
- };
413
-
414
287
  // src/shared/error-utils.ts
415
288
  function notifyError(error, notifier, fallbackMessage) {
416
289
  const resolved = error instanceof Error ? error : Object.assign(new Error(fallbackMessage), { cause: error });
417
- if (!resolved.__XmaxNotified) {
290
+ if (!resolved.__XmaxNotified && notifier) {
418
291
  resolved.__XmaxNotified = true;
419
292
  const message = resolved.message || fallbackMessage;
420
- if (notifier) {
421
- notifier(message, error);
422
- } else if (typeof window !== "undefined" && typeof document !== "undefined") {
423
- browserToast.error(message);
424
- }
293
+ notifier(message, error);
425
294
  }
426
295
  return resolved;
427
296
  }
@@ -483,7 +352,7 @@ var XmaxOpenClient = class {
483
352
  }
484
353
  throw notifyError(error, this.onError, message);
485
354
  }
486
- /** Stop heartbeat, abort in-flight API requests, and suppress error toasts during teardown. */
355
+ /** Stop heartbeat, abort in-flight API requests, and suppress error notifications during teardown. */
487
356
  beginTeardown() {
488
357
  this.suppressErrorNotification = true;
489
358
  this.stopHeartbeat();
@@ -643,6 +512,23 @@ var XmaxOpenClient = class {
643
512
  async uploadVideo(file) {
644
513
  return this.uploadObject(file, "video/");
645
514
  }
515
+ /**
516
+ * Upload an image then run Playground-style `/cos/image/check`.
517
+ * Returns the checked URL. Existing {@link uploadImage} is unchanged.
518
+ */
519
+ async uploadAndCheckImage(file) {
520
+ const uploaded = await this.uploadImage(file);
521
+ const data = await this.request("POST", "/cos/image/check", {
522
+ url: uploaded.url
523
+ });
524
+ if (!data?.url) {
525
+ this.throwError(this.i18n.t("errors.imageCheckMissingUrl"));
526
+ }
527
+ if (data.safe === false) {
528
+ this.throwError(this.i18n.t("errors.imageCheckUnsafe"));
529
+ }
530
+ return data.url;
531
+ }
646
532
  startHeartbeat(sessionUid, intervalMs = 1e4, onHeartbeat, onError) {
647
533
  this.stopHeartbeat();
648
534
  const heartbeat = async () => {
@@ -1455,45 +1341,6 @@ var _RtcManager = class _RtcManager {
1455
1341
  sentFrameRate: this.lastObservedSentFrameRate
1456
1342
  });
1457
1343
  }
1458
- /** @deprecated Use {@link ensurePublishedInputBeforeStart}. */
1459
- async waitForRtcOutboundBeforeStart(options) {
1460
- const timeoutMs = options?.timeoutMs ?? PUBLISH_READY_TIMEOUT_MS;
1461
- const publishAgeMs = this.publishStartedAtMs > 0 ? performance.now() - this.publishStartedAtMs : 0;
1462
- const localFramesPromise = publishAgeMs >= PUBLISH_WARM_SKIP_MS ? Promise.resolve({ ready: true, frameCount: 0, elapsedMs: 0 }) : this.waitForPublishedInputFrames({
1463
- minFrames: PUBLISH_START_MIN_FRAMES,
1464
- timeoutMs: PUBLISH_START_FRAME_TIMEOUT_MS
1465
- });
1466
- const [, rtcReady] = await Promise.all([
1467
- localFramesPromise,
1468
- this.waitForLocalPublishReady({ timeoutMs })
1469
- ]);
1470
- return rtcReady;
1471
- }
1472
- /** @deprecated Use {@link waitForRtcOutboundBeforeStart}. */
1473
- async waitForPublishedInputFramesBeforeStart() {
1474
- const waitOptions = this.resolveInputFrameWaitOptions();
1475
- const waitTasks = [
1476
- this.waitForLocalPublishReady({ timeoutMs: PUBLISH_READY_TIMEOUT_MS })
1477
- ];
1478
- if (waitOptions) {
1479
- waitTasks.push(
1480
- this.waitForMinPublishDuration(waitOptions.minPublishMs),
1481
- this.waitForPublishedInputFrames({
1482
- minFrames: waitOptions.minFrames,
1483
- timeoutMs: waitOptions.timeoutMs
1484
- })
1485
- );
1486
- }
1487
- const [rtcResult, ...rest] = await Promise.all(waitTasks);
1488
- const rtcSend = rtcResult;
1489
- const frameResult = waitOptions ? rest[1] : { ready: true, frameCount: 0, elapsedMs: 0 };
1490
- return {
1491
- ...frameResult,
1492
- rtcSendReady: rtcSend.ready,
1493
- rtcSendReason: rtcSend.reason,
1494
- rtcSendElapsedMs: rtcSend.elapsedSincePublishMs
1495
- };
1496
- }
1497
1344
  async waitForMinPublishDuration(minMs) {
1498
1345
  if (minMs <= 0 || this.publishStartedAtMs <= 0) {
1499
1346
  return;
@@ -2457,17 +2304,6 @@ function shouldSampleAtMediaTime(lastMediaTimeS, mediaTimeS) {
2457
2304
  }
2458
2305
  return mediaTimeS > lastMediaTimeS + MEDIA_TIME_EPSILON_S;
2459
2306
  }
2460
- function sampleCanvasFingerprint(ctx, width, height) {
2461
- const points = [
2462
- [0, 0],
2463
- [Math.max(0, (width >> 1) - 1), Math.max(0, (height >> 1) - 1)],
2464
- [Math.max(0, width - 1), Math.max(0, height - 1)]
2465
- ];
2466
- return points.map(([x, y]) => {
2467
- const data = ctx.getImageData(x, y, 1, 1).data;
2468
- return `${data[0]},${data[1]},${data[2]}`;
2469
- }).join("|");
2470
- }
2471
2307
  async function applyPublishTrackConstraints(track, width, height) {
2472
2308
  if (typeof track.applyConstraints !== "function") {
2473
2309
  return;
@@ -2540,12 +2376,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
2540
2376
  let lastDrawMediaTimeS = -1;
2541
2377
  let videoFrameCallbackId = null;
2542
2378
  let rafId = null;
2543
- const logPublishFrames = options.logPublishFrames ?? false;
2544
- let publishFrameIndex = 0;
2545
- let lastPublishWallMs = 0;
2546
- let lastPublishMediaTimeS = -1;
2547
- let publishFramesInWindow = 0;
2548
- let publishWindowStartMs = 0;
2549
2379
  const drawFrame = () => {
2550
2380
  if (destroyed) {
2551
2381
  return;
@@ -2559,52 +2389,13 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
2559
2389
  sourceHeight
2560
2390
  );
2561
2391
  };
2562
- const logPublishedFrame = (mediaTimeS, presentedFrames) => {
2563
- if (!logPublishFrames) {
2564
- return;
2565
- }
2566
- publishFrameIndex += 1;
2567
- const wallNowMs = performance.now();
2568
- const wallDeltaMs = lastPublishWallMs > 0 ? wallNowMs - lastPublishWallMs : 0;
2569
- const mediaDeltaS = lastPublishMediaTimeS >= 0 ? mediaTimeS - lastPublishMediaTimeS : 0;
2570
- lastPublishWallMs = wallNowMs;
2571
- lastPublishMediaTimeS = mediaTimeS;
2572
- publishFramesInWindow += 1;
2573
- if (publishWindowStartMs === 0) {
2574
- publishWindowStartMs = wallNowMs;
2575
- }
2576
- const fingerprint = sampleCanvasFingerprint(ctx, outputWidth, outputHeight);
2577
- console.warn("[upload-video \u2192 publishFrame]", {
2578
- frameIndex: publishFrameIndex,
2579
- mediaTimeS: Number(mediaTimeS.toFixed(4)),
2580
- mediaDeltaS: Number(mediaDeltaS.toFixed(4)),
2581
- wallDeltaMs: Number(wallDeltaMs.toFixed(1)),
2582
- effectiveFps: wallDeltaMs > 0 ? Number((1e3 / wallDeltaMs).toFixed(1)) : null,
2583
- presentedFrames,
2584
- size: `${outputWidth}\xD7${outputHeight}`,
2585
- fingerprint
2586
- });
2587
- const windowElapsedMs = wallNowMs - publishWindowStartMs;
2588
- if (windowElapsedMs >= 1e3) {
2589
- console.warn("[upload-video \u2192 publishFps]", {
2590
- framesInLast1s: publishFramesInWindow,
2591
- avgFps: Number((publishFramesInWindow / (windowElapsedMs / 1e3)).toFixed(2)),
2592
- videoCurrentTime: Number(videoEl.currentTime.toFixed(4)),
2593
- videoPaused: videoEl.paused,
2594
- videoReadyState: videoEl.readyState
2595
- });
2596
- publishFramesInWindow = 0;
2597
- publishWindowStartMs = wallNowMs;
2598
- }
2599
- };
2600
- const onPlaybackSample = (mediaTimeS, presentedFrames) => {
2392
+ const onPlaybackSample = (mediaTimeS) => {
2601
2393
  if (destroyed || !shouldSampleAtMediaTime(lastDrawMediaTimeS, mediaTimeS)) {
2602
2394
  return;
2603
2395
  }
2604
2396
  lastDrawMediaTimeS = mediaTimeS;
2605
2397
  lastAdvanceAt = Date.now();
2606
2398
  drawFrame();
2607
- logPublishedFrame(mediaTimeS, presentedFrames);
2608
2399
  };
2609
2400
  const schedulePlaybackWatch = () => {
2610
2401
  if (destroyed) {
@@ -2613,7 +2404,7 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
2613
2404
  const video = videoEl;
2614
2405
  if (video.requestVideoFrameCallback) {
2615
2406
  videoFrameCallbackId = video.requestVideoFrameCallback((_now, metadata) => {
2616
- onPlaybackSample(metadata.mediaTime, metadata.presentedFrames);
2407
+ onPlaybackSample(metadata.mediaTime);
2617
2408
  schedulePlaybackWatch();
2618
2409
  });
2619
2410
  return;
@@ -2624,7 +2415,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
2624
2415
  });
2625
2416
  };
2626
2417
  drawFrame();
2627
- logPublishedFrame(videoEl.currentTime);
2628
2418
  schedulePlaybackWatch();
2629
2419
  const ensurePlaying = () => {
2630
2420
  if (destroyed) {
@@ -2646,18 +2436,6 @@ async function createVideoFileStream(fileOrUrl, options = {}) {
2646
2436
  videoEl.addEventListener("ended", ensurePlaying);
2647
2437
  videoEl.addEventListener("stalled", ensurePlaying);
2648
2438
  videoEl.addEventListener("waiting", ensurePlaying);
2649
- if (logPublishFrames) {
2650
- const logPlaybackEvent = (eventName) => {
2651
- console.warn("[upload-video \u2192 playbackEvent]", {
2652
- event: eventName,
2653
- currentTime: Number(videoEl.currentTime.toFixed(4)),
2654
- readyState: videoEl.readyState,
2655
- paused: videoEl.paused
2656
- });
2657
- };
2658
- videoEl.addEventListener("waiting", () => logPlaybackEvent("waiting"));
2659
- videoEl.addEventListener("stalled", () => logPlaybackEvent("stalled"));
2660
- }
2661
2439
  const healthIntervalMs = options.healthIntervalMs ?? 3e3;
2662
2440
  let healthTimer = null;
2663
2441
  if (options.onHealthReport) {
@@ -3155,18 +2933,9 @@ function XmaxProvider({ config, children }) {
3155
2933
  const detachRemoteContainer = react.useCallback(() => {
3156
2934
  rtcManagerRef.current?.setRemoteVideoContainer(null);
3157
2935
  }, []);
3158
- const notifyUserError = react.useCallback((message, error) => {
3159
- if (externalOnError) {
3160
- externalOnError(message, error);
3161
- return;
3162
- }
3163
- if (typeof window !== "undefined" && typeof document !== "undefined") {
3164
- browserToast.error(message);
3165
- }
3166
- }, [externalOnError]);
3167
2936
  const reportError = react.useCallback((error, fallbackMessage) => {
3168
- return notifyError(error, notifyUserError, fallbackMessage ?? sdkI18n.t("errors.requestFailed"));
3169
- }, [notifyUserError, sdkI18n]);
2937
+ return notifyError(error, externalOnError, fallbackMessage ?? sdkI18n.t("errors.requestFailed"));
2938
+ }, [externalOnError, sdkI18n]);
3170
2939
  const rtcManagerRef = react.useRef(null);
3171
2940
  if (!rtcManagerRef.current) {
3172
2941
  rtcManagerRef.current = new RtcManager({
@@ -3195,11 +2964,11 @@ function XmaxProvider({ config, children }) {
3195
2964
  baseUrl: config.baseUrl,
3196
2965
  locale: config.locale,
3197
2966
  i18n: sdkI18n,
3198
- onError: notifyUserError
2967
+ onError: externalOnError
3199
2968
  });
3200
2969
  clientRef.current = created;
3201
2970
  return created;
3202
- }, [config.apiKey, config.authToken, config.baseUrl, config.locale, notifyUserError, sdkI18n]);
2971
+ }, [config.apiKey, config.authToken, config.baseUrl, config.locale, externalOnError, sdkI18n]);
3203
2972
  const ensureConnected = react.useCallback(async () => {
3204
2973
  const client = getClient();
3205
2974
  const rtc = rtcManagerRef.current;
@@ -3609,11 +3378,6 @@ function XmaxProvider({ config, children }) {
3609
3378
  if (!activeTaskUid) {
3610
3379
  return;
3611
3380
  }
3612
- console.log("[Xmax] sendTracks", {
3613
- taskUid: activeTaskUid,
3614
- targetSize: sessionTargetSize,
3615
- tracks: options.tracks
3616
- });
3617
3381
  try {
3618
3382
  const event = createTracksRtcRoomEvent({
3619
3383
  userId: rtc.snapshot.userId ?? void 0,
@@ -3666,9 +3430,6 @@ function XmaxProvider({ config, children }) {
3666
3430
  debugLogRef.current("lifecycle", "warn", "remote output stalled", info);
3667
3431
  };
3668
3432
  }, []);
3669
- const changeModel = react.useCallback(async () => {
3670
- return;
3671
- }, []);
3672
3433
  const bindLocalView = react.useCallback((el) => {
3673
3434
  localContainerRef.current = el;
3674
3435
  rtcManagerRef.current?.setLocalVideoContainer(el);
@@ -3711,7 +3472,6 @@ function XmaxProvider({ config, children }) {
3711
3472
  start,
3712
3473
  sendTracks,
3713
3474
  stop,
3714
- changeModel,
3715
3475
  bindLocalView,
3716
3476
  bindRemoteView
3717
3477
  }), [
@@ -3736,7 +3496,6 @@ function XmaxProvider({ config, children }) {
3736
3496
  start,
3737
3497
  sendTracks,
3738
3498
  stop,
3739
- changeModel,
3740
3499
  bindLocalView,
3741
3500
  bindRemoteView
3742
3501
  ]);