@3dsource/angular-unreal-module 0.0.171 → 0.0.172
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 +421 -229
- package/fesm2022/3dsource-angular-unreal-module.mjs +979 -868
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +1 -1
- package/types/3dsource-angular-unreal-module.d.ts +81 -7
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, ChangeDetectionStrategy, Component, InjectionToken, inject, DestroyRef, Injectable, signal, effect, untracked, computed, ElementRef, viewChild, afterNextRender, HostListener, SecurityContext, Pipe, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
import { createAction, props, createReducer, on, createFeature,
|
|
5
|
-
import { whereNot, Falsy, Logger, clampf, lerp, getCanvasCached, getSnapshot, fitIntoRectangle, generateUuid, Truthy, tapLog, Semaphore, COLOR_CODES, where, KeyboardNumericCode, InvertedKeyMap, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
6
|
-
import { filter, map as map$1, distinctUntilChanged, takeWhile, takeUntil, catchError, tap, timeout, finalize, first, switchMap as switchMap$1, withLatestFrom, exhaustMap, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
|
|
2
|
+
import { input, output, ChangeDetectionStrategy, Component, InjectionToken, inject, DestroyRef, Injectable, signal, effect, untracked, computed, ElementRef, viewChild, afterNextRender, HostListener, TemplateRef, Directive, SecurityContext, Pipe, contentChild, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet, NgOptimizedImage, JsonPipe } from '@angular/common';
|
|
4
|
+
import { createAction, props, createReducer, on, createFeature, createSelector, Store, provideState } from '@ngrx/store';
|
|
7
5
|
import { Actions, ofType, createEffect, provideEffects } from '@ngrx/effects';
|
|
6
|
+
import { Subject, skip, share, timer, of, take, defer, switchMap, from, throwError, Observable, EMPTY, retry, merge, timeout as timeout$1, repeat, BehaviorSubject, interval, map as map$1, takeUntil as takeUntil$1, fromEvent, tap as tap$1, throttleTime, delay, concat, debounceTime, mergeMap, NEVER, ignoreElements, startWith, scan, timestamp, pairwise, concatMap, animationFrameScheduler, shareReplay, firstValueFrom, asyncScheduler, filter as filter$1, withLatestFrom as withLatestFrom$1, Subscription, bufferTime, combineLatestWith } from 'rxjs';
|
|
7
|
+
import { whereNot, lerp, clampf, Falsy, generateUuid, Truthy, Logger, tapLog, Semaphore, COLOR_CODES, getCanvasCached, getSnapshot, fitIntoRectangle, where, KeyboardNumericCode, InvertedKeyMap, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
8
|
+
import { filter, takeUntil, catchError, tap, map, timeout, finalize, first, switchMap as switchMap$1, distinctUntilChanged, withLatestFrom, exhaustMap, takeWhile, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
|
|
8
9
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
9
10
|
import { HttpClient } from '@angular/common/http';
|
|
10
11
|
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
11
12
|
import { MetaBoxCommand, EPayloadVersion } from '@3dsource/types-unreal';
|
|
12
13
|
import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
13
|
-
import { NgOptimizedImage, JsonPipe } from '@angular/common';
|
|
14
14
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
15
15
|
|
|
16
16
|
class UnrealButtonComponent {
|
|
@@ -34,14 +34,246 @@ class UnrealButtonComponent {
|
|
|
34
34
|
event.preventDefault();
|
|
35
35
|
this.clicked.emit(event);
|
|
36
36
|
}
|
|
37
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
38
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
37
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: UnrealButtonComponent, isStandalone: true, selector: "app-unreal-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
39
39
|
}
|
|
40
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
40
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealButtonComponent, decorators: [{
|
|
41
41
|
type: Component,
|
|
42
|
-
args: [{ selector: 'app-unreal-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\
|
|
42
|
+
args: [{ selector: 'app-unreal-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"] }]
|
|
43
43
|
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
|
|
44
44
|
|
|
45
|
+
function AnswerHandler(msg) {
|
|
46
|
+
this.onWebRtcAnswer$.next(msg);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function ConfigHandler(msg) {
|
|
50
|
+
this.onConfig$.next(msg);
|
|
51
|
+
//DO NOT REMOVE. Possible required in future for SFU
|
|
52
|
+
/*this.send({
|
|
53
|
+
type: OrchestrationMessageTypes.listStreamers,
|
|
54
|
+
correlationId: this.correlationId,
|
|
55
|
+
});*/
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function IceCandidateHandler(msg) {
|
|
59
|
+
this.onWebRtcIce$.next(msg.candidate);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const scoped = (templateString) => `[UNREAL] ${templateString[0]}`;
|
|
63
|
+
const unrealCommandCallback = createAction(scoped `unreal command callback`, props());
|
|
64
|
+
const commandStarted = createAction(scoped `command started`, props());
|
|
65
|
+
const commandCompleted = createAction(scoped `command completed`, props());
|
|
66
|
+
const trackMixpanelEvent = createAction(scoped `track Mixpanel event`, props());
|
|
67
|
+
const trackTelemetryData = createAction(scoped `track telemetry data`, props());
|
|
68
|
+
const setMaxFps = createAction(scoped `change fps`, props());
|
|
69
|
+
const destroyRemoteConnections = createAction(scoped `destroyRemoteConnections`, props());
|
|
70
|
+
const destroyUnrealScene = createAction(scoped `destroyUnrealScene`);
|
|
71
|
+
const setCirrusConnected = createAction(scoped `cirrusConnected`);
|
|
72
|
+
const setCirrusDisconnected = createAction(scoped `cirrusDisconnected`);
|
|
73
|
+
const changeStatusMainVideoOnScene = createAction(scoped `change status main video on scene`, props());
|
|
74
|
+
const setAwsInstance = createAction(scoped `set aws instance`, props());
|
|
75
|
+
const setStatusMessage = createAction(scoped `set status message`, props());
|
|
76
|
+
const setStatusPercentSignallingServer = createAction(scoped `change status percent signalling server`, props());
|
|
77
|
+
const setFreezeFrame = createAction(scoped `set freeze frame`, props());
|
|
78
|
+
const setStreamClientCompanyId = createAction(scoped `set stream client company id`, props());
|
|
79
|
+
const setStreamViewId = createAction(scoped `set stream view id`, props());
|
|
80
|
+
const setIntroImageSrc = createAction(scoped `set intro image src`, props());
|
|
81
|
+
const setLoadingImageSrc = createAction(scoped `set loading image src`, props());
|
|
82
|
+
const setIntroVideoSrc = createAction(scoped `set intro video src`, props());
|
|
83
|
+
const resetIntroSrc = createAction(scoped `reset intro src`);
|
|
84
|
+
const setFreezeFrameFromVideo = createAction(scoped `set freeze frame from video`, props());
|
|
85
|
+
const setEstablishingConnection = createAction(scoped `set establishing connection`, props());
|
|
86
|
+
const dataChannelConnected = createAction(scoped `data channel connected`, props());
|
|
87
|
+
const dataChannelReady = createAction(scoped `dataChannelReady`);
|
|
88
|
+
const setConfig = createAction(scoped `set config`, props());
|
|
89
|
+
const disconnectStream = createAction(scoped `disconnectStream`, props());
|
|
90
|
+
const dropConnection = createAction(scoped `dropConnection`);
|
|
91
|
+
const setViewportReady = createAction(scoped `set viewport ready`);
|
|
92
|
+
const setViewportNotReady = createAction(scoped `set viewport not ready`);
|
|
93
|
+
const changeStreamResolutionAction = createAction(scoped `change stream resolution`, props());
|
|
94
|
+
const setSignalingName = createAction(scoped `set aws instanceName`, props());
|
|
95
|
+
const setOrchestrationParameters = createAction(scoped `set orchestration parameters`, props());
|
|
96
|
+
/**
|
|
97
|
+
* Dispatched when the orchestration server signals that the reserved
|
|
98
|
+
* instance is ready to serve the stream (`instanceReady` WS message).
|
|
99
|
+
* Carries the stream-machine coordinates — `originInstanceUri` is used to
|
|
100
|
+
* open the second (stream-machine) signalling socket. Also consumed by
|
|
101
|
+
* telemetry as a phase marker.
|
|
102
|
+
*/
|
|
103
|
+
const instanceReady = createAction(scoped `instance ready`, props());
|
|
104
|
+
/**
|
|
105
|
+
* Dispatched when `RegionsPingService.getFastest()` begins — right
|
|
106
|
+
* before the region-list HTTP request goes out. Bookends the entire
|
|
107
|
+
* region-discovery flow together with {@link regionResolved}.
|
|
108
|
+
* Observability-only — no state change.
|
|
109
|
+
*/
|
|
110
|
+
const regionPingFetchStart = createAction(scoped `region ping fetch start`);
|
|
111
|
+
/**
|
|
112
|
+
* Dispatched once `RegionsPingService.getProviders()` returns the region
|
|
113
|
+
* list — i.e., the fetch step is done and the actual per-region ping
|
|
114
|
+
* sweep is about to start. Splits the region-discovery waterfall into
|
|
115
|
+
* two legs: config fetch vs. ping sweep. Observability-only.
|
|
116
|
+
*/
|
|
117
|
+
const regionPingFetchEnd = createAction(scoped `region ping fetch end`);
|
|
118
|
+
/**
|
|
119
|
+
* Dispatched once the closest region has been resolved by the
|
|
120
|
+
* regions-ping service. Carries every sampled ping RTT to the winning
|
|
121
|
+
* region (one entry per probe — `checkLatency` issues `ping_count`
|
|
122
|
+
* sequential pings per region) so consumers can inspect variance /
|
|
123
|
+
* jitter, not just the mean. Observability-only — no state change.
|
|
124
|
+
*/
|
|
125
|
+
const regionResolved = createAction(scoped `region resolved`, props());
|
|
126
|
+
/**
|
|
127
|
+
* Dispatched around the HTTP polling roundup inside `getAwsInstance`
|
|
128
|
+
* (old orchestration flow). Only fires when polling is actually used
|
|
129
|
+
* (i.e., signaling URL is not a direct `ws://` / `wss://` endpoint).
|
|
130
|
+
* Observability-only — no state change.
|
|
131
|
+
*/
|
|
132
|
+
const pollingStarted = createAction(scoped `polling started`);
|
|
133
|
+
const pollingEnded = createAction(scoped `polling ended`);
|
|
134
|
+
/**
|
|
135
|
+
* Dispatched once for every `retry()` attempt inside the signalling
|
|
136
|
+
* connect pipeline. Two kinds:
|
|
137
|
+
*
|
|
138
|
+
* - `'connect'` — outer retry around the whole connect pipeline
|
|
139
|
+
* (region ping → AWS instance → WebSocket). Fires when the WS
|
|
140
|
+
* errors (e.g. "WebSocket closed before open") and the entire
|
|
141
|
+
* pipeline is re-subscribed. See `SIGNALLING.md` — every one of
|
|
142
|
+
* these currently triggers a fresh region-ping storm.
|
|
143
|
+
* - `'orchestration'` — inner retry inside `getAwsInstance`,
|
|
144
|
+
* advancing `urlGen` to the next candidate signalling URL when
|
|
145
|
+
* polling fails or returns an error payload.
|
|
146
|
+
*
|
|
147
|
+
* Observability-only — no state change. Surfaces in the viewer's
|
|
148
|
+
* Anomalies table as `signaling_retry` rows so a session that
|
|
149
|
+
* needed N tries shows N entries with their reasons.
|
|
150
|
+
*/
|
|
151
|
+
const signalingRetryAttempted = createAction(scoped `signaling retry attempted`, props());
|
|
152
|
+
/**
|
|
153
|
+
* Dispatched when the client has just sent an SDP answer back to Cirrus
|
|
154
|
+
* after receiving the server-initiated offer. Observability-only.
|
|
155
|
+
*/
|
|
156
|
+
const answerSent = createAction(scoped `answer sent`);
|
|
157
|
+
const setOrchestrationMessage = createAction(scoped `set orchestration message`, props());
|
|
158
|
+
const setOrchestrationProgress = createAction(scoped `set orchestration progress`, props());
|
|
159
|
+
const setOrchestrationContext = createAction(scoped `set orchestration params`, props());
|
|
160
|
+
const updateCirrusInfo = createAction(scoped `set unrealInfo`, props());
|
|
161
|
+
const setLoopBackCommandIsCompleted = createAction(scoped `set loopBack command is completed`);
|
|
162
|
+
const setAfkTimerVisible = createAction(scoped `set afk timer visible`);
|
|
163
|
+
const setAfkTimerHide = createAction(scoped `set afk timer hide`);
|
|
164
|
+
const setAfkTimerCountdown = createAction(scoped `set afk timer count down`, props());
|
|
165
|
+
const showUnrealErrorMessage = createAction(scoped `show unreal error message`, props());
|
|
166
|
+
const initSignalling = createAction(scoped `init signalling`);
|
|
167
|
+
/**
|
|
168
|
+
* Dispatched when a prefetched connection parked on `window.__stream` by the
|
|
169
|
+
* `stream-prefetch.js` head-script is adopted instead of opening a fresh
|
|
170
|
+
* `connectToSignaling`. Marks cirrus connected and records the adopted machine
|
|
171
|
+
* in one transaction; the data channel / app-init chain then proceeds via
|
|
172
|
+
* `dataChannelConnected` dispatched from `WebRtcPlayerService`.
|
|
173
|
+
*
|
|
174
|
+
* Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
|
|
175
|
+
* app (e.g. metabox) sets those authoritatively from its own data before
|
|
176
|
+
* `initSignalling`, and the prefetch script's ids are connection-internal only.
|
|
177
|
+
*/
|
|
178
|
+
const streamAdopted = createAction(scoped `stream adopted`, props());
|
|
179
|
+
const startStream = createAction(scoped `startStream`, props());
|
|
180
|
+
const resetConfig = createAction(scoped `reset config`);
|
|
181
|
+
const resetAfk = createAction(scoped `reset afk action`);
|
|
182
|
+
const resetWarnTimeout = createAction(scoped `reset config warn timeout`);
|
|
183
|
+
/**
|
|
184
|
+
* Fan-in for "cancel an in-flight signalling attempt". Dispatched by the
|
|
185
|
+
* abortEstablishingConnection$ effect whenever any of these source actions
|
|
186
|
+
* fire: `setCirrusDisconnected` (cirrus dropped), `dropConnection` (user
|
|
187
|
+
* called drop), `destroyUnrealScene` (component teardown). Consumers
|
|
188
|
+
* (`SignallingService.abort$`, `setDataChannelTimeoutCheck$.abort$`) listen
|
|
189
|
+
* to this one action instead of the trio so the "abort" intent has a single
|
|
190
|
+
* named entry in Redux DevTools and one subscription site to update.
|
|
191
|
+
*/
|
|
192
|
+
const abortEstablishingConnection = createAction(scoped `abortEstablishingConnection`);
|
|
193
|
+
const setUnrealPlaywrightConfig = createAction(scoped `set unreal playwright config`);
|
|
194
|
+
const saveAnalyticsEvent = createAction(scoped `save analytics event`, props());
|
|
195
|
+
/** Action to trigger WebRTC peer reconnection (keeps signaling connection) */
|
|
196
|
+
const reconnectPeer = createAction(scoped `reconnect peer`, props());
|
|
197
|
+
/** Action to reset the data channel state before reconnection */
|
|
198
|
+
const resetDataChannelForReconnect = createAction(scoped `reset data channel for reconnect`);
|
|
199
|
+
/** Action dispatched when peer reconnection succeeds */
|
|
200
|
+
const reconnectPeerSuccess = createAction(scoped `reconnect peer success`);
|
|
201
|
+
/** Action dispatched when all peer reconnection attempts are exhausted */
|
|
202
|
+
const reconnectPeerFailed = createAction(scoped `reconnect peer failed`, props());
|
|
203
|
+
/** Action dispatched when ICE connection state changes to failed/disconnected */
|
|
204
|
+
const iceConnectionFailed = createAction(scoped `ice connection failed`, props());
|
|
205
|
+
const forceResizeViewport = createAction(scoped `force resize viewport`);
|
|
206
|
+
const videoAdaptedToContainer = createAction(scoped `video adapted to container`);
|
|
207
|
+
const videoStreamInitialized = createAction(scoped `video stream initialized`);
|
|
208
|
+
const dropDC = createAction(scoped `drop data channel`);
|
|
209
|
+
const dropPC = createAction(scoped `drop peer connection`);
|
|
210
|
+
const showLoadingProgress = createAction(scoped `show loading progress`, props());
|
|
211
|
+
const showResumeStreamPopup = createAction(scoped `show resume stream popup`, props());
|
|
212
|
+
const showUserInactivityTimeoutPopup = createAction(scoped `show user inactivity timeout popup`, props());
|
|
213
|
+
const setUserInactivityTimeout = createAction(scoped `set user inactivity timeout`, props());
|
|
214
|
+
const resetUserInactivityTimeout = createAction(scoped `reset user inactivity timeout`);
|
|
215
|
+
|
|
216
|
+
const WSCloseCode_NORMAL_CLOSURE = 3000;
|
|
217
|
+
const WSCloseCode_NORMAL_AFK_TIMEOUT = 3001;
|
|
218
|
+
const WSCloseCode_NORMAL_MANUAL_DISCONNECT = 3002;
|
|
219
|
+
const WSCloseCode_FORCE_CIRRUS_CLOSE = 3003;
|
|
220
|
+
const WSCloseCode_UNKNOWN = 1000;
|
|
221
|
+
const WSCloseCode_CIRRUS_PLAYER_DISCONNECTED = 1001;
|
|
222
|
+
const WSCloseCode_CIRRUS_ABNORMAL_CLOSURE = 1006;
|
|
223
|
+
const WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR = 1013;
|
|
224
|
+
const WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER = 1011;
|
|
225
|
+
const WSCloseCodes = [
|
|
226
|
+
WSCloseCode_NORMAL_CLOSURE,
|
|
227
|
+
WSCloseCode_NORMAL_AFK_TIMEOUT,
|
|
228
|
+
WSCloseCode_NORMAL_MANUAL_DISCONNECT,
|
|
229
|
+
WSCloseCode_FORCE_CIRRUS_CLOSE,
|
|
230
|
+
WSCloseCode_UNKNOWN,
|
|
231
|
+
WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
|
|
232
|
+
WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
|
|
233
|
+
WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
|
|
234
|
+
WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
const DisconnectReason = {
|
|
238
|
+
Afk: 'Afk',
|
|
239
|
+
None: 'None',
|
|
240
|
+
Destroy: 'Destroy',
|
|
241
|
+
DataChannelClosed: 'DataChannelClosed',
|
|
242
|
+
DataChannelTimeout: 'DataChannelTimeout',
|
|
243
|
+
WebRTCError: 'WebRTCError',
|
|
244
|
+
WebSocketError: 'WebSocketError',
|
|
245
|
+
WebSocketClose: 'WebSocketClose',
|
|
246
|
+
DropConnection: 'DropConnection',
|
|
247
|
+
OrchestrationPlayerDisconnected: 'OrchestrationPlayerDisconnected',
|
|
248
|
+
OrchestrationStreamerDisconnected: 'OrchestrationStreamerDisconnected',
|
|
249
|
+
IceConnectionFailed: 'IceConnectionFailed',
|
|
250
|
+
ReconnectFailed: 'ReconnectFailed',
|
|
251
|
+
NewConnectionAttempt: 'NewConnectionAttempt',
|
|
252
|
+
AbortEstablishingConnection: 'AbortEstablishingConnection',
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
export interface RequestReservation extends InstanceMessageBase {
|
|
257
|
+
type: 'requestReservation';
|
|
258
|
+
}
|
|
259
|
+
*/
|
|
260
|
+
const OrchestrationMessageTypes = {
|
|
261
|
+
error: 'error',
|
|
262
|
+
offer: 'offer',
|
|
263
|
+
answer: 'answer',
|
|
264
|
+
ssInfo: 'ssInfo',
|
|
265
|
+
config: 'config',
|
|
266
|
+
playerCount: 'playerCount',
|
|
267
|
+
iceCandidate: 'iceCandidate',
|
|
268
|
+
streamerList: 'streamerList',
|
|
269
|
+
requestStream: 'requestStream',
|
|
270
|
+
listStreamers: 'listStreamers',
|
|
271
|
+
instanceReady: 'instanceReady',
|
|
272
|
+
p2pEstablished: 'p2pEstablished',
|
|
273
|
+
instanceReserved: 'instanceReserved',
|
|
274
|
+
interruptClientStream: 'interruptClientStream',
|
|
275
|
+
};
|
|
276
|
+
|
|
45
277
|
const SpecialKeyCodes = {
|
|
46
278
|
BackSpace: 8,
|
|
47
279
|
Shift: 16,
|
|
@@ -140,67 +372,6 @@ const InputOptions = {
|
|
|
140
372
|
suppressBrowserKeys: true,
|
|
141
373
|
};
|
|
142
374
|
|
|
143
|
-
const WSCloseCode_NORMAL_CLOSURE = 3000;
|
|
144
|
-
const WSCloseCode_NORMAL_AFK_TIMEOUT = 3001;
|
|
145
|
-
const WSCloseCode_NORMAL_MANUAL_DISCONNECT = 3002;
|
|
146
|
-
const WSCloseCode_FORCE_CIRRUS_CLOSE = 3003;
|
|
147
|
-
const WSCloseCode_UNKNOWN = 1000;
|
|
148
|
-
const WSCloseCode_CIRRUS_PLAYER_DISCONNECTED = 1001;
|
|
149
|
-
const WSCloseCode_CIRRUS_ABNORMAL_CLOSURE = 1006;
|
|
150
|
-
const WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR = 1013;
|
|
151
|
-
const WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER = 1011;
|
|
152
|
-
const WSCloseCodes = [
|
|
153
|
-
WSCloseCode_NORMAL_CLOSURE,
|
|
154
|
-
WSCloseCode_NORMAL_AFK_TIMEOUT,
|
|
155
|
-
WSCloseCode_NORMAL_MANUAL_DISCONNECT,
|
|
156
|
-
WSCloseCode_FORCE_CIRRUS_CLOSE,
|
|
157
|
-
WSCloseCode_UNKNOWN,
|
|
158
|
-
WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
|
|
159
|
-
WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
|
|
160
|
-
WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
|
|
161
|
-
WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
const DisconnectReason = {
|
|
165
|
-
Afk: 'Afk',
|
|
166
|
-
None: 'None',
|
|
167
|
-
Destroy: 'Destroy',
|
|
168
|
-
DataChannelClosed: 'DataChannelClosed',
|
|
169
|
-
DataChannelTimeout: 'DataChannelTimeout',
|
|
170
|
-
WebRTCError: 'WebRTCError',
|
|
171
|
-
WebSocketError: 'WebSocketError',
|
|
172
|
-
WebSocketClose: 'WebSocketClose',
|
|
173
|
-
DropConnection: 'DropConnection',
|
|
174
|
-
OrchestrationPlayerDisconnected: 'OrchestrationPlayerDisconnected',
|
|
175
|
-
OrchestrationStreamerDisconnected: 'OrchestrationStreamerDisconnected',
|
|
176
|
-
IceConnectionFailed: 'IceConnectionFailed',
|
|
177
|
-
ReconnectFailed: 'ReconnectFailed',
|
|
178
|
-
NewConnectionAttempt: 'NewConnectionAttempt',
|
|
179
|
-
AbortEstablishingConnection: 'AbortEstablishingConnection',
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/*
|
|
183
|
-
export interface RequestReservation extends InstanceMessageBase {
|
|
184
|
-
type: 'requestReservation';
|
|
185
|
-
}
|
|
186
|
-
*/
|
|
187
|
-
const OrchestrationMessageTypes = {
|
|
188
|
-
error: 'error',
|
|
189
|
-
offer: 'offer',
|
|
190
|
-
answer: 'answer',
|
|
191
|
-
ssInfo: 'ssInfo',
|
|
192
|
-
config: 'config',
|
|
193
|
-
playerCount: 'playerCount',
|
|
194
|
-
iceCandidate: 'iceCandidate',
|
|
195
|
-
streamerList: 'streamerList',
|
|
196
|
-
requestStream: 'requestStream',
|
|
197
|
-
listStreamers: 'listStreamers',
|
|
198
|
-
instanceReady: 'instanceReady',
|
|
199
|
-
p2pEstablished: 'p2pEstablished',
|
|
200
|
-
instanceReserved: 'instanceReserved',
|
|
201
|
-
interruptClientStream: 'interruptClientStream',
|
|
202
|
-
};
|
|
203
|
-
|
|
204
375
|
/** Disconnect reasons that should trigger remote connection cleanup. */
|
|
205
376
|
const DESTROY_DISCONNECT_REASONS = [
|
|
206
377
|
DisconnectReason.Afk,
|
|
@@ -300,160 +471,6 @@ const UnrealStatusMessage = {
|
|
|
300
471
|
STARTING_YOUR_SESSION: 'Starting your session',
|
|
301
472
|
};
|
|
302
473
|
|
|
303
|
-
const scoped = (templateString) => `[UNREAL] ${templateString[0]}`;
|
|
304
|
-
const unrealCommandCallback = createAction(scoped `unreal command callback`, props());
|
|
305
|
-
const commandStarted = createAction(scoped `command started`, props());
|
|
306
|
-
const commandCompleted = createAction(scoped `command completed`, props());
|
|
307
|
-
const trackMixpanelEvent = createAction(scoped `track Mixpanel event`, props());
|
|
308
|
-
const trackTelemetryData = createAction(scoped `track telemetry data`, props());
|
|
309
|
-
const setMaxFps = createAction(scoped `change fps`, props());
|
|
310
|
-
const destroyRemoteConnections = createAction(scoped `destroyRemoteConnections`, props());
|
|
311
|
-
const destroyUnrealScene = createAction(scoped `destroyUnrealScene`);
|
|
312
|
-
const setCirrusConnected = createAction(scoped `cirrusConnected`);
|
|
313
|
-
const setCirrusDisconnected = createAction(scoped `cirrusDisconnected`);
|
|
314
|
-
const changeStatusMainVideoOnScene = createAction(scoped `change status main video on scene`, props());
|
|
315
|
-
const setAwsInstance = createAction(scoped `set aws instance`, props());
|
|
316
|
-
const setStatusMessage = createAction(scoped `set status message`, props());
|
|
317
|
-
const setStatusPercentSignallingServer = createAction(scoped `change status percent signalling server`, props());
|
|
318
|
-
const setFreezeFrame = createAction(scoped `set freeze frame`, props());
|
|
319
|
-
const setStreamClientCompanyId = createAction(scoped `set stream client company id`, props());
|
|
320
|
-
const setStreamViewId = createAction(scoped `set stream view id`, props());
|
|
321
|
-
const setIntroImageSrc = createAction(scoped `set intro image src`, props());
|
|
322
|
-
const setLoadingImageSrc = createAction(scoped `set loading image src`, props());
|
|
323
|
-
const setIntroVideoSrc = createAction(scoped `set intro video src`, props());
|
|
324
|
-
const resetIntroSrc = createAction(scoped `reset intro src`);
|
|
325
|
-
const setFreezeFrameFromVideo = createAction(scoped `set freeze frame from video`, props());
|
|
326
|
-
const setEstablishingConnection = createAction(scoped `set establishing connection`, props());
|
|
327
|
-
const dataChannelConnected = createAction(scoped `data channel connected`, props());
|
|
328
|
-
const dataChannelReady = createAction(scoped `dataChannelReady`);
|
|
329
|
-
const setConfig = createAction(scoped `set config`, props());
|
|
330
|
-
const disconnectStream = createAction(scoped `disconnectStream`, props());
|
|
331
|
-
const dropConnection = createAction(scoped `dropConnection`);
|
|
332
|
-
const setViewportReady = createAction(scoped `set viewport ready`);
|
|
333
|
-
const setViewportNotReady = createAction(scoped `set viewport not ready`);
|
|
334
|
-
const changeStreamResolutionAction = createAction(scoped `change stream resolution`, props());
|
|
335
|
-
const setSignalingName = createAction(scoped `set aws instanceName`, props());
|
|
336
|
-
const setOrchestrationParameters = createAction(scoped `set orchestration parameters`, props());
|
|
337
|
-
/**
|
|
338
|
-
* Dispatched when the orchestration server signals that the reserved
|
|
339
|
-
* instance is ready to serve the stream (`instanceReady` WS message).
|
|
340
|
-
* Carries the stream-machine coordinates — `originInstanceUri` is used to
|
|
341
|
-
* open the second (stream-machine) signalling socket. Also consumed by
|
|
342
|
-
* telemetry as a phase marker.
|
|
343
|
-
*/
|
|
344
|
-
const instanceReady = createAction(scoped `instance ready`, props());
|
|
345
|
-
/**
|
|
346
|
-
* Dispatched when `RegionsPingService.getFastest()` begins — right
|
|
347
|
-
* before the region-list HTTP request goes out. Bookends the entire
|
|
348
|
-
* region-discovery flow together with {@link regionResolved}.
|
|
349
|
-
* Observability-only — no state change.
|
|
350
|
-
*/
|
|
351
|
-
const regionPingFetchStart = createAction(scoped `region ping fetch start`);
|
|
352
|
-
/**
|
|
353
|
-
* Dispatched once `RegionsPingService.getProviders()` returns the region
|
|
354
|
-
* list — i.e., the fetch step is done and the actual per-region ping
|
|
355
|
-
* sweep is about to start. Splits the region-discovery waterfall into
|
|
356
|
-
* two legs: config fetch vs. ping sweep. Observability-only.
|
|
357
|
-
*/
|
|
358
|
-
const regionPingFetchEnd = createAction(scoped `region ping fetch end`);
|
|
359
|
-
/**
|
|
360
|
-
* Dispatched once the closest region has been resolved by the
|
|
361
|
-
* regions-ping service. Carries every sampled ping RTT to the winning
|
|
362
|
-
* region (one entry per probe — `checkLatency` issues `ping_count`
|
|
363
|
-
* sequential pings per region) so consumers can inspect variance /
|
|
364
|
-
* jitter, not just the mean. Observability-only — no state change.
|
|
365
|
-
*/
|
|
366
|
-
const regionResolved = createAction(scoped `region resolved`, props());
|
|
367
|
-
/**
|
|
368
|
-
* Dispatched around the HTTP polling roundup inside `getAwsInstance`
|
|
369
|
-
* (old orchestration flow). Only fires when polling is actually used
|
|
370
|
-
* (i.e., signaling URL is not a direct `ws://` / `wss://` endpoint).
|
|
371
|
-
* Observability-only — no state change.
|
|
372
|
-
*/
|
|
373
|
-
const pollingStarted = createAction(scoped `polling started`);
|
|
374
|
-
const pollingEnded = createAction(scoped `polling ended`);
|
|
375
|
-
/**
|
|
376
|
-
* Dispatched once for every `retry()` attempt inside the signalling
|
|
377
|
-
* connect pipeline. Two kinds:
|
|
378
|
-
*
|
|
379
|
-
* - `'connect'` — outer retry around the whole connect pipeline
|
|
380
|
-
* (region ping → AWS instance → WebSocket). Fires when the WS
|
|
381
|
-
* errors (e.g. "WebSocket closed before open") and the entire
|
|
382
|
-
* pipeline is re-subscribed. See `SIGNALLING.md` — every one of
|
|
383
|
-
* these currently triggers a fresh region-ping storm.
|
|
384
|
-
* - `'orchestration'` — inner retry inside `getAwsInstance`,
|
|
385
|
-
* advancing `urlGen` to the next candidate signalling URL when
|
|
386
|
-
* polling fails or returns an error payload.
|
|
387
|
-
*
|
|
388
|
-
* Observability-only — no state change. Surfaces in the viewer's
|
|
389
|
-
* Anomalies table as `signaling_retry` rows so a session that
|
|
390
|
-
* needed N tries shows N entries with their reasons.
|
|
391
|
-
*/
|
|
392
|
-
const signalingRetryAttempted = createAction(scoped `signaling retry attempted`, props());
|
|
393
|
-
/**
|
|
394
|
-
* Dispatched when the client has just sent an SDP answer back to Cirrus
|
|
395
|
-
* after receiving the server-initiated offer. Observability-only.
|
|
396
|
-
*/
|
|
397
|
-
const answerSent = createAction(scoped `answer sent`);
|
|
398
|
-
const setOrchestrationMessage = createAction(scoped `set orchestration message`, props());
|
|
399
|
-
const setOrchestrationProgress = createAction(scoped `set orchestration progress`, props());
|
|
400
|
-
const setOrchestrationContext = createAction(scoped `set orchestration params`, props());
|
|
401
|
-
const updateCirrusInfo = createAction(scoped `set unrealInfo`, props());
|
|
402
|
-
const setLoopBackCommandIsCompleted = createAction(scoped `set loopBack command is completed`);
|
|
403
|
-
const setAfkTimerVisible = createAction(scoped `set afk timer visible`);
|
|
404
|
-
const setAfkTimerHide = createAction(scoped `set afk timer hide`);
|
|
405
|
-
const setAfkTimerCountdown = createAction(scoped `set afk timer count down`, props());
|
|
406
|
-
const showUnrealErrorMessage = createAction(scoped `show unreal error message`, props());
|
|
407
|
-
const initSignalling = createAction(scoped `init signalling`);
|
|
408
|
-
/**
|
|
409
|
-
* Dispatched when a prefetched connection parked on `window.__stream` by the
|
|
410
|
-
* `stream-prefetch.js` head-script is adopted instead of opening a fresh
|
|
411
|
-
* `connectToSignaling`. Marks cirrus connected and records the adopted machine
|
|
412
|
-
* in one transaction; the data channel / app-init chain then proceeds via
|
|
413
|
-
* `dataChannelConnected` dispatched from `WebRtcPlayerService`.
|
|
414
|
-
*
|
|
415
|
-
* Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
|
|
416
|
-
* app (e.g. metabox) sets those authoritatively from its own data before
|
|
417
|
-
* `initSignalling`, and the prefetch script's ids are connection-internal only.
|
|
418
|
-
*/
|
|
419
|
-
const streamAdopted = createAction(scoped `stream adopted`, props());
|
|
420
|
-
const startStream = createAction(scoped `startStream`, props());
|
|
421
|
-
const resetConfig = createAction(scoped `reset config`);
|
|
422
|
-
const resetAfk = createAction(scoped `reset afk action`);
|
|
423
|
-
const resetWarnTimeout = createAction(scoped `reset config warn timeout`);
|
|
424
|
-
/**
|
|
425
|
-
* Fan-in for "cancel an in-flight signalling attempt". Dispatched by the
|
|
426
|
-
* abortEstablishingConnection$ effect whenever any of these source actions
|
|
427
|
-
* fire: `setCirrusDisconnected` (cirrus dropped), `dropConnection` (user
|
|
428
|
-
* called drop), `destroyUnrealScene` (component teardown). Consumers
|
|
429
|
-
* (`SignallingService.abort$`, `setDataChannelTimeoutCheck$.abort$`) listen
|
|
430
|
-
* to this one action instead of the trio so the "abort" intent has a single
|
|
431
|
-
* named entry in Redux DevTools and one subscription site to update.
|
|
432
|
-
*/
|
|
433
|
-
const abortEstablishingConnection = createAction(scoped `abortEstablishingConnection`);
|
|
434
|
-
const setUnrealPlaywrightConfig = createAction(scoped `set unreal playwright config`);
|
|
435
|
-
const saveAnalyticsEvent = createAction(scoped `save analytics event`, props());
|
|
436
|
-
/** Action to trigger WebRTC peer reconnection (keeps signaling connection) */
|
|
437
|
-
const reconnectPeer = createAction(scoped `reconnect peer`, props());
|
|
438
|
-
/** Action to reset the data channel state before reconnection */
|
|
439
|
-
const resetDataChannelForReconnect = createAction(scoped `reset data channel for reconnect`);
|
|
440
|
-
/** Action dispatched when peer reconnection succeeds */
|
|
441
|
-
const reconnectPeerSuccess = createAction(scoped `reconnect peer success`);
|
|
442
|
-
/** Action dispatched when all peer reconnection attempts are exhausted */
|
|
443
|
-
const reconnectPeerFailed = createAction(scoped `reconnect peer failed`, props());
|
|
444
|
-
/** Action dispatched when ICE connection state changes to failed/disconnected */
|
|
445
|
-
const iceConnectionFailed = createAction(scoped `ice connection failed`, props());
|
|
446
|
-
const forceResizeViewport = createAction(scoped `force resize viewport`);
|
|
447
|
-
const videoAdaptedToContainer = createAction(scoped `video adapted to container`);
|
|
448
|
-
const videoStreamInitialized = createAction(scoped `video stream initialized`);
|
|
449
|
-
const dropDC = createAction(scoped `drop data channel`);
|
|
450
|
-
const dropPC = createAction(scoped `drop peer connection`);
|
|
451
|
-
const showLoadingProgress = createAction(scoped `show loading progress`, props());
|
|
452
|
-
const showResumeStreamPopup = createAction(scoped `show resume stream popup`, props());
|
|
453
|
-
const showUserInactivityTimeoutPopup = createAction(scoped `show user inactivity timeout popup`, props());
|
|
454
|
-
const setUserInactivityTimeout = createAction(scoped `set user inactivity timeout`, props());
|
|
455
|
-
const resetUserInactivityTimeout = createAction(scoped `reset user inactivity timeout`);
|
|
456
|
-
|
|
457
474
|
const COMMAND_EXILE_TIMEOUT_MS = 10_000;
|
|
458
475
|
function exileExpiredCommands(commandsInProgress, idToRemove, now) {
|
|
459
476
|
let remaining = commandsInProgress.filter(whereNot({ id: idToRemove }));
|
|
@@ -755,454 +772,35 @@ const unrealReducer = createReducer(initialState, on(changeStatusMainVideoOnScen
|
|
|
755
772
|
return {
|
|
756
773
|
...state,
|
|
757
774
|
cirrusConnected: true,
|
|
758
|
-
viewportReady: true,
|
|
759
|
-
dataChannelConnected: true,
|
|
760
|
-
isVideoPlaying: true,
|
|
761
|
-
};
|
|
762
|
-
}), on(destroyUnrealScene, () => {
|
|
763
|
-
// Pin `disconnectReason: Destroy` so any in-flight disconnectStream
|
|
764
|
-
// actions are ignored by the sticky-Destroy guard above.
|
|
765
|
-
return { ...initialState, disconnectReason: DisconnectReason.Destroy };
|
|
766
|
-
}), on(commandStarted, (state, { id, command, timeStamp }) => ({
|
|
767
|
-
...state,
|
|
768
|
-
totalCommandsStarted: state.totalCommandsStarted + 1,
|
|
769
|
-
commandsInProgress: [
|
|
770
|
-
...state.commandsInProgress,
|
|
771
|
-
{ id, command, timeStamp },
|
|
772
|
-
],
|
|
773
|
-
})), on(commandCompleted, (state, { id, now }) => {
|
|
774
|
-
const { commandsInProgress, exiled } = exileExpiredCommands(state.commandsInProgress, id, now);
|
|
775
|
-
return {
|
|
776
|
-
...state,
|
|
777
|
-
commandsInProgress,
|
|
778
|
-
// +1 for the just-completed command, +exiled for stragglers we GC'd.
|
|
779
|
-
totalCommandsCompleted: state.totalCommandsCompleted + 1 + exiled,
|
|
780
|
-
};
|
|
781
|
-
}));
|
|
782
|
-
|
|
783
|
-
const unrealFeature = createFeature({
|
|
784
|
-
name: 'unrealFeature',
|
|
785
|
-
reducer: unrealReducer,
|
|
786
|
-
});
|
|
787
|
-
|
|
788
|
-
class SubService {
|
|
789
|
-
constructor() {
|
|
790
|
-
this.destroyRef = inject(DestroyRef);
|
|
791
|
-
this.destroy$ = new Subject();
|
|
792
|
-
this.actions$ = inject(Actions);
|
|
793
|
-
this.store = inject(Store);
|
|
794
|
-
this.disconnect$ = this.store
|
|
795
|
-
.select(unrealFeature.selectCirrusConnected)
|
|
796
|
-
.pipe(skip(1), filter(Falsy), share());
|
|
797
|
-
this.destroyRef.onDestroy(() => {
|
|
798
|
-
this.destroy$.next();
|
|
799
|
-
this.destroy$.complete();
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
function AnswerHandler(msg) {
|
|
805
|
-
this.onWebRtcAnswer$.next(msg);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
function ConfigHandler(msg) {
|
|
809
|
-
this.onConfig$.next(msg);
|
|
810
|
-
//DO NOT REMOVE. Possible required in future for SFU
|
|
811
|
-
/*this.send({
|
|
812
|
-
type: OrchestrationMessageTypes.listStreamers,
|
|
813
|
-
correlationId: this.correlationId,
|
|
814
|
-
});*/
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
function IceCandidateHandler(msg) {
|
|
818
|
-
this.onWebRtcIce$.next(msg.candidate);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function InstanceReadyHandler(msg) {
|
|
822
|
-
const payload = msg?.payload;
|
|
823
|
-
if (!payload) {
|
|
824
|
-
Logger.warn('instanceReady received without payload — ignoring');
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
if (!payload.originInstanceUri) {
|
|
828
|
-
Logger.warn('instanceReady without originInstanceUri — ignoring');
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
// Emit for observability (telemetry) and store the stream-machine coords.
|
|
832
|
-
this.store.dispatch(instanceReady(payload));
|
|
833
|
-
// This is the answer `requestCirrusViaSocket` is waiting for: the Cirrus
|
|
834
|
-
// address (`originInstanceUri`) plus the connection id to hand it. The socket
|
|
835
|
-
// itself is opened by the shared `connectToCirrus`, not here.
|
|
836
|
-
this.onInstanceReady$.next(payload);
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
function InstanceReservedHandler(msg) {
|
|
840
|
-
this.store.dispatch(setOrchestrationParameters({
|
|
841
|
-
instanceName: msg.payload.instanceId,
|
|
842
|
-
streamRequestId: msg.payload.streamRequestId,
|
|
843
|
-
eta: msg.payload.eta ?? 150,
|
|
844
|
-
}));
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function PlayerCountHandler(msg) {
|
|
848
|
-
Logger.log(msg);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
function SSInfoHandler(msg) {
|
|
852
|
-
this.store.dispatch(updateCirrusInfo({ ssData: msg.data }));
|
|
853
|
-
return null;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
const dropCodes = [
|
|
857
|
-
WSCloseCode_UNKNOWN,
|
|
858
|
-
WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
|
|
859
|
-
WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
|
|
860
|
-
WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
|
|
861
|
-
WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
|
|
862
|
-
];
|
|
863
|
-
function OnCloseHandler(e) {
|
|
864
|
-
const message = `WebSocket closed: ${JSON.stringify(e.code)} - ${e.reason}`;
|
|
865
|
-
Logger.warn(message);
|
|
866
|
-
this.store.dispatch(setCirrusDisconnected());
|
|
867
|
-
if (dropCodes.includes(e.code)) {
|
|
868
|
-
this.store.dispatch(dropConnection());
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
function OnErrorHandler(e) {
|
|
873
|
-
Logger.warn(`WS error: ${JSON.stringify(e)}`);
|
|
874
|
-
this.store.dispatch(disconnectStream({
|
|
875
|
-
reason: DisconnectReason.WebSocketError,
|
|
876
|
-
message: 'WebSocket Error',
|
|
877
|
-
}));
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
function OnMessageHandler(e) {
|
|
881
|
-
const handleData = (data) => {
|
|
882
|
-
//Logger.colored(...COLOR_CODES.FROM_SIGNALING, data);
|
|
883
|
-
const msg = JSON.parse(data);
|
|
884
|
-
this.handleMessage(msg);
|
|
885
|
-
};
|
|
886
|
-
if (typeof e.data === 'string') {
|
|
887
|
-
try {
|
|
888
|
-
handleData(e.data);
|
|
889
|
-
}
|
|
890
|
-
catch (err) {
|
|
891
|
-
Logger.warn('OnMessageHandler: failed to parse string message', err);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
else if (e.data instanceof Blob) {
|
|
895
|
-
e.data
|
|
896
|
-
.text()
|
|
897
|
-
.then(handleData)
|
|
898
|
-
.catch((err) => Logger.warn('OnMessageHandler: failed to parse Blob message', err));
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* Open handler of the CIRRUS socket only (`addWsHandlers`), so
|
|
904
|
-
* `setCirrusConnected` now means what it says. It used to also send
|
|
905
|
-
* `requestStream` here, which made the flag fire on the orchestration control
|
|
906
|
-
* socket — a whole provisioning wait (`eta`, ~150 s) before any Cirrus existed.
|
|
907
|
-
* `requestStream` belongs to the control socket and is sent by
|
|
908
|
-
* `requestCirrusViaSocket`.
|
|
909
|
-
*/
|
|
910
|
-
function OnOpenHandler() {
|
|
911
|
-
this.store.dispatch(setCirrusConnected());
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/**
|
|
915
|
-
* Keeps the max of numbers seen so far; resets to 0 whenever `reset$` emits.
|
|
916
|
-
*/
|
|
917
|
-
const keepMaxUntilReset = (reset$) => (source$) => merge(source$, reset$.pipe(map(() => null))).pipe(scan((max, value) => (value === null ? 0 : Math.max(max, value)), 0));
|
|
918
|
-
|
|
919
|
-
// Reused across every inbound data-channel message — instantiating a
|
|
920
|
-
// TextDecoder per call adds needless GC churn on a hot path.
|
|
921
|
-
const utf16Decoder = new TextDecoder('utf-16');
|
|
922
|
-
function decodeData(anyData) {
|
|
923
|
-
try {
|
|
924
|
-
return utf16Decoder.decode(anyData);
|
|
925
|
-
}
|
|
926
|
-
catch {
|
|
927
|
-
return '';
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
const dispatchResize = () => {
|
|
932
|
-
window.dispatchEvent(new Event('resize'));
|
|
933
|
-
};
|
|
934
|
-
|
|
935
|
-
const errorCodes = {
|
|
936
|
-
code404: 'Your asset is being synced on Metabox servers and is not yet available in Metabox Studio or Metabox Configurator. Please check again later after syncing is complete. ',
|
|
937
|
-
};
|
|
938
|
-
function getRtcErrorMessage(code) {
|
|
939
|
-
if (code === null) {
|
|
940
|
-
return undefined;
|
|
941
|
-
}
|
|
942
|
-
return errorCodes[`code${code}`];
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
const JUMP_THRESHOLD = 0.95;
|
|
946
|
-
const MAX_TRANSITION_DURATION_MS = 200;
|
|
947
|
-
/**
|
|
948
|
-
* Maps a 0..1 stream directly to a 0..100 integer percent stream.
|
|
949
|
-
* No animation — emits whatever the source emits, rounded and clamped.
|
|
950
|
-
*/
|
|
951
|
-
const floatToPercents = () => (source) => source.pipe(map$1((value) => clampf(0, 100, Math.round(value * 100))));
|
|
952
|
-
/**
|
|
953
|
-
* Maps a 0..1 progress stream to a smoothed 0..100 integer percent stream.
|
|
954
|
-
* Animates between consecutive values over up to 200ms; jumps directly when
|
|
955
|
-
* the delta exceeds 0.95 (treated as a reset, not a real progression).
|
|
956
|
-
*/
|
|
957
|
-
const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWith({ value: 0, timestamp: 0 }), pairwise(), concatMap(([prev, curr]) => {
|
|
958
|
-
const isJump = Math.abs(curr.value - prev.value) > JUMP_THRESHOLD;
|
|
959
|
-
const dt = prev.timestamp ? curr.timestamp - prev.timestamp : 0;
|
|
960
|
-
if (isJump || dt === 0) {
|
|
961
|
-
return of(curr.value);
|
|
962
|
-
}
|
|
963
|
-
return smoothTransition(prev.value, curr.value, Math.min(dt, MAX_TRANSITION_DURATION_MS));
|
|
964
|
-
}), floatToPercents());
|
|
965
|
-
/**
|
|
966
|
-
* Smoothly interpolates from `start` to `end` over `duration`ms using the
|
|
967
|
-
* animation frame scheduler. Completes when the transition finishes.
|
|
968
|
-
*
|
|
969
|
-
* NOTE: duplicates `smoothTransition` from `@3dsource/utils`. The utils version
|
|
970
|
-
* is missing `takeWhile(... < 1, true)` and never completes — which would
|
|
971
|
-
* deadlock the `concatMap` above. Keep this local copy until utils is fixed.
|
|
972
|
-
* Not exported: internal to `floatToSmoothPercents`.
|
|
973
|
-
*/
|
|
974
|
-
const smoothTransition = (start, end, duration) => {
|
|
975
|
-
const startTime = animationFrameScheduler.now();
|
|
976
|
-
return interval(0, animationFrameScheduler).pipe(map$1(() => clampf(0, 1, (animationFrameScheduler.now() - startTime) / duration)), distinctUntilChanged(), takeWhile((fraction) => fraction < 1, true), map$1((fraction) => lerp(start, end, fraction)));
|
|
977
|
-
};
|
|
978
|
-
|
|
979
|
-
const getImageFromVideoStream = (takeSizeFrom = 'video', imageOutput, sizes) => {
|
|
980
|
-
try {
|
|
981
|
-
const video = document.getElementById(STREAMING_VIDEO_ID);
|
|
982
|
-
const { canvas, ctx } = getCanvasCached('video');
|
|
983
|
-
canvas.width =
|
|
984
|
-
takeSizeFrom === 'video'
|
|
985
|
-
? sizes?.width || video?.clientWidth || FULL_HD_WIDTH
|
|
986
|
-
: FULL_HD_WIDTH;
|
|
987
|
-
canvas.height =
|
|
988
|
-
takeSizeFrom === 'video'
|
|
989
|
-
? sizes?.height || video?.clientHeight || FULL_HD_HEIGHT
|
|
990
|
-
: FULL_HD_HEIGHT;
|
|
991
|
-
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
992
|
-
return getSnapshot(canvas, canvas.width, imageOutput);
|
|
993
|
-
}
|
|
994
|
-
catch {
|
|
995
|
-
return null;
|
|
996
|
-
}
|
|
997
|
-
};
|
|
998
|
-
|
|
999
|
-
/**
|
|
1000
|
-
* Generator that cycles through `urls` indefinitely. Each call to
|
|
1001
|
-
* `getActiveUrl(urls)` returns a fresh generator with its own counter,
|
|
1002
|
-
* so concurrent generators (e.g., overlapping reconnect attempts) do
|
|
1003
|
-
* not share state. The counter is initialized once per generator
|
|
1004
|
-
* instance — before any `yield` — so each `.next()` call advances
|
|
1005
|
-
* within that single generator.
|
|
1006
|
-
*/
|
|
1007
|
-
function* getActiveUrl(urls) {
|
|
1008
|
-
let index = 0;
|
|
1009
|
-
while (true) {
|
|
1010
|
-
yield urls[index++ % urls.length];
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
class LatencyTimings {
|
|
1015
|
-
constructor() {
|
|
1016
|
-
this.TestStartTimeMs = null;
|
|
1017
|
-
this.UEReceiptTimeMs = null;
|
|
1018
|
-
this.UEEncodeMs = null;
|
|
1019
|
-
this.UECaptureToSendMs = null;
|
|
1020
|
-
this.UETransmissionTimeMs = null;
|
|
1021
|
-
this.BrowserReceiptTimeMs = null;
|
|
1022
|
-
this.FrameDisplayDeltaTimeMs = null;
|
|
1023
|
-
}
|
|
1024
|
-
Reset() {
|
|
1025
|
-
this.TestStartTimeMs = null;
|
|
1026
|
-
this.UEReceiptTimeMs = null;
|
|
1027
|
-
this.UEEncodeMs = null;
|
|
1028
|
-
this.UECaptureToSendMs = null;
|
|
1029
|
-
this.UETransmissionTimeMs = null;
|
|
1030
|
-
this.BrowserReceiptTimeMs = null;
|
|
1031
|
-
this.FrameDisplayDeltaTimeMs = null;
|
|
1032
|
-
}
|
|
1033
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1034
|
-
SetUETimings(UETimings) {
|
|
1035
|
-
this.UEReceiptTimeMs = UETimings.ReceiptTimeMs;
|
|
1036
|
-
this.UEEncodeMs = UETimings.EncodeMs;
|
|
1037
|
-
this.UECaptureToSendMs = UETimings.CaptureToSendMs;
|
|
1038
|
-
this.UETransmissionTimeMs = UETimings.TransmissionTimeMs;
|
|
1039
|
-
this.BrowserReceiptTimeMs = Date.now();
|
|
1040
|
-
}
|
|
1041
|
-
SetFrameDisplayDeltaTime(DeltaTimeMs) {
|
|
1042
|
-
if (this.FrameDisplayDeltaTimeMs == null) {
|
|
1043
|
-
this.FrameDisplayDeltaTimeMs = Math.round(DeltaTimeMs);
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
function qpToQuality(VideoEncoderQP) {
|
|
1049
|
-
const orangeQP = 26;
|
|
1050
|
-
const redQP = 35;
|
|
1051
|
-
let quality = 'lime';
|
|
1052
|
-
if (VideoEncoderQP > redQP) {
|
|
1053
|
-
quality = 'red';
|
|
1054
|
-
}
|
|
1055
|
-
else if (VideoEncoderQP > orangeQP) {
|
|
1056
|
-
quality = 'orange';
|
|
1057
|
-
}
|
|
1058
|
-
return quality;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
/**
|
|
1062
|
-
* Base64-encodes a byte array.
|
|
1063
|
-
*
|
|
1064
|
-
* Builds the intermediate binary string in fixed-size chunks instead of
|
|
1065
|
-
* concatenating one character at a time. The naive `bytes.reduce((s, b) => s +
|
|
1066
|
-
* String.fromCharCode(b), '')` is O(n²) (each `+` re-copies the growing string)
|
|
1067
|
-
* and stalls the main thread for a full-resolution frame; chunking keeps it
|
|
1068
|
-
* O(n). The chunk size stays under the argument-count limit of
|
|
1069
|
-
* `String.fromCharCode.apply`/spread.
|
|
1070
|
-
*
|
|
1071
|
-
* @param bytes - The raw bytes to encode.
|
|
1072
|
-
* @returns The Base64 representation of `bytes`.
|
|
1073
|
-
*/
|
|
1074
|
-
function uint8ToBase64(bytes) {
|
|
1075
|
-
const CHUNK_SIZE = 0x8000;
|
|
1076
|
-
let binary = '';
|
|
1077
|
-
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
1078
|
-
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
|
|
1079
|
-
}
|
|
1080
|
-
return btoa(binary);
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
function fromResizeObserver(elem) {
|
|
1084
|
-
return new Observable((subscriber) => {
|
|
1085
|
-
const observer = new window.ResizeObserver((entries) => subscriber.next(entries));
|
|
1086
|
-
observer.observe(elem);
|
|
1087
|
-
return () => observer.unobserve(elem);
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
/*
|
|
1092
|
-
* Copyright (c) 2026.
|
|
1093
|
-
* 3DSource.com. Sergii Karanda steve@3dsource.com. All Rights Reserved.
|
|
1094
|
-
*/
|
|
1095
|
-
/**
|
|
1096
|
-
* Rounds a number to the nearest even integer (rounding up for odd values).
|
|
1097
|
-
*
|
|
1098
|
-
* Video encoders (H.264/H.265) require even dimensions because chroma subsampling
|
|
1099
|
-
* operates on 2×2 pixel blocks. Odd dimensions cause encoding artifacts or failures.
|
|
1100
|
-
*
|
|
1101
|
-
* @param value - The number to round to the nearest even integer.
|
|
1102
|
-
* @returns The nearest even integer greater than or equal to the input.
|
|
1103
|
-
*
|
|
1104
|
-
* @example
|
|
1105
|
-
* makeEven(1079) // 1080
|
|
1106
|
-
* makeEven(1080) // 1080
|
|
1107
|
-
* makeEven(1081) // 1082
|
|
1108
|
-
*/
|
|
1109
|
-
function makeEven(value) {
|
|
1110
|
-
return Math.floor((value + 1) / 2) * 2;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
const FULL_HD_PIXELS = FULL_HD_WIDTH * FULL_HD_HEIGHT;
|
|
1114
|
-
const UHD_PIXELS = FULL_HD_WIDTH * 2 * (FULL_HD_HEIGHT * 2);
|
|
1115
|
-
/**
|
|
1116
|
-
* Calculates the optimal stream resolution for studio mode.
|
|
1117
|
-
*
|
|
1118
|
-
* Fits the studio aspect ratio into the container (scaled by pixelRatio), then
|
|
1119
|
-
* caps the total pixel count to a budget (Full HD or 4K) to avoid overloading
|
|
1120
|
-
* the GPU/encoder while maximizing visual quality.
|
|
1121
|
-
*
|
|
1122
|
-
* The pixel budget approach (instead of per-dimension caps) ensures that
|
|
1123
|
-
* non-standard aspect ratios (portrait, ultra-wide, square) utilize available
|
|
1124
|
-
* pixels efficiently — e.g. a tall 1080×1920 stream uses the same pixel budget
|
|
1125
|
-
* as a wide 1920×1080 stream.
|
|
1126
|
-
*
|
|
1127
|
-
* Resolution is always capped at the studio dimensions — never upscaled beyond
|
|
1128
|
-
* what the Unreal scene was designed for.
|
|
1129
|
-
*
|
|
1130
|
-
* @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
|
|
1131
|
-
* @param params.containerWidth - CSS width of the video container in pixels.
|
|
1132
|
-
* @param params.containerHeight - CSS height of the video container in pixels.
|
|
1133
|
-
* @param params.studioWidth - Target width of the MetaBox Studio scene.
|
|
1134
|
-
* @param params.studioHeight - Target height of the MetaBox Studio scene.
|
|
1135
|
-
* @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
|
|
1136
|
-
* otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
|
|
1137
|
-
* @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
|
|
1138
|
-
* and `scale` factor relative to the container's device-pixel size.
|
|
1139
|
-
*/
|
|
1140
|
-
function getResizeStudioValues(params) {
|
|
1141
|
-
const { pixelRatio, containerWidth, containerHeight, studioWidth, studioHeight, maxResolution, } = params;
|
|
1142
|
-
const maxSpace = {
|
|
1143
|
-
w: containerWidth * pixelRatio,
|
|
1144
|
-
h: containerHeight * pixelRatio,
|
|
1145
|
-
};
|
|
1146
|
-
const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
|
|
1147
|
-
const videoSizePixelPerfect = fitIntoRectangle({ x: 0, y: 0, w: studioWidth, h: studioHeight }, { x: 0, y: 0, ...maxSpace });
|
|
1148
|
-
let w = videoSizePixelPerfect.w;
|
|
1149
|
-
let h = videoSizePixelPerfect.h;
|
|
1150
|
-
if (w * h > maxPixels) {
|
|
1151
|
-
// Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
|
|
1152
|
-
// → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
|
|
1153
|
-
// Applying the same `s` to both dimensions preserves the aspect ratio.
|
|
1154
|
-
const scaleFactor = Math.sqrt(maxPixels / (w * h));
|
|
1155
|
-
w = w * scaleFactor;
|
|
1156
|
-
h = h * scaleFactor;
|
|
1157
|
-
}
|
|
1158
|
-
const out = fitIntoRectangle(videoSizePixelPerfect, {
|
|
1159
|
-
x: videoSizePixelPerfect.x,
|
|
1160
|
-
y: videoSizePixelPerfect.y,
|
|
1161
|
-
w,
|
|
1162
|
-
h,
|
|
1163
|
-
});
|
|
1164
|
-
out.w = makeEven(out.w);
|
|
1165
|
-
out.h = makeEven(out.h);
|
|
1166
|
-
return out;
|
|
1167
|
-
}
|
|
1168
|
-
/**
|
|
1169
|
-
* Calculates the optimal stream resolution for configurator (non-studio) mode.
|
|
1170
|
-
*
|
|
1171
|
-
* Uses the full container area (scaled by pixelRatio) as the stream resolution,
|
|
1172
|
-
* then caps total pixel count to a budget (Full HD or 4K) to prevent excessive
|
|
1173
|
-
* GPU/encoder load while preserving the container's aspect ratio.
|
|
1174
|
-
*
|
|
1175
|
-
* Unlike {@link getResizeStudioValues}, there is no fixed studio resolution to
|
|
1176
|
-
* fit into — the container itself defines the aspect ratio, and the stream fills
|
|
1177
|
-
* it entirely (no letterboxing).
|
|
1178
|
-
*
|
|
1179
|
-
* @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
|
|
1180
|
-
* @param params.containerWidth - CSS width of the video container in pixels.
|
|
1181
|
-
* @param params.containerHeight - CSS height of the video container in pixels.
|
|
1182
|
-
* @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
|
|
1183
|
-
* otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
|
|
1184
|
-
* @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
|
|
1185
|
-
* and `scale` factor (1 when no downscale needed, <1 when capped).
|
|
1186
|
-
*/
|
|
1187
|
-
function getResizeValuesUniversal(params) {
|
|
1188
|
-
const { pixelRatio, containerWidth, containerHeight, maxResolution } = params;
|
|
1189
|
-
const maxSpace = {
|
|
1190
|
-
w: containerWidth * pixelRatio,
|
|
1191
|
-
h: containerHeight * pixelRatio,
|
|
775
|
+
viewportReady: true,
|
|
776
|
+
dataChannelConnected: true,
|
|
777
|
+
isVideoPlaying: true,
|
|
1192
778
|
};
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
779
|
+
}), on(destroyUnrealScene, () => {
|
|
780
|
+
// Pin `disconnectReason: Destroy` so any in-flight disconnectStream
|
|
781
|
+
// actions are ignored by the sticky-Destroy guard above.
|
|
782
|
+
return { ...initialState, disconnectReason: DisconnectReason.Destroy };
|
|
783
|
+
}), on(commandStarted, (state, { id, command, timeStamp }) => ({
|
|
784
|
+
...state,
|
|
785
|
+
totalCommandsStarted: state.totalCommandsStarted + 1,
|
|
786
|
+
commandsInProgress: [
|
|
787
|
+
...state.commandsInProgress,
|
|
788
|
+
{ id, command, timeStamp },
|
|
789
|
+
],
|
|
790
|
+
})), on(commandCompleted, (state, { id, now }) => {
|
|
791
|
+
const { commandsInProgress, exiled } = exileExpiredCommands(state.commandsInProgress, id, now);
|
|
792
|
+
return {
|
|
793
|
+
...state,
|
|
794
|
+
commandsInProgress,
|
|
795
|
+
// +1 for the just-completed command, +exiled for stragglers we GC'd.
|
|
796
|
+
totalCommandsCompleted: state.totalCommandsCompleted + 1 + exiled,
|
|
797
|
+
};
|
|
798
|
+
}));
|
|
799
|
+
|
|
800
|
+
const unrealFeature = createFeature({
|
|
801
|
+
name: 'unrealFeature',
|
|
802
|
+
reducer: unrealReducer,
|
|
803
|
+
});
|
|
1206
804
|
|
|
1207
805
|
/**
|
|
1208
806
|
* `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
|
|
@@ -1332,14 +930,30 @@ class WebrtcErrorModalComponent {
|
|
|
1332
930
|
close() {
|
|
1333
931
|
this.#dialogRef.close();
|
|
1334
932
|
}
|
|
1335
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1336
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.
|
|
933
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
934
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1337
935
|
}
|
|
1338
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
936
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
|
|
1339
937
|
type: Component,
|
|
1340
|
-
args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\
|
|
938
|
+
args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"] }]
|
|
1341
939
|
}] });
|
|
1342
940
|
|
|
941
|
+
class SubService {
|
|
942
|
+
constructor() {
|
|
943
|
+
this.destroyRef = inject(DestroyRef);
|
|
944
|
+
this.destroy$ = new Subject();
|
|
945
|
+
this.actions$ = inject(Actions);
|
|
946
|
+
this.store = inject(Store);
|
|
947
|
+
this.disconnect$ = this.store
|
|
948
|
+
.select(unrealFeature.selectCirrusConnected)
|
|
949
|
+
.pipe(skip(1), filter(Falsy), share());
|
|
950
|
+
this.destroyRef.onDestroy(() => {
|
|
951
|
+
this.destroy$.next();
|
|
952
|
+
this.destroy$.complete();
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
1343
957
|
class CommandTelemetryService extends SubService {
|
|
1344
958
|
constructor() {
|
|
1345
959
|
super();
|
|
@@ -1542,10 +1156,10 @@ class CommandTelemetryService extends SubService {
|
|
|
1542
1156
|
this.trackTime(out);
|
|
1543
1157
|
funcToDecorate(out);
|
|
1544
1158
|
}
|
|
1545
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1546
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
1159
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1160
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, providedIn: 'root' }); }
|
|
1547
1161
|
}
|
|
1548
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, decorators: [{
|
|
1549
1163
|
type: Injectable,
|
|
1550
1164
|
args: [{ providedIn: 'root' }]
|
|
1551
1165
|
}], ctorParameters: () => [] });
|
|
@@ -1566,10 +1180,10 @@ class DevModeService {
|
|
|
1566
1180
|
localStorage.removeItem('devMode');
|
|
1567
1181
|
}
|
|
1568
1182
|
}
|
|
1569
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1570
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
1183
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1184
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
|
|
1571
1185
|
}
|
|
1572
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1186
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, decorators: [{
|
|
1573
1187
|
type: Injectable,
|
|
1574
1188
|
args: [{
|
|
1575
1189
|
providedIn: 'root',
|
|
@@ -1615,7 +1229,7 @@ class RegionsPingService {
|
|
|
1615
1229
|
return of(cached).pipe(tap(() => this.store.dispatch(regionPingFetchEnd())), tap((data) => this.store.dispatch(regionResolved({
|
|
1616
1230
|
region: data.region_code,
|
|
1617
1231
|
pingsMs: data.result,
|
|
1618
|
-
}))), map
|
|
1232
|
+
}))), map((data) => data.region_code));
|
|
1619
1233
|
}
|
|
1620
1234
|
// No regions URL and no cache: there is nothing to ping. Bail out loudly
|
|
1621
1235
|
// instead of letting `HttpClient.get('')` request the current document
|
|
@@ -1638,7 +1252,7 @@ class RegionsPingService {
|
|
|
1638
1252
|
}), tap((data) => this.store.dispatch(regionResolved({
|
|
1639
1253
|
region: data?.region_code ?? '',
|
|
1640
1254
|
pingsMs: data?.result ?? [],
|
|
1641
|
-
}))), map
|
|
1255
|
+
}))), map((data) => data?.region_code));
|
|
1642
1256
|
});
|
|
1643
1257
|
}
|
|
1644
1258
|
/**
|
|
@@ -1888,10 +1502,10 @@ class RegionsPingService {
|
|
|
1888
1502
|
}
|
|
1889
1503
|
}
|
|
1890
1504
|
}
|
|
1891
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1892
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
1505
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1506
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, providedIn: 'root' }); }
|
|
1893
1507
|
}
|
|
1894
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1508
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, decorators: [{
|
|
1895
1509
|
type: Injectable,
|
|
1896
1510
|
args: [{ providedIn: 'root' }]
|
|
1897
1511
|
}], ctorParameters: () => [] });
|
|
@@ -2228,7 +1842,7 @@ class SignallingService extends SubService {
|
|
|
2228
1842
|
// itself at `INNER_RETRY_LIMIT`; only its exhaustion reaches the outer retry,
|
|
2229
1843
|
// which re-picks the region (rare, real "region down"). Outer delay > inner,
|
|
2230
1844
|
// so escalation is bounded and region discovery runs once per outer cycle.
|
|
2231
|
-
const connectCycle$ = this.getRegion().pipe(tap((region) => this.region.set(region ?? '')), map
|
|
1845
|
+
const connectCycle$ = this.getRegion().pipe(tap((region) => this.region.set(region ?? '')), map((region) => this.adaptUrlsToRegion(urlList, region)), switchMap((urls) => this.connectAttempt(urls)), takeUntil(this.abort$));
|
|
2232
1846
|
return connectCycle$.pipe(retry({
|
|
2233
1847
|
delay: (err, attempt) => {
|
|
2234
1848
|
this.store.dispatch(signalingRetryAttempted({
|
|
@@ -2353,7 +1967,7 @@ class SignallingService extends SubService {
|
|
|
2353
1967
|
* `kind`: nothing was requested.
|
|
2354
1968
|
*/
|
|
2355
1969
|
requestCirrusDirect(url) {
|
|
2356
|
-
return this.waitForClientAndViewIds().pipe(map
|
|
1970
|
+
return this.waitForClientAndViewIds().pipe(map(() => ({
|
|
2357
1971
|
wsUrl: url,
|
|
2358
1972
|
pollingUrl: null,
|
|
2359
1973
|
instanceName: 'Direct Connection',
|
|
@@ -2375,7 +1989,7 @@ class SignallingService extends SubService {
|
|
|
2375
1989
|
}
|
|
2376
1990
|
}), filter(({ clientId, viewId }) => !!clientId && !!viewId), take(1), switchMap(({ clientId, viewId }) => this.pollLoop(`${url}${clientId}/${viewId}`).pipe(tap((data) => {
|
|
2377
1991
|
lastResp = data;
|
|
2378
|
-
}))), map
|
|
1992
|
+
}))), map((data) => ({
|
|
2379
1993
|
wsUrl: httpUrlToWs(`${location.protocol}//${data.signallingServer}`),
|
|
2380
1994
|
pollingUrl: url,
|
|
2381
1995
|
instanceName: data.signallingServer ?? '',
|
|
@@ -2431,7 +2045,7 @@ class SignallingService extends SubService {
|
|
|
2431
2045
|
this.controlWs = control;
|
|
2432
2046
|
Logger.log('ORCHESTRATION CONTROL WS OPEN');
|
|
2433
2047
|
this.sendRequestStream();
|
|
2434
|
-
return merge(this.onInstanceReady$.pipe(map
|
|
2048
|
+
return merge(this.onInstanceReady$.pipe(map((payload) => ({
|
|
2435
2049
|
wsUrl: payload.originInstanceUri,
|
|
2436
2050
|
// The endpoint that answered — the orchestration URL here, the HTTP
|
|
2437
2051
|
// polling URL in the other flow. Shown as `Orchestration:` in the overlay.
|
|
@@ -2723,10 +2337,10 @@ class SignallingService extends SubService {
|
|
|
2723
2337
|
Logger.log('Start Getting Region');
|
|
2724
2338
|
return this.regionsPingService.getFastest().pipe(take(1));
|
|
2725
2339
|
}
|
|
2726
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
2727
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
2340
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2341
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, providedIn: 'root' }); }
|
|
2728
2342
|
}
|
|
2729
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2343
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, decorators: [{
|
|
2730
2344
|
type: Injectable,
|
|
2731
2345
|
args: [{ providedIn: 'root' }]
|
|
2732
2346
|
}], ctorParameters: () => [] });
|
|
@@ -2754,7 +2368,7 @@ class VideoService extends SubService {
|
|
|
2754
2368
|
this.videoStats$ = this.videoTrack$.pipe(
|
|
2755
2369
|
// If videoTrack$ emits null, switch to EMPTY → the current interval is canceled.
|
|
2756
2370
|
switchMap$1((track) => track
|
|
2757
|
-
? interval(250).pipe(map(() => track.pcClient), switchMap$1((pcClient) => from(this.getStats(pcClient))), filter(Truthy))
|
|
2371
|
+
? interval(250).pipe(map$1(() => track.pcClient), switchMap$1((pcClient) => from(this.getStats(pcClient))), filter(Truthy))
|
|
2758
2372
|
: of(null)), filter(Truthy), share());
|
|
2759
2373
|
this.destroyAbort = new AbortController();
|
|
2760
2374
|
// Teardown is wired ONCE here instead of per `create()`. The per-create
|
|
@@ -3141,10 +2755,10 @@ class VideoService extends SubService {
|
|
|
3141
2755
|
this.armGestureRetry(audio);
|
|
3142
2756
|
}
|
|
3143
2757
|
}
|
|
3144
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3145
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
2758
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2759
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, providedIn: 'root' }); }
|
|
3146
2760
|
}
|
|
3147
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2761
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, decorators: [{
|
|
3148
2762
|
type: Injectable,
|
|
3149
2763
|
args: [{ providedIn: 'root' }]
|
|
3150
2764
|
}], ctorParameters: () => [] });
|
|
@@ -3600,25 +3214,25 @@ class WebRtcPlayerService extends SubService {
|
|
|
3600
3214
|
}
|
|
3601
3215
|
handlePeerConnectionEvents(pcClient) {
|
|
3602
3216
|
fromEvent(pcClient, 'signalingstatechange')
|
|
3603
|
-
.pipe(map
|
|
3217
|
+
.pipe(map(() => this.pcClient?.signalingState), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3604
3218
|
.subscribe((state) => {
|
|
3605
3219
|
Logger.info('[Signaling state change] |', state, '|');
|
|
3606
3220
|
this.commandTelemetryService.trackStopCommand('EXT-Signaling state change', true, { state, multi: true });
|
|
3607
3221
|
});
|
|
3608
3222
|
fromEvent(pcClient, 'iceconnectionstatechange')
|
|
3609
|
-
.pipe(map
|
|
3223
|
+
.pipe(map(() => this.pcClient?.iceConnectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3610
3224
|
.subscribe((state) => {
|
|
3611
3225
|
Logger.info('[Browser ICE connection] |', state, '|');
|
|
3612
3226
|
this.commandTelemetryService.trackStopCommand('EXT-Browser ICE connection', true, { state, multi: true });
|
|
3613
3227
|
});
|
|
3614
3228
|
fromEvent(pcClient, 'icegatheringstatechange')
|
|
3615
|
-
.pipe(map
|
|
3229
|
+
.pipe(map(() => this.pcClient?.iceGatheringState), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3616
3230
|
.subscribe((state) => {
|
|
3617
3231
|
Logger.info('[Browser ICE gathering] |', state, '|');
|
|
3618
3232
|
this.commandTelemetryService.trackStopCommand('EXT-Browser ICE gathering', true, { state, multi: true });
|
|
3619
3233
|
});
|
|
3620
3234
|
fromEvent(pcClient, 'connectionstatechange')
|
|
3621
|
-
.pipe(map
|
|
3235
|
+
.pipe(map(() => this.pcClient?.connectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3622
3236
|
.subscribe((state) => {
|
|
3623
3237
|
Logger.info('[RTCPeerConnection state] |', state, '|');
|
|
3624
3238
|
// A genuine ICE failure (not a manual dropDC/dropPC, which recover via
|
|
@@ -3635,7 +3249,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3635
3249
|
}
|
|
3636
3250
|
});
|
|
3637
3251
|
fromEvent(pcClient, 'icecandidate')
|
|
3638
|
-
.pipe(map
|
|
3252
|
+
.pipe(map((e) => e.candidate), filter(Truthy), tap$1((candidate) => Logger.info('[Browser ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|')), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3639
3253
|
.subscribe((candidate) => this.signallingSrv.send({
|
|
3640
3254
|
type: 'iceCandidate',
|
|
3641
3255
|
candidate,
|
|
@@ -3643,7 +3257,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3643
3257
|
// When the server creates the DataChannel (server-offer flow),
|
|
3644
3258
|
// we receive it here via the 'datachannel' event
|
|
3645
3259
|
fromEvent(pcClient, 'datachannel')
|
|
3646
|
-
.pipe(tap$1((e) => Logger.info(`[DATACHANNEL] Received remote DC: label="${e.channel.label}" id=${e.channel.id} protocol="${e.channel.protocol}" ordered=${e.channel.ordered}`)), map
|
|
3260
|
+
.pipe(tap$1((e) => Logger.info(`[DATACHANNEL] Received remote DC: label="${e.channel.label}" id=${e.channel.id} protocol="${e.channel.protocol}" ordered=${e.channel.ordered}`)), map((e) => e.channel), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3647
3261
|
.subscribe((datachannel) => {
|
|
3648
3262
|
this.dcClient = this.setupDataChannelCallbacks(datachannel);
|
|
3649
3263
|
});
|
|
@@ -3654,10 +3268,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3654
3268
|
' readyState=' +
|
|
3655
3269
|
e.track.readyState)), share());
|
|
3656
3270
|
onTrack$
|
|
3657
|
-
.pipe(filter((e) => e.track.kind === 'audio'), map
|
|
3271
|
+
.pipe(filter((e) => e.track.kind === 'audio'), map((e) => e.streams[0]))
|
|
3658
3272
|
.subscribe((stream) => this.videoService.attachAudioStream(stream));
|
|
3659
3273
|
onTrack$
|
|
3660
|
-
.pipe(filter((e) => e.track.kind === 'video'), map
|
|
3274
|
+
.pipe(filter((e) => e.track.kind === 'video'), map((e) => e.streams[0]), tap$1(() => Logger.info('Set video source from video track ontrack.')))
|
|
3661
3275
|
.subscribe((stream) => {
|
|
3662
3276
|
if (this.pcClient) {
|
|
3663
3277
|
this.videoService.attachVideoStream(stream, this.pcClient);
|
|
@@ -3758,7 +3372,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3758
3372
|
`[DATACHANNEL] Message received on "${datachannel.label}" id=${datachannel.id}, byteCode=${view[0]}, size=${view.byteLength}`,
|
|
3759
3373
|
);
|
|
3760
3374
|
}),*/
|
|
3761
|
-
map
|
|
3375
|
+
map((e) => e.data), takeUntil(merge(this.disconnect$, this.destroy$)))
|
|
3762
3376
|
.subscribe((data) => this.onDataChannelMessage$.next(data));
|
|
3763
3377
|
return datachannel;
|
|
3764
3378
|
}
|
|
@@ -3810,10 +3424,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3810
3424
|
Logger.error("Couldn't create answer", e);
|
|
3811
3425
|
}
|
|
3812
3426
|
}
|
|
3813
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3814
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
3427
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3428
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, providedIn: 'root' }); }
|
|
3815
3429
|
}
|
|
3816
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3430
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, decorators: [{
|
|
3817
3431
|
type: Injectable,
|
|
3818
3432
|
args: [{ providedIn: 'root' }]
|
|
3819
3433
|
}], ctorParameters: () => [] });
|
|
@@ -3939,10 +3553,10 @@ class StreamAdoptionService {
|
|
|
3939
3553
|
this.webRtc.adopt(parked.pc, parked.dc, parked.stream, parked.config ?? {}, parked.dcBuffer);
|
|
3940
3554
|
return true;
|
|
3941
3555
|
}
|
|
3942
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3943
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
3556
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3557
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, providedIn: 'root' }); }
|
|
3944
3558
|
}
|
|
3945
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3559
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, decorators: [{
|
|
3946
3560
|
type: Injectable,
|
|
3947
3561
|
args: [{ providedIn: 'root' }]
|
|
3948
3562
|
}] });
|
|
@@ -3974,10 +3588,10 @@ class UnrealCallbackService {
|
|
|
3974
3588
|
* ```
|
|
3975
3589
|
*/
|
|
3976
3590
|
fromUnrealCallback(command) {
|
|
3977
|
-
return this.actions$.pipe(ofType(unrealCommandCallback), map
|
|
3591
|
+
return this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.command === command),
|
|
3978
3592
|
// Cast is required: after a `command`-based filter TS cannot narrow to a
|
|
3979
3593
|
// type discriminated on `callback`. The unwrapped object IS the full callback.
|
|
3980
|
-
map
|
|
3594
|
+
map((data) => data));
|
|
3981
3595
|
}
|
|
3982
3596
|
/**
|
|
3983
3597
|
* Sends a command and observes the matching response by correlationId.
|
|
@@ -4001,19 +3615,19 @@ class UnrealCallbackService {
|
|
|
4001
3615
|
observeCommandResponse(data, sender, timeOut = 60000, dispatchOnTimeout = true) {
|
|
4002
3616
|
const correlationId = generateUuid();
|
|
4003
3617
|
return defer(() => {
|
|
4004
|
-
const observable = this.actions$.pipe(ofType(unrealCommandCallback), map
|
|
3618
|
+
const observable = this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.correlationId === correlationId), timeout$1(timeOut), catchError(() => dispatchOnTimeout
|
|
4005
3619
|
? of({ command: 'timeout', correlationId: 'timeout' })
|
|
4006
3620
|
: of(null)), take(1), tapLog('Command Response Observer'), filter(Truthy),
|
|
4007
3621
|
// Cast: response is matched by correlationId, so it is the callback for K.
|
|
4008
|
-
map
|
|
3622
|
+
map((data) => data));
|
|
4009
3623
|
setTimeout(() => sender({ ...data, correlationId }), 0);
|
|
4010
3624
|
return observable;
|
|
4011
3625
|
});
|
|
4012
3626
|
}
|
|
4013
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4014
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
3627
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3628
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, providedIn: 'root' }); }
|
|
4015
3629
|
}
|
|
4016
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3630
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, decorators: [{
|
|
4017
3631
|
type: Injectable,
|
|
4018
3632
|
args: [{ providedIn: 'root' }]
|
|
4019
3633
|
}] });
|
|
@@ -4130,10 +3744,10 @@ class UnrealCommunicatorService extends SubService {
|
|
|
4130
3744
|
requestQualityControl() {
|
|
4131
3745
|
this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
4132
3746
|
}
|
|
4133
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4134
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
3747
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3748
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, providedIn: 'root' }); }
|
|
4135
3749
|
}
|
|
4136
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3750
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
|
|
4137
3751
|
type: Injectable,
|
|
4138
3752
|
args: [{ providedIn: 'root' }]
|
|
4139
3753
|
}], ctorParameters: () => [] });
|
|
@@ -4147,12 +3761,12 @@ class UnrealErrorModalComponent {
|
|
|
4147
3761
|
close() {
|
|
4148
3762
|
this.#dialogRef.close();
|
|
4149
3763
|
}
|
|
4150
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4151
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.
|
|
3764
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3765
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4152
3766
|
}
|
|
4153
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3767
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
|
|
4154
3768
|
type: Component,
|
|
4155
|
-
args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div class=\"unreal-modal\">\
|
|
3769
|
+
args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"] }]
|
|
4156
3770
|
}] });
|
|
4157
3771
|
|
|
4158
3772
|
class UnrealEffects {
|
|
@@ -4178,7 +3792,7 @@ class UnrealEffects {
|
|
|
4178
3792
|
.select(unrealFeature.selectDataChannelConnected)
|
|
4179
3793
|
.pipe(filter(Truthy));
|
|
4180
3794
|
this.destroyConnections$ = createEffect(() => {
|
|
4181
|
-
return this.actions$.pipe(ofType(destroyUnrealScene), map(() => destroyRemoteConnections({ reason: DisconnectReason.Destroy })));
|
|
3795
|
+
return this.actions$.pipe(ofType(destroyUnrealScene), map$1(() => destroyRemoteConnections({ reason: DisconnectReason.Destroy })));
|
|
4182
3796
|
});
|
|
4183
3797
|
// Stage 3 — accurate region re-ping in the background once the stream is up.
|
|
4184
3798
|
// A few seconds after the data channel is ready (so it doesn't compete with
|
|
@@ -4197,10 +3811,10 @@ class UnrealEffects {
|
|
|
4197
3811
|
// subscribe to single intent (and it shows up as a distinct entry in the
|
|
4198
3812
|
// Redux DevTools timeline).
|
|
4199
3813
|
this.abortEstablishingConnection$ = createEffect(() => {
|
|
4200
|
-
return this.actions$.pipe(ofType(setCirrusDisconnected, dropConnection, destroyUnrealScene), map(() => abortEstablishingConnection()));
|
|
3814
|
+
return this.actions$.pipe(ofType(setCirrusDisconnected, dropConnection, destroyUnrealScene), map$1(() => abortEstablishingConnection()));
|
|
4201
3815
|
});
|
|
4202
3816
|
this.resetAfk$ = createEffect(() => {
|
|
4203
|
-
return this.actions$.pipe(ofType(setConfig, setUserInactivityTimeout, resetWarnTimeout, resetConfig), map(() => resetAfk()));
|
|
3817
|
+
return this.actions$.pipe(ofType(setConfig, setUserInactivityTimeout, resetWarnTimeout, resetConfig), map$1(() => resetAfk()));
|
|
4204
3818
|
});
|
|
4205
3819
|
this.iframeMessaging$ = createEffect(() => {
|
|
4206
3820
|
const cirrusConnected$ = this.store
|
|
@@ -4213,16 +3827,16 @@ class UnrealEffects {
|
|
|
4213
3827
|
// Skip initial false; emit null on every viewport state change
|
|
4214
3828
|
const viewportReset$ = this.store
|
|
4215
3829
|
.select(unrealFeature.selectViewportReady)
|
|
4216
|
-
.pipe(skip(1), delay(500), map(() => null));
|
|
3830
|
+
.pipe(skip(1), delay(500), map$1(() => null));
|
|
4217
3831
|
return merge(cirrusStatus$, this.store.select(unrealFeature.selectStatusMessage), viewportReset$).pipe(debounceTime(0), distinctUntilChanged(), tapLog('STATUS=>'), tap((status) => this.postToScreenLocker(status)));
|
|
4218
3832
|
}, { dispatch: false });
|
|
4219
3833
|
this.setSignalingTo100$ = createEffect(() => {
|
|
4220
|
-
return this.actions$.pipe(ofType(setAwsInstance), map(() => setStatusPercentSignallingServer({ percent: 100 })));
|
|
3834
|
+
return this.actions$.pipe(ofType(setAwsInstance), map$1(() => setStatusPercentSignallingServer({ percent: 100 })));
|
|
4221
3835
|
});
|
|
4222
3836
|
this.setOrchestrationParameters$ = createEffect(() => {
|
|
4223
|
-
return this.actions$.pipe(ofType(setOrchestrationParameters), map(({ eta }) => eta), filter((value) => value > 0), switchMap((total) => {
|
|
3837
|
+
return this.actions$.pipe(ofType(setOrchestrationParameters), map$1(({ eta }) => eta), filter((value) => value > 0), switchMap((total) => {
|
|
4224
3838
|
// Emit every second: 0,1,2,...,total (inclusive)
|
|
4225
|
-
return timer(0, 1000).pipe(takeUntil(this.connectionCompleted$), take(total + 1), map((sec) => sec / total), distinctUntilChanged(), map((progressComplete) => setOrchestrationProgress({ progressComplete })));
|
|
3839
|
+
return timer(0, 1000).pipe(takeUntil(this.connectionCompleted$), take(total + 1), map$1((sec) => sec / total), distinctUntilChanged(), map$1((progressComplete) => setOrchestrationProgress({ progressComplete })));
|
|
4226
3840
|
}));
|
|
4227
3841
|
});
|
|
4228
3842
|
this.setDataChannelTimeoutCheck$ = createEffect(() => {
|
|
@@ -4269,7 +3883,7 @@ class UnrealEffects {
|
|
|
4269
3883
|
return of(null);
|
|
4270
3884
|
}),
|
|
4271
3885
|
// map response to the destroy action that ngrx will dispatch
|
|
4272
|
-
map(() => disconnectStream({
|
|
3886
|
+
map$1(() => disconnectStream({
|
|
4273
3887
|
reason: DisconnectReason.DataChannelTimeout,
|
|
4274
3888
|
message: 'Data Channel Timeout',
|
|
4275
3889
|
})));
|
|
@@ -4293,24 +3907,24 @@ class UnrealEffects {
|
|
|
4293
3907
|
* a visible flicker (video flashing to black).
|
|
4294
3908
|
*/
|
|
4295
3909
|
this.forceViewportNotReady$ = createEffect(() => {
|
|
4296
|
-
return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectViewportReady)), filter(([, viewportReady]) => viewportReady), map(() => setViewportNotReady()));
|
|
3910
|
+
return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectViewportReady)), filter(([, viewportReady]) => viewportReady), map$1(() => setViewportNotReady()));
|
|
4297
3911
|
});
|
|
4298
3912
|
this.resetCirrusOnDestroy$ = createEffect(() => {
|
|
4299
|
-
return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectCirrusConnected)), filter(([, cirrusConnected]) => cirrusConnected), map(() => setCirrusDisconnected()));
|
|
3913
|
+
return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectCirrusConnected)), filter(([, cirrusConnected]) => cirrusConnected), map$1(() => setCirrusDisconnected()));
|
|
4300
3914
|
});
|
|
4301
3915
|
this.destroyRemoteConnections$ = createEffect(() => {
|
|
4302
3916
|
return this.actions$.pipe(ofType(destroyRemoteConnections), tap(({ reason }) => {
|
|
4303
3917
|
this.webRtcPlayerService.releaseRemoteConnections(reason);
|
|
4304
|
-
}), filter(({ reason }) => reason === DisconnectReason.DropConnection), map(() => dropConnection()));
|
|
3918
|
+
}), filter(({ reason }) => reason === DisconnectReason.DropConnection), map$1(() => dropConnection()));
|
|
4305
3919
|
});
|
|
4306
3920
|
this.destroyConnectionAndRestart$ = createEffect(() => {
|
|
4307
|
-
return this.actions$.pipe(ofType(setCirrusDisconnected), withLatestFrom(this.store.select(unrealFeature.selectDisconnectReason)), filter(([, reason]) => reason === DisconnectReason.DataChannelTimeout), map(() => initSignalling()));
|
|
3921
|
+
return this.actions$.pipe(ofType(setCirrusDisconnected), withLatestFrom(this.store.select(unrealFeature.selectDisconnectReason)), filter(([, reason]) => reason === DisconnectReason.DataChannelTimeout), map$1(() => initSignalling()));
|
|
4308
3922
|
});
|
|
4309
3923
|
this.showUnrealError$ = createEffect(() => {
|
|
4310
|
-
return this.actions$.pipe(ofType(showUnrealErrorMessage), map(({ code }) => getRtcErrorMessage(code)), distinctUntilChanged(), filter(Truthy),
|
|
3924
|
+
return this.actions$.pipe(ofType(showUnrealErrorMessage), map$1(({ code }) => getRtcErrorMessage(code)), distinctUntilChanged(), filter(Truthy), exhaustMap((content) => this.dialog.open(UnrealErrorModalComponent, {
|
|
4311
3925
|
scrollStrategy: this.scrollStrategy,
|
|
4312
3926
|
data: { content },
|
|
4313
|
-
}).closed), map(() => showUnrealErrorMessage({ code: null })));
|
|
3927
|
+
}).closed), map$1(() => showUnrealErrorMessage({ code: null })));
|
|
4314
3928
|
});
|
|
4315
3929
|
/**
|
|
4316
3930
|
* `dataChannelReady` is a ONCE-PER-SESSION signal: it starts app init
|
|
@@ -4355,21 +3969,21 @@ class UnrealEffects {
|
|
|
4355
3969
|
// we proceed only after no more commands are started for 50 ms.
|
|
4356
3970
|
return this.actions$.pipe(ofType(commandStarted), debounceTime(50), take(1), switchMap(() => this.unrealCallbackService.observeCommandResponse({ command: MetaBoxCommand.FLoopBackCommand }, (data) => this.commandsSender.sendCommandToUnreal(data))), switchMap(() => this.videoService.videoStats$), filter(({ aggregatedStats: s }) => !!s.framesPerSecond &&
|
|
4357
3971
|
s.framesPerSecond > MINIMAL_FPS &&
|
|
4358
|
-
(s.framesDecoded ?? 0) > 15), take(1), map(() => setLoopBackCommandIsCompleted()));
|
|
3972
|
+
(s.framesDecoded ?? 0) > 15), take(1), map$1(() => setLoopBackCommandIsCompleted()));
|
|
4359
3973
|
}));
|
|
4360
3974
|
});
|
|
4361
3975
|
this.setViewportReadyBySetLoopBackCommandIsCompleted$ = createEffect(() => {
|
|
4362
|
-
return this.actions$.pipe(ofType(setLoopBackCommandIsCompleted, reconnectPeerSuccess), tap(() => this.commandTelemetryService.trackStopCommand('EXT-SetViewportReady', false, { ready: true })), map(() => setViewportReady()));
|
|
3976
|
+
return this.actions$.pipe(ofType(setLoopBackCommandIsCompleted, reconnectPeerSuccess), tap(() => this.commandTelemetryService.trackStopCommand('EXT-SetViewportReady', false, { ready: true })), map$1(() => setViewportReady()));
|
|
4363
3977
|
});
|
|
4364
3978
|
this.startStream$ = createEffect(() => {
|
|
4365
|
-
return this.actions$.pipe(ofType(startStream), map(() => initSignalling()));
|
|
3979
|
+
return this.actions$.pipe(ofType(startStream), map$1(() => initSignalling()));
|
|
4366
3980
|
});
|
|
4367
3981
|
// When the video stream is initialized but autoplay didn't kick in
|
|
4368
3982
|
// (browser blocked it; user gesture pending), the user may need extra
|
|
4369
3983
|
// time before interacting. Refresh the AFK timer so it doesn't tick
|
|
4370
3984
|
// toward an inactivity warning while we're waiting for permission.
|
|
4371
3985
|
this.resetAfkOnPausedVideoInit$ = createEffect(() => {
|
|
4372
|
-
return this.actions$.pipe(ofType(videoStreamInitialized), filter(() => !!this.videoService.video?.paused), map(() => resetAfk()));
|
|
3986
|
+
return this.actions$.pipe(ofType(videoStreamInitialized), filter(() => !!this.videoService.video?.paused), map$1(() => resetAfk()));
|
|
4373
3987
|
});
|
|
4374
3988
|
/**
|
|
4375
3989
|
* Effect: `disconnectReasonHandling$`
|
|
@@ -4392,7 +4006,7 @@ class UnrealEffects {
|
|
|
4392
4006
|
return false;
|
|
4393
4007
|
}
|
|
4394
4008
|
return DESTROY_DISCONNECT_REASONS.includes(reason);
|
|
4395
|
-
}), map(({ reason }) => destroyRemoteConnections({ reason })));
|
|
4009
|
+
}), map$1(({ reason }) => destroyRemoteConnections({ reason })));
|
|
4396
4010
|
});
|
|
4397
4011
|
/**
|
|
4398
4012
|
* Effect: `handleDataChannelClosed$`
|
|
@@ -4406,7 +4020,7 @@ class UnrealEffects {
|
|
|
4406
4020
|
reason === DisconnectReason.IceConnectionFailed) &&
|
|
4407
4021
|
this.canPeerReconnect()), tap(({ reason }) => {
|
|
4408
4022
|
Logger.warn(`[Reconnect] ${reason}, initiating peer reconnection`);
|
|
4409
|
-
}), map(() => reconnectPeer({
|
|
4023
|
+
}), map$1(() => reconnectPeer({
|
|
4410
4024
|
attempt: 1,
|
|
4411
4025
|
maxAttempts: RECONNECT_CONFIG.maxAttempts,
|
|
4412
4026
|
delay: 0,
|
|
@@ -4424,7 +4038,7 @@ class UnrealEffects {
|
|
|
4424
4038
|
*/
|
|
4425
4039
|
this.resetStateForPeerReconnect$ = createEffect(() => {
|
|
4426
4040
|
return this.actions$.pipe(ofType(reconnectPeer), filter(() => RECONNECT_CONFIG.enabled), filter(({ attempt }) => attempt === 1), // Only reset on the first attempt
|
|
4427
|
-
map(() => resetDataChannelForReconnect()));
|
|
4041
|
+
map$1(() => resetDataChannelForReconnect()));
|
|
4428
4042
|
});
|
|
4429
4043
|
/**
|
|
4430
4044
|
* Effect: `executePeerReconnect$`
|
|
@@ -4442,7 +4056,7 @@ class UnrealEffects {
|
|
|
4442
4056
|
return of(this.scheduleRetryOrFail(attempt, maxAttempts, 'Signaling connection lost during peer reconnection'));
|
|
4443
4057
|
}
|
|
4444
4058
|
// Monitor for successful data channel connection
|
|
4445
|
-
return this.actions$.pipe(ofType(dataChannelConnected), take(1), timeout$1(this.dataChannelConnectionTimeout), tap(() => Logger.info('[Reconnect] Peer reconnection successful!')), map(() => reconnectPeerSuccess()), catchError(() => {
|
|
4059
|
+
return this.actions$.pipe(ofType(dataChannelConnected), take(1), timeout$1(this.dataChannelConnectionTimeout), tap(() => Logger.info('[Reconnect] Peer reconnection successful!')), map$1(() => reconnectPeerSuccess()), catchError(() => {
|
|
4446
4060
|
if (attempt < maxAttempts) {
|
|
4447
4061
|
Logger.warn(`[Reconnect] Peer reconnection attempt ${attempt} timed out, scheduling retry`);
|
|
4448
4062
|
}
|
|
@@ -4460,7 +4074,7 @@ class UnrealEffects {
|
|
|
4460
4074
|
* Falls back to full disconnection which may trigger full reconnection.
|
|
4461
4075
|
*/
|
|
4462
4076
|
this.handlePeerReconnectFailed$ = createEffect(() => {
|
|
4463
|
-
return this.actions$.pipe(ofType(reconnectPeerFailed), map(({ reason }) => disconnectStream({
|
|
4077
|
+
return this.actions$.pipe(ofType(reconnectPeerFailed), map$1(({ reason }) => disconnectStream({
|
|
4464
4078
|
reason: DisconnectReason.ReconnectFailed,
|
|
4465
4079
|
message: reason,
|
|
4466
4080
|
})));
|
|
@@ -4496,9 +4110,9 @@ class UnrealEffects {
|
|
|
4496
4110
|
// carries a correlationId resolves a previously started command.
|
|
4497
4111
|
// Skip in Playwright mode (deterministic command IDs are issued directly).
|
|
4498
4112
|
this.listenUnrealCallbackByInitSignalling$ = createEffect(() => {
|
|
4499
|
-
return this.actions$.pipe(ofType(initSignalling), filter(() => !this.unrealInitialConfig?.playwright), switchMap(() => this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json
|
|
4113
|
+
return this.actions$.pipe(ofType(initSignalling), filter(() => !this.unrealInitialConfig?.playwright), switchMap(() => this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => 'commandCallback' in json
|
|
4500
4114
|
? json.commandCallback?.correlationId
|
|
4501
|
-
: json?.correlationId), filter(Truthy), map((id) => commandCompleted({ id, now: Date.now() })))));
|
|
4115
|
+
: json?.correlationId), filter(Truthy), map$1((id) => commandCompleted({ id, now: Date.now() })))));
|
|
4502
4116
|
});
|
|
4503
4117
|
this.connectToSignaling$ = createEffect(() => {
|
|
4504
4118
|
return this.actions$.pipe(ofType(initSignalling), withLatestFrom(this.store.select(unrealFeature.selectMatchUrls), this.store.select(selectIsAutostart), this.store.select(unrealFeature.selectCirrusConnected)), filter(([, , autoStart, cirrusConnected]) => {
|
|
@@ -4506,7 +4120,7 @@ class UnrealEffects {
|
|
|
4506
4120
|
Logger.warn(`SIGNALING REQUEST can't be called when cirrus connection is already established.`);
|
|
4507
4121
|
}
|
|
4508
4122
|
return autoStart && !cirrusConnected;
|
|
4509
|
-
}), map(([, matchMakerUrls]) => [...matchMakerUrls].filter(Truthy)), filter((urls) => urls.length > 0),
|
|
4123
|
+
}), map$1(([, matchMakerUrls]) => [...matchMakerUrls].filter(Truthy)), filter((urls) => urls.length > 0),
|
|
4510
4124
|
// Ensure a single in-flight request per attempt.
|
|
4511
4125
|
exhaustMap((urls) =>
|
|
4512
4126
|
// If a prefetched `window.__stream` is ready — or still connecting —
|
|
@@ -4523,35 +4137,434 @@ class UnrealEffects {
|
|
|
4523
4137
|
ignoreElements(), startWith(setEstablishingConnection({ value: true })))));
|
|
4524
4138
|
});
|
|
4525
4139
|
}
|
|
4526
|
-
canPeerReconnect() {
|
|
4527
|
-
return RECONNECT_CONFIG.enabled && this.signallingService.isConnected();
|
|
4140
|
+
canPeerReconnect() {
|
|
4141
|
+
return RECONNECT_CONFIG.enabled && this.signallingService.isConnected();
|
|
4142
|
+
}
|
|
4143
|
+
/**
|
|
4144
|
+
* Either schedules the next peer-reconnect attempt or gives up with the
|
|
4145
|
+
* supplied reason. Used in two `executePeerReconnect$` branches that share
|
|
4146
|
+
* the same retry-or-fail decision.
|
|
4147
|
+
*/
|
|
4148
|
+
scheduleRetryOrFail(attempt, maxAttempts, exhaustedReason) {
|
|
4149
|
+
return attempt < maxAttempts
|
|
4150
|
+
? reconnectPeer({ attempt: attempt + 1, maxAttempts })
|
|
4151
|
+
: reconnectPeerFailed({ reason: exhaustedReason });
|
|
4152
|
+
}
|
|
4153
|
+
postToScreenLocker(text) {
|
|
4154
|
+
try {
|
|
4155
|
+
const el = document.getElementById(this.unrealInitialConfig?.screenLockerContainerId ??
|
|
4156
|
+
SCREEN_LOCKER_CONTAINER_ID);
|
|
4157
|
+
el?.contentWindow?.postMessage(text, '*');
|
|
4158
|
+
}
|
|
4159
|
+
catch {
|
|
4160
|
+
// Fails silently if cross-origin
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4164
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects }); }
|
|
4165
|
+
}
|
|
4166
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects, decorators: [{
|
|
4167
|
+
type: Injectable
|
|
4168
|
+
}] });
|
|
4169
|
+
|
|
4170
|
+
function InstanceReadyHandler(msg) {
|
|
4171
|
+
const payload = msg?.payload;
|
|
4172
|
+
if (!payload) {
|
|
4173
|
+
Logger.warn('instanceReady received without payload — ignoring');
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
if (!payload.originInstanceUri) {
|
|
4177
|
+
Logger.warn('instanceReady without originInstanceUri — ignoring');
|
|
4178
|
+
return;
|
|
4179
|
+
}
|
|
4180
|
+
// Emit for observability (telemetry) and store the stream-machine coords.
|
|
4181
|
+
this.store.dispatch(instanceReady(payload));
|
|
4182
|
+
// This is the answer `requestCirrusViaSocket` is waiting for: the Cirrus
|
|
4183
|
+
// address (`originInstanceUri`) plus the connection id to hand it. The socket
|
|
4184
|
+
// itself is opened by the shared `connectToCirrus`, not here.
|
|
4185
|
+
this.onInstanceReady$.next(payload);
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
function InstanceReservedHandler(msg) {
|
|
4189
|
+
this.store.dispatch(setOrchestrationParameters({
|
|
4190
|
+
instanceName: msg.payload.instanceId,
|
|
4191
|
+
streamRequestId: msg.payload.streamRequestId,
|
|
4192
|
+
eta: msg.payload.eta ?? 150,
|
|
4193
|
+
}));
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
function PlayerCountHandler(msg) {
|
|
4197
|
+
Logger.log(msg);
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
function SSInfoHandler(msg) {
|
|
4201
|
+
this.store.dispatch(updateCirrusInfo({ ssData: msg.data }));
|
|
4202
|
+
return null;
|
|
4203
|
+
}
|
|
4204
|
+
|
|
4205
|
+
const dropCodes = [
|
|
4206
|
+
WSCloseCode_UNKNOWN,
|
|
4207
|
+
WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
|
|
4208
|
+
WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
|
|
4209
|
+
WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
|
|
4210
|
+
WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
|
|
4211
|
+
];
|
|
4212
|
+
function OnCloseHandler(e) {
|
|
4213
|
+
const message = `WebSocket closed: ${JSON.stringify(e.code)} - ${e.reason}`;
|
|
4214
|
+
Logger.warn(message);
|
|
4215
|
+
this.store.dispatch(setCirrusDisconnected());
|
|
4216
|
+
if (dropCodes.includes(e.code)) {
|
|
4217
|
+
this.store.dispatch(dropConnection());
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
|
|
4221
|
+
function OnErrorHandler(e) {
|
|
4222
|
+
Logger.warn(`WS error: ${JSON.stringify(e)}`);
|
|
4223
|
+
this.store.dispatch(disconnectStream({
|
|
4224
|
+
reason: DisconnectReason.WebSocketError,
|
|
4225
|
+
message: 'WebSocket Error',
|
|
4226
|
+
}));
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4229
|
+
function OnMessageHandler(e) {
|
|
4230
|
+
const handleData = (data) => {
|
|
4231
|
+
//Logger.colored(...COLOR_CODES.FROM_SIGNALING, data);
|
|
4232
|
+
const msg = JSON.parse(data);
|
|
4233
|
+
this.handleMessage(msg);
|
|
4234
|
+
};
|
|
4235
|
+
if (typeof e.data === 'string') {
|
|
4236
|
+
try {
|
|
4237
|
+
handleData(e.data);
|
|
4238
|
+
}
|
|
4239
|
+
catch (err) {
|
|
4240
|
+
Logger.warn('OnMessageHandler: failed to parse string message', err);
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
else if (e.data instanceof Blob) {
|
|
4244
|
+
e.data
|
|
4245
|
+
.text()
|
|
4246
|
+
.then(handleData)
|
|
4247
|
+
.catch((err) => Logger.warn('OnMessageHandler: failed to parse Blob message', err));
|
|
4248
|
+
}
|
|
4249
|
+
}
|
|
4250
|
+
|
|
4251
|
+
/**
|
|
4252
|
+
* Open handler of the CIRRUS socket only (`addWsHandlers`), so
|
|
4253
|
+
* `setCirrusConnected` now means what it says. It used to also send
|
|
4254
|
+
* `requestStream` here, which made the flag fire on the orchestration control
|
|
4255
|
+
* socket — a whole provisioning wait (`eta`, ~150 s) before any Cirrus existed.
|
|
4256
|
+
* `requestStream` belongs to the control socket and is sent by
|
|
4257
|
+
* `requestCirrusViaSocket`.
|
|
4258
|
+
*/
|
|
4259
|
+
function OnOpenHandler() {
|
|
4260
|
+
this.store.dispatch(setCirrusConnected());
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4263
|
+
/**
|
|
4264
|
+
* Keeps the max of numbers seen so far; resets to 0 whenever `reset$` emits.
|
|
4265
|
+
*/
|
|
4266
|
+
const keepMaxUntilReset = (reset$) => (source$) => merge(source$, reset$.pipe(map$1(() => null))).pipe(scan((max, value) => (value === null ? 0 : Math.max(max, value)), 0));
|
|
4267
|
+
|
|
4268
|
+
// Reused across every inbound data-channel message — instantiating a
|
|
4269
|
+
// TextDecoder per call adds needless GC churn on a hot path.
|
|
4270
|
+
const utf16Decoder = new TextDecoder('utf-16');
|
|
4271
|
+
function decodeData(anyData) {
|
|
4272
|
+
try {
|
|
4273
|
+
return utf16Decoder.decode(anyData);
|
|
4274
|
+
}
|
|
4275
|
+
catch {
|
|
4276
|
+
return '';
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
const dispatchResize = () => {
|
|
4281
|
+
window.dispatchEvent(new Event('resize'));
|
|
4282
|
+
};
|
|
4283
|
+
|
|
4284
|
+
const errorCodes = {
|
|
4285
|
+
code404: 'Your asset is being synced on Metabox servers and is not yet available in Metabox Studio or Metabox Configurator. Please check again later after syncing is complete. ',
|
|
4286
|
+
};
|
|
4287
|
+
function getRtcErrorMessage(code) {
|
|
4288
|
+
if (code === null) {
|
|
4289
|
+
return undefined;
|
|
4290
|
+
}
|
|
4291
|
+
return errorCodes[`code${code}`];
|
|
4292
|
+
}
|
|
4293
|
+
|
|
4294
|
+
const JUMP_THRESHOLD = 0.95;
|
|
4295
|
+
const MAX_TRANSITION_DURATION_MS = 200;
|
|
4296
|
+
/**
|
|
4297
|
+
* Maps a 0..1 stream directly to a 0..100 integer percent stream.
|
|
4298
|
+
* No animation — emits whatever the source emits, rounded and clamped.
|
|
4299
|
+
*/
|
|
4300
|
+
const floatToPercents = () => (source) => source.pipe(map((value) => clampf(0, 100, Math.round(value * 100))));
|
|
4301
|
+
/**
|
|
4302
|
+
* Maps a 0..1 progress stream to a smoothed 0..100 integer percent stream.
|
|
4303
|
+
* Animates between consecutive values over up to 200ms; jumps directly when
|
|
4304
|
+
* the delta exceeds 0.95 (treated as a reset, not a real progression).
|
|
4305
|
+
*/
|
|
4306
|
+
const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWith({ value: 0, timestamp: 0 }), pairwise(), concatMap(([prev, curr]) => {
|
|
4307
|
+
const isJump = Math.abs(curr.value - prev.value) > JUMP_THRESHOLD;
|
|
4308
|
+
const dt = prev.timestamp ? curr.timestamp - prev.timestamp : 0;
|
|
4309
|
+
if (isJump || dt === 0) {
|
|
4310
|
+
return of(curr.value);
|
|
4311
|
+
}
|
|
4312
|
+
return smoothTransition(prev.value, curr.value, Math.min(dt, MAX_TRANSITION_DURATION_MS));
|
|
4313
|
+
}), floatToPercents());
|
|
4314
|
+
/**
|
|
4315
|
+
* Smoothly interpolates from `start` to `end` over `duration`ms using the
|
|
4316
|
+
* animation frame scheduler. Completes when the transition finishes.
|
|
4317
|
+
*
|
|
4318
|
+
* NOTE: duplicates `smoothTransition` from `@3dsource/utils`. The utils version
|
|
4319
|
+
* is missing `takeWhile(... < 1, true)` and never completes — which would
|
|
4320
|
+
* deadlock the `concatMap` above. Keep this local copy until utils is fixed.
|
|
4321
|
+
* Not exported: internal to `floatToSmoothPercents`.
|
|
4322
|
+
*/
|
|
4323
|
+
const smoothTransition = (start, end, duration) => {
|
|
4324
|
+
const startTime = animationFrameScheduler.now();
|
|
4325
|
+
return interval(0, animationFrameScheduler).pipe(map(() => clampf(0, 1, (animationFrameScheduler.now() - startTime) / duration)), distinctUntilChanged(), takeWhile((fraction) => fraction < 1, true), map((fraction) => lerp(start, end, fraction)));
|
|
4326
|
+
};
|
|
4327
|
+
|
|
4328
|
+
const getImageFromVideoStream = (takeSizeFrom = 'video', imageOutput, sizes) => {
|
|
4329
|
+
try {
|
|
4330
|
+
const video = document.getElementById(STREAMING_VIDEO_ID);
|
|
4331
|
+
const { canvas, ctx } = getCanvasCached('video');
|
|
4332
|
+
canvas.width =
|
|
4333
|
+
takeSizeFrom === 'video'
|
|
4334
|
+
? sizes?.width || video?.clientWidth || FULL_HD_WIDTH
|
|
4335
|
+
: FULL_HD_WIDTH;
|
|
4336
|
+
canvas.height =
|
|
4337
|
+
takeSizeFrom === 'video'
|
|
4338
|
+
? sizes?.height || video?.clientHeight || FULL_HD_HEIGHT
|
|
4339
|
+
: FULL_HD_HEIGHT;
|
|
4340
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
4341
|
+
return getSnapshot(canvas, canvas.width, imageOutput);
|
|
4342
|
+
}
|
|
4343
|
+
catch {
|
|
4344
|
+
return null;
|
|
4345
|
+
}
|
|
4346
|
+
};
|
|
4347
|
+
|
|
4348
|
+
/**
|
|
4349
|
+
* Generator that cycles through `urls` indefinitely. Each call to
|
|
4350
|
+
* `getActiveUrl(urls)` returns a fresh generator with its own counter,
|
|
4351
|
+
* so concurrent generators (e.g., overlapping reconnect attempts) do
|
|
4352
|
+
* not share state. The counter is initialized once per generator
|
|
4353
|
+
* instance — before any `yield` — so each `.next()` call advances
|
|
4354
|
+
* within that single generator.
|
|
4355
|
+
*/
|
|
4356
|
+
function* getActiveUrl(urls) {
|
|
4357
|
+
let index = 0;
|
|
4358
|
+
while (true) {
|
|
4359
|
+
yield urls[index++ % urls.length];
|
|
4528
4360
|
}
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4363
|
+
class LatencyTimings {
|
|
4364
|
+
constructor() {
|
|
4365
|
+
this.TestStartTimeMs = null;
|
|
4366
|
+
this.UEReceiptTimeMs = null;
|
|
4367
|
+
this.UEEncodeMs = null;
|
|
4368
|
+
this.UECaptureToSendMs = null;
|
|
4369
|
+
this.UETransmissionTimeMs = null;
|
|
4370
|
+
this.BrowserReceiptTimeMs = null;
|
|
4371
|
+
this.FrameDisplayDeltaTimeMs = null;
|
|
4538
4372
|
}
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4373
|
+
Reset() {
|
|
4374
|
+
this.TestStartTimeMs = null;
|
|
4375
|
+
this.UEReceiptTimeMs = null;
|
|
4376
|
+
this.UEEncodeMs = null;
|
|
4377
|
+
this.UECaptureToSendMs = null;
|
|
4378
|
+
this.UETransmissionTimeMs = null;
|
|
4379
|
+
this.BrowserReceiptTimeMs = null;
|
|
4380
|
+
this.FrameDisplayDeltaTimeMs = null;
|
|
4381
|
+
}
|
|
4382
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4383
|
+
SetUETimings(UETimings) {
|
|
4384
|
+
this.UEReceiptTimeMs = UETimings.ReceiptTimeMs;
|
|
4385
|
+
this.UEEncodeMs = UETimings.EncodeMs;
|
|
4386
|
+
this.UECaptureToSendMs = UETimings.CaptureToSendMs;
|
|
4387
|
+
this.UETransmissionTimeMs = UETimings.TransmissionTimeMs;
|
|
4388
|
+
this.BrowserReceiptTimeMs = Date.now();
|
|
4389
|
+
}
|
|
4390
|
+
SetFrameDisplayDeltaTime(DeltaTimeMs) {
|
|
4391
|
+
if (this.FrameDisplayDeltaTimeMs == null) {
|
|
4392
|
+
this.FrameDisplayDeltaTimeMs = Math.round(DeltaTimeMs);
|
|
4547
4393
|
}
|
|
4548
4394
|
}
|
|
4549
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4550
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealEffects }); }
|
|
4551
4395
|
}
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4396
|
+
|
|
4397
|
+
function qpToQuality(VideoEncoderQP) {
|
|
4398
|
+
const orangeQP = 26;
|
|
4399
|
+
const redQP = 35;
|
|
4400
|
+
let quality = 'lime';
|
|
4401
|
+
if (VideoEncoderQP > redQP) {
|
|
4402
|
+
quality = 'red';
|
|
4403
|
+
}
|
|
4404
|
+
else if (VideoEncoderQP > orangeQP) {
|
|
4405
|
+
quality = 'orange';
|
|
4406
|
+
}
|
|
4407
|
+
return quality;
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4410
|
+
/**
|
|
4411
|
+
* Base64-encodes a byte array.
|
|
4412
|
+
*
|
|
4413
|
+
* Builds the intermediate binary string in fixed-size chunks instead of
|
|
4414
|
+
* concatenating one character at a time. The naive `bytes.reduce((s, b) => s +
|
|
4415
|
+
* String.fromCharCode(b), '')` is O(n²) (each `+` re-copies the growing string)
|
|
4416
|
+
* and stalls the main thread for a full-resolution frame; chunking keeps it
|
|
4417
|
+
* O(n). The chunk size stays under the argument-count limit of
|
|
4418
|
+
* `String.fromCharCode.apply`/spread.
|
|
4419
|
+
*
|
|
4420
|
+
* @param bytes - The raw bytes to encode.
|
|
4421
|
+
* @returns The Base64 representation of `bytes`.
|
|
4422
|
+
*/
|
|
4423
|
+
function uint8ToBase64(bytes) {
|
|
4424
|
+
const CHUNK_SIZE = 0x8000;
|
|
4425
|
+
let binary = '';
|
|
4426
|
+
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
4427
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
|
|
4428
|
+
}
|
|
4429
|
+
return btoa(binary);
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
function fromResizeObserver(elem) {
|
|
4433
|
+
return new Observable((subscriber) => {
|
|
4434
|
+
const observer = new window.ResizeObserver((entries) => subscriber.next(entries));
|
|
4435
|
+
observer.observe(elem);
|
|
4436
|
+
return () => observer.unobserve(elem);
|
|
4437
|
+
});
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4440
|
+
/*
|
|
4441
|
+
* Copyright (c) 2026.
|
|
4442
|
+
* 3DSource.com. Sergii Karanda steve@3dsource.com. All Rights Reserved.
|
|
4443
|
+
*/
|
|
4444
|
+
/**
|
|
4445
|
+
* Rounds a number to the nearest even integer (rounding up for odd values).
|
|
4446
|
+
*
|
|
4447
|
+
* Video encoders (H.264/H.265) require even dimensions because chroma subsampling
|
|
4448
|
+
* operates on 2×2 pixel blocks. Odd dimensions cause encoding artifacts or failures.
|
|
4449
|
+
*
|
|
4450
|
+
* @param value - The number to round to the nearest even integer.
|
|
4451
|
+
* @returns The nearest even integer greater than or equal to the input.
|
|
4452
|
+
*
|
|
4453
|
+
* @example
|
|
4454
|
+
* makeEven(1079) // 1080
|
|
4455
|
+
* makeEven(1080) // 1080
|
|
4456
|
+
* makeEven(1081) // 1082
|
|
4457
|
+
*/
|
|
4458
|
+
function makeEven(value) {
|
|
4459
|
+
return Math.floor((value + 1) / 2) * 2;
|
|
4460
|
+
}
|
|
4461
|
+
|
|
4462
|
+
const FULL_HD_PIXELS = FULL_HD_WIDTH * FULL_HD_HEIGHT;
|
|
4463
|
+
const UHD_PIXELS = FULL_HD_WIDTH * 2 * (FULL_HD_HEIGHT * 2);
|
|
4464
|
+
/**
|
|
4465
|
+
* Calculates the optimal stream resolution for studio mode.
|
|
4466
|
+
*
|
|
4467
|
+
* Fits the studio aspect ratio into the container (scaled by pixelRatio), then
|
|
4468
|
+
* caps the total pixel count to a budget (Full HD or 4K) to avoid overloading
|
|
4469
|
+
* the GPU/encoder while maximizing visual quality.
|
|
4470
|
+
*
|
|
4471
|
+
* The pixel budget approach (instead of per-dimension caps) ensures that
|
|
4472
|
+
* non-standard aspect ratios (portrait, ultra-wide, square) utilize available
|
|
4473
|
+
* pixels efficiently — e.g. a tall 1080×1920 stream uses the same pixel budget
|
|
4474
|
+
* as a wide 1920×1080 stream.
|
|
4475
|
+
*
|
|
4476
|
+
* Resolution is always capped at the studio dimensions — never upscaled beyond
|
|
4477
|
+
* what the Unreal scene was designed for.
|
|
4478
|
+
*
|
|
4479
|
+
* @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
|
|
4480
|
+
* @param params.containerWidth - CSS width of the video container in pixels.
|
|
4481
|
+
* @param params.containerHeight - CSS height of the video container in pixels.
|
|
4482
|
+
* @param params.studioWidth - Target width of the MetaBox Studio scene.
|
|
4483
|
+
* @param params.studioHeight - Target height of the MetaBox Studio scene.
|
|
4484
|
+
* @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
|
|
4485
|
+
* otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
|
|
4486
|
+
* @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
|
|
4487
|
+
* and `scale` factor relative to the container's device-pixel size.
|
|
4488
|
+
*/
|
|
4489
|
+
function getResizeStudioValues(params) {
|
|
4490
|
+
const { pixelRatio, containerWidth, containerHeight, studioWidth, studioHeight, maxResolution, } = params;
|
|
4491
|
+
const maxSpace = {
|
|
4492
|
+
w: containerWidth * pixelRatio,
|
|
4493
|
+
h: containerHeight * pixelRatio,
|
|
4494
|
+
};
|
|
4495
|
+
const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
|
|
4496
|
+
const videoSizePixelPerfect = fitIntoRectangle({ x: 0, y: 0, w: studioWidth, h: studioHeight }, { x: 0, y: 0, ...maxSpace });
|
|
4497
|
+
let w = videoSizePixelPerfect.w;
|
|
4498
|
+
let h = videoSizePixelPerfect.h;
|
|
4499
|
+
if (w * h > maxPixels) {
|
|
4500
|
+
// Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
|
|
4501
|
+
// → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
|
|
4502
|
+
// Applying the same `s` to both dimensions preserves the aspect ratio.
|
|
4503
|
+
const scaleFactor = Math.sqrt(maxPixels / (w * h));
|
|
4504
|
+
w = w * scaleFactor;
|
|
4505
|
+
h = h * scaleFactor;
|
|
4506
|
+
}
|
|
4507
|
+
const out = fitIntoRectangle(videoSizePixelPerfect, {
|
|
4508
|
+
x: videoSizePixelPerfect.x,
|
|
4509
|
+
y: videoSizePixelPerfect.y,
|
|
4510
|
+
w,
|
|
4511
|
+
h,
|
|
4512
|
+
});
|
|
4513
|
+
out.w = makeEven(out.w);
|
|
4514
|
+
out.h = makeEven(out.h);
|
|
4515
|
+
return out;
|
|
4516
|
+
}
|
|
4517
|
+
/**
|
|
4518
|
+
* Calculates the optimal stream resolution for configurator (non-studio) mode.
|
|
4519
|
+
*
|
|
4520
|
+
* Uses the full container area (scaled by pixelRatio) as the stream resolution,
|
|
4521
|
+
* then caps total pixel count to a budget (Full HD or 4K) to prevent excessive
|
|
4522
|
+
* GPU/encoder load while preserving the container's aspect ratio.
|
|
4523
|
+
*
|
|
4524
|
+
* Unlike {@link getResizeStudioValues}, there is no fixed studio resolution to
|
|
4525
|
+
* fit into — the container itself defines the aspect ratio, and the stream fills
|
|
4526
|
+
* it entirely (no letterboxing).
|
|
4527
|
+
*
|
|
4528
|
+
* @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
|
|
4529
|
+
* @param params.containerWidth - CSS width of the video container in pixels.
|
|
4530
|
+
* @param params.containerHeight - CSS height of the video container in pixels.
|
|
4531
|
+
* @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
|
|
4532
|
+
* otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
|
|
4533
|
+
* @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
|
|
4534
|
+
* and `scale` factor (1 when no downscale needed, <1 when capped).
|
|
4535
|
+
*/
|
|
4536
|
+
function getResizeValuesUniversal(params) {
|
|
4537
|
+
const { pixelRatio, containerWidth, containerHeight, maxResolution } = params;
|
|
4538
|
+
const maxSpace = {
|
|
4539
|
+
w: containerWidth * pixelRatio,
|
|
4540
|
+
h: containerHeight * pixelRatio,
|
|
4541
|
+
};
|
|
4542
|
+
const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
|
|
4543
|
+
let w = maxSpace.w;
|
|
4544
|
+
let h = maxSpace.h;
|
|
4545
|
+
if (w * h > maxPixels) {
|
|
4546
|
+
// Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
|
|
4547
|
+
// → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
|
|
4548
|
+
// Applying the same `s` to both dimensions preserves the aspect ratio.
|
|
4549
|
+
const scaleFactor = Math.sqrt(maxPixels / (w * h));
|
|
4550
|
+
w = w * scaleFactor;
|
|
4551
|
+
h = h * scaleFactor;
|
|
4552
|
+
}
|
|
4553
|
+
return { w: makeEven(w), h: makeEven(h), x: 0, y: 0, scale: w / maxSpace.w };
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4556
|
+
/**
|
|
4557
|
+
* Picks the class that carries the decoration of a UI part: the host class when
|
|
4558
|
+
* one is supplied, the built-in one otherwise. An empty string counts as "not
|
|
4559
|
+
* supplied" so a part never ends up with no styling at all.
|
|
4560
|
+
*/
|
|
4561
|
+
function resolveSkin(classes, part, fallback) {
|
|
4562
|
+
const custom = classes[part];
|
|
4563
|
+
if (custom === undefined || custom === '') {
|
|
4564
|
+
return fallback;
|
|
4565
|
+
}
|
|
4566
|
+
return custom;
|
|
4567
|
+
}
|
|
4555
4568
|
|
|
4556
4569
|
class AFKService extends SubService {
|
|
4557
4570
|
constructor() {
|
|
@@ -4667,10 +4680,10 @@ class AFKService extends SubService {
|
|
|
4667
4680
|
}
|
|
4668
4681
|
}, 1000);
|
|
4669
4682
|
}
|
|
4670
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4671
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4683
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4684
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, providedIn: 'root' }); }
|
|
4672
4685
|
}
|
|
4673
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4686
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, decorators: [{
|
|
4674
4687
|
type: Injectable,
|
|
4675
4688
|
args: [{ providedIn: 'root' }]
|
|
4676
4689
|
}], ctorParameters: () => [] });
|
|
@@ -4720,10 +4733,10 @@ class LoadingProgressService {
|
|
|
4720
4733
|
// `switchMap` cancels the inner subscription on every visibility change
|
|
4721
4734
|
// so stale emissions can't leak through.
|
|
4722
4735
|
#boundedProgress$;
|
|
4723
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4724
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4736
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4737
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, providedIn: 'root' }); }
|
|
4725
4738
|
}
|
|
4726
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4739
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, decorators: [{
|
|
4727
4740
|
type: Injectable,
|
|
4728
4741
|
args: [{ providedIn: 'root' }]
|
|
4729
4742
|
}] });
|
|
@@ -4809,10 +4822,10 @@ class FreezeFrameService extends SubService {
|
|
|
4809
4822
|
progress: 1,
|
|
4810
4823
|
}));
|
|
4811
4824
|
}
|
|
4812
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4813
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4825
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4826
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, providedIn: 'root' }); }
|
|
4814
4827
|
}
|
|
4815
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, decorators: [{
|
|
4816
4829
|
type: Injectable,
|
|
4817
4830
|
args: [{ providedIn: 'root' }]
|
|
4818
4831
|
}], ctorParameters: () => [] });
|
|
@@ -5025,10 +5038,10 @@ class AggregatorService extends SubService {
|
|
|
5025
5038
|
Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
|
|
5026
5039
|
}
|
|
5027
5040
|
}
|
|
5028
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5029
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5041
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5042
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, providedIn: 'root' }); }
|
|
5030
5043
|
}
|
|
5031
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5044
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, decorators: [{
|
|
5032
5045
|
type: Injectable,
|
|
5033
5046
|
args: [{ providedIn: 'root' }]
|
|
5034
5047
|
}], ctorParameters: () => [] });
|
|
@@ -5174,7 +5187,7 @@ class ConsoleExtensionsService extends SubService {
|
|
|
5174
5187
|
// `store.select` replays the current value synchronously, so if it already
|
|
5175
5188
|
// equals `target` this resolves immediately; otherwise it waits for the
|
|
5176
5189
|
// transition or falls back to `false` after `timeoutMs`.
|
|
5177
|
-
return firstValueFrom(this.store.select(unrealFeature.selectDataChannelConnected).pipe(filter((connected) => connected === target), take(1), map(() => true), timeout$1({ first: timeoutMs, with: () => of(false) })));
|
|
5190
|
+
return firstValueFrom(this.store.select(unrealFeature.selectDataChannelConnected).pipe(filter((connected) => connected === target), take(1), map$1(() => true), timeout$1({ first: timeoutMs, with: () => of(false) })));
|
|
5178
5191
|
}
|
|
5179
5192
|
sleep(ms) {
|
|
5180
5193
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -5189,10 +5202,10 @@ class ConsoleExtensionsService extends SubService {
|
|
|
5189
5202
|
Logger.info('emitCommand(command) => send command to Unreal Engine.');
|
|
5190
5203
|
Logger.info('stressTest({iterations}) => hammer reconnect: repeatedly drop DC/PC and assert recovery.');
|
|
5191
5204
|
}
|
|
5192
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5193
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5205
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5206
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, providedIn: 'root' }); }
|
|
5194
5207
|
}
|
|
5195
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5208
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
|
|
5196
5209
|
type: Injectable,
|
|
5197
5210
|
args: [{ providedIn: 'root' }]
|
|
5198
5211
|
}], ctorParameters: () => [] });
|
|
@@ -5271,8 +5284,8 @@ class InputService extends SubService {
|
|
|
5271
5284
|
if (this.unrealConfig?.playwright) {
|
|
5272
5285
|
return;
|
|
5273
5286
|
}
|
|
5274
|
-
const visibilityHiddenTrigger$ = fromEvent(document, 'visibilitychange').pipe(map
|
|
5275
|
-
const visibilityVisibleTrigger$ = fromEvent(document, 'visibilitychange').pipe(map
|
|
5287
|
+
const visibilityHiddenTrigger$ = fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'hidden'), filter(Truthy));
|
|
5288
|
+
const visibilityVisibleTrigger$ = fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'visible'), filter(Truthy), startWith(true));
|
|
5276
5289
|
this.deactivatedVideoTrigger$ = merge(this.disconnect$, this.reInit$, visibilityHiddenTrigger$, this.destroy$);
|
|
5277
5290
|
merge(visibilityVisibleTrigger$, this.store.select(unrealFeature.selectViewportReady).pipe(filter(Truthy)))
|
|
5278
5291
|
.pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
|
|
@@ -5693,10 +5706,10 @@ class InputService extends SubService {
|
|
|
5693
5706
|
this.sendInputData(data.buffer);
|
|
5694
5707
|
});
|
|
5695
5708
|
}
|
|
5696
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5697
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5709
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5710
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, providedIn: 'root' }); }
|
|
5698
5711
|
}
|
|
5699
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5712
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, decorators: [{
|
|
5700
5713
|
type: Injectable,
|
|
5701
5714
|
args: [{ providedIn: 'root' }]
|
|
5702
5715
|
}], ctorParameters: () => [] });
|
|
@@ -5726,7 +5739,7 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5726
5739
|
return this.videoService.videoStats$.pipe(throttleTime(5000, asyncScheduler, {
|
|
5727
5740
|
leading: true,
|
|
5728
5741
|
trailing: true,
|
|
5729
|
-
}), withLatestFrom(this.store.select(unrealFeature.selectAwsInstance), signalingReadyTime$, viewPortReadyTime$), map
|
|
5742
|
+
}), withLatestFrom(this.store.select(unrealFeature.selectAwsInstance), signalingReadyTime$, viewPortReadyTime$), map(([data, signalingServer, signalingReadyTime, viewPortReadyTime,]) => this.mapEventData({
|
|
5730
5743
|
data,
|
|
5731
5744
|
signalingServer,
|
|
5732
5745
|
startTimeUtc,
|
|
@@ -5742,7 +5755,7 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5742
5755
|
* Used with `withLatestFrom` so events carry a stable duration for the whole session.
|
|
5743
5756
|
*/
|
|
5744
5757
|
readyTimeSince(readyState$, startedAt) {
|
|
5745
|
-
return readyState$.pipe(filter(Boolean), take$1(1), map
|
|
5758
|
+
return readyState$.pipe(filter(Boolean), take$1(1), map(() => Date.now() - startedAt), startWith$1(undefined));
|
|
5746
5759
|
}
|
|
5747
5760
|
mapEventData(params) {
|
|
5748
5761
|
const { data, signalingServer, startTimeUtc, signalingReadyTime, viewPortReadyTime, } = params;
|
|
@@ -5765,10 +5778,10 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5765
5778
|
VideoEncoderQP,
|
|
5766
5779
|
};
|
|
5767
5780
|
}
|
|
5768
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5769
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5781
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5782
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, providedIn: 'root' }); }
|
|
5770
5783
|
}
|
|
5771
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5784
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
|
|
5772
5785
|
type: Injectable,
|
|
5773
5786
|
args: [{ providedIn: 'root' }]
|
|
5774
5787
|
}], ctorParameters: () => [] });
|
|
@@ -5893,7 +5906,7 @@ class StreamStatusTelemetryService2 {
|
|
|
5893
5906
|
* `startWith(null)` seed makes `withLatestFrom` on this stream safe even
|
|
5894
5907
|
* before the first video stat arrives (common at data-channel-open).
|
|
5895
5908
|
*/
|
|
5896
|
-
this.selectedPair$ = this.videoService.videoStats$.pipe(map((s) => s.aggregatedStats.selectedPair ?? null), scan((acc, curr) => curr ?? acc, null), startWith(null));
|
|
5909
|
+
this.selectedPair$ = this.videoService.videoStats$.pipe(map$1((s) => s.aggregatedStats.selectedPair ?? null), scan((acc, curr) => curr ?? acc, null), startWith(null));
|
|
5897
5910
|
/**
|
|
5898
5911
|
* Correlation-matched Observable: emits once when the first `loopBack`
|
|
5899
5912
|
* command's corresponding `command completed` action fires. Built from
|
|
@@ -5963,7 +5976,7 @@ class StreamStatusTelemetryService2 {
|
|
|
5963
5976
|
// never ran or its cache expired.
|
|
5964
5977
|
{
|
|
5965
5978
|
id: 'region-resolved',
|
|
5966
|
-
event: this.actions$.pipe(ofType(regionResolved), take(1), map(({ region, pingsMs }) => ({
|
|
5979
|
+
event: this.actions$.pipe(ofType(regionResolved), take(1), map$1(({ region, pingsMs }) => ({
|
|
5967
5980
|
region,
|
|
5968
5981
|
pingsMs: pingsMs.length ? `${pingsMs.join(', ')} ms` : null,
|
|
5969
5982
|
}))),
|
|
@@ -6009,7 +6022,7 @@ class StreamStatusTelemetryService2 {
|
|
|
6009
6022
|
// is shipped under — see {@link SessionState.wireId}.
|
|
6010
6023
|
{
|
|
6011
6024
|
id: 'ssinfo-received',
|
|
6012
|
-
event: this.store.select(unrealFeature.selectSsData).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.store.select(unrealFeature.selectAwsInstance), this.store.select(selectCirrusConnectionId)), map(([ssData, aws, connectionId]) => ({
|
|
6025
|
+
event: this.store.select(unrealFeature.selectSsData).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.store.select(unrealFeature.selectAwsInstance), this.store.select(selectCirrusConnectionId)), map$1(([ssData, aws, connectionId]) => ({
|
|
6013
6026
|
client: aws.wsUrl,
|
|
6014
6027
|
instanceName: aws.instanceName,
|
|
6015
6028
|
...ssData,
|
|
@@ -6054,7 +6067,7 @@ class StreamStatusTelemetryService2 {
|
|
|
6054
6067
|
id: 'datachannel-connected',
|
|
6055
6068
|
event: this.store
|
|
6056
6069
|
.select(unrealFeature.selectDataChannelConnected)
|
|
6057
|
-
.pipe(filter$1(Boolean), take(1), map(() => ({
|
|
6070
|
+
.pipe(filter$1(Boolean), take(1), map$1(() => ({
|
|
6058
6071
|
iceCandidateCount: this.session?.iceCandidateCount ?? 0,
|
|
6059
6072
|
handshakeFlow: this.session?.handshakeFlow ?? null,
|
|
6060
6073
|
}))),
|
|
@@ -6086,7 +6099,7 @@ class StreamStatusTelemetryService2 {
|
|
|
6086
6099
|
// fired at Unreal before the viewport was ready.
|
|
6087
6100
|
{
|
|
6088
6101
|
id: 'viewport-ready',
|
|
6089
|
-
event: this.store.select(unrealFeature.selectViewportReady).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.selectedPair$), map(([, selectedPair]) => ({
|
|
6102
|
+
event: this.store.select(unrealFeature.selectViewportReady).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.selectedPair$), map$1(([, selectedPair]) => ({
|
|
6090
6103
|
localCandidate: fmtCandidate(selectedPair?.local),
|
|
6091
6104
|
remoteCandidate: fmtCandidate(selectedPair?.remote),
|
|
6092
6105
|
commandCount: this.session?.commandCount ?? 0,
|
|
@@ -6870,10 +6883,10 @@ class StreamStatusTelemetryService2 {
|
|
|
6870
6883
|
emit(event, data) {
|
|
6871
6884
|
this.store.dispatch(trackTelemetryData({ event, data }));
|
|
6872
6885
|
}
|
|
6873
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
6874
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
6886
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6887
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, providedIn: 'root' }); }
|
|
6875
6888
|
}
|
|
6876
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
6889
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, decorators: [{
|
|
6877
6890
|
type: Injectable,
|
|
6878
6891
|
args: [{ providedIn: 'root' }]
|
|
6879
6892
|
}], ctorParameters: () => [] });
|
|
@@ -7009,10 +7022,10 @@ class AnalyticsService extends SubService {
|
|
|
7009
7022
|
Logger.log('Analytics Event:', name, params);
|
|
7010
7023
|
this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
|
|
7011
7024
|
}
|
|
7012
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7013
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
7025
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7026
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
|
|
7014
7027
|
}
|
|
7015
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7028
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, decorators: [{
|
|
7016
7029
|
type: Injectable,
|
|
7017
7030
|
args: [{ providedIn: 'root' }]
|
|
7018
7031
|
}], ctorParameters: () => [] });
|
|
@@ -7379,10 +7392,10 @@ class FpsMonitorService extends SubService {
|
|
|
7379
7392
|
}
|
|
7380
7393
|
return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
|
|
7381
7394
|
}
|
|
7382
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7383
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
7395
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7396
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, providedIn: 'root' }); }
|
|
7384
7397
|
}
|
|
7385
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, decorators: [{
|
|
7386
7399
|
type: Injectable,
|
|
7387
7400
|
args: [{ providedIn: 'root' }]
|
|
7388
7401
|
}], ctorParameters: () => [] });
|
|
@@ -7396,19 +7409,34 @@ class AfkTimeoutModalComponent {
|
|
|
7396
7409
|
this.afkCountdown = this.#store.selectSignal(unrealFeature.selectAfkCountdown);
|
|
7397
7410
|
this.isShowAfkPopup = computed(() => this.isAfkTimerVisible() && this.showAfkTimeoutPopup(), /* @ts-ignore */
|
|
7398
7411
|
...(ngDevMode ? [{ debugName: "isShowAfkPopup" }] : /* istanbul ignore next */ []));
|
|
7412
|
+
this.uiClasses = input({}, /* @ts-ignore */
|
|
7413
|
+
...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
|
|
7414
|
+
this.contentTemplate = input(null, /* @ts-ignore */
|
|
7415
|
+
...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
|
|
7416
|
+
this.scrimSkin = computed(() => resolveSkin(this.uiClasses(), 'afkScrim', 'afk-scrim'), /* @ts-ignore */
|
|
7417
|
+
...(ngDevMode ? [{ debugName: "scrimSkin" }] : /* istanbul ignore next */ []));
|
|
7418
|
+
this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'afkCard', 'resume-box'), /* @ts-ignore */
|
|
7419
|
+
...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
|
|
7420
|
+
this.buttonSkin = computed(() => resolveSkin(this.uiClasses(), 'afkButton', 'afk-button'), /* @ts-ignore */
|
|
7421
|
+
...(ngDevMode ? [{ debugName: "buttonSkin" }] : /* istanbul ignore next */ []));
|
|
7422
|
+
// Created once: identity stays stable, reactivity lives in the signals.
|
|
7423
|
+
this.slotContext = {
|
|
7424
|
+
countdown: this.afkCountdown,
|
|
7425
|
+
reset: () => this.resetAfk(),
|
|
7426
|
+
};
|
|
7399
7427
|
}
|
|
7400
7428
|
#store;
|
|
7401
7429
|
#afkService;
|
|
7402
7430
|
resetAfk() {
|
|
7403
7431
|
this.#afkService.reset();
|
|
7404
7432
|
}
|
|
7405
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7406
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7433
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7434
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7407
7435
|
}
|
|
7408
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7436
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
|
|
7409
7437
|
type: Component,
|
|
7410
|
-
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "@if (isShowAfkPopup()) {\
|
|
7411
|
-
}] });
|
|
7438
|
+
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"] }]
|
|
7439
|
+
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
7412
7440
|
|
|
7413
7441
|
class FreezeFrameComponent {
|
|
7414
7442
|
constructor() {
|
|
@@ -7417,12 +7445,12 @@ class FreezeFrameComponent {
|
|
|
7417
7445
|
this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
|
|
7418
7446
|
}
|
|
7419
7447
|
#store;
|
|
7420
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7421
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7448
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7449
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: FreezeFrameComponent, isStandalone: true, selector: "app-freeze-frame", ngImport: i0, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7422
7450
|
}
|
|
7423
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7451
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameComponent, decorators: [{
|
|
7424
7452
|
type: Component,
|
|
7425
|
-
args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\
|
|
7453
|
+
args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"] }]
|
|
7426
7454
|
}] });
|
|
7427
7455
|
|
|
7428
7456
|
class ImageLoadingSrcComponent {
|
|
@@ -7435,12 +7463,12 @@ class ImageLoadingSrcComponent {
|
|
|
7435
7463
|
loadingImageError() {
|
|
7436
7464
|
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
7437
7465
|
}
|
|
7438
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7439
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7466
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7467
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7440
7468
|
}
|
|
7441
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7469
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
7442
7470
|
type: Component,
|
|
7443
|
-
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\
|
|
7471
|
+
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"] }]
|
|
7444
7472
|
}] });
|
|
7445
7473
|
|
|
7446
7474
|
class StatGraphComponent {
|
|
@@ -7521,17 +7549,60 @@ class StatGraphComponent {
|
|
|
7521
7549
|
}
|
|
7522
7550
|
this.draw();
|
|
7523
7551
|
}
|
|
7524
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7525
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.
|
|
7552
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7553
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.1", type: StatGraphComponent, isStandalone: true, selector: "app-stat-graph", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, stat: { classPropertyName: "stat", publicName: "stat", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tickStep: { classPropertyName: "tickStep", publicName: "tickStep", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "graph", first: true, predicate: ["graph"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7526
7554
|
}
|
|
7527
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7555
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StatGraphComponent, decorators: [{
|
|
7528
7556
|
type: Component,
|
|
7529
|
-
args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\
|
|
7557
|
+
args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"] }]
|
|
7530
7558
|
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], stat: [{ type: i0.Input, args: [{ isSignal: true, alias: "stat", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tickStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickStep", required: false }] }], graph: [{ type: i0.ViewChild, args: ['graph', { isSignal: true }] }], resize: [{
|
|
7531
7559
|
type: HostListener,
|
|
7532
7560
|
args: ['window:resize']
|
|
7533
7561
|
}] } });
|
|
7534
7562
|
|
|
7563
|
+
class UnrealResumeSlotDirective {
|
|
7564
|
+
constructor() {
|
|
7565
|
+
this.template = inject(TemplateRef);
|
|
7566
|
+
}
|
|
7567
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7568
|
+
return true;
|
|
7569
|
+
}
|
|
7570
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealResumeSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7571
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealResumeSlotDirective, isStandalone: true, selector: "ng-template[unrealResumeSlot]", ngImport: i0 }); }
|
|
7572
|
+
}
|
|
7573
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealResumeSlotDirective, decorators: [{
|
|
7574
|
+
type: Directive,
|
|
7575
|
+
args: [{ selector: 'ng-template[unrealResumeSlot]' }]
|
|
7576
|
+
}] });
|
|
7577
|
+
class UnrealAfkSlotDirective {
|
|
7578
|
+
constructor() {
|
|
7579
|
+
this.template = inject(TemplateRef);
|
|
7580
|
+
}
|
|
7581
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7582
|
+
return true;
|
|
7583
|
+
}
|
|
7584
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealAfkSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7585
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealAfkSlotDirective, isStandalone: true, selector: "ng-template[unrealAfkSlot]", ngImport: i0 }); }
|
|
7586
|
+
}
|
|
7587
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealAfkSlotDirective, decorators: [{
|
|
7588
|
+
type: Directive,
|
|
7589
|
+
args: [{ selector: 'ng-template[unrealAfkSlot]' }]
|
|
7590
|
+
}] });
|
|
7591
|
+
class UnrealStatusSlotDirective {
|
|
7592
|
+
constructor() {
|
|
7593
|
+
this.template = inject(TemplateRef);
|
|
7594
|
+
}
|
|
7595
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7596
|
+
return true;
|
|
7597
|
+
}
|
|
7598
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7599
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealStatusSlotDirective, isStandalone: true, selector: "ng-template[unrealStatusSlot]", ngImport: i0 }); }
|
|
7600
|
+
}
|
|
7601
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusSlotDirective, decorators: [{
|
|
7602
|
+
type: Directive,
|
|
7603
|
+
args: [{ selector: 'ng-template[unrealStatusSlot]' }]
|
|
7604
|
+
}] });
|
|
7605
|
+
|
|
7535
7606
|
class UnrealSpinnerComponent {
|
|
7536
7607
|
constructor() {
|
|
7537
7608
|
this.size = input(32, /* @ts-ignore */
|
|
@@ -7550,12 +7621,12 @@ class UnrealSpinnerComponent {
|
|
|
7550
7621
|
this.viewBox = computed(() => `0 0 ${this.size()} ${this.size()}`, /* @ts-ignore */
|
|
7551
7622
|
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
7552
7623
|
}
|
|
7553
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7554
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
7624
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7625
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: UnrealSpinnerComponent, isStandalone: true, selector: "app-unreal-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7555
7626
|
}
|
|
7556
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7627
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSpinnerComponent, decorators: [{
|
|
7557
7628
|
type: Component,
|
|
7558
|
-
args: [{ selector: 'app-unreal-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\
|
|
7629
|
+
args: [{ selector: 'app-unreal-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"] }]
|
|
7559
7630
|
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], strokeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeColor", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
7560
7631
|
|
|
7561
7632
|
class UnrealStatusComponent {
|
|
@@ -7568,16 +7639,29 @@ class UnrealStatusComponent {
|
|
|
7568
7639
|
this.showLoadingProgress = this.#store.selectSignal(unrealFeature.selectShowLoadingProgress);
|
|
7569
7640
|
this.isShowLoadingPercentsPopup = computed(() => this.showLoader() && this.showLoadingProgress(), /* @ts-ignore */
|
|
7570
7641
|
...(ngDevMode ? [{ debugName: "isShowLoadingPercentsPopup" }] : /* istanbul ignore next */ []));
|
|
7642
|
+
this.uiClasses = input({}, /* @ts-ignore */
|
|
7643
|
+
...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
|
|
7644
|
+
this.contentTemplate = input(null, /* @ts-ignore */
|
|
7645
|
+
...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
|
|
7646
|
+
this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'statusCard', 'status-box'), /* @ts-ignore */
|
|
7647
|
+
...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
|
|
7648
|
+
this.messageSkin = computed(() => resolveSkin(this.uiClasses(), 'statusMessage', 'status-box__message'), /* @ts-ignore */
|
|
7649
|
+
...(ngDevMode ? [{ debugName: "messageSkin" }] : /* istanbul ignore next */ []));
|
|
7650
|
+
// Created once: identity stays stable, reactivity lives in the signals.
|
|
7651
|
+
this.slotContext = {
|
|
7652
|
+
percents: this.smoothPercents,
|
|
7653
|
+
message: computed(() => this.awsInstance()?.message),
|
|
7654
|
+
};
|
|
7571
7655
|
}
|
|
7572
7656
|
#store;
|
|
7573
7657
|
#loadingProgress;
|
|
7574
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7575
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7658
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7659
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"], dependencies: [{ kind: "component", type: UnrealSpinnerComponent, selector: "app-unreal-spinner", inputs: ["size", "strokeWidth", "strokeColor", "data-testid", "ariaLabel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7576
7660
|
}
|
|
7577
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7661
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
7578
7662
|
type: Component,
|
|
7579
|
-
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealSpinnerComponent], template: "@if (isShowLoadingPercentsPopup()) {\
|
|
7580
|
-
}] });
|
|
7663
|
+
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealSpinnerComponent, NgTemplateOutlet], template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"] }]
|
|
7664
|
+
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
7581
7665
|
|
|
7582
7666
|
class SafePipe {
|
|
7583
7667
|
constructor() {
|
|
@@ -7607,10 +7691,10 @@ class SafePipe {
|
|
|
7607
7691
|
// content instead of disabling framework security checks.
|
|
7608
7692
|
return (this.sanitizer.sanitize(context, value) ?? '');
|
|
7609
7693
|
}
|
|
7610
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7611
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.
|
|
7694
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
7695
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
|
|
7612
7696
|
}
|
|
7613
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7697
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, decorators: [{
|
|
7614
7698
|
type: Pipe,
|
|
7615
7699
|
args: [{
|
|
7616
7700
|
name: 'safe',
|
|
@@ -7723,18 +7807,28 @@ class VideoStatsComponent {
|
|
|
7723
7807
|
elements: this.elementsToShow(),
|
|
7724
7808
|
}));
|
|
7725
7809
|
}
|
|
7726
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7727
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7810
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7811
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"], dependencies: [{ kind: "component", type: StatGraphComponent, selector: "app-stat-graph", inputs: ["label", "stat", "color", "tickStep"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7728
7812
|
}
|
|
7729
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7813
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
7730
7814
|
type: Component,
|
|
7731
|
-
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\
|
|
7815
|
+
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"] }]
|
|
7732
7816
|
}], ctorParameters: () => [] });
|
|
7733
7817
|
|
|
7734
7818
|
class ResumeStreamButtonComponent {
|
|
7735
7819
|
#store;
|
|
7736
7820
|
constructor() {
|
|
7737
7821
|
this.#store = inject(Store);
|
|
7822
|
+
this.uiClasses = input({}, /* @ts-ignore */
|
|
7823
|
+
...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
|
|
7824
|
+
this.contentTemplate = input(null, /* @ts-ignore */
|
|
7825
|
+
...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
|
|
7826
|
+
this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeCard', 'resume-box'), /* @ts-ignore */
|
|
7827
|
+
...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
|
|
7828
|
+
this.textSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeText', 'resume-box__text'), /* @ts-ignore */
|
|
7829
|
+
...(ngDevMode ? [{ debugName: "textSkin" }] : /* istanbul ignore next */ []));
|
|
7830
|
+
this.buttonSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeButton', 'connect-button'), /* @ts-ignore */
|
|
7831
|
+
...(ngDevMode ? [{ debugName: "buttonSkin" }] : /* istanbul ignore next */ []));
|
|
7738
7832
|
this.streamConfig = this.#store.selectSignal(selectStreamConfig);
|
|
7739
7833
|
this.isSecondStart = signal(this.streamConfig()?.autoStart && location.protocol === 'https:', /* @ts-ignore */
|
|
7740
7834
|
...(ngDevMode ? [{ debugName: "isSecondStart" }] : /* istanbul ignore next */ []));
|
|
@@ -7755,6 +7849,14 @@ class ResumeStreamButtonComponent {
|
|
|
7755
7849
|
}, /* @ts-ignore */
|
|
7756
7850
|
...(ngDevMode ? [{ debugName: "isAfkDisconnect" }] : /* istanbul ignore next */ []));
|
|
7757
7851
|
this.cirrusConnected = this.#store.selectSignal(unrealFeature.selectCirrusConnected);
|
|
7852
|
+
// Created once: the object identity must stay stable, reactivity lives in the
|
|
7853
|
+
// signals it carries. Declared after the signals it references so field
|
|
7854
|
+
// initialisation order holds.
|
|
7855
|
+
this.slotContext = {
|
|
7856
|
+
isSecondStart: this.isSecondStart,
|
|
7857
|
+
isAfkDisconnect: this.isAfkDisconnect,
|
|
7858
|
+
start: () => this.connect(),
|
|
7859
|
+
};
|
|
7758
7860
|
let wasConnected = this.cirrusConnected();
|
|
7759
7861
|
effect(() => {
|
|
7760
7862
|
const connected = this.cirrusConnected();
|
|
@@ -7770,13 +7872,13 @@ class ResumeStreamButtonComponent {
|
|
|
7770
7872
|
disconnect() {
|
|
7771
7873
|
this.isSecondStart.set(true);
|
|
7772
7874
|
}
|
|
7773
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7774
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7875
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7876
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7775
7877
|
}
|
|
7776
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7878
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
7777
7879
|
type: Component,
|
|
7778
|
-
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "@if (isShowResumeButton()) {\
|
|
7779
|
-
}], ctorParameters: () => [] });
|
|
7880
|
+
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"] }]
|
|
7881
|
+
}], ctorParameters: () => [], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
7780
7882
|
|
|
7781
7883
|
class IntroSrcComponent {
|
|
7782
7884
|
#store;
|
|
@@ -7840,12 +7942,12 @@ class IntroSrcComponent {
|
|
|
7840
7942
|
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
7841
7943
|
videoContainer.appendChild(videoElement);
|
|
7842
7944
|
}
|
|
7843
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7844
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
7945
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7946
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7845
7947
|
}
|
|
7846
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7948
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
7847
7949
|
type: Component,
|
|
7848
|
-
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\
|
|
7950
|
+
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"] }]
|
|
7849
7951
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
7850
7952
|
|
|
7851
7953
|
class UnrealSceneComponent {
|
|
@@ -7879,6 +7981,15 @@ class UnrealSceneComponent {
|
|
|
7879
7981
|
}, /* @ts-ignore */
|
|
7880
7982
|
...(ngDevMode ? [{ debugName: "resolutionSize" }] : /* istanbul ignore next */ []));
|
|
7881
7983
|
this.changeMouseOverScene = output();
|
|
7984
|
+
/** Host classes replacing the built-in decoration of the scene overlays. */
|
|
7985
|
+
this.uiClasses = input({}, /* @ts-ignore */
|
|
7986
|
+
...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
|
|
7987
|
+
this.resumeSlot = contentChild(UnrealResumeSlotDirective, /* @ts-ignore */
|
|
7988
|
+
...(ngDevMode ? [{ debugName: "resumeSlot" }] : /* istanbul ignore next */ []));
|
|
7989
|
+
this.afkSlot = contentChild(UnrealAfkSlotDirective, /* @ts-ignore */
|
|
7990
|
+
...(ngDevMode ? [{ debugName: "afkSlot" }] : /* istanbul ignore next */ []));
|
|
7991
|
+
this.statusSlot = contentChild(UnrealStatusSlotDirective, /* @ts-ignore */
|
|
7992
|
+
...(ngDevMode ? [{ debugName: "statusSlot" }] : /* istanbul ignore next */ []));
|
|
7882
7993
|
this.videoElement = viewChild('videoContainer', /* @ts-ignore */
|
|
7883
7994
|
...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
|
|
7884
7995
|
this.resolutionValues$ = toObservable(this.resolutionSize);
|
|
@@ -7976,7 +8087,7 @@ class UnrealSceneComponent {
|
|
|
7976
8087
|
this.height = height;
|
|
7977
8088
|
}));
|
|
7978
8089
|
const resizeRequired$ = merge(this.actions$.pipe(ofType(videoStreamInitialized)), fromEvent(window, 'resize'));
|
|
7979
|
-
const videoStreamSizeChanged$ = this.videoService.videoStats$.pipe(filter(() => !this.isFreezeFrameLoading()), map
|
|
8090
|
+
const videoStreamSizeChanged$ = this.videoService.videoStats$.pipe(filter(() => !this.isFreezeFrameLoading()), map((stats) => ({
|
|
7980
8091
|
w: stats.aggregatedStats.frameWidth || 0,
|
|
7981
8092
|
h: stats.aggregatedStats.frameHeight || 0,
|
|
7982
8093
|
})), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
|
|
@@ -7985,8 +8096,8 @@ class UnrealSceneComponent {
|
|
|
7985
8096
|
.pipe(debounceTime(DEBOUNCE_TO_MANY_RESIZE_CALLS), switchMap(() => {
|
|
7986
8097
|
const key = Math.random();
|
|
7987
8098
|
// Poll 3 times to capture late-arriving DOM measurements after layout settles
|
|
7988
|
-
return timer(0, 300).pipe(take(3), map
|
|
7989
|
-
}), map
|
|
8099
|
+
return timer(0, 300).pipe(take(3), map(() => key));
|
|
8100
|
+
}), map((key) => ({ key, ...this.resizeValues })), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
|
|
7990
8101
|
fpIsASameAsB(previous.h, current.h, SAME_SIZE_THRESHOLD) &&
|
|
7991
8102
|
previous.key === current.key), tap((size) => this.adaptVideo(size)),
|
|
7992
8103
|
// Key excluded: only dispatch when actual pixel dimensions change
|
|
@@ -8065,10 +8176,10 @@ class UnrealSceneComponent {
|
|
|
8065
8176
|
},
|
|
8066
8177
|
});
|
|
8067
8178
|
}
|
|
8068
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8069
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer id=\"player\"></div>\r\n\r\n <app-intro-src />\r\n <app-image-loading-src />\r\n <app-resume-stream-button />\r\n <app-unreal-status />\r\n <app-freeze-frame />\r\n <app-afk-timeout-modal />\r\n\r\n <ng-content select=\"app-pdf\"></ng-content>\r\n <ng-content select=\"app-show-case\"></ng-content>\r\n\r\n @if (isDevMode) {\r\n <app-video-stats />\r\n }\r\n</div>\r\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0D%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal" }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status" }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button" }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8179
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8180
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null }, uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, queries: [{ propertyName: "resumeSlot", first: true, predicate: UnrealResumeSlotDirective, descendants: true, isSignal: true }, { propertyName: "afkSlot", first: true, predicate: UnrealAfkSlotDirective, descendants: true, isSignal: true }, { propertyName: "statusSlot", first: true, predicate: UnrealStatusSlotDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8070
8181
|
}
|
|
8071
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
8072
8183
|
type: Component,
|
|
8073
8184
|
args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
8074
8185
|
AfkTimeoutModalComponent,
|
|
@@ -8078,8 +8189,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
8078
8189
|
ResumeStreamButtonComponent,
|
|
8079
8190
|
ImageLoadingSrcComponent,
|
|
8080
8191
|
IntroSrcComponent,
|
|
8081
|
-
], template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer id=\"player\"></div>\r\n\r\n <app-intro-src />\r\n <app-image-loading-src />\r\n <app-resume-stream-button />\r\n <app-unreal-status />\r\n <app-freeze-frame />\r\n <app-afk-timeout-modal />\r\n\r\n <ng-content select=\"app-pdf\"></ng-content>\r\n <ng-content select=\"app-show-case\"></ng-content>\r\n\r\n @if (isDevMode) {\r\n <app-video-stats />\r\n }\r\n</div>\r\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0D%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"] }]
|
|
8082
|
-
}], ctorParameters: () => [], propDecorators: { useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], resolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutionSize", required: false }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], onMouseOver: [{
|
|
8192
|
+
], template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"] }]
|
|
8193
|
+
}], ctorParameters: () => [], propDecorators: { useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], resolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutionSize", required: false }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], resumeSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealResumeSlotDirective), { isSignal: true }] }], afkSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealAfkSlotDirective), { isSignal: true }] }], statusSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealStatusSlotDirective), { isSignal: true }] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], onMouseOver: [{
|
|
8083
8194
|
type: HostListener,
|
|
8084
8195
|
args: ['mouseover']
|
|
8085
8196
|
}], onMouseOut: [{
|
|
@@ -8138,5 +8249,5 @@ function provideUnrealModule() {
|
|
|
8138
8249
|
* Generated bundle index. Do not edit.
|
|
8139
8250
|
*/
|
|
8140
8251
|
|
|
8141
|
-
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, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, 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, StreamAdoptionService, 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, isMetaboxMode, 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, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
8252
|
+
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, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, 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, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, 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, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, 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, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
8142
8253
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|