@3dsource/angular-unreal-module 0.0.146-dev.9 → 0.0.148-dev.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/LICENSE +14 -14
- package/README.md +370 -361
- package/fesm2022/3dsource-angular-unreal-module.mjs +253 -675
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +1 -1
- package/types/3dsource-angular-unreal-module.d.ts +69 -293
- package/js/stream-prefetch.js +0 -4
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ import { Store } from '@ngrx/store';
|
|
|
11
11
|
import { Actions } from '@ngrx/effects';
|
|
12
12
|
import { IKeyCode, ImageOutputValues, Area } from '@3dsource/utils';
|
|
13
13
|
import { SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';
|
|
14
|
-
import { MetaBoxCommandPacket, MetaBoxCommandList,
|
|
14
|
+
import { MetaBoxCommandPacket, MetaBoxCommandList, MetaBoxCallbackList, FOnSceneStateCallback, FOnFocusObjectCallback, FCameraChangedCallback, FOnObjectTransformChangedCallback, FOnChangeSequenceChangedCallback, FOnFinishSequenceChangedCallback } from '@3dsource/types-unreal';
|
|
15
15
|
import * as node_modules__ngrx_effects_types_ngrx_effects from 'node_modules/@ngrx/effects/types/ngrx-effects';
|
|
16
16
|
|
|
17
17
|
declare class AfkTimeoutModalComponent {
|
|
@@ -231,6 +231,18 @@ interface FreezeFrameMessage {
|
|
|
231
231
|
progress: number | null;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
interface ReconnectConfig {
|
|
235
|
+
/** Enable auto-reconnection when WebRTC or DataChannel connection is lost. Default: true */
|
|
236
|
+
enabled?: boolean;
|
|
237
|
+
/** Maximum number of reconnection attempts before giving up. Default: 3 */
|
|
238
|
+
maxAttempts?: number;
|
|
239
|
+
/** Delay in milliseconds between reconnection attempts. Default: 1000 */
|
|
240
|
+
delayMs?: number;
|
|
241
|
+
/** Reconnect on ICE connection failure (disconnected/failed state). Default: true */
|
|
242
|
+
onIceFailure?: boolean;
|
|
243
|
+
/** Reconnect on DataChannel close. Default: true */
|
|
244
|
+
onDataChannelClose?: boolean;
|
|
245
|
+
}
|
|
234
246
|
interface UnrealInitialConfig {
|
|
235
247
|
playwright?: boolean;
|
|
236
248
|
customErrorsEndpoint?: string;
|
|
@@ -241,65 +253,8 @@ interface UnrealInitialConfig {
|
|
|
241
253
|
streamTelemetryV2Url?: string;
|
|
242
254
|
fpsMonitor?: boolean;
|
|
243
255
|
autoHighResolution?: boolean;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
interface SignalingData {
|
|
247
|
-
instanceType: string;
|
|
248
|
-
branchInfo: string;
|
|
249
|
-
cirrusVersion: string;
|
|
250
|
-
streamerVersion: string;
|
|
251
|
-
streamPath: string;
|
|
252
|
-
streamApp: string;
|
|
253
|
-
connectionId: string;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Live WebRTC connection parked on `window.__stream` by the `stream-prefetch.js`
|
|
258
|
-
* head-script, ready for the Angular services to ADOPT instead of building a
|
|
259
|
-
* connection from scratch. The shape is the handoff contract between that
|
|
260
|
-
* framework-free script and {@link StreamAdoptionService} — keep the two in sync.
|
|
261
|
-
*/
|
|
262
|
-
interface ParkedStream {
|
|
263
|
-
state: 'connecting' | 'ready' | 'failed' | 'adopted';
|
|
264
|
-
pc?: RTCPeerConnection;
|
|
265
|
-
dc?: RTCDataChannel;
|
|
266
|
-
/** video(+audio) MediaStream from the `track` event */
|
|
267
|
-
stream?: MediaStream;
|
|
268
|
-
/** live signalling socket (handshake already done, `requestStream` sent) */
|
|
269
|
-
ws?: WebSocket;
|
|
270
|
-
/** `data` from the streamer's `ssInfo` message — received before adoption */
|
|
271
|
-
ssData?: SignalingData;
|
|
272
|
-
/** = resolved wsUrl of the winning machine */
|
|
273
|
-
machineId?: string;
|
|
274
|
-
/** `peerConnectionOptions` the machine sent in its `config` message */
|
|
275
|
-
config?: RTCConfiguration;
|
|
276
|
-
/** ids the script generated; Angular reuses them (no regeneration) */
|
|
277
|
-
ids: {
|
|
278
|
-
clientId: string;
|
|
279
|
-
viewId: string;
|
|
280
|
-
correlationId: string;
|
|
281
|
-
};
|
|
282
|
-
/** DataChannel messages received before adoption, replayed on adopt */
|
|
283
|
-
dcBuffer: ArrayBuffer[];
|
|
284
|
-
/** `performance.now()` marks for the prefetch waterfall (telemetry) */
|
|
285
|
-
timings: Record<string, number>;
|
|
286
|
-
failReason?: string;
|
|
287
|
-
failError?: string;
|
|
288
|
-
/** Stops the script's watchdog and flips state to `adopted`. */
|
|
289
|
-
adopt: () => ParkedStream;
|
|
290
|
-
/**
|
|
291
|
-
* Register a one-shot callback fired the instant the stream settles
|
|
292
|
-
* (`ready`/`failed`); fires on the next microtask if already settled. Lets
|
|
293
|
-
* {@link StreamAdoptionService} adopt event-driven instead of polling.
|
|
294
|
-
* Optional — absent on head-script versions predating the hook, where the
|
|
295
|
-
* service falls back to polling.
|
|
296
|
-
*/
|
|
297
|
-
onSettled?: (cb: (state: ParkedStream['state']) => void) => void;
|
|
298
|
-
}
|
|
299
|
-
declare global {
|
|
300
|
-
interface Window {
|
|
301
|
-
__stream?: ParkedStream;
|
|
302
|
-
}
|
|
256
|
+
/** Configuration for auto-reconnection behavior */
|
|
257
|
+
reconnect?: ReconnectConfig;
|
|
303
258
|
}
|
|
304
259
|
|
|
305
260
|
declare const SpecialKeyCodes: {
|
|
@@ -391,9 +346,6 @@ declare const MIN_CONTAINER_SIZE = 2;
|
|
|
391
346
|
declare const MINIMAL_FPS = 6;
|
|
392
347
|
declare const STREAMING_VIDEO_ID = "streamingVideo";
|
|
393
348
|
declare const STREAMING_AUDIO_ID = "streamingAudio";
|
|
394
|
-
declare const CONSOLE_COMMAND_ENABLE_MESSAGES = "EnableAllScreenMessages";
|
|
395
|
-
declare const CONSOLE_COMMAND_DISABLE_MESSAGES = "DisableAllScreenMessages";
|
|
396
|
-
declare const CONSOLE_COMMAND_PIXEL_QUALITY = "PixelStreaming.FreezeFrameQuality 95";
|
|
397
349
|
declare const FULL_HD_WIDTH = 1920;
|
|
398
350
|
declare const FULL_HD_HEIGHT = 1080;
|
|
399
351
|
declare const WS_TIMEOUT = 6000;
|
|
@@ -412,29 +364,16 @@ declare const REGION_PING_CACHE_TTL_MS: number;
|
|
|
412
364
|
declare const REGION_PING_ACCURATE_SAMPLES = 3;
|
|
413
365
|
declare const REGION_PING_WARMUP_DEADLINE_MS = 1500;
|
|
414
366
|
declare const REGION_PING_BACKGROUND_REFRESH_DELAY_MS = 5000;
|
|
415
|
-
declare const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
367
|
+
declare const DEFAULT_RECONNECT_ENABLED = true;
|
|
368
|
+
declare const DEFAULT_RECONNECT_MAX_ATTEMPTS = 3;
|
|
369
|
+
declare const DEFAULT_RECONNECT_DELAY_MS = 1000;
|
|
370
|
+
declare const DEFAULT_RECONNECT_ON_ICE_FAILURE = true;
|
|
371
|
+
declare const DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE = true;
|
|
420
372
|
declare const UnrealStatusMessage: {
|
|
421
373
|
readonly CONNECTING_TO_SESSION: "Connecting to session.";
|
|
422
374
|
readonly STARTING_YOUR_SESSION: "Starting your session";
|
|
423
375
|
};
|
|
424
376
|
|
|
425
|
-
interface NormalizeAndQuantizeUnsignedValue {
|
|
426
|
-
inRange: boolean;
|
|
427
|
-
x: number;
|
|
428
|
-
y: number;
|
|
429
|
-
}
|
|
430
|
-
interface UnquantizeAndDenormalizeUnsignedValue {
|
|
431
|
-
x: number;
|
|
432
|
-
y: number;
|
|
433
|
-
}
|
|
434
|
-
interface NormalizeAndQuantizeSignedValue {
|
|
435
|
-
x: number;
|
|
436
|
-
y: number;
|
|
437
|
-
}
|
|
438
377
|
interface InputProps {
|
|
439
378
|
controlScheme: ControlSchemeValues;
|
|
440
379
|
suppressBrowserKeys: boolean;
|
|
@@ -442,6 +381,16 @@ interface InputProps {
|
|
|
442
381
|
|
|
443
382
|
type Quality = 'lime' | 'red' | 'orange';
|
|
444
383
|
|
|
384
|
+
interface SignalingData {
|
|
385
|
+
instanceType: string;
|
|
386
|
+
branchInfo: string;
|
|
387
|
+
cirrusVersion: string;
|
|
388
|
+
streamerVersion: string;
|
|
389
|
+
streamPath: string;
|
|
390
|
+
streamApp: string;
|
|
391
|
+
connectionId: string;
|
|
392
|
+
}
|
|
393
|
+
|
|
445
394
|
declare const OrchestrationMessageTypes: {
|
|
446
395
|
readonly ping: "ping";
|
|
447
396
|
readonly error: "error";
|
|
@@ -906,7 +855,6 @@ declare class InputService extends SubService {
|
|
|
906
855
|
private isKeyCodeBrowserKey;
|
|
907
856
|
private getKeyCode;
|
|
908
857
|
private registerKeyboardEvents;
|
|
909
|
-
private isIgnoredViewportKey;
|
|
910
858
|
private startListenKeys;
|
|
911
859
|
static ɵfac: i0.ɵɵFactoryDeclaration<InputService, never>;
|
|
912
860
|
static ɵprov: i0.ɵɵInjectableDeclaration<InputService>;
|
|
@@ -931,15 +879,8 @@ declare class RegionsPingService {
|
|
|
931
879
|
* entry is well-formed and still within {@link REGION_PING_CACHE_TTL_MS}.
|
|
932
880
|
* All access is guarded — `localStorage` can throw (private mode, disabled
|
|
933
881
|
* storage) or be absent (non-browser).
|
|
934
|
-
*
|
|
935
|
-
* Public so adopted connections (which skip `getFastest`) can replay the
|
|
936
|
-
* region-resolving telemetry phase from the same cached winner — see
|
|
937
|
-
* `UnrealEffects.regionTelemetryOnAdopt$`.
|
|
938
882
|
*/
|
|
939
|
-
readCachedWinner
|
|
940
|
-
region_code: string;
|
|
941
|
-
result: number[];
|
|
942
|
-
} | null;
|
|
883
|
+
private readCachedWinner;
|
|
943
884
|
private writeCachedWinner;
|
|
944
885
|
/**
|
|
945
886
|
* Accurate, OFF-critical-path refresh of the region cache. Mirrors the
|
|
@@ -1061,15 +1002,6 @@ declare class SignallingService extends SubService {
|
|
|
1061
1002
|
private pollLoop;
|
|
1062
1003
|
private connectToCirrus;
|
|
1063
1004
|
private addWsHandlers;
|
|
1064
|
-
/**
|
|
1065
|
-
* Adopt a live signalling socket opened by the `stream-prefetch.js`
|
|
1066
|
-
* head-script. The socket is already OPEN and `requestStream` was already
|
|
1067
|
-
* sent, so — unlike {@link addWsHandlers} — we attach message/close/error
|
|
1068
|
-
* handlers but deliberately skip {@link OnOpenHandler} (which would
|
|
1069
|
-
* `setCirrusConnected` + re-`sendRequestStream`). Reuses the head-script's
|
|
1070
|
-
* `correlationId` so subsequent correlated messages line up.
|
|
1071
|
-
*/
|
|
1072
|
-
adoptSocket(ws: WebSocket, correlationId: string): void;
|
|
1073
1005
|
private showStatusMessage;
|
|
1074
1006
|
/**
|
|
1075
1007
|
* Close the connection with the signaling server
|
|
@@ -1089,64 +1021,6 @@ declare class SignallingService extends SubService {
|
|
|
1089
1021
|
static ɵprov: i0.ɵɵInjectableDeclaration<SignallingService>;
|
|
1090
1022
|
}
|
|
1091
1023
|
|
|
1092
|
-
/**
|
|
1093
|
-
* Adopts a WebRTC connection prefetched by the `stream-prefetch.js` head-script
|
|
1094
|
-
* and parked on `window.__stream`, instead of running `connectToSignaling` from
|
|
1095
|
-
* scratch. Called from the same seam where signalling normally starts
|
|
1096
|
-
* (`connectToSignaling$` effect); if there is nothing ready to adopt it returns
|
|
1097
|
-
* `false` and the caller falls back to the normal connect — strictly additive.
|
|
1098
|
-
*/
|
|
1099
|
-
declare class StreamAdoptionService {
|
|
1100
|
-
private readonly store;
|
|
1101
|
-
private readonly signalling;
|
|
1102
|
-
private readonly webRtc;
|
|
1103
|
-
/**
|
|
1104
|
-
* Decide adoption, WAITING for an in-flight prefetch instead of racing it.
|
|
1105
|
-
*
|
|
1106
|
-
* - nothing parked → emit `false` at once (caller connects normally).
|
|
1107
|
-
* - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
|
|
1108
|
-
* - still `connecting` → wait for the script's `onSettled` callback (no
|
|
1109
|
-
* polling latency) and adopt-if-ready the instant it fires; on older
|
|
1110
|
-
* scripts without the hook, fall back to a `timer` poll.
|
|
1111
|
-
*
|
|
1112
|
-
* Deliberately NO time budget: for DIRECT orchestration the prefetch holds
|
|
1113
|
-
* the socket open while the orchestrator provisions a machine, which can take
|
|
1114
|
-
* minutes (150–200s+). A fixed deadline would make Angular give up and open a
|
|
1115
|
-
* second connection mid-provisioning — exactly the race/orphan this avoids.
|
|
1116
|
-
* The wait is bounded by liveness instead: the script flips the parked state
|
|
1117
|
-
* to `failed` on a dead socket (`ws.onclose`/`onerror`), and the caller wraps
|
|
1118
|
-
* this in `takeUntil(abortEstablishingConnection)`, so a route change / teardown
|
|
1119
|
-
* cancels it. Emits exactly once. Cancelling runs no adoption — which is what
|
|
1120
|
-
* stops a fast route-switch from starting overlapping connections.
|
|
1121
|
-
*
|
|
1122
|
-
* Wrapped in `defer` so the `tryAdopt()` side effect (which dispatches
|
|
1123
|
-
* `streamAdopted`) runs at SUBSCRIPTION time, not when the observable is
|
|
1124
|
-
* built. The effect prepends `startWith(setEstablishingConnection(true))`,
|
|
1125
|
-
* which starts the telemetry session and subscribes its phase catalog; that
|
|
1126
|
-
* must happen BEFORE `streamAdopted` → `regionTelemetryOnAdopt$` replays
|
|
1127
|
-
* `regionResolved`, or the region phase fires into a session that doesn't
|
|
1128
|
-
* exist yet and is lost. `defer` guarantees that ordering.
|
|
1129
|
-
*/
|
|
1130
|
-
awaitAndAdopt$(): Observable<boolean>;
|
|
1131
|
-
/**
|
|
1132
|
-
* Event-driven wait: resolve the instant the script's `onSettled` callback
|
|
1133
|
-
* fires (ready/failed), then adopt-if-ready. Emits exactly once.
|
|
1134
|
-
*
|
|
1135
|
-
* A coarse {@link ADOPT_EVENT_SAFETY_MS} interval is a backstop only — if
|
|
1136
|
-
* `onSettled` somehow never fires it still settles, without adding latency to
|
|
1137
|
-
* the normal case. Teardown (route change → unsubscribe) sets `done`, so a
|
|
1138
|
-
* late callback after cancel can't trigger a stray adoption.
|
|
1139
|
-
*/
|
|
1140
|
-
private awaitSettled$;
|
|
1141
|
-
/**
|
|
1142
|
-
* @returns `true` if a ready parked stream was adopted (caller must NOT
|
|
1143
|
-
* start a fresh connection), `false` otherwise.
|
|
1144
|
-
*/
|
|
1145
|
-
tryAdopt(): boolean;
|
|
1146
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<StreamAdoptionService, never>;
|
|
1147
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<StreamAdoptionService>;
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
1024
|
declare class StreamStatusTelemetryService extends SubService {
|
|
1151
1025
|
private readonly videoService;
|
|
1152
1026
|
private readonly unrealConfig;
|
|
@@ -1234,17 +1108,6 @@ declare class StreamStatusTelemetryService2 {
|
|
|
1234
1108
|
private readonly disconnectReason$;
|
|
1235
1109
|
private readonly errorMessage$;
|
|
1236
1110
|
private readonly viewPortReady$;
|
|
1237
|
-
/**
|
|
1238
|
-
* Synchronous adoption flag. The `streamAdopted` reducer sets it BEFORE any
|
|
1239
|
-
* action subscriber runs, so the connection-phase closers (which fire inside
|
|
1240
|
-
* the same dispatch, e.g. `ssinfo-received` off the `ssData` state change)
|
|
1241
|
-
* can read it and defer to the prefetch-timed attribution emitted by
|
|
1242
|
-
* {@link emitAdoptedConnection} instead of recording the live wall-clock.
|
|
1243
|
-
*/
|
|
1244
|
-
private readonly adopted$;
|
|
1245
|
-
/** Streamer identity for the adopted signaling phase params. */
|
|
1246
|
-
private readonly ssData$;
|
|
1247
|
-
private readonly awsInstance$;
|
|
1248
1111
|
private session;
|
|
1249
1112
|
/**
|
|
1250
1113
|
* Whether a session has already started during the current page lifetime.
|
|
@@ -1308,36 +1171,6 @@ declare class StreamStatusTelemetryService2 {
|
|
|
1308
1171
|
* are derived from neighbor phases.
|
|
1309
1172
|
*/
|
|
1310
1173
|
private emitPhaseEnded;
|
|
1311
|
-
/**
|
|
1312
|
-
* Emit the region / signaling / webrtc phases for an ADOPTED connection.
|
|
1313
|
-
*
|
|
1314
|
-
* The prefetch script established the connection in PARALLEL with page load,
|
|
1315
|
-
* so the phases are positioned at their real (anchor-relative) spans — shifted
|
|
1316
|
-
* LEFT to overlap the HTML-loading / route-idle rows — rather than sequentially
|
|
1317
|
-
* after them. That's the whole point of the prefetch: the handshake already
|
|
1318
|
-
* happened while the page was loading. Each phase ships:
|
|
1319
|
-
* - `duration` — the real sub-step time the prefetch spent.
|
|
1320
|
-
* - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
|
|
1321
|
-
* - `adoptionAtMs` — where Angular took over (the next phase, Unreal
|
|
1322
|
-
* communication, resumes here on the sequential timeline).
|
|
1323
|
-
* - savings params: `prefetchConnectMs` (full handshake), `prefetchSavedMs`
|
|
1324
|
-
* (done before Angular was ready), `adoptionWaitMs` (real connect→adopted
|
|
1325
|
-
* wait), `adoptionOverheadMs` (prefetch-ready → adopted gap).
|
|
1326
|
-
*/
|
|
1327
|
-
private emitAdoptedConnection;
|
|
1328
|
-
/**
|
|
1329
|
-
* Emit one adopted phase positioned at its real `spanStartMs` (left-shifted
|
|
1330
|
-
* to overlap page load) with its real prefetch `duration`. `prefetched`,
|
|
1331
|
-
* `spanStartMs` and `adoptionAtMs` ride as top-level wire fields the viewer
|
|
1332
|
-
* uses to lay the bar out; the rest become display params.
|
|
1333
|
-
*/
|
|
1334
|
-
private emitAdoptedPhase;
|
|
1335
|
-
/** Streamer identity params for the adopted signaling phase — mirrors the
|
|
1336
|
-
* `ssinfo-received` closer's shape (client / instanceName / …ssData). */
|
|
1337
|
-
private adoptedSignalingParams;
|
|
1338
|
-
/** Read the region-ping cache the prefetch reused (localStorage), so the
|
|
1339
|
-
* adopted region phase can still report the winning region + samples. */
|
|
1340
|
-
private readRegionCache;
|
|
1341
1174
|
private handleWindow;
|
|
1342
1175
|
private evaluateAnomalies;
|
|
1343
1176
|
private updateMaxFpsTarget;
|
|
@@ -1566,16 +1399,6 @@ declare class WebRtcPlayerService extends SubService {
|
|
|
1566
1399
|
* @returns true if reconnection was initiated, false if signaling is not connected
|
|
1567
1400
|
*/
|
|
1568
1401
|
reconnectPeer(): boolean;
|
|
1569
|
-
/**
|
|
1570
|
-
* Adopt a fully-negotiated connection prefetched by `stream-prefetch.js`:
|
|
1571
|
-
* take ownership of its PeerConnection, DataChannel and media stream instead
|
|
1572
|
-
* of running the handshake. The head-script attached property-based handlers
|
|
1573
|
-
* (`pc.onicecandidate`, `dc.onmessage`, …) and buffered inbound DC messages;
|
|
1574
|
-
* here we detach those, wire our own (addEventListener-based) handlers, replay
|
|
1575
|
-
* the buffer in order, then drive `onDataChannelConnected` manually because the
|
|
1576
|
-
* DataChannel is already open (its `open` event won't fire again).
|
|
1577
|
-
*/
|
|
1578
|
-
adopt(pc: RTCPeerConnection, dc: RTCDataChannel, stream: MediaStream, config: RTCConfiguration, dcBuffer: ArrayBuffer[]): void;
|
|
1579
1402
|
private setConfig;
|
|
1580
1403
|
private handlePeerConnectionEvents;
|
|
1581
1404
|
private setupTransceiversAsync;
|
|
@@ -1841,44 +1664,45 @@ declare class FpsMonitorService extends SubService {
|
|
|
1841
1664
|
static ɵprov: i0.ɵɵInjectableDeclaration<FpsMonitorService>;
|
|
1842
1665
|
}
|
|
1843
1666
|
|
|
1667
|
+
/**
|
|
1668
|
+
* `MetaBoxCommandList` / `MetaBoxCallbackList` are keyed by string-**enum**
|
|
1669
|
+
* members, which are nominal: a plain string literal like
|
|
1670
|
+
* `'loadProductCommandCallback'` is NOT assignable to the enum key
|
|
1671
|
+
* `MetaBoxCallback.FLoadProductCommandCallback`. So template-literal lookups
|
|
1672
|
+
* against `keyof MetaBoxCallbackList` always miss. We first re-key the callback
|
|
1673
|
+
* list by its plain string values, then bridge command→callback by string.
|
|
1674
|
+
*/
|
|
1675
|
+
type CallbackByString = {
|
|
1676
|
+
[C in keyof MetaBoxCallbackList as `${C & string}`]: MetaBoxCallbackList[C];
|
|
1677
|
+
};
|
|
1678
|
+
/**
|
|
1679
|
+
* Resolves a command key to its matching callback type via the
|
|
1680
|
+
* `F*Command` → `F*CommandCallback` naming convention
|
|
1681
|
+
* (e.g. command `'loadProduct'` → callback `'loadProductCommandCallback'`).
|
|
1682
|
+
*/
|
|
1683
|
+
type CommandCallbackFor<K extends keyof MetaBoxCommandList> = `${K & string}CommandCallback` extends keyof CallbackByString ? CallbackByString[`${K & string}CommandCallback`] : never;
|
|
1684
|
+
/** Every command keyed to its real callback type. */
|
|
1685
|
+
type UnrealCommandCallbackMap = {
|
|
1686
|
+
[K in keyof MetaBoxCommandList]: CommandCallbackFor<K>;
|
|
1687
|
+
};
|
|
1844
1688
|
/**
|
|
1845
1689
|
* Custom Unreal callback events that are not part of MetaBoxCommandList.
|
|
1846
1690
|
* These events are pushed from Unreal to the frontend via the data channel.
|
|
1691
|
+
* Keys are the runtime `command` values used for filtering.
|
|
1847
1692
|
*/
|
|
1848
1693
|
interface UnrealCallbackEventMap {
|
|
1849
|
-
onSceneState:
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
payload: FProductPayload;
|
|
1856
|
-
};
|
|
1857
|
-
cameraChanged: {
|
|
1858
|
-
command: 'cameraChanged';
|
|
1859
|
-
payload: FCameraChangedPayload;
|
|
1860
|
-
};
|
|
1861
|
-
onObjectTransformChanged: {
|
|
1862
|
-
command: 'onObjectTransformChanged';
|
|
1863
|
-
payload: {
|
|
1864
|
-
objectName: string;
|
|
1865
|
-
transform: FTransformJson;
|
|
1866
|
-
};
|
|
1867
|
-
};
|
|
1868
|
-
onChangeSequence: {
|
|
1869
|
-
command: 'onChangeSequence';
|
|
1870
|
-
payload: unknown;
|
|
1871
|
-
};
|
|
1872
|
-
onFinishedSequence: {
|
|
1873
|
-
command: 'onFinishedSequence';
|
|
1874
|
-
payload: unknown;
|
|
1875
|
-
};
|
|
1694
|
+
onSceneState: FOnSceneStateCallback;
|
|
1695
|
+
onFocusObject: FOnFocusObjectCallback;
|
|
1696
|
+
cameraChanged: FCameraChangedCallback;
|
|
1697
|
+
onObjectTransformChanged: FOnObjectTransformChangedCallback;
|
|
1698
|
+
onChangeSequence: FOnChangeSequenceChangedCallback;
|
|
1699
|
+
onFinishedSequence: FOnFinishSequenceChangedCallback;
|
|
1876
1700
|
}
|
|
1877
1701
|
/**
|
|
1878
|
-
* Combined map of all known callback
|
|
1879
|
-
*
|
|
1702
|
+
* Combined map of all known callback types: every command mapped to its real
|
|
1703
|
+
* callback (`MetaBoxCallbackList`) + the custom event callbacks.
|
|
1880
1704
|
*/
|
|
1881
|
-
type UnrealCallbackDescriptor =
|
|
1705
|
+
type UnrealCallbackDescriptor = UnrealCommandCallbackMap & UnrealCallbackEventMap;
|
|
1882
1706
|
declare class UnrealCallbackService {
|
|
1883
1707
|
private readonly actions$;
|
|
1884
1708
|
/**
|
|
@@ -1923,7 +1747,7 @@ declare class UnrealCallbackService {
|
|
|
1923
1747
|
* .subscribe();
|
|
1924
1748
|
* ```
|
|
1925
1749
|
*/
|
|
1926
|
-
observeCommandResponse<K extends keyof MetaBoxCommandList, T extends MetaBoxCommandList[K] = MetaBoxCommandList[K]>(data: T, sender: (data: T) => void, timeOut?: number, dispatchOnTimeout?: boolean): node_modules_rxjs_dist_types.Observable<
|
|
1750
|
+
observeCommandResponse<K extends keyof MetaBoxCommandList, T extends MetaBoxCommandList[K] = MetaBoxCommandList[K]>(data: T, sender: (data: T) => void, timeOut?: number, dispatchOnTimeout?: boolean): node_modules_rxjs_dist_types.Observable<CommandCallbackFor<K>>;
|
|
1927
1751
|
static ɵfac: i0.ɵɵFactoryDeclaration<UnrealCallbackService, never>;
|
|
1928
1752
|
static ɵprov: i0.ɵɵInjectableDeclaration<UnrealCallbackService>;
|
|
1929
1753
|
}
|
|
@@ -2636,44 +2460,6 @@ declare const showUnrealErrorMessage: node_modules__ngrx_store_types_ngrx_store.
|
|
|
2636
2460
|
error?: string;
|
|
2637
2461
|
} & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
|
|
2638
2462
|
declare const initSignalling: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, () => node_modules__ngrx_store_types_ngrx_store.Action<string>>;
|
|
2639
|
-
/**
|
|
2640
|
-
* Dispatched when a prefetched connection parked on `window.__stream` by the
|
|
2641
|
-
* `stream-prefetch.js` head-script is adopted instead of opening a fresh
|
|
2642
|
-
* `connectToSignaling`. Marks cirrus connected and records the adopted machine
|
|
2643
|
-
* in one transaction; the data channel / app-init chain then proceeds via
|
|
2644
|
-
* `dataChannelConnected` dispatched from `WebRtcPlayerService`.
|
|
2645
|
-
*
|
|
2646
|
-
* Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
|
|
2647
|
-
* app (e.g. metabox) sets those authoritatively from its own data before
|
|
2648
|
-
* `initSignalling`, and the prefetch script's ids are connection-internal only.
|
|
2649
|
-
*/
|
|
2650
|
-
declare const streamAdopted: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
|
|
2651
|
-
machineId: string | null;
|
|
2652
|
-
ssData: SignalingData | null;
|
|
2653
|
-
/**
|
|
2654
|
-
* `performance.now()` marks the prefetch script recorded while it
|
|
2655
|
-
* established the connection (`prefetch_start` / `ws_open` / `dc_open` /
|
|
2656
|
-
* `ready`), on the page navigation timeline. The telemetry service uses
|
|
2657
|
-
* them to attribute the signaling / webrtc phase durations to the time the
|
|
2658
|
-
* prefetch actually spent — instead of dumping the whole pre-adoption wait
|
|
2659
|
-
* onto whichever phase closer happens to fire first. `null` when adopting a
|
|
2660
|
-
* stream that carried no timings.
|
|
2661
|
-
*/
|
|
2662
|
-
timings: Record<string, number> | null;
|
|
2663
|
-
}) => {
|
|
2664
|
-
machineId: string | null;
|
|
2665
|
-
ssData: SignalingData | null;
|
|
2666
|
-
/**
|
|
2667
|
-
* `performance.now()` marks the prefetch script recorded while it
|
|
2668
|
-
* established the connection (`prefetch_start` / `ws_open` / `dc_open` /
|
|
2669
|
-
* `ready`), on the page navigation timeline. The telemetry service uses
|
|
2670
|
-
* them to attribute the signaling / webrtc phase durations to the time the
|
|
2671
|
-
* prefetch actually spent — instead of dumping the whole pre-adoption wait
|
|
2672
|
-
* onto whichever phase closer happens to fire first. `null` when adopting a
|
|
2673
|
-
* stream that carried no timings.
|
|
2674
|
-
*/
|
|
2675
|
-
timings: Record<string, number> | null;
|
|
2676
|
-
} & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
|
|
2677
2463
|
declare const startStream: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
|
|
2678
2464
|
config: Partial<StreamConfig>;
|
|
2679
2465
|
}) => {
|
|
@@ -2770,11 +2556,11 @@ declare class UnrealEffects {
|
|
|
2770
2556
|
private readonly commandTelemetryService;
|
|
2771
2557
|
private readonly regionsPingService;
|
|
2772
2558
|
private readonly signallingService;
|
|
2773
|
-
private readonly streamAdoptionService;
|
|
2774
2559
|
private readonly videoService;
|
|
2775
2560
|
private readonly unrealCallbackService;
|
|
2776
2561
|
private dataChannelConnectionTimeout;
|
|
2777
2562
|
private connectionCompleted$;
|
|
2563
|
+
private reconnectConfig;
|
|
2778
2564
|
destroyConnections$: node_modules_rxjs_dist_types.Observable<{
|
|
2779
2565
|
reason: _3dsource_angular_unreal_module.DisconnectReasonType;
|
|
2780
2566
|
} & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
|
|
@@ -2842,8 +2628,8 @@ declare class UnrealEffects {
|
|
|
2842
2628
|
* Effect: `handleDataChannelClosed$`
|
|
2843
2629
|
*
|
|
2844
2630
|
* Triggers peer reconnection when DataChannel closes unexpectedly.
|
|
2845
|
-
* Only triggers if reconnection is enabled
|
|
2846
|
-
* is still connected.
|
|
2631
|
+
* Only triggers if reconnection is enabled, onDataChannelClose is true,
|
|
2632
|
+
* and the signaling WebSocket is still connected.
|
|
2847
2633
|
*/
|
|
2848
2634
|
handleDataChannelClosed$: node_modules_rxjs_dist_types.Observable<{
|
|
2849
2635
|
attempt: number;
|
|
@@ -2888,9 +2674,7 @@ declare class UnrealEffects {
|
|
|
2888
2674
|
id: string;
|
|
2889
2675
|
now: number;
|
|
2890
2676
|
} & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
|
|
2891
|
-
connectToSignaling$: node_modules_rxjs_dist_types.Observable<
|
|
2892
|
-
value: boolean;
|
|
2893
|
-
} & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
|
|
2677
|
+
connectToSignaling$: node_modules_rxjs_dist_types.Observable<WebSocket> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
|
|
2894
2678
|
private canPeerReconnect;
|
|
2895
2679
|
/**
|
|
2896
2680
|
* Either schedules the next peer-reconnect attempt or gives up with the
|
|
@@ -2907,7 +2691,6 @@ declare const unrealFeature: {
|
|
|
2907
2691
|
name: "unrealFeature";
|
|
2908
2692
|
reducer: node_modules__ngrx_store_types_ngrx_store.ActionReducer<_3dsource_angular_unreal_module.UnrealState, node_modules__ngrx_store_types_ngrx_store.Action<string>>;
|
|
2909
2693
|
selectUnrealFeatureState: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, _3dsource_angular_unreal_module.UnrealState, (featureState: _3dsource_angular_unreal_module.UnrealState) => _3dsource_angular_unreal_module.UnrealState>;
|
|
2910
|
-
selectAdopted: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
|
|
2911
2694
|
selectFreezeFrame: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, _3dsource_angular_unreal_module.FreezeFrameMessage, (featureState: _3dsource_angular_unreal_module.UnrealState) => _3dsource_angular_unreal_module.FreezeFrameMessage>;
|
|
2912
2695
|
selectIsVideoPlaying: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
|
|
2913
2696
|
selectStatusMessage: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, string | null, (featureState: _3dsource_angular_unreal_module.UnrealState) => string | null>;
|
|
@@ -2964,13 +2747,6 @@ interface UnrealState {
|
|
|
2964
2747
|
isAfkTimerVisible: boolean;
|
|
2965
2748
|
afkCountdown: number;
|
|
2966
2749
|
cirrusConnected: boolean;
|
|
2967
|
-
/**
|
|
2968
|
-
* True once a prefetched connection has been adopted (`streamAdopted`).
|
|
2969
|
-
* Read synchronously by the telemetry service so the connection-phase
|
|
2970
|
-
* closers know to defer to the prefetch-timed attribution instead of the
|
|
2971
|
-
* live-event one. Reset on every fresh attempt / disconnect.
|
|
2972
|
-
*/
|
|
2973
|
-
adopted: boolean;
|
|
2974
2750
|
viewportReady: boolean;
|
|
2975
2751
|
freezeFrameFromVideo: FreezeFrameMessage;
|
|
2976
2752
|
freezeFrame: FreezeFrameMessage;
|
|
@@ -3056,5 +2832,5 @@ declare const selectUserInactivityDetected: node_modules__ngrx_store_types_ngrx_
|
|
|
3056
2832
|
/** Used by external consumers (e.g., metabox). Do not remove. */
|
|
3057
2833
|
declare const selectIsVideoPlayingAndDataChannelConnected: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: boolean, s2: boolean) => boolean>;
|
|
3058
2834
|
|
|
3059
|
-
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler,
|
|
3060
|
-
export type { AggregatedStat, AnySignalingMessage, AwsInstance, CandidateMessage, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DataFlowCheckResult, DisconnectReasonType, EmittedMilestone, EventId, ForceClientDisconnect, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues,
|
|
2835
|
+
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, smoothTransition, startStream, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
2836
|
+
export type { AggregatedStat, AnySignalingMessage, AwsInstance, CandidateMessage, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DataFlowCheckResult, DisconnectReasonType, EmittedMilestone, EventId, ForceClientDisconnect, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues, OrchestrationErrorMessage, OrchestrationMessageType, P2PEstablishedMessage, PhaseOverlay, PhaseParam, PingMessage, PlayerCountMessage, PollingOrchestrationMessage, Quality, ReceivedFile, ReconnectConfig, RequestStream, SSInfo, SelectedIceCandidatePair, SignalingData, SignalingMessageHandler, SignalingMessageMap, StreamConfig, StreamRequestContext, StreamResolutionProps, StreamerListMessage, TelemetryType, UnknownFields, UnrealCallbackDescriptor, UnrealCallbackEventMap, UnrealCallbackJson, UnrealCallbackJsonWrapped, UnrealInitialConfig, UnrealState, WSCloseCodesValues, streamPreparedForUserInteractionMessage };
|
package/js/stream-prefetch.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
"use strict";(()=>{"use strict";const f="metabox-configurator",m=/metabox-configurator\/(modular|basic)\/([^/?#]+)/i,g="3dsource:region-ping",k="assets/config.json",w="42e01f";function l(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{const t=Math.random()*16|0;return(o==="x"?t:t&3|8).toString(16)})}function I(o){return o.replace("http://","ws://").replace("https://","wss://")}const h="[stream-prefetch]",s=(...o)=>console.log(h,...o),c=(...o)=>console.warn(h,...o),u=(...o)=>console.error(h,...o);class y{constructor(){const t=document.currentScript||(()=>{const n=document.getElementsByTagName("script");return n[n.length-1]})(),e=t&&t.dataset||{};this.configUrl=e.configUrl||k,this.fallbackPollingUrl=e.fallbackUrl||"",this.skipRouteCheck=this.boolOr(e.skipRouteCheck,!1),this.config={ws_timeout:this.numberOr(e.wsTimeout,6e3),poll_timeout:this.numberOr(e.pollTimeout,4e3)};const i=new URLSearchParams(window.location.search);this.forceTURN=i.has("ForceTURN"),this.forceMaxBundle=i.has("ForceMaxBundle"),this.forceMonoAudio=i.has("forceMono"),this.ids={clientId:l(),viewId:l(),correlationId:l()},this.context=null,this.environmentId=void 0,this.orchestrationType="",this.region="",this.requireEnvironmentId=!0,this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.wsTimeoutId=null,this.settled=!1}run(){if(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window))return;if(this.skipRouteCheck){this.context={},this.requireEnvironmentId=!1,c("skipRouteCheck=true \u2014 ignoring URL gate, route, context and environmentId; using fallback polling"),this.publishParked("connecting"),this.connect().catch(e=>this.fail("exception",e));return}if(window.location.href.indexOf(f)===-1){s("skip \u2014 URL does not contain gate",`"${f}"`);return}const t=this.parseConfiguratorUrl();t?(this.context={id:t.contextId,data:{configuratorId:t.configuratorId}},this.requireEnvironmentId=!0,s("start",{contextId:t.contextId,configuratorId:t.configuratorId,ids:this.ids})):(this.context={},this.requireEnvironmentId=!1,c("URL is not a configurator route \u2014 prefetching with empty context {} and no required environmentId",window.location.pathname)),this.publishParked("connecting"),this.connect().catch(e=>this.fail("exception",e))}parseConfiguratorUrl(){const t=window.location.pathname.match(m);return t?{contextId:t[1].toLowerCase()==="modular"?"metaboxModularConfigurator":"metaboxBasicConfigurator",configuratorId:decodeURIComponent(t[2])}:null}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",s("region from cache:",this.region||"(none)"),(this.skipRouteCheck?Promise.resolve(null):this.fetchConfig()).then(e=>{let i;if(e)i=this.chooseEndpoint(e);else if(this.fallbackPollingUrl)c("no app config \u2014 falling back to polling",this.fallbackPollingUrl),i={type:"polling",url:this.fallbackPollingUrl,environmentId:""},this.requireEnvironmentId=!1;else{this.fail("no-config");return}if(!i){this.fail("no-endpoint");return}if(s("endpoint chosen",{type:i.type,url:i.url,environmentId:i.environmentId}),this.requireEnvironmentId&&!i.environmentId){this.fail("no-environment-id");return}this.orchestrationType=i.type,this.environmentId=i.environmentId||void 0;const n=this.adaptUrlToRegion(i.url);return(i.type==="polling"?this.pollOrchestration(n):Promise.resolve(n)).then(a=>{if(!a){this.fail("no-ws-url");return}return this.parked.machineId=a,s("opening socket",a),this.openSocket(a)})})}fetchConfig(){const t=new URL(this.configUrl,window.location.origin).href;return this.fetchWithTimeout(t,{credentials:"omit"},this.config.poll_timeout).then(e=>e.ok?e.json().catch(()=>null):null).catch(()=>null)}chooseEndpoint(t){const e=t.newSignalling,i=this.firstVersionUrl(e&&e.versions);if(i&&/^wss?:\/\//i.test(i))return{type:"direct",url:i,environmentId:e&&e.environmentId||""};const n=t.signalling,r=this.firstVersionUrl(n&&n.versions);return r?(this.requireEnvironmentId=!1,{type:"polling",url:r,environmentId:n&&n.environmentId||""}):null}firstVersionUrl(t){if(!t||typeof t!="object")return"";for(const e of Object.keys(t))if(t[e])return t[e];return""}pollOrchestration(t){const e=`${t}${this.ids.clientId}/${this.ids.viewId}`;return this.fetchWithTimeout(e,{credentials:"omit"},this.config.poll_timeout).then(i=>i.ok?i.json().catch(()=>({})):null).then(i=>i&&i.signallingServer?I(`${window.location.protocol}//${i.signallingServer}`):null).catch(()=>null)}adaptUrlToRegion(t){return this.region&&t.indexOf(":region")===-1?t.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):t}openSocket(t){const e=new WebSocket(t);e.binaryType="arraybuffer",this.ws=e,this.parked.ws=e,this.wsTimeoutId=setTimeout(()=>{e.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),e.onopen=()=>{clearTimeout(this.wsTimeoutId),this.mark("ws_open"),s("WS open \u2192 sending requestStream",{environmentId:this.environmentId,region:this.region,context:this.context}),this.sendRequestStream()},e.onmessage=i=>this.onWsMessage(i),e.onerror=i=>{u("WS error",i),this.fail("ws-error")},e.onclose=i=>{!this.settled&&this.parked.state!=="ready"&&(c("WS closed before ready",{code:i&&i.code}),this.fail("ws-closed"))}}sendRequestStream(){this.send({type:"requestStream",correlationId:this.ids.correlationId,payload:{region:this.region,environmentId:this.environmentId,context:this.context}})}onWsMessage(t){let e;try{const i=typeof t.data=="string"?t.data:null;if(i===null)return;e=JSON.parse(i)}catch{return}switch(s("WS \u2190",e.type),e.type){case"ssInfo":this.parked.ssData=e.data;break;case"config":this.onConfig(e);break;case"offer":this.onOffer(e);break;case"answer":this.onAnswer(e);break;case"iceCandidate":this.onIceCandidate(e.candidate);break;case"ping":this.send({type:"pong",source:"front"});break;case"streamerDisconnected":case"playerDisconnected":this.fail("streamer-disconnected");break;case"error":this.fail("orchestration-error");break;default:break}}onConfig(t){if(this.pc)return;const e=Object.assign({},t.peerConnectionOptions);this.forceTURN&&(e.iceTransportPolicy="relay"),e.bundlePolicy=this.forceMaxBundle?"max-bundle":"balanced",e.iceCandidatePoolSize=1,this.parked.config=e;const i=new RTCPeerConnection(e);this.pc=i,this.parked.pc=i,s("PeerConnection created from config"),i.onicecandidate=n=>{n.candidate&&this.send({type:"iceCandidate",candidate:n.candidate})},i.ondatachannel=n=>this.wireDataChannel(n.channel),i.ontrack=n=>{n.track&&n.track.kind==="video"&&n.streams[0]&&(s("video track received"),this.stream=n.streams[0],this.parked.stream=this.stream,this.maybeReady())}}onOffer(t){return this.pc?(this.remoteDescriptionSet=!1,this.iceBuffer.length=0,this.pc.setRemoteDescription(t).then(()=>(this.remoteDescriptionSet=!0,this.flushIce(),this.pc.createAnswer())).then(e=>(e.sdp=this.mungeSDP(e.sdp||""),this.pc.setLocalDescription(e).then(()=>{s("WS \u2192 answer sent"),this.send(e)}))).catch(e=>this.fail("offer-failed",e))):Promise.resolve()}onAnswer(t){return this.pc?this.pc.setRemoteDescription(t).then(()=>{this.remoteDescriptionSet=!0,this.flushIce()}).catch(e=>this.fail("answer-failed",e)):Promise.resolve()}onIceCandidate(t){t&&(this.forceTURN&&String(t.candidate).indexOf("relay")<0||(this.remoteDescriptionSet&&this.pc?this.pc.addIceCandidate(t).catch(()=>{}):this.iceBuffer.push(t)))}flushIce(){for(const t of this.iceBuffer)this.pc.addIceCandidate(t).catch(()=>{});this.iceBuffer.length=0}wireDataChannel(t){t.binaryType="arraybuffer",this.dc=t,this.parked.dc=t,t.onmessage=e=>{this.parked.dcBuffer.push(e.data)},t.onopen=()=>{s("DataChannel open"),this.mark("dc_open"),this.maybeReady()},t.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&(c("DataChannel closed before ready"),this.fail("dc-closed"))},t.readyState==="open"&&this.maybeReady()}maybeReady(){this.settled||!this.dc||this.dc.readyState!=="open"||this.stream&&(this.settled=!0,this.mark("ready"),this.parked.state="ready",s("READY \u2014 parked on window.__stream",this.parked.timings),this.fireSettled())}publishParked(t){const e=this;this.parked={state:t,pc:null,dc:null,stream:null,ws:null,ssData:void 0,machineId:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return e.clearTimers(),this.state="adopted",this},onSettled(i){if(typeof i=="function"){if(this.state!=="connecting"){const n=this.state;Promise.resolve().then(()=>i(n));return}e.settledCb=i}}},window.__stream=this.parked}fireSettled(){const t=this.settledCb;if(t){this.settledCb=null;try{t(this.parked.state)}catch{}}}clearTimers(){this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null)}fail(t,e){if(!(this.parked&&(this.parked.state==="adopted"||this.parked.state==="failed"))){u("FAILED:",t,e||""),this.settled=!0,this.clearTimers();try{this.dc&&this.dc.close()}catch{}try{this.pc&&this.pc.close()}catch{}try{this.ws&&this.ws.close()}catch{}this.parked&&(this.parked.state="failed",this.parked.failReason=t,e&&(this.parked.failError=String(e&&e.message||e)),this.fireSettled())}}mungeSDP(t){let e=this.prioritizeH264Profile(t,w);e=e.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,`$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r
|
|
2
|
-
`);let i="maxaveragebitrate=510000;";return i+=this.forceMonoAudio?"stereo=0;":"stereo=1;",i+="useinbandfec=1",e=e.replace("useinbandfec=1",i),e}prioritizeH264Profile(t,e){const i=t.split(`\r
|
|
3
|
-
`),n=[];for(const r of i)if(r.startsWith("a=fmtp:")&&r.toLowerCase().includes(`profile-level-id=${e}`)){const a=r.split(":")[1]&&r.split(":")[1].split(" ")[0];a&&n.push(a)}return n.length===0?t:i.map(r=>{if(!r.startsWith("m=video"))return r;const a=r.split(" "),x=a.slice(0,3),p=a.slice(3),b=[...n.filter(d=>p.includes(d)),...p.filter(d=>!n.includes(d))];return[...x,...b].join(" ")}).join(`\r
|
|
4
|
-
`)}send(t){const e=typeof t=="string"?t:JSON.stringify(t);if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(e)}catch{}}mark(t){this.parked&&(this.parked.timings[t]=performance.now())}readRegion(){try{const t=localStorage.getItem(g);if(!t)return null;const e=JSON.parse(t);return!e||typeof e.region_code!="string"||typeof e.ts!="number"||Date.now()-e.ts>=2592e6?null:e.region_code}catch{return null}}fetchWithTimeout(t,e,i){const n=new AbortController;e.signal=n.signal;const r=setTimeout(()=>n.abort(),i);return fetch(t,e).finally(()=>clearTimeout(r))}numberOr(t,e){const i=Number(t);return t!=null&&t!==""&&!Number.isNaN(i)?i:e}boolOr(t,e){return t==="true"||t===""?!0:t==="false"?!1:e}}new y().run()})();
|