@3dsource/angular-unreal-module 0.0.108 → 0.0.110
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 +369 -369
- package/fesm2022/3dsource-angular-unreal-module.mjs +528 -915
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +1 -1
- package/types/3dsource-angular-unreal-module.d.ts +13 -59
- package/types/3dsource-angular-unreal-module.d.ts.map +0 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, ChangeDetectionStrategy, Component, Injectable, DestroyRef, signal, Pipe, input, ElementRef, viewChild,
|
|
2
|
+
import { InjectionToken, inject, ChangeDetectionStrategy, Component, Injectable, DestroyRef, effect, untracked, signal, Pipe, input, ElementRef, viewChild, afterNextRender, HostListener, computed, output, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
|
|
3
3
|
import { SourceButtonComponent, SourceLoadingComponent } from '@3dsource/source-ui-native';
|
|
4
|
-
import { map as map$1, distinctUntilChanged, takeWhile, filter, tap, withLatestFrom, exhaustMap, catchError, takeUntil, switchMap as switchMap$1, timeout as timeout$1, debounceTime as debounceTime$1, delay, skip as skip$1 } from 'rxjs/operators';
|
|
5
|
-
import { Logger, calculateMedian, clampf, lerp, getCanvasCached, getSnapshot, fitIntoRectangle, whereNot, Truthy, Falsy, tapLog, generateUuid, COLOR_CODES, where, KeyboardNumericCode, InvertedKeyMap, Semaphore, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
6
4
|
import { merge, map, scan, concatMap, of, animationFrameScheduler, interval, Observable, debounceTime, switchMap, take, fromEvent, EMPTY, timer, timeout, mergeMap, Subject, skip, share, from, throwError, defer, retry, tap as tap$1, startWith, takeUntil as takeUntil$1, auditTime, filter as filter$1, throttleTime, BehaviorSubject, combineLatestWith, distinctUntilChanged as distinctUntilChanged$1, concat } from 'rxjs';
|
|
7
5
|
import { createAction, props, createReducer, on, createFeature, createSelector, Store, provideState } from '@ngrx/store';
|
|
8
6
|
import { Actions, createEffect, ofType, provideEffects } from '@ngrx/effects';
|
|
7
|
+
import { map as map$1, distinctUntilChanged, takeWhile, filter, tap, withLatestFrom, exhaustMap, catchError, takeUntil, switchMap as switchMap$1, timeout as timeout$1, debounceTime as debounceTime$1, delay, skip as skip$1 } from 'rxjs/operators';
|
|
8
|
+
import { Logger, calculateMedian, clampf, lerp, getCanvasCached, getSnapshot, fitIntoRectangle, whereNot, Truthy, Falsy, tapLog, generateUuid, COLOR_CODES, where, KeyboardNumericCode, InvertedKeyMap, Semaphore, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
9
9
|
import { concatLatestFrom } from '@ngrx/operators';
|
|
10
10
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
11
11
|
import { HttpClient } from '@angular/common/http';
|
|
12
12
|
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
13
|
-
import { MetaBoxCommand } from '@3dsource/types-unreal';
|
|
13
|
+
import { MetaBoxCommand, EPayloadVersion } from '@3dsource/types-unreal';
|
|
14
|
+
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
14
15
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
15
16
|
import { NgOptimizedImage, AsyncPipe, JsonPipe } from '@angular/common';
|
|
16
|
-
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
17
17
|
import * as i1 from '@angular/forms';
|
|
18
18
|
import { FormsModule } from '@angular/forms';
|
|
19
19
|
|
|
@@ -1179,12 +1179,12 @@ class UnrealErrorModalComponent {
|
|
|
1179
1179
|
close() {
|
|
1180
1180
|
this.#dialogRef.close();
|
|
1181
1181
|
}
|
|
1182
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1183
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
1182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1183
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"src-modal src-modal--small\">\n <header class=\"src-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"src-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"src-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"src-modal__footer\">\n <src-button (onClick)=\"close()\">Ok</src-button>\n </div>\n</div>\n", styles: [".src-modal__header{padding:16px 24px 0}\n"], dependencies: [{ kind: "component", type: SourceButtonComponent, selector: "src-button", inputs: ["type", "appearance", "weight", "size", "context", "customClass", "isFullWidth", "isPressed", "isDisabled", "isLoading", "isInverted", "srcButtonConfig", "formID", "data-testid", "ariaLabel"], outputs: ["onClick", "onSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1184
1184
|
}
|
|
1185
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
|
|
1186
1186
|
type: Component,
|
|
1187
|
-
args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "<div class=\"src-modal src-modal--small\">\
|
|
1187
|
+
args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "<div class=\"src-modal src-modal--small\">\n <header class=\"src-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"src-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"src-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"src-modal__footer\">\n <src-button (onClick)=\"close()\">Ok</src-button>\n </div>\n</div>\n", styles: [".src-modal__header{padding:16px 24px 0}\n"] }]
|
|
1188
1188
|
}] });
|
|
1189
1189
|
|
|
1190
1190
|
/**
|
|
@@ -1568,10 +1568,10 @@ class UnrealEffects {
|
|
|
1568
1568
|
}));
|
|
1569
1569
|
}, { dispatch: false });
|
|
1570
1570
|
}
|
|
1571
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1572
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1571
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1572
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealEffects }); }
|
|
1573
1573
|
}
|
|
1574
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1574
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealEffects, decorators: [{
|
|
1575
1575
|
type: Injectable
|
|
1576
1576
|
}] });
|
|
1577
1577
|
|
|
@@ -1585,10 +1585,10 @@ class CommandsEffects {
|
|
|
1585
1585
|
: json?.correlationId), filter(Truthy), map((id) => commandCompleted({ id })))));
|
|
1586
1586
|
});
|
|
1587
1587
|
}
|
|
1588
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1589
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1588
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandsEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1589
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandsEffects }); }
|
|
1590
1590
|
}
|
|
1591
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1591
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandsEffects, decorators: [{
|
|
1592
1592
|
type: Injectable
|
|
1593
1593
|
}] });
|
|
1594
1594
|
|
|
@@ -1611,29 +1611,42 @@ class SubService {
|
|
|
1611
1611
|
class AFKService extends SubService {
|
|
1612
1612
|
constructor() {
|
|
1613
1613
|
super();
|
|
1614
|
-
// Optionally detect if the user is not interacting (AFK) and disconnect them.
|
|
1615
|
-
this.enabled = true; // Set to true to enable the AFK system.
|
|
1616
|
-
this.closeTimeout = DEFAULT_AFK_TIMEOUT_PERIOD; // The time after the warning when we disconnect the user.
|
|
1617
1614
|
this.active = false; // Whether the AFK system is currently looking for inactivity.
|
|
1618
1615
|
this.countdown = 0; // The inactivity warning overlay has a countdown to show time until disconnect.
|
|
1619
|
-
this.
|
|
1616
|
+
this.warnTimeout = this.store.selectSignal(selectWarnTimeout);
|
|
1620
1617
|
this.isViewportReady = this.store.selectSignal(unrealFeature.selectViewportReady);
|
|
1621
1618
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
1619
|
+
/** Ticks every time warnTimeout changes or resetAfk action fires */
|
|
1620
|
+
this.afkResetTrigger = toSignal(merge(this.store.select(selectWarnTimeout), this.actions$.pipe(ofType(resetAfk))));
|
|
1621
|
+
/** Ticks when cirrus disconnects */
|
|
1622
|
+
this.disconnected = toSignal(this.disconnect$);
|
|
1622
1623
|
this.destroyRef.onDestroy(() => this.clearTimers());
|
|
1623
|
-
this.init();
|
|
1624
|
-
}
|
|
1625
|
-
init() {
|
|
1626
1624
|
if (this.unrealConfig?.playwright) {
|
|
1627
1625
|
return;
|
|
1628
1626
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1627
|
+
// Reset AFK warning timer when warnTimeout changes or resetAfk action fires
|
|
1628
|
+
effect(() => {
|
|
1629
|
+
this.afkResetTrigger();
|
|
1630
|
+
untracked(() => {
|
|
1631
|
+
if (this.isViewportReady()) {
|
|
1632
|
+
this.resetAfkWarningTimer();
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
});
|
|
1636
|
+
// Start AFK warning timer when viewport becomes ready
|
|
1637
|
+
effect(() => {
|
|
1638
|
+
const ready = this.isViewportReady();
|
|
1639
|
+
if (ready) {
|
|
1640
|
+
untracked(() => this.startAfkWarningTimer());
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
// Stop on disconnect
|
|
1644
|
+
effect(() => {
|
|
1645
|
+
const disconnected = this.disconnected();
|
|
1646
|
+
if (disconnected !== undefined) {
|
|
1647
|
+
untracked(() => this.stop());
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1637
1650
|
}
|
|
1638
1651
|
hideOverlay() {
|
|
1639
1652
|
this.store.dispatch(setAfkTimerHide());
|
|
@@ -1642,7 +1655,7 @@ class AFKService extends SubService {
|
|
|
1642
1655
|
* Start a timer which when elapsed will warn the user they are inactive.
|
|
1643
1656
|
*/
|
|
1644
1657
|
startAfkWarningTimer() {
|
|
1645
|
-
this.active =
|
|
1658
|
+
this.active = true;
|
|
1646
1659
|
this.resetAfkWarningTimer();
|
|
1647
1660
|
}
|
|
1648
1661
|
/**
|
|
@@ -1653,7 +1666,7 @@ class AFKService extends SubService {
|
|
|
1653
1666
|
this.clearTimers();
|
|
1654
1667
|
this.warnTimer = setTimeout(() => {
|
|
1655
1668
|
this.showAfkOverlay();
|
|
1656
|
-
}, (this.
|
|
1669
|
+
}, (this.warnTimeout() || DEFAULT_AFK_TIMEOUT) * 1000);
|
|
1657
1670
|
}
|
|
1658
1671
|
}
|
|
1659
1672
|
/**
|
|
@@ -1682,7 +1695,7 @@ class AFKService extends SubService {
|
|
|
1682
1695
|
}
|
|
1683
1696
|
// Pause the timer while the user is looking at the inactivity warning overlay.
|
|
1684
1697
|
this.active = false;
|
|
1685
|
-
this.countdown =
|
|
1698
|
+
this.countdown = DEFAULT_AFK_TIMEOUT_PERIOD;
|
|
1686
1699
|
this.store.dispatch(setAfkTimerVisible());
|
|
1687
1700
|
this.updateCountDown(this.countdown);
|
|
1688
1701
|
if (InputOptions.controlScheme === ControlScheme.LockedMouse) {
|
|
@@ -1695,7 +1708,7 @@ class AFKService extends SubService {
|
|
|
1695
1708
|
this.hideOverlay();
|
|
1696
1709
|
this.store.dispatch(disconnectStream({
|
|
1697
1710
|
reason: DisconnectReason.Afk,
|
|
1698
|
-
message: `AFK timeout:${this.
|
|
1711
|
+
message: `AFK timeout:${this.warnTimeout()} seconds, popup timeout:${DEFAULT_AFK_TIMEOUT_PERIOD} seconds`,
|
|
1699
1712
|
}));
|
|
1700
1713
|
clearInterval(this.countdownTimer);
|
|
1701
1714
|
}
|
|
@@ -1704,10 +1717,10 @@ class AFKService extends SubService {
|
|
|
1704
1717
|
}
|
|
1705
1718
|
}, 1000);
|
|
1706
1719
|
}
|
|
1707
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1708
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1720
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1721
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AFKService }); }
|
|
1709
1722
|
}
|
|
1710
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1723
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AFKService, decorators: [{
|
|
1711
1724
|
type: Injectable
|
|
1712
1725
|
}], ctorParameters: () => [] });
|
|
1713
1726
|
|
|
@@ -1795,10 +1808,10 @@ class FreezeFrameService extends SubService {
|
|
|
1795
1808
|
progress: 1,
|
|
1796
1809
|
}));
|
|
1797
1810
|
}
|
|
1798
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1799
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1811
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1812
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FreezeFrameService }); }
|
|
1800
1813
|
}
|
|
1801
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1814
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FreezeFrameService, decorators: [{
|
|
1802
1815
|
type: Injectable
|
|
1803
1816
|
}], ctorParameters: () => [] });
|
|
1804
1817
|
|
|
@@ -2074,10 +2087,10 @@ class VideoService extends SubService {
|
|
|
2074
2087
|
error: () => ({}),
|
|
2075
2088
|
});
|
|
2076
2089
|
}
|
|
2077
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2078
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
2090
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: VideoService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2091
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: VideoService }); }
|
|
2079
2092
|
}
|
|
2080
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2093
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: VideoService, decorators: [{
|
|
2081
2094
|
type: Injectable
|
|
2082
2095
|
}] });
|
|
2083
2096
|
|
|
@@ -2283,10 +2296,10 @@ class CommandTelemetryService {
|
|
|
2283
2296
|
this.trackTime(out);
|
|
2284
2297
|
funcToDecorate(out);
|
|
2285
2298
|
}
|
|
2286
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2287
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
2299
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2300
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandTelemetryService }); }
|
|
2288
2301
|
}
|
|
2289
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2302
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CommandTelemetryService, decorators: [{
|
|
2290
2303
|
type: Injectable
|
|
2291
2304
|
}], ctorParameters: () => [] });
|
|
2292
2305
|
|
|
@@ -2860,10 +2873,10 @@ class SignallingService extends SubService {
|
|
|
2860
2873
|
Logger.log('Start Getting Region');
|
|
2861
2874
|
return this.regionsPingService.getFastest().pipe(take(1));
|
|
2862
2875
|
}
|
|
2863
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2864
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
2876
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2877
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: SignallingService }); }
|
|
2865
2878
|
}
|
|
2866
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2879
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: SignallingService, decorators: [{
|
|
2867
2880
|
type: Injectable
|
|
2868
2881
|
}], ctorParameters: () => [] });
|
|
2869
2882
|
|
|
@@ -2878,103 +2891,243 @@ class WebRtcPlayerService extends SubService {
|
|
|
2878
2891
|
this.useMic = false;
|
|
2879
2892
|
this.forceTURN = false;
|
|
2880
2893
|
this.forceMonoAudio = false;
|
|
2894
|
+
/** Whether the remote SDP has been applied to the current peer connection */
|
|
2895
|
+
this.remoteDescriptionSet = false;
|
|
2896
|
+
/** ICE candidates received before the remote description was set */
|
|
2897
|
+
this.iceCandidateBuffer = [];
|
|
2881
2898
|
this.isReconnecting = this.store.selectSignal(unrealFeature.selectIsReconnecting);
|
|
2882
2899
|
this.init();
|
|
2883
2900
|
this.actions$.pipe(ofType(dropDC)).subscribe(() => this.dcClient?.close());
|
|
2884
2901
|
this.actions$.pipe(ofType(dropPC)).subscribe(() => this.pcClient?.close());
|
|
2885
2902
|
}
|
|
2886
2903
|
init() {
|
|
2887
|
-
const iceCandidateBuffer = [];
|
|
2888
|
-
const processBuffer = () => {
|
|
2889
|
-
iceCandidateBuffer.forEach((cnd) => {
|
|
2890
|
-
this.handleCandidateFromServer(cnd);
|
|
2891
|
-
});
|
|
2892
|
-
iceCandidateBuffer.length = 0;
|
|
2893
|
-
};
|
|
2894
2904
|
this.signallingSrv.onConfig$.subscribe((config) => {
|
|
2895
2905
|
this.videoService.create();
|
|
2896
2906
|
this.setConfig(config);
|
|
2897
2907
|
});
|
|
2908
|
+
// Server-initiated offer: set remote description and respond with answer
|
|
2909
|
+
this.signallingSrv.onOffer$.pipe(filter(Truthy)).subscribe((offer) => {
|
|
2910
|
+
void this.handleServerOffer(offer);
|
|
2911
|
+
});
|
|
2912
|
+
// Answer to a client-initiated offer
|
|
2898
2913
|
this.signallingSrv.onWebRtcAnswer$
|
|
2899
2914
|
.pipe(filter(Truthy))
|
|
2900
2915
|
.subscribe((answer) => {
|
|
2901
|
-
this.
|
|
2902
|
-
processBuffer();
|
|
2903
|
-
});
|
|
2904
|
-
this.signallingSrv.onOffer$.pipe(filter(Truthy)).subscribe(() => {
|
|
2905
|
-
void this.createWebRtcOffer();
|
|
2916
|
+
void this.handleServerAnswer(answer);
|
|
2906
2917
|
});
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
.
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
if (
|
|
2913
|
-
|
|
2918
|
+
// ICE candidates — buffered until remote description is set
|
|
2919
|
+
this.signallingSrv.onWebRtcIce$.subscribe((candidate) => {
|
|
2920
|
+
this.commandTelemetryService.trackStopCommand('EXT-iceCandidate', true, {
|
|
2921
|
+
multi: true,
|
|
2922
|
+
});
|
|
2923
|
+
if (this.remoteDescriptionSet) {
|
|
2924
|
+
this.handleCandidateFromServer(candidate);
|
|
2925
|
+
}
|
|
2926
|
+
else {
|
|
2927
|
+
this.iceCandidateBuffer.push(candidate);
|
|
2914
2928
|
}
|
|
2915
2929
|
});
|
|
2916
2930
|
}
|
|
2931
|
+
/**
|
|
2932
|
+
* Handles an SDP offer received from the server.
|
|
2933
|
+
* Creates a new peer connection, applies the remote offer,
|
|
2934
|
+
* then responds with an SDP answer.
|
|
2935
|
+
*
|
|
2936
|
+
* The DataChannel is NOT created here — the server creates it,
|
|
2937
|
+
* and we receive it via the `datachannel` event on the peer connection.
|
|
2938
|
+
*/
|
|
2939
|
+
async handleServerOffer(offer) {
|
|
2940
|
+
Logger.info('Received offer from server, creating answer');
|
|
2941
|
+
try {
|
|
2942
|
+
this.remoteDescriptionSet = false;
|
|
2943
|
+
this.iceCandidateBuffer.length = 0;
|
|
2944
|
+
if (!this.pcClient) {
|
|
2945
|
+
this.setupPeerConnection(this.cfg);
|
|
2946
|
+
}
|
|
2947
|
+
// Offer already defines media transceivers — don't add extras
|
|
2948
|
+
await this.pcClient?.setRemoteDescription(offer);
|
|
2949
|
+
this.remoteDescriptionSet = true;
|
|
2950
|
+
this.flushIceCandidateBuffer();
|
|
2951
|
+
await this.createAnswer(this.pcClient);
|
|
2952
|
+
}
|
|
2953
|
+
catch (e) {
|
|
2954
|
+
Logger.error('Failed to handle server offer', e);
|
|
2955
|
+
this.store.dispatch(disconnectStream({
|
|
2956
|
+
reason: DisconnectReason.WebRTCError,
|
|
2957
|
+
message: 'WebRTCError: Failed to handle server offer',
|
|
2958
|
+
}));
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Handles an SDP answer received from the server in response to our offer.
|
|
2963
|
+
* Applies the remote description and flushes any buffered ICE candidates.
|
|
2964
|
+
*/
|
|
2965
|
+
async handleServerAnswer(answer) {
|
|
2966
|
+
Logger.info('Received answer from server');
|
|
2967
|
+
try {
|
|
2968
|
+
await this.pcClient?.setRemoteDescription(answer);
|
|
2969
|
+
this.remoteDescriptionSet = true;
|
|
2970
|
+
this.flushIceCandidateBuffer();
|
|
2971
|
+
}
|
|
2972
|
+
catch (e) {
|
|
2973
|
+
Logger.error('Failed to set remote description from answer', e);
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
/** Drains buffered ICE candidates after the remote description has been set */
|
|
2977
|
+
flushIceCandidateBuffer() {
|
|
2978
|
+
for (const candidate of this.iceCandidateBuffer) {
|
|
2979
|
+
this.handleCandidateFromServer(candidate);
|
|
2980
|
+
}
|
|
2981
|
+
this.iceCandidateBuffer.length = 0;
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Creates a client-initiated WebRTC offer and sends it to the server.
|
|
2985
|
+
* When the client offers, it also creates the DataChannel.
|
|
2986
|
+
* Used for peer reconnection through the existing signaling connection.
|
|
2987
|
+
*/
|
|
2917
2988
|
async createWebRtcOffer() {
|
|
2918
|
-
Logger.info('Creating offer');
|
|
2919
|
-
let offer;
|
|
2989
|
+
Logger.info('Creating client-initiated offer');
|
|
2920
2990
|
try {
|
|
2921
|
-
|
|
2991
|
+
this.remoteDescriptionSet = false;
|
|
2992
|
+
this.iceCandidateBuffer.length = 0;
|
|
2993
|
+
if (!this.pcClient) {
|
|
2994
|
+
this.setupPeerConnection(this.cfg);
|
|
2995
|
+
}
|
|
2996
|
+
// Client offers: transceivers first, then DC, then offer
|
|
2997
|
+
await this.setupTransceiversAsync(this.pcClient);
|
|
2998
|
+
this.dcClient = this.createDataChannel(this.pcClient, 'UnrealDcConnection', { ordered: true });
|
|
2999
|
+
await this.createOffer(this.pcClient);
|
|
2922
3000
|
}
|
|
2923
|
-
catch {
|
|
3001
|
+
catch (e) {
|
|
3002
|
+
Logger.error('Failed to create WebRTC offer', e);
|
|
2924
3003
|
this.store.dispatch(disconnectStream({
|
|
2925
3004
|
reason: DisconnectReason.WebRTCError,
|
|
2926
3005
|
message: 'WebRTCError: Offer Error',
|
|
2927
3006
|
}));
|
|
2928
3007
|
}
|
|
2929
|
-
|
|
3008
|
+
}
|
|
3009
|
+
/**
|
|
3010
|
+
* Initializes a new RTCPeerConnection with event handlers.
|
|
3011
|
+
* Transceivers are NOT added here — the caller is responsible for adding
|
|
3012
|
+
* them at the correct point depending on the negotiation flow.
|
|
3013
|
+
*/
|
|
3014
|
+
setupPeerConnection(config) {
|
|
3015
|
+
this.closePC();
|
|
3016
|
+
Logger.log('Creating new RTCPeerConnection with config');
|
|
3017
|
+
this.pcClient = new RTCPeerConnection(config);
|
|
3018
|
+
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE gathering');
|
|
3019
|
+
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE connection');
|
|
3020
|
+
this.commandTelemetryService.trackStartCommand('EXT-Signaling state change');
|
|
3021
|
+
this.handlePeerConnectionEvents(this.pcClient);
|
|
3022
|
+
this.disconnect$.pipe(take(1)).subscribe(() => {
|
|
3023
|
+
this.closePC();
|
|
3024
|
+
});
|
|
2930
3025
|
}
|
|
2931
3026
|
createDataChannel(pc, label, options) {
|
|
2932
|
-
// This is the primary data channel code path when we are "offering"
|
|
2933
3027
|
const datachannel = pc.createDataChannel(label, options);
|
|
2934
3028
|
return this.setupDataChannelCallbacks(datachannel);
|
|
2935
3029
|
}
|
|
2936
|
-
receiveAnswer(answer) {
|
|
2937
|
-
this.pcClient?.setRemoteDescription(answer);
|
|
2938
|
-
}
|
|
2939
3030
|
handleCandidateFromServer(iceCandidate) {
|
|
2940
3031
|
try {
|
|
2941
3032
|
const candidate = new RTCIceCandidate(iceCandidate);
|
|
2942
3033
|
Logger.info('[Unreal ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
2943
|
-
//
|
|
3034
|
+
// If forcing TURN, reject any candidates not relay
|
|
2944
3035
|
if (this.forceTURN) {
|
|
2945
|
-
// check if no relay address is found, if so, we are assuming it means no TURN server
|
|
2946
3036
|
if (candidate.candidate.indexOf('relay') < 0) {
|
|
2947
3037
|
Logger.warn('Dropping candidate because it was not TURN relay.', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
2948
3038
|
return;
|
|
2949
3039
|
}
|
|
2950
3040
|
}
|
|
2951
|
-
this.pcClient?.addIceCandidate(candidate).catch(
|
|
2952
|
-
|
|
3041
|
+
this.pcClient?.addIceCandidate(candidate).catch((e) => {
|
|
3042
|
+
Logger.warn('Failed to add ICE candidate', e);
|
|
2953
3043
|
});
|
|
2954
3044
|
}
|
|
2955
3045
|
catch (e) {
|
|
2956
3046
|
Logger.error('Error handleCandidateFromServer', e);
|
|
2957
3047
|
}
|
|
2958
3048
|
}
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3049
|
+
/**
|
|
3050
|
+
* Reorders the `m=video` line in the SDP so that payload types matching
|
|
3051
|
+
* the given H.264 `profile-level-id` appear first, making the browser
|
|
3052
|
+
* prefer that profile during codec negotiation.
|
|
3053
|
+
*
|
|
3054
|
+
* A `profile-level-id` is a 3-byte hex string (`XXYYZZ`) defined in
|
|
3055
|
+
* RFC 6184 that encodes three H.264 parameters:
|
|
3056
|
+
* - **Profile IDC** (`XX`) — the H.264 profile.
|
|
3057
|
+
* - **Profile IOP** (`YY`) — constraint flags that further narrow the profile.
|
|
3058
|
+
* - **Level IDC** (`ZZ`) — the level, which caps resolution/framerate/bitrate.
|
|
3059
|
+
*
|
|
3060
|
+
* ### H.264 profiles relevant to Unreal Engine Pixel Streaming
|
|
3061
|
+
*
|
|
3062
|
+
* | profile-level-id | Profile | Level | Notes |
|
|
3063
|
+
* |------------------|----------------------------|-------|----------------------------------------------|
|
|
3064
|
+
* | `42001f` | Baseline | 3.1 | No B-frames, low latency; legacy devices |
|
|
3065
|
+
* | `42e01f` | Constrained Baseline | 3.1 | Widest HW decode support; **recommended** |
|
|
3066
|
+
* | `4d001f` | Main | 3.1 | B-frames + CABAC; better compression |
|
|
3067
|
+
* | `4d4028` | Main | 4.0 | Up to 1080p60; common desktop target |
|
|
3068
|
+
* | `640028` | High | 4.0 | Best quality/compression; most GPUs support |
|
|
3069
|
+
* | `64002a` | High | 4.2 | Up to 1080p120 or 4K30 |
|
|
3070
|
+
* | `640033` | High | 5.1 | Up to 4K60; requires modern HW |
|
|
3071
|
+
* | `640034` | High | 5.2 | Up to 4K120; high-end HW only |
|
|
3072
|
+
* | `6e001f` | High 10 | 3.1 | 10-bit color; limited browser support |
|
|
3073
|
+
* | `f4001f` | High 4:4:4 Predictive | 3.1 | Lossless capable; rare in browsers |
|
|
3074
|
+
*
|
|
3075
|
+
* UE Pixel Streaming defaults to Constrained Baseline (`42e01f`) or High (`6400xx`)
|
|
3076
|
+
* depending on engine version and `WebRTC.H264Profile` CVar.
|
|
3077
|
+
*
|
|
3078
|
+
* We prioritize `42e01f` because it guarantees hardware decoding on
|
|
3079
|
+
* virtually all client devices (desktop, mobile, embedded), avoiding
|
|
3080
|
+
* fallback to software decoding or negotiation of a higher profile
|
|
3081
|
+
* that the client GPU may not accelerate.
|
|
3082
|
+
*/
|
|
3083
|
+
prioritizeH264Profile(sdp, profileLevelId) {
|
|
3084
|
+
const lines = sdp.split('\r\n');
|
|
3085
|
+
const targetPts = [];
|
|
3086
|
+
for (const line of lines) {
|
|
3087
|
+
if (line.startsWith('a=fmtp:') &&
|
|
3088
|
+
line.toLowerCase().includes(`profile-level-id=${profileLevelId}`)) {
|
|
3089
|
+
const pt = line.split(':')[1]?.split(' ')[0];
|
|
3090
|
+
if (pt)
|
|
3091
|
+
targetPts.push(pt);
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
if (targetPts.length === 0)
|
|
3095
|
+
return sdp;
|
|
3096
|
+
return lines
|
|
3097
|
+
.map((line) => {
|
|
3098
|
+
if (!line.startsWith('m=video'))
|
|
3099
|
+
return line;
|
|
3100
|
+
const parts = line.split(' ');
|
|
3101
|
+
// parts: m=video <port> <proto> <pt1> <pt2> ...
|
|
3102
|
+
const header = parts.slice(0, 3);
|
|
3103
|
+
const pts = parts.slice(3);
|
|
3104
|
+
const prioritized = [
|
|
3105
|
+
...targetPts.filter((pt) => pts.includes(pt)),
|
|
3106
|
+
...pts.filter((pt) => !targetPts.includes(pt)),
|
|
3107
|
+
];
|
|
3108
|
+
return [...header, ...prioritized].join(' ');
|
|
3109
|
+
})
|
|
3110
|
+
.join('\r\n');
|
|
3111
|
+
}
|
|
3112
|
+
mungeSDP(sdp) {
|
|
3113
|
+
let mungedSDP = this.prioritizeH264Profile(sdp, '42e01f');
|
|
3114
|
+
mungedSDP = mungedSDP.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm, '$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r\n');
|
|
3115
|
+
// Set max bitrate to highest bitrate Opus supports
|
|
3116
|
+
let audioSDP = 'maxaveragebitrate=510000;';
|
|
2963
3117
|
if (this.useMic) {
|
|
2964
|
-
//
|
|
3118
|
+
// Set the max capture rate to 48khz (so we can send high-quality audio from mic)
|
|
2965
3119
|
audioSDP += 'sprop-maxcapturerate=48000;';
|
|
2966
3120
|
}
|
|
2967
3121
|
// Force mono or stereo based on whether ?forceMono was passed or not
|
|
2968
|
-
audioSDP += this.forceMonoAudio
|
|
2969
|
-
|
|
2970
|
-
: 'sprop-stereo=1;stereo=1;';
|
|
2971
|
-
// enable in-band forward error correction for opus audio
|
|
3122
|
+
audioSDP += this.forceMonoAudio ? 'stereo=0;' : 'stereo=1;';
|
|
3123
|
+
// Enable in-band forward error correction for opus audio
|
|
2972
3124
|
audioSDP += 'useinbandfec=1';
|
|
2973
3125
|
// We use the line 'useinbandfec=1' (which Opus uses) to set our Opus specific audio parameters.
|
|
2974
|
-
|
|
3126
|
+
mungedSDP = mungedSDP?.replace('useinbandfec=1', audioSDP);
|
|
3127
|
+
return mungedSDP;
|
|
2975
3128
|
}
|
|
2976
3129
|
/**
|
|
2977
|
-
* Closes existing PeerConnection
|
|
3130
|
+
* Closes existing PeerConnection and DataChannel, resets negotiation state.
|
|
2978
3131
|
*/
|
|
2979
3132
|
closePC() {
|
|
2980
3133
|
if (this.pcClient) {
|
|
@@ -2987,6 +3140,8 @@ class WebRtcPlayerService extends SubService {
|
|
|
2987
3140
|
}
|
|
2988
3141
|
this.dcClient?.close();
|
|
2989
3142
|
this.dcClient = null;
|
|
3143
|
+
this.remoteDescriptionSet = false;
|
|
3144
|
+
this.iceCandidateBuffer.length = 0;
|
|
2990
3145
|
}
|
|
2991
3146
|
canSend() {
|
|
2992
3147
|
return this.dcClient && this.dcClient.readyState === 'open';
|
|
@@ -3023,9 +3178,9 @@ class WebRtcPlayerService extends SubService {
|
|
|
3023
3178
|
}
|
|
3024
3179
|
}
|
|
3025
3180
|
/**
|
|
3026
|
-
*
|
|
3027
|
-
*
|
|
3028
|
-
* the existing WebSocket connection.
|
|
3181
|
+
* Reconnects only the WebRTC peer connection without re-establishing signaling.
|
|
3182
|
+
* Closes the current PeerConnection and creates a new client-initiated offer
|
|
3183
|
+
* through the existing WebSocket connection.
|
|
3029
3184
|
* @returns true if reconnection was initiated, false if signaling is not connected
|
|
3030
3185
|
*/
|
|
3031
3186
|
reconnectPeer() {
|
|
@@ -3058,11 +3213,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3058
3213
|
this.cfg.bundlePolicy = urlParams.has('ForceMaxBundle')
|
|
3059
3214
|
? 'max-bundle'
|
|
3060
3215
|
: 'balanced';
|
|
3061
|
-
|
|
3062
|
-
//Variables
|
|
3063
|
-
//**********************
|
|
3064
|
-
this.pcClient = null;
|
|
3065
|
-
this.dcClient = null;
|
|
3216
|
+
this.cfg.iceCandidatePoolSize = 1;
|
|
3066
3217
|
// When ?useMic check for SSL or localhost
|
|
3067
3218
|
const isLocalhostConnection = location.hostname === 'localhost' || location.hostname === '127.0.0.1';
|
|
3068
3219
|
const isHttpsConnection = location.protocol === 'https:';
|
|
@@ -3071,23 +3222,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3071
3222
|
Logger.error('Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access.');
|
|
3072
3223
|
Logger.error("For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'");
|
|
3073
3224
|
}
|
|
3074
|
-
|
|
3075
|
-
async createPeerConnection(config) {
|
|
3076
|
-
this.closePC();
|
|
3077
|
-
this.pcClient = new RTCPeerConnection(config);
|
|
3078
|
-
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE gathering');
|
|
3079
|
-
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE connection');
|
|
3080
|
-
this.commandTelemetryService.trackStartCommand('EXT-Signaling state change');
|
|
3081
|
-
this.handlePeerConnectionEvents(this.pcClient);
|
|
3082
|
-
await this.setupTransceiversAsync(this.pcClient);
|
|
3083
|
-
this.dcClient = this.createDataChannel(this.pcClient, 'UnrealDcConnection', {
|
|
3084
|
-
// See https://www.w3.org/TR/webrtc/#dom-rtcdatachannelinit for values (this is needed for Firefox to be consistent with Chrome.)
|
|
3085
|
-
ordered: true,
|
|
3086
|
-
});
|
|
3087
|
-
this.disconnect$.pipe(take(1)).subscribe(() => {
|
|
3088
|
-
this.closePC();
|
|
3089
|
-
});
|
|
3090
|
-
await this.createOffer(this.pcClient);
|
|
3225
|
+
this.setupPeerConnection(this.cfg);
|
|
3091
3226
|
}
|
|
3092
3227
|
handlePeerConnectionEvents(pcClient) {
|
|
3093
3228
|
fromEvent(pcClient, 'signalingstatechange')
|
|
@@ -3116,8 +3251,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3116
3251
|
fromEvent(pcClient, 'icecandidate')
|
|
3117
3252
|
.pipe(map$1((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(this.disconnect$))
|
|
3118
3253
|
.subscribe((candidate) => this.signallingSrv.send({ type: 'iceCandidate', candidate }));
|
|
3254
|
+
// When the server creates the DataChannel (server-offer flow),
|
|
3255
|
+
// we receive it here via the 'datachannel' event
|
|
3119
3256
|
fromEvent(pcClient, 'datachannel')
|
|
3120
|
-
.pipe(tap$1(() => Logger.info(
|
|
3257
|
+
.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$1((e) => e.channel), takeUntil(this.disconnect$))
|
|
3121
3258
|
.subscribe((datachannel) => {
|
|
3122
3259
|
this.dcClient = this.setupDataChannelCallbacks(datachannel);
|
|
3123
3260
|
});
|
|
@@ -3225,7 +3362,14 @@ class WebRtcPlayerService extends SubService {
|
|
|
3225
3362
|
this.onDataChannelConnected();
|
|
3226
3363
|
});
|
|
3227
3364
|
fromEvent(datachannel, 'message')
|
|
3228
|
-
.pipe(
|
|
3365
|
+
.pipe(
|
|
3366
|
+
/* tap((e: MessageEvent) => {
|
|
3367
|
+
const view = new Uint8Array(e.data);
|
|
3368
|
+
Logger.info(
|
|
3369
|
+
`[DATACHANNEL] Message received on "${datachannel.label}" id=${datachannel.id}, byteCode=${view[0]}, size=${view.byteLength}`,
|
|
3370
|
+
);
|
|
3371
|
+
}),*/
|
|
3372
|
+
map$1((e) => e.data), takeUntil(this.disconnect$))
|
|
3229
3373
|
.subscribe((data) => this.onDataChannelMessage$.next(data));
|
|
3230
3374
|
return datachannel;
|
|
3231
3375
|
}
|
|
@@ -3242,26 +3386,44 @@ class WebRtcPlayerService extends SubService {
|
|
|
3242
3386
|
}
|
|
3243
3387
|
this.store.dispatch(dataChannelConnected({ statusMessage }));
|
|
3244
3388
|
}
|
|
3389
|
+
/**
|
|
3390
|
+
* Creates an SDP offer, applies SDP munging, sets it as a local description,
|
|
3391
|
+
* and sends it to the server via signaling.
|
|
3392
|
+
* Transceivers already configure media directions, so deprecated
|
|
3393
|
+
* offerToReceive* options are not used.
|
|
3394
|
+
*/
|
|
3245
3395
|
async createOffer(pcClient) {
|
|
3246
3396
|
try {
|
|
3247
|
-
const offer = await pcClient.createOffer(
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
});
|
|
3251
|
-
this.mungeSDP(offer);
|
|
3252
|
-
pcClient?.setLocalDescription(offer);
|
|
3397
|
+
const offer = await pcClient.createOffer();
|
|
3398
|
+
offer.sdp = this.mungeSDP(offer.sdp ?? '');
|
|
3399
|
+
await pcClient.setLocalDescription(offer);
|
|
3253
3400
|
this.signallingSrv.send(offer);
|
|
3254
3401
|
}
|
|
3255
3402
|
catch {
|
|
3256
3403
|
Logger.error("Couldn't create offer");
|
|
3257
3404
|
}
|
|
3258
3405
|
}
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3406
|
+
/**
|
|
3407
|
+
* Creates an SDP answer, applies SDP munging, sets it as a local description,
|
|
3408
|
+
* and sends it to the server via signaling.
|
|
3409
|
+
*/
|
|
3410
|
+
async createAnswer(pcClient) {
|
|
3411
|
+
try {
|
|
3412
|
+
const answer = await pcClient.createAnswer();
|
|
3413
|
+
answer.sdp = this.mungeSDP(answer.sdp ?? '');
|
|
3414
|
+
await pcClient.setLocalDescription(answer);
|
|
3415
|
+
this.signallingSrv.send(answer);
|
|
3416
|
+
}
|
|
3417
|
+
catch (e) {
|
|
3418
|
+
Logger.error("Couldn't create answer", e);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3422
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WebRtcPlayerService }); }
|
|
3423
|
+
}
|
|
3424
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WebRtcPlayerService, decorators: [{
|
|
3425
|
+
type: Injectable
|
|
3426
|
+
}], ctorParameters: () => [] });
|
|
3265
3427
|
|
|
3266
3428
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3267
3429
|
const deepEqual = (a, b) => {
|
|
@@ -3603,10 +3765,10 @@ class AggregatorService extends SubService {
|
|
|
3603
3765
|
Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
|
|
3604
3766
|
}
|
|
3605
3767
|
}
|
|
3606
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3607
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
3768
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3769
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AggregatorService }); }
|
|
3608
3770
|
}
|
|
3609
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3771
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AggregatorService, decorators: [{
|
|
3610
3772
|
type: Injectable
|
|
3611
3773
|
}], ctorParameters: () => [] });
|
|
3612
3774
|
|
|
@@ -3694,10 +3856,10 @@ class ConsoleExtensionsService extends SubService {
|
|
|
3694
3856
|
Logger.info('setWarnTime() => set time to appear the AFK window.');
|
|
3695
3857
|
Logger.info('emitCommand(command) => send command to Unreal Engine.');
|
|
3696
3858
|
}
|
|
3697
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3698
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
3859
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3860
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ConsoleExtensionsService }); }
|
|
3699
3861
|
}
|
|
3700
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3862
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
|
|
3701
3863
|
type: Injectable
|
|
3702
3864
|
}], ctorParameters: () => [] });
|
|
3703
3865
|
|
|
@@ -3713,10 +3875,10 @@ class DevModeService {
|
|
|
3713
3875
|
localStorage.removeItem('devMode');
|
|
3714
3876
|
}
|
|
3715
3877
|
}
|
|
3716
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3717
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
3878
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3879
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
|
|
3718
3880
|
}
|
|
3719
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3881
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DevModeService, decorators: [{
|
|
3720
3882
|
type: Injectable,
|
|
3721
3883
|
args: [{
|
|
3722
3884
|
providedIn: 'root',
|
|
@@ -3732,6 +3894,8 @@ class UnrealCommunicatorService {
|
|
|
3732
3894
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
3733
3895
|
this.destroy$ = new Subject();
|
|
3734
3896
|
this.cirrusConnected = this.store.selectSignal(unrealFeature.selectCirrusConnected);
|
|
3897
|
+
this.afkIgnoredCommands = new Set(['executeConsoleCommand']);
|
|
3898
|
+
this.skipAfkReset = false;
|
|
3735
3899
|
this.init();
|
|
3736
3900
|
}
|
|
3737
3901
|
init() {
|
|
@@ -3758,7 +3922,11 @@ class UnrealCommunicatorService {
|
|
|
3758
3922
|
const uniqId = data?.correlationId ?? generateUuid();
|
|
3759
3923
|
const sendData = { ...data, correlationId: uniqId };
|
|
3760
3924
|
Logger.colored(...COLOR_CODES.TO_UNREAL, sendData);
|
|
3925
|
+
if (this.afkIgnoredCommands.has(data.command)) {
|
|
3926
|
+
this.skipAfkReset = true;
|
|
3927
|
+
}
|
|
3761
3928
|
this.emitUIInteraction(sendData);
|
|
3929
|
+
this.skipAfkReset = false;
|
|
3762
3930
|
this.store.dispatch(commandStarted({ id: uniqId, command: data.command }));
|
|
3763
3931
|
}
|
|
3764
3932
|
}
|
|
@@ -3782,7 +3950,9 @@ class UnrealCommunicatorService {
|
|
|
3782
3950
|
sendInputData(data) {
|
|
3783
3951
|
this.isPlaywrightMode();
|
|
3784
3952
|
try {
|
|
3785
|
-
this.
|
|
3953
|
+
if (!this.skipAfkReset) {
|
|
3954
|
+
this.store.dispatch(resetAfk());
|
|
3955
|
+
}
|
|
3786
3956
|
this.webRtcPlayerService.send(data);
|
|
3787
3957
|
}
|
|
3788
3958
|
catch (error) {
|
|
@@ -3819,10 +3989,10 @@ class UnrealCommunicatorService {
|
|
|
3819
3989
|
requestQualityControl() {
|
|
3820
3990
|
this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
3821
3991
|
}
|
|
3822
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3823
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
3992
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3993
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCommunicatorService }); }
|
|
3824
3994
|
}
|
|
3825
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3995
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
|
|
3826
3996
|
type: Injectable
|
|
3827
3997
|
}], ctorParameters: () => [] });
|
|
3828
3998
|
|
|
@@ -4316,690 +4486,145 @@ class RegionsPingService {
|
|
|
4316
4486
|
constructor() {
|
|
4317
4487
|
this.httpClient = inject(HttpClient);
|
|
4318
4488
|
this.unrealInitialConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
4319
|
-
this.config = {
|
|
4320
|
-
ping_count: 2,
|
|
4321
|
-
ping_timeout: 2000,
|
|
4322
|
-
max_parallel_requests: 10,
|
|
4323
|
-
bust_cache: true,
|
|
4324
|
-
};
|
|
4325
|
-
}
|
|
4326
|
-
getFastest(regionListUrl = this.unrealInitialConfig?.regionsPingUrl || '') {
|
|
4327
|
-
return this.getProviders(regionListUrl).pipe(switchMap((providers) => this.getPingResult(providers)), catchError(() => of(null)), tapLog('PingResult'), map$1((data) => data?.region_code));
|
|
4328
|
-
}
|
|
4329
|
-
getPingResult(providers) {
|
|
4330
|
-
const regions = providers.regions;
|
|
4331
|
-
this.config.ping_timeout = providers.timeout || this.config.ping_timeout;
|
|
4332
|
-
return from(this.startPinging(regions));
|
|
4333
|
-
}
|
|
4334
|
-
getProviders(regionList = this.unrealInitialConfig?.regionsPingUrl || '') {
|
|
4335
|
-
return this.httpClient.get(regionList);
|
|
4336
|
-
}
|
|
4337
|
-
startPinging(endpoints) {
|
|
4338
|
-
// eslint-disable-next-line no-async-promise-executor
|
|
4339
|
-
return new Promise(async (resolve) => {
|
|
4340
|
-
const pingResults = [];
|
|
4341
|
-
const semaphore = new Semaphore(10);
|
|
4342
|
-
const tasks = endpoints.map(async ({ region_code, url, timeout }) => {
|
|
4343
|
-
await semaphore.acquire();
|
|
4344
|
-
try {
|
|
4345
|
-
const result = await this.checkLatency(url, timeout);
|
|
4346
|
-
const data = { region_code, result };
|
|
4347
|
-
pingResults.push({ region_code, result });
|
|
4348
|
-
resolve(data);
|
|
4349
|
-
}
|
|
4350
|
-
catch {
|
|
4351
|
-
pingResults.push({ region_code: undefined, result: [] });
|
|
4352
|
-
}
|
|
4353
|
-
finally {
|
|
4354
|
-
semaphore.release();
|
|
4355
|
-
}
|
|
4356
|
-
const okValues = pingResults.filter((pingResult) => pingResult.result.length > 1);
|
|
4357
|
-
if (okValues.length) {
|
|
4358
|
-
return okValues[0];
|
|
4359
|
-
}
|
|
4360
|
-
return okValues;
|
|
4361
|
-
});
|
|
4362
|
-
await Promise.all(tasks);
|
|
4363
|
-
resolve(null);
|
|
4364
|
-
});
|
|
4365
|
-
}
|
|
4366
|
-
async checkLatency(endpoint, timeout = this.config.ping_timeout) {
|
|
4367
|
-
const pingResults = [];
|
|
4368
|
-
for (let i = 0; i < this.config.ping_count; i++) {
|
|
4369
|
-
const startTime = performance.now();
|
|
4370
|
-
try {
|
|
4371
|
-
await this.fetchWithTimeout(this.config.bust_cache
|
|
4372
|
-
? `${endpoint}?&cache_buster=${performance.now()}`
|
|
4373
|
-
: endpoint, {
|
|
4374
|
-
method: 'GET',
|
|
4375
|
-
mode: 'no-cors',
|
|
4376
|
-
headers: {
|
|
4377
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
4378
|
-
Pragma: 'no-cache',
|
|
4379
|
-
Expires: '0',
|
|
4380
|
-
},
|
|
4381
|
-
credentials: 'omit', // Optional: prevents sending or receiving cookies, which can affect caching.
|
|
4382
|
-
}, timeout);
|
|
4383
|
-
}
|
|
4384
|
-
catch {
|
|
4385
|
-
//Do not remove this block, else finally will not work!
|
|
4386
|
-
}
|
|
4387
|
-
finally {
|
|
4388
|
-
const latency = Math.round(performance.now() - startTime);
|
|
4389
|
-
pingResults.push(latency);
|
|
4390
|
-
}
|
|
4391
|
-
}
|
|
4392
|
-
return pingResults;
|
|
4393
|
-
}
|
|
4394
|
-
async fetchWithTimeout(url, options = {}, timeout) {
|
|
4395
|
-
const controller = new AbortController();
|
|
4396
|
-
options.signal = controller.signal;
|
|
4397
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
4398
|
-
try {
|
|
4399
|
-
const response = await fetch(url, options);
|
|
4400
|
-
clearTimeout(timeoutId);
|
|
4401
|
-
return response;
|
|
4402
|
-
}
|
|
4403
|
-
catch (error) {
|
|
4404
|
-
clearTimeout(timeoutId);
|
|
4405
|
-
throw error;
|
|
4406
|
-
}
|
|
4407
|
-
}
|
|
4408
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4409
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: RegionsPingService }); }
|
|
4410
|
-
}
|
|
4411
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: RegionsPingService, decorators: [{
|
|
4412
|
-
type: Injectable
|
|
4413
|
-
}] });
|
|
4414
|
-
|
|
4415
|
-
class StreamStatusTelemetryService {
|
|
4416
|
-
#store;
|
|
4417
|
-
#videoService;
|
|
4418
|
-
constructor() {
|
|
4419
|
-
this.#store = inject(Store);
|
|
4420
|
-
this.#videoService = inject(VideoService);
|
|
4421
|
-
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
4422
|
-
this.init();
|
|
4423
|
-
}
|
|
4424
|
-
init() {
|
|
4425
|
-
if (this.unrealConfig?.playwright) {
|
|
4426
|
-
return;
|
|
4427
|
-
}
|
|
4428
|
-
this.#videoService.videoStats$
|
|
4429
|
-
.pipe(withLatestFrom(this.#store.select(unrealFeature.selectAwsInstance), this.#store.select(unrealFeature.selectLowBandwidth), this.#store.select(unrealFeature.selectLowBandwidthStats), this.#store.select(unrealFeature.selectCirrusConnected)), auditTime(5000), filter(([, , , , cirrusConnected]) => cirrusConnected), map$1(([data, signalingServer, isLowBandwidth, lbmStats]) => this.mapEventData(data, signalingServer, isLowBandwidth, lbmStats)))
|
|
4430
|
-
.subscribe((data) => this.trackEventToMixPanel(data));
|
|
4431
|
-
}
|
|
4432
|
-
mapEventData(data, signalingServer, isLowBandwidth, lbmStats) {
|
|
4433
|
-
const { bitrate, VideoEncoderQP, framesPerSecond, frameWidth, frameHeight, jitter, packetsLost, currentRoundTripTime, runTime, } = data.aggregatedStats;
|
|
4434
|
-
return {
|
|
4435
|
-
runTime,
|
|
4436
|
-
frameWidth,
|
|
4437
|
-
frameHeight,
|
|
4438
|
-
isLowBandwidth,
|
|
4439
|
-
client: signalingServer.wsUrl,
|
|
4440
|
-
pixelRatio: window.devicePixelRatio,
|
|
4441
|
-
framesPerSecond,
|
|
4442
|
-
jitter,
|
|
4443
|
-
packetsLost,
|
|
4444
|
-
instanceName: signalingServer.instanceName,
|
|
4445
|
-
bitrate,
|
|
4446
|
-
lbmStats,
|
|
4447
|
-
rtt: currentRoundTripTime,
|
|
4448
|
-
VideoEncoderQP,
|
|
4449
|
-
};
|
|
4450
|
-
}
|
|
4451
|
-
trackEventToMixPanel(data) {
|
|
4452
|
-
this.#store.dispatch(trackMixpanelEvent({ event: 'streamStatus', data }));
|
|
4453
|
-
}
|
|
4454
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4455
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StreamStatusTelemetryService }); }
|
|
4456
|
-
}
|
|
4457
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
|
|
4458
|
-
type: Injectable
|
|
4459
|
-
}], ctorParameters: () => [] });
|
|
4460
|
-
|
|
4461
|
-
class WebRtcPlayerService2 extends SubService {
|
|
4462
|
-
constructor() {
|
|
4463
|
-
super();
|
|
4464
|
-
this.onDataChannelMessage$ = new Subject();
|
|
4465
|
-
this.signallingSrv = inject(SignallingService);
|
|
4466
|
-
this.videoService = inject(VideoService);
|
|
4467
|
-
this.commandTelemetryService = inject(CommandTelemetryService);
|
|
4468
|
-
this.cfg = {};
|
|
4469
|
-
this.useMic = false;
|
|
4470
|
-
this.forceTURN = false;
|
|
4471
|
-
this.forceMonoAudio = false;
|
|
4472
|
-
/** Whether the remote SDP has been applied to the current peer connection */
|
|
4473
|
-
this.remoteDescriptionSet = false;
|
|
4474
|
-
/** ICE candidates received before the remote description was set */
|
|
4475
|
-
this.iceCandidateBuffer = [];
|
|
4476
|
-
this.isReconnecting = this.store.selectSignal(unrealFeature.selectIsReconnecting);
|
|
4477
|
-
this.init();
|
|
4478
|
-
this.actions$.pipe(ofType(dropDC)).subscribe(() => this.dcClient?.close());
|
|
4479
|
-
this.actions$.pipe(ofType(dropPC)).subscribe(() => this.pcClient?.close());
|
|
4480
|
-
}
|
|
4481
|
-
init() {
|
|
4482
|
-
this.signallingSrv.onConfig$.subscribe((config) => {
|
|
4483
|
-
this.videoService.create();
|
|
4484
|
-
this.setConfig(config);
|
|
4485
|
-
});
|
|
4486
|
-
// Server-initiated offer: set remote description and respond with answer
|
|
4487
|
-
this.signallingSrv.onOffer$.pipe(filter(Truthy)).subscribe((offer) => {
|
|
4488
|
-
void this.handleServerOffer(offer);
|
|
4489
|
-
});
|
|
4490
|
-
// Answer to a client-initiated offer
|
|
4491
|
-
this.signallingSrv.onWebRtcAnswer$
|
|
4492
|
-
.pipe(filter(Truthy))
|
|
4493
|
-
.subscribe((answer) => {
|
|
4494
|
-
void this.handleServerAnswer(answer);
|
|
4495
|
-
});
|
|
4496
|
-
// ICE candidates — buffered until remote description is set
|
|
4497
|
-
this.signallingSrv.onWebRtcIce$.subscribe((candidate) => {
|
|
4498
|
-
this.commandTelemetryService.trackStopCommand('EXT-iceCandidate', true, {
|
|
4499
|
-
multi: true,
|
|
4500
|
-
});
|
|
4501
|
-
if (this.remoteDescriptionSet) {
|
|
4502
|
-
this.handleCandidateFromServer(candidate);
|
|
4503
|
-
}
|
|
4504
|
-
else {
|
|
4505
|
-
this.iceCandidateBuffer.push(candidate);
|
|
4506
|
-
}
|
|
4507
|
-
});
|
|
4508
|
-
}
|
|
4509
|
-
/**
|
|
4510
|
-
* Handles an SDP offer received from the server.
|
|
4511
|
-
* Creates a new peer connection, applies the remote offer,
|
|
4512
|
-
* then responds with an SDP answer.
|
|
4513
|
-
*
|
|
4514
|
-
* The DataChannel is NOT created here — the server creates it,
|
|
4515
|
-
* and we receive it via the `datachannel` event on the peer connection.
|
|
4516
|
-
*/
|
|
4517
|
-
async handleServerOffer(offer) {
|
|
4518
|
-
Logger.info('Received offer from server, creating answer');
|
|
4519
|
-
try {
|
|
4520
|
-
this.remoteDescriptionSet = false;
|
|
4521
|
-
this.iceCandidateBuffer.length = 0;
|
|
4522
|
-
if (!this.pcClient) {
|
|
4523
|
-
this.setupPeerConnection(this.cfg);
|
|
4524
|
-
}
|
|
4525
|
-
// Offer already defines media transceivers — don't add extras
|
|
4526
|
-
await this.pcClient?.setRemoteDescription(offer);
|
|
4527
|
-
this.remoteDescriptionSet = true;
|
|
4528
|
-
this.flushIceCandidateBuffer();
|
|
4529
|
-
await this.createAnswer(this.pcClient);
|
|
4530
|
-
}
|
|
4531
|
-
catch (e) {
|
|
4532
|
-
Logger.error('Failed to handle server offer', e);
|
|
4533
|
-
this.store.dispatch(disconnectStream({
|
|
4534
|
-
reason: DisconnectReason.WebRTCError,
|
|
4535
|
-
message: 'WebRTCError: Failed to handle server offer',
|
|
4536
|
-
}));
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
|
-
/**
|
|
4540
|
-
* Handles an SDP answer received from the server in response to our offer.
|
|
4541
|
-
* Applies the remote description and flushes any buffered ICE candidates.
|
|
4542
|
-
*/
|
|
4543
|
-
async handleServerAnswer(answer) {
|
|
4544
|
-
Logger.info('Received answer from server');
|
|
4545
|
-
try {
|
|
4546
|
-
await this.pcClient?.setRemoteDescription(answer);
|
|
4547
|
-
this.remoteDescriptionSet = true;
|
|
4548
|
-
this.flushIceCandidateBuffer();
|
|
4549
|
-
}
|
|
4550
|
-
catch (e) {
|
|
4551
|
-
Logger.error('Failed to set remote description from answer', e);
|
|
4552
|
-
}
|
|
4553
|
-
}
|
|
4554
|
-
/** Drains buffered ICE candidates after the remote description has been set */
|
|
4555
|
-
flushIceCandidateBuffer() {
|
|
4556
|
-
for (const candidate of this.iceCandidateBuffer) {
|
|
4557
|
-
this.handleCandidateFromServer(candidate);
|
|
4558
|
-
}
|
|
4559
|
-
this.iceCandidateBuffer.length = 0;
|
|
4560
|
-
}
|
|
4561
|
-
/**
|
|
4562
|
-
* Creates a client-initiated WebRTC offer and sends it to the server.
|
|
4563
|
-
* When the client offers, it also creates the DataChannel.
|
|
4564
|
-
* Used for peer reconnection through the existing signaling connection.
|
|
4565
|
-
*/
|
|
4566
|
-
async createWebRtcOffer() {
|
|
4567
|
-
Logger.info('Creating client-initiated offer');
|
|
4568
|
-
try {
|
|
4569
|
-
this.remoteDescriptionSet = false;
|
|
4570
|
-
this.iceCandidateBuffer.length = 0;
|
|
4571
|
-
if (!this.pcClient) {
|
|
4572
|
-
this.setupPeerConnection(this.cfg);
|
|
4573
|
-
}
|
|
4574
|
-
// Client offers: transceivers first, then DC, then offer
|
|
4575
|
-
await this.setupTransceiversAsync(this.pcClient);
|
|
4576
|
-
this.dcClient = this.createDataChannel(this.pcClient, 'UnrealDcConnection', { ordered: true });
|
|
4577
|
-
await this.createOffer(this.pcClient);
|
|
4578
|
-
}
|
|
4579
|
-
catch (e) {
|
|
4580
|
-
Logger.error('Failed to create WebRTC offer', e);
|
|
4581
|
-
this.store.dispatch(disconnectStream({
|
|
4582
|
-
reason: DisconnectReason.WebRTCError,
|
|
4583
|
-
message: 'WebRTCError: Offer Error',
|
|
4584
|
-
}));
|
|
4585
|
-
}
|
|
4586
|
-
}
|
|
4587
|
-
/**
|
|
4588
|
-
* Initializes a new RTCPeerConnection with event handlers.
|
|
4589
|
-
* Transceivers are NOT added here — the caller is responsible for adding
|
|
4590
|
-
* them at the correct point depending on the negotiation flow.
|
|
4591
|
-
*/
|
|
4592
|
-
setupPeerConnection(config) {
|
|
4593
|
-
this.closePC();
|
|
4594
|
-
Logger.log('Creating new RTCPeerConnection with config');
|
|
4595
|
-
this.pcClient = new RTCPeerConnection(config);
|
|
4596
|
-
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE gathering');
|
|
4597
|
-
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE connection');
|
|
4598
|
-
this.commandTelemetryService.trackStartCommand('EXT-Signaling state change');
|
|
4599
|
-
this.handlePeerConnectionEvents(this.pcClient);
|
|
4600
|
-
this.disconnect$.pipe(take(1)).subscribe(() => {
|
|
4601
|
-
this.closePC();
|
|
4602
|
-
});
|
|
4603
|
-
}
|
|
4604
|
-
createDataChannel(pc, label, options) {
|
|
4605
|
-
const datachannel = pc.createDataChannel(label, options);
|
|
4606
|
-
return this.setupDataChannelCallbacks(datachannel);
|
|
4607
|
-
}
|
|
4608
|
-
handleCandidateFromServer(iceCandidate) {
|
|
4609
|
-
try {
|
|
4610
|
-
const candidate = new RTCIceCandidate(iceCandidate);
|
|
4611
|
-
Logger.info('[Unreal ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
4612
|
-
// If forcing TURN, reject any candidates not relay
|
|
4613
|
-
if (this.forceTURN) {
|
|
4614
|
-
if (candidate.candidate.indexOf('relay') < 0) {
|
|
4615
|
-
Logger.warn('Dropping candidate because it was not TURN relay.', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
4616
|
-
return;
|
|
4617
|
-
}
|
|
4618
|
-
}
|
|
4619
|
-
this.pcClient?.addIceCandidate(candidate).catch((e) => {
|
|
4620
|
-
Logger.warn('Failed to add ICE candidate', e);
|
|
4621
|
-
});
|
|
4622
|
-
}
|
|
4623
|
-
catch (e) {
|
|
4624
|
-
Logger.error('Error handleCandidateFromServer', e);
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
|
-
/**
|
|
4628
|
-
* Reorders the `m=video` line in the SDP so that payload types matching
|
|
4629
|
-
* the given H.264 `profile-level-id` appear first, making the browser
|
|
4630
|
-
* prefer that profile during codec negotiation.
|
|
4631
|
-
*
|
|
4632
|
-
* A `profile-level-id` is a 3-byte hex string (`XXYYZZ`) defined in
|
|
4633
|
-
* RFC 6184 that encodes three H.264 parameters:
|
|
4634
|
-
* - **Profile IDC** (`XX`) — the H.264 profile.
|
|
4635
|
-
* - **Profile IOP** (`YY`) — constraint flags that further narrow the profile.
|
|
4636
|
-
* - **Level IDC** (`ZZ`) — the level, which caps resolution/framerate/bitrate.
|
|
4637
|
-
*
|
|
4638
|
-
* ### H.264 profiles relevant to Unreal Engine Pixel Streaming
|
|
4639
|
-
*
|
|
4640
|
-
* | profile-level-id | Profile | Level | Notes |
|
|
4641
|
-
* |------------------|----------------------------|-------|----------------------------------------------|
|
|
4642
|
-
* | `42001f` | Baseline | 3.1 | No B-frames, low latency; legacy devices |
|
|
4643
|
-
* | `42e01f` | Constrained Baseline | 3.1 | Widest HW decode support; **recommended** |
|
|
4644
|
-
* | `4d001f` | Main | 3.1 | B-frames + CABAC; better compression |
|
|
4645
|
-
* | `4d4028` | Main | 4.0 | Up to 1080p60; common desktop target |
|
|
4646
|
-
* | `640028` | High | 4.0 | Best quality/compression; most GPUs support |
|
|
4647
|
-
* | `64002a` | High | 4.2 | Up to 1080p120 or 4K30 |
|
|
4648
|
-
* | `640033` | High | 5.1 | Up to 4K60; requires modern HW |
|
|
4649
|
-
* | `640034` | High | 5.2 | Up to 4K120; high-end HW only |
|
|
4650
|
-
* | `6e001f` | High 10 | 3.1 | 10-bit color; limited browser support |
|
|
4651
|
-
* | `f4001f` | High 4:4:4 Predictive | 3.1 | Lossless capable; rare in browsers |
|
|
4652
|
-
*
|
|
4653
|
-
* UE Pixel Streaming defaults to Constrained Baseline (`42e01f`) or High (`6400xx`)
|
|
4654
|
-
* depending on engine version and `WebRTC.H264Profile` CVar.
|
|
4655
|
-
*
|
|
4656
|
-
* We prioritize `42e01f` because it guarantees hardware decoding on
|
|
4657
|
-
* virtually all client devices (desktop, mobile, embedded), avoiding
|
|
4658
|
-
* fallback to software decoding or negotiation of a higher profile
|
|
4659
|
-
* that the client GPU may not accelerate.
|
|
4660
|
-
*/
|
|
4661
|
-
prioritizeH264Profile(sdp, profileLevelId) {
|
|
4662
|
-
const lines = sdp.split('\r\n');
|
|
4663
|
-
const targetPts = [];
|
|
4664
|
-
for (const line of lines) {
|
|
4665
|
-
if (line.startsWith('a=fmtp:') &&
|
|
4666
|
-
line.toLowerCase().includes(`profile-level-id=${profileLevelId}`)) {
|
|
4667
|
-
const pt = line.split(':')[1]?.split(' ')[0];
|
|
4668
|
-
if (pt)
|
|
4669
|
-
targetPts.push(pt);
|
|
4670
|
-
}
|
|
4671
|
-
}
|
|
4672
|
-
if (targetPts.length === 0)
|
|
4673
|
-
return sdp;
|
|
4674
|
-
return lines
|
|
4675
|
-
.map((line) => {
|
|
4676
|
-
if (!line.startsWith('m=video'))
|
|
4677
|
-
return line;
|
|
4678
|
-
const parts = line.split(' ');
|
|
4679
|
-
// parts: m=video <port> <proto> <pt1> <pt2> ...
|
|
4680
|
-
const header = parts.slice(0, 3);
|
|
4681
|
-
const pts = parts.slice(3);
|
|
4682
|
-
const prioritized = [
|
|
4683
|
-
...targetPts.filter((pt) => pts.includes(pt)),
|
|
4684
|
-
...pts.filter((pt) => !targetPts.includes(pt)),
|
|
4685
|
-
];
|
|
4686
|
-
return [...header, ...prioritized].join(' ');
|
|
4687
|
-
})
|
|
4688
|
-
.join('\r\n');
|
|
4689
|
-
}
|
|
4690
|
-
mungeSDP(sdp) {
|
|
4691
|
-
let mungedSDP = this.prioritizeH264Profile(sdp, '42e01f');
|
|
4692
|
-
mungedSDP = mungedSDP.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm, '$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r\n');
|
|
4693
|
-
// Set max bitrate to highest bitrate Opus supports
|
|
4694
|
-
let audioSDP = 'maxaveragebitrate=510000;';
|
|
4695
|
-
if (this.useMic) {
|
|
4696
|
-
// Set the max capture rate to 48khz (so we can send high-quality audio from mic)
|
|
4697
|
-
audioSDP += 'sprop-maxcapturerate=48000;';
|
|
4698
|
-
}
|
|
4699
|
-
// Force mono or stereo based on whether ?forceMono was passed or not
|
|
4700
|
-
audioSDP += this.forceMonoAudio ? 'stereo=0;' : 'stereo=1;';
|
|
4701
|
-
// Enable in-band forward error correction for opus audio
|
|
4702
|
-
audioSDP += 'useinbandfec=1';
|
|
4703
|
-
// We use the line 'useinbandfec=1' (which Opus uses) to set our Opus specific audio parameters.
|
|
4704
|
-
mungedSDP = mungedSDP?.replace('useinbandfec=1', audioSDP);
|
|
4705
|
-
return mungedSDP;
|
|
4706
|
-
}
|
|
4707
|
-
/**
|
|
4708
|
-
* Closes existing PeerConnection and DataChannel, resets negotiation state.
|
|
4709
|
-
*/
|
|
4710
|
-
closePC() {
|
|
4711
|
-
if (this.pcClient) {
|
|
4712
|
-
Logger.warn('Closing existing PeerConnection');
|
|
4713
|
-
}
|
|
4714
|
-
this.pcClient?.close();
|
|
4715
|
-
this.pcClient = null;
|
|
4716
|
-
if (this.dcClient) {
|
|
4717
|
-
Logger.warn('Closing existing DataChannel');
|
|
4718
|
-
}
|
|
4719
|
-
this.dcClient?.close();
|
|
4720
|
-
this.dcClient = null;
|
|
4721
|
-
this.remoteDescriptionSet = false;
|
|
4722
|
-
this.iceCandidateBuffer.length = 0;
|
|
4723
|
-
}
|
|
4724
|
-
canSend() {
|
|
4725
|
-
return this.dcClient && this.dcClient.readyState === 'open';
|
|
4726
|
-
}
|
|
4727
|
-
send(data) {
|
|
4728
|
-
if (this.canSend()) {
|
|
4729
|
-
this.dcClient?.send(data);
|
|
4730
|
-
}
|
|
4731
|
-
else {
|
|
4732
|
-
Logger.colored('black', 'yellow', `DataChannel connection not prepared or in state: ${this.dcClient?.readyState}`);
|
|
4733
|
-
// Trigger peer reconnection if DC is not open and we're not yet reconnecting
|
|
4734
|
-
this.tryReconnectOnSendFailure();
|
|
4735
|
-
}
|
|
4736
|
-
}
|
|
4737
|
-
/**
|
|
4738
|
-
* Attempts to reconnect the peer when send fails due to DataChannel not being open.
|
|
4739
|
-
* This handles cases where the DC connection is broken, but no error events are fired.
|
|
4740
|
-
*/
|
|
4741
|
-
tryReconnectOnSendFailure() {
|
|
4742
|
-
// Skip if already reconnecting or signaling is not connected
|
|
4743
|
-
if (this.isReconnecting()) {
|
|
4744
|
-
Logger.info('[Reconnect] Already reconnecting, skipping duplicate attempt');
|
|
4745
|
-
return;
|
|
4746
|
-
}
|
|
4747
|
-
if (!this.signallingSrv.isConnected()) {
|
|
4748
|
-
Logger.warn('[Reconnect] Cannot reconnect: Signaling not connected');
|
|
4749
|
-
return;
|
|
4750
|
-
}
|
|
4751
|
-
// Check if DC exists but is in a non-open state (closing, closed, or connecting stuck)
|
|
4752
|
-
const dcState = this.dcClient?.readyState;
|
|
4753
|
-
if (dcState && dcState !== 'open') {
|
|
4754
|
-
Logger.warn(`[Reconnect] DataChannel in "${dcState}" state during send, initiating peer reconnection`);
|
|
4755
|
-
this.store.dispatch(reconnectPeer({ attempt: 1, maxAttempts: 3, delay: 0 }));
|
|
4756
|
-
}
|
|
4757
|
-
}
|
|
4758
|
-
/**
|
|
4759
|
-
* Reconnects only the WebRTC peer connection without re-establishing signaling.
|
|
4760
|
-
* Closes the current PeerConnection and creates a new client-initiated offer
|
|
4761
|
-
* through the existing WebSocket connection.
|
|
4762
|
-
* @returns true if reconnection was initiated, false if signaling is not connected
|
|
4763
|
-
*/
|
|
4764
|
-
reconnectPeer() {
|
|
4765
|
-
if (!this.signallingSrv.isConnected()) {
|
|
4766
|
-
Logger.error('[Reconnect] Cannot reconnect peer: Signaling not connected');
|
|
4767
|
-
return false;
|
|
4768
|
-
}
|
|
4769
|
-
if (!this.cfg || Object.keys(this.cfg).length === 0) {
|
|
4770
|
-
Logger.error('[Reconnect] Cannot reconnect peer: No config available');
|
|
4771
|
-
return false;
|
|
4772
|
-
}
|
|
4773
|
-
Logger.info('[Reconnect] Initiating peer reconnection');
|
|
4774
|
-
// Close only the PeerConnection, keep WebSocket alive
|
|
4775
|
-
this.closePC();
|
|
4776
|
-
// Create a new WebRTC offer using the stored config
|
|
4777
|
-
void this.createWebRtcOffer();
|
|
4778
|
-
return true;
|
|
4779
|
-
}
|
|
4780
|
-
setConfig(parOptions = {}) {
|
|
4781
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
4782
|
-
//**********************
|
|
4783
|
-
//Config setup
|
|
4784
|
-
//**********************
|
|
4785
|
-
this.cfg = { ...parOptions.peerConnectionOptions };
|
|
4786
|
-
this.forceTURN = urlParams.has('ForceTURN');
|
|
4787
|
-
if (this.forceTURN) {
|
|
4788
|
-
Logger.info('Forcing TURN usage by setting ICE Transport Policy in peer connection config.');
|
|
4789
|
-
this.cfg.iceTransportPolicy = 'relay';
|
|
4790
|
-
}
|
|
4791
|
-
this.cfg.bundlePolicy = urlParams.has('ForceMaxBundle')
|
|
4792
|
-
? 'max-bundle'
|
|
4793
|
-
: 'balanced';
|
|
4794
|
-
this.cfg.iceCandidatePoolSize = 1;
|
|
4795
|
-
// When ?useMic check for SSL or localhost
|
|
4796
|
-
const isLocalhostConnection = location.hostname === 'localhost' || location.hostname === '127.0.0.1';
|
|
4797
|
-
const isHttpsConnection = location.protocol === 'https:';
|
|
4798
|
-
if (this.useMic && !isLocalhostConnection && !isHttpsConnection) {
|
|
4799
|
-
this.useMic = false;
|
|
4800
|
-
Logger.error('Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access.');
|
|
4801
|
-
Logger.error("For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'");
|
|
4802
|
-
}
|
|
4803
|
-
this.setupPeerConnection(this.cfg);
|
|
4804
|
-
}
|
|
4805
|
-
handlePeerConnectionEvents(pcClient) {
|
|
4806
|
-
fromEvent(pcClient, 'signalingstatechange')
|
|
4807
|
-
.pipe(map$1(() => this.pcClient?.signalingState), takeUntil(this.disconnect$))
|
|
4808
|
-
.subscribe((state) => {
|
|
4809
|
-
Logger.info('[Signaling state change] |', state, '|');
|
|
4810
|
-
this.commandTelemetryService.trackStopCommand('EXT-Signaling state change', true, { state, multi: true });
|
|
4811
|
-
});
|
|
4812
|
-
fromEvent(pcClient, 'iceconnectionstatechange')
|
|
4813
|
-
.pipe(map$1(() => this.pcClient?.iceConnectionState), takeUntil(this.disconnect$))
|
|
4814
|
-
.subscribe((state) => {
|
|
4815
|
-
Logger.info('[Browser ICE connection] |', state, '|');
|
|
4816
|
-
this.commandTelemetryService.trackStopCommand('EXT-Browser ICE connection', true, { state, multi: true });
|
|
4817
|
-
});
|
|
4818
|
-
fromEvent(pcClient, 'icegatheringstatechange')
|
|
4819
|
-
.pipe(map$1(() => this.pcClient?.iceGatheringState), takeUntil(this.disconnect$))
|
|
4820
|
-
.subscribe((state) => {
|
|
4821
|
-
Logger.info('[Browser ICE gathering] |', state, '|');
|
|
4822
|
-
this.commandTelemetryService.trackStopCommand('EXT-Browser ICE gathering', true, { state, multi: true });
|
|
4823
|
-
});
|
|
4824
|
-
fromEvent(pcClient, 'connectionstatechange')
|
|
4825
|
-
.pipe(map$1(() => this.pcClient?.connectionState), takeUntil(this.disconnect$))
|
|
4826
|
-
.subscribe((state) => {
|
|
4827
|
-
Logger.info('[RTCPeerConnection state] |', state, '|');
|
|
4828
|
-
});
|
|
4829
|
-
fromEvent(pcClient, 'icecandidate')
|
|
4830
|
-
.pipe(map$1((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(this.disconnect$))
|
|
4831
|
-
.subscribe((candidate) => this.signallingSrv.send({ type: 'iceCandidate', candidate }));
|
|
4832
|
-
// When the server creates the DataChannel (server-offer flow),
|
|
4833
|
-
// we receive it here via the 'datachannel' event
|
|
4834
|
-
fromEvent(pcClient, 'datachannel')
|
|
4835
|
-
.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$1((e) => e.channel), takeUntil(this.disconnect$))
|
|
4836
|
-
.subscribe((datachannel) => {
|
|
4837
|
-
this.dcClient = this.setupDataChannelCallbacks(datachannel);
|
|
4838
|
-
});
|
|
4839
|
-
const onTrack$ = fromEvent(pcClient, 'track').pipe(takeUntil(this.disconnect$), filter((e) => !!e.track), tap$1((e) => Logger.info('Got track - ' +
|
|
4840
|
-
e.track.kind +
|
|
4841
|
-
' id=' +
|
|
4842
|
-
e.track.id +
|
|
4843
|
-
' readyState=' +
|
|
4844
|
-
e.track.readyState)), share());
|
|
4845
|
-
onTrack$
|
|
4846
|
-
.pipe(filter((e) => e.track.kind === 'audio'), map$1((e) => e.streams[0]))
|
|
4847
|
-
.subscribe((stream) => this.videoService.attachAudioStream(stream));
|
|
4848
|
-
onTrack$
|
|
4849
|
-
.pipe(filter((e) => e.track.kind === 'video'), map$1((e) => e.streams[0]), tap$1(() => Logger.info('Set video source from video track ontrack.')))
|
|
4850
|
-
.subscribe((stream) => {
|
|
4851
|
-
if (this.pcClient) {
|
|
4852
|
-
this.videoService.attachVideoStream(stream, this.pcClient);
|
|
4853
|
-
}
|
|
4854
|
-
});
|
|
4489
|
+
this.config = {
|
|
4490
|
+
ping_count: 2,
|
|
4491
|
+
ping_timeout: 2000,
|
|
4492
|
+
max_parallel_requests: 10,
|
|
4493
|
+
bust_cache: true,
|
|
4494
|
+
};
|
|
4855
4495
|
}
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4496
|
+
getFastest(regionListUrl = this.unrealInitialConfig?.regionsPingUrl || '') {
|
|
4497
|
+
return this.getProviders(regionListUrl).pipe(switchMap((providers) => this.getPingResult(providers)), catchError(() => of(null)), tapLog('PingResult'), map$1((data) => data?.region_code));
|
|
4498
|
+
}
|
|
4499
|
+
getPingResult(providers) {
|
|
4500
|
+
const regions = providers.regions;
|
|
4501
|
+
this.config.ping_timeout = providers.timeout || this.config.ping_timeout;
|
|
4502
|
+
return from(this.startPinging(regions));
|
|
4503
|
+
}
|
|
4504
|
+
getProviders(regionList = this.unrealInitialConfig?.regionsPingUrl || '') {
|
|
4505
|
+
return this.httpClient.get(regionList);
|
|
4506
|
+
}
|
|
4507
|
+
startPinging(endpoints) {
|
|
4508
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
4509
|
+
return new Promise(async (resolve) => {
|
|
4510
|
+
const pingResults = [];
|
|
4511
|
+
const semaphore = new Semaphore(10);
|
|
4512
|
+
const tasks = endpoints.map(async ({ region_code, url, timeout }) => {
|
|
4513
|
+
await semaphore.acquire();
|
|
4514
|
+
try {
|
|
4515
|
+
const result = await this.checkLatency(url, timeout);
|
|
4516
|
+
const data = { region_code, result };
|
|
4517
|
+
pingResults.push({ region_code, result });
|
|
4518
|
+
resolve(data);
|
|
4875
4519
|
}
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
const stream = await navigator.mediaDevices.getUserMedia({
|
|
4879
|
-
video: false,
|
|
4880
|
-
audio: audioSendOptions,
|
|
4881
|
-
});
|
|
4882
|
-
if (stream) {
|
|
4883
|
-
if (hasTransceivers) {
|
|
4884
|
-
for (const transceiver of pc.getTransceivers()) {
|
|
4885
|
-
if (transceiver &&
|
|
4886
|
-
transceiver.receiver &&
|
|
4887
|
-
transceiver.receiver.track &&
|
|
4888
|
-
transceiver.receiver.track.kind === 'audio') {
|
|
4889
|
-
for (const track of stream.getTracks()) {
|
|
4890
|
-
if (track.kind && track.kind === 'audio') {
|
|
4891
|
-
await transceiver.sender.replaceTrack(track);
|
|
4892
|
-
transceiver.direction = 'sendrecv';
|
|
4893
|
-
}
|
|
4894
|
-
}
|
|
4895
|
-
}
|
|
4896
|
-
}
|
|
4520
|
+
catch {
|
|
4521
|
+
pingResults.push({ region_code: undefined, result: [] });
|
|
4897
4522
|
}
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4523
|
+
finally {
|
|
4524
|
+
semaphore.release();
|
|
4525
|
+
}
|
|
4526
|
+
const okValues = pingResults.filter((pingResult) => pingResult.result.length > 1);
|
|
4527
|
+
if (okValues.length) {
|
|
4528
|
+
return okValues[0];
|
|
4904
4529
|
}
|
|
4530
|
+
return okValues;
|
|
4531
|
+
});
|
|
4532
|
+
await Promise.all(tasks);
|
|
4533
|
+
resolve(null);
|
|
4534
|
+
});
|
|
4535
|
+
}
|
|
4536
|
+
async checkLatency(endpoint, timeout = this.config.ping_timeout) {
|
|
4537
|
+
const pingResults = [];
|
|
4538
|
+
for (let i = 0; i < this.config.ping_count; i++) {
|
|
4539
|
+
const startTime = performance.now();
|
|
4540
|
+
try {
|
|
4541
|
+
await this.fetchWithTimeout(this.config.bust_cache
|
|
4542
|
+
? `${endpoint}?&cache_buster=${performance.now()}`
|
|
4543
|
+
: endpoint, {
|
|
4544
|
+
method: 'GET',
|
|
4545
|
+
mode: 'no-cors',
|
|
4546
|
+
headers: {
|
|
4547
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
4548
|
+
Pragma: 'no-cache',
|
|
4549
|
+
Expires: '0',
|
|
4550
|
+
},
|
|
4551
|
+
credentials: 'omit', // Optional: prevents sending or receiving cookies, which can affect caching.
|
|
4552
|
+
}, timeout);
|
|
4905
4553
|
}
|
|
4906
|
-
|
|
4907
|
-
|
|
4554
|
+
catch {
|
|
4555
|
+
//Do not remove this block, else finally will not work!
|
|
4556
|
+
}
|
|
4557
|
+
finally {
|
|
4558
|
+
const latency = Math.round(performance.now() - startTime);
|
|
4559
|
+
pingResults.push(latency);
|
|
4908
4560
|
}
|
|
4909
4561
|
}
|
|
4562
|
+
return pingResults;
|
|
4910
4563
|
}
|
|
4911
|
-
|
|
4564
|
+
async fetchWithTimeout(url, options = {}, timeout) {
|
|
4565
|
+
const controller = new AbortController();
|
|
4566
|
+
options.signal = controller.signal;
|
|
4567
|
+
const timeoutId = setTimeout(() => controller.abort(new DOMException('Request timed out', 'TimeoutError')), timeout);
|
|
4912
4568
|
try {
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
datachannel.binaryType = 'arraybuffer';
|
|
4917
|
-
fromEvent(datachannel, 'close')
|
|
4918
|
-
.pipe(
|
|
4919
|
-
// Only dispatch disconnect if not already reconnecting to avoid infinite loops
|
|
4920
|
-
filter(() => !this.isReconnecting()), take(1))
|
|
4921
|
-
.subscribe((e) => {
|
|
4922
|
-
Logger.warn(`[DATACHANNEL] Data channel disconnected: ${datachannel.label}(${datachannel.id})`, e);
|
|
4923
|
-
this.store.dispatch(disconnectStream({
|
|
4924
|
-
reason: DisconnectReason.DataChannelClosed,
|
|
4925
|
-
message: 'DataChannelClosed',
|
|
4926
|
-
}));
|
|
4927
|
-
});
|
|
4928
|
-
fromEvent(datachannel, 'error')
|
|
4929
|
-
.pipe(takeUntil(this.disconnect$))
|
|
4930
|
-
.subscribe((e) => {
|
|
4931
|
-
const message = `[DATACHANNEL] Data channel "${datachannel.label}" error. id:${datachannel.id}`;
|
|
4932
|
-
Logger.error(message, e);
|
|
4933
|
-
});
|
|
4934
|
-
fromEvent(datachannel, 'open')
|
|
4935
|
-
.pipe(tap$1(() => {
|
|
4936
|
-
Logger.info(`[DATACHANNEL] Data channel "${datachannel.label}" connected. id:${datachannel.id}`);
|
|
4937
|
-
}), takeUntil(this.disconnect$))
|
|
4938
|
-
.subscribe(() => {
|
|
4939
|
-
this.commandTelemetryService.trackStopCommand('EXT-DataChannel Connection');
|
|
4940
|
-
this.onDataChannelConnected();
|
|
4941
|
-
});
|
|
4942
|
-
fromEvent(datachannel, 'message')
|
|
4943
|
-
.pipe(
|
|
4944
|
-
/* tap((e: MessageEvent) => {
|
|
4945
|
-
const view = new Uint8Array(e.data);
|
|
4946
|
-
Logger.info(
|
|
4947
|
-
`[DATACHANNEL] Message received on "${datachannel.label}" id=${datachannel.id}, byteCode=${view[0]}, size=${view.byteLength}`,
|
|
4948
|
-
);
|
|
4949
|
-
}),*/
|
|
4950
|
-
map$1((e) => e.data), takeUntil(this.disconnect$))
|
|
4951
|
-
.subscribe((data) => this.onDataChannelMessage$.next(data));
|
|
4952
|
-
return datachannel;
|
|
4569
|
+
const response = await fetch(url, options);
|
|
4570
|
+
clearTimeout(timeoutId);
|
|
4571
|
+
return response;
|
|
4953
4572
|
}
|
|
4954
|
-
catch (
|
|
4955
|
-
|
|
4956
|
-
|
|
4573
|
+
catch (error) {
|
|
4574
|
+
clearTimeout(timeoutId);
|
|
4575
|
+
throw error;
|
|
4957
4576
|
}
|
|
4958
4577
|
}
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
}
|
|
4965
|
-
|
|
4578
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4579
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: RegionsPingService }); }
|
|
4580
|
+
}
|
|
4581
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: RegionsPingService, decorators: [{
|
|
4582
|
+
type: Injectable
|
|
4583
|
+
}] });
|
|
4584
|
+
|
|
4585
|
+
class StreamStatusTelemetryService {
|
|
4586
|
+
#store;
|
|
4587
|
+
#videoService;
|
|
4588
|
+
constructor() {
|
|
4589
|
+
this.#store = inject(Store);
|
|
4590
|
+
this.#videoService = inject(VideoService);
|
|
4591
|
+
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
4592
|
+
this.init();
|
|
4966
4593
|
}
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
* Transceivers already configure media directions, so deprecated
|
|
4971
|
-
* offerToReceive* options are not used.
|
|
4972
|
-
*/
|
|
4973
|
-
async createOffer(pcClient) {
|
|
4974
|
-
try {
|
|
4975
|
-
const offer = await pcClient.createOffer();
|
|
4976
|
-
offer.sdp = this.mungeSDP(offer.sdp ?? '');
|
|
4977
|
-
await pcClient.setLocalDescription(offer);
|
|
4978
|
-
this.signallingSrv.send(offer);
|
|
4979
|
-
}
|
|
4980
|
-
catch {
|
|
4981
|
-
Logger.error("Couldn't create offer");
|
|
4594
|
+
init() {
|
|
4595
|
+
if (this.unrealConfig?.playwright) {
|
|
4596
|
+
return;
|
|
4982
4597
|
}
|
|
4598
|
+
this.#videoService.videoStats$
|
|
4599
|
+
.pipe(withLatestFrom(this.#store.select(unrealFeature.selectAwsInstance), this.#store.select(unrealFeature.selectLowBandwidth), this.#store.select(unrealFeature.selectLowBandwidthStats), this.#store.select(unrealFeature.selectCirrusConnected)), auditTime(5000), filter(([, , , , cirrusConnected]) => cirrusConnected), map$1(([data, signalingServer, isLowBandwidth, lbmStats]) => this.mapEventData(data, signalingServer, isLowBandwidth, lbmStats)))
|
|
4600
|
+
.subscribe((data) => this.trackEventToMixPanel(data));
|
|
4983
4601
|
}
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4602
|
+
mapEventData(data, signalingServer, isLowBandwidth, lbmStats) {
|
|
4603
|
+
const { bitrate, VideoEncoderQP, framesPerSecond, frameWidth, frameHeight, jitter, packetsLost, currentRoundTripTime, runTime, } = data.aggregatedStats;
|
|
4604
|
+
return {
|
|
4605
|
+
runTime,
|
|
4606
|
+
frameWidth,
|
|
4607
|
+
frameHeight,
|
|
4608
|
+
isLowBandwidth,
|
|
4609
|
+
client: signalingServer.wsUrl,
|
|
4610
|
+
pixelRatio: window.devicePixelRatio,
|
|
4611
|
+
framesPerSecond,
|
|
4612
|
+
jitter,
|
|
4613
|
+
packetsLost,
|
|
4614
|
+
instanceName: signalingServer.instanceName,
|
|
4615
|
+
bitrate,
|
|
4616
|
+
lbmStats,
|
|
4617
|
+
rtt: currentRoundTripTime,
|
|
4618
|
+
VideoEncoderQP,
|
|
4619
|
+
};
|
|
4998
4620
|
}
|
|
4999
|
-
|
|
5000
|
-
|
|
4621
|
+
trackEventToMixPanel(data) {
|
|
4622
|
+
this.#store.dispatch(trackMixpanelEvent({ event: 'streamStatus', data }));
|
|
4623
|
+
}
|
|
4624
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4625
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: StreamStatusTelemetryService }); }
|
|
5001
4626
|
}
|
|
5002
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
4627
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
|
|
5003
4628
|
type: Injectable
|
|
5004
4629
|
}], ctorParameters: () => [] });
|
|
5005
4630
|
|
|
@@ -5035,10 +4660,10 @@ class FileHandlerService {
|
|
|
5035
4660
|
setTimeout(() => sender(out), 0);
|
|
5036
4661
|
return observable;
|
|
5037
4662
|
}
|
|
5038
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5039
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
4663
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FileHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4664
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FileHandlerService }); }
|
|
5040
4665
|
}
|
|
5041
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
4666
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FileHandlerService, decorators: [{
|
|
5042
4667
|
type: Injectable
|
|
5043
4668
|
}] });
|
|
5044
4669
|
|
|
@@ -5127,10 +4752,10 @@ class AnalyticsService extends SubService {
|
|
|
5127
4752
|
});
|
|
5128
4753
|
});
|
|
5129
4754
|
}
|
|
5130
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5131
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
4755
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4756
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AnalyticsService }); }
|
|
5132
4757
|
}
|
|
5133
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
4758
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AnalyticsService, decorators: [{
|
|
5134
4759
|
type: Injectable
|
|
5135
4760
|
}], ctorParameters: () => [] });
|
|
5136
4761
|
|
|
@@ -5497,10 +5122,10 @@ class FpsMonitorService {
|
|
|
5497
5122
|
}
|
|
5498
5123
|
return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
|
|
5499
5124
|
}
|
|
5500
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5501
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
5125
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5126
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FpsMonitorService }); }
|
|
5502
5127
|
}
|
|
5503
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5128
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FpsMonitorService, decorators: [{
|
|
5504
5129
|
type: Injectable
|
|
5505
5130
|
}], ctorParameters: () => [] });
|
|
5506
5131
|
|
|
@@ -5571,10 +5196,10 @@ class UnrealCallbackService {
|
|
|
5571
5196
|
setTimeout(() => sender({ ...data, correlationId }), 0);
|
|
5572
5197
|
return observable;
|
|
5573
5198
|
}
|
|
5574
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5575
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
5199
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5200
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCallbackService }); }
|
|
5576
5201
|
}
|
|
5577
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5202
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealCallbackService, decorators: [{
|
|
5578
5203
|
type: Injectable
|
|
5579
5204
|
}] });
|
|
5580
5205
|
|
|
@@ -5590,12 +5215,12 @@ class AfkTimeoutModalComponent {
|
|
|
5590
5215
|
resetAfk() {
|
|
5591
5216
|
this.#afkService.reset();
|
|
5592
5217
|
}
|
|
5593
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5594
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5218
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5219
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", ngImport: i0, template: "@if (isAfkTimerVisible()) {\n <div (click)=\"resetAfk()\" class=\"clickableState\" id=\"videoPlayOverlay\">\n <div class=\"resume-box\">\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 <src-button\n [isFullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </src-button>\n </div>\n </div>\n}\n", styles: ["#videoPlayOverlay{position:absolute;z-index:30;top:0;width:100%;height:100%;font-size:1.8em;font-family:var(--src-font-family-body);background-color:#646464b3}.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(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .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}.resume-box .resume-box__pic .text-number{color:var(--src-colors-text-default, #1f2937);text-align:center;font-family:var(--src-font-family-body);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(--src-font-family-body);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--src-text-body-secondary, #6b7280)}.resume-box__text .resume-box__heading{color:var(--src-text-body-main, #1f2937);text-align:center;font-family:var(--src-font-family-body);font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"], dependencies: [{ kind: "component", type: SourceButtonComponent, selector: "src-button", inputs: ["type", "appearance", "weight", "size", "context", "customClass", "isFullWidth", "isPressed", "isDisabled", "isLoading", "isInverted", "srcButtonConfig", "formID", "data-testid", "ariaLabel"], outputs: ["onClick", "onSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5595
5220
|
}
|
|
5596
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5221
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
|
|
5597
5222
|
type: Component,
|
|
5598
|
-
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isAfkTimerVisible()) {\
|
|
5223
|
+
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isAfkTimerVisible()) {\n <div (click)=\"resetAfk()\" class=\"clickableState\" id=\"videoPlayOverlay\">\n <div class=\"resume-box\">\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 <src-button\n [isFullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </src-button>\n </div>\n </div>\n}\n", styles: ["#videoPlayOverlay{position:absolute;z-index:30;top:0;width:100%;height:100%;font-size:1.8em;font-family:var(--src-font-family-body);background-color:#646464b3}.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(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .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}.resume-box .resume-box__pic .text-number{color:var(--src-colors-text-default, #1f2937);text-align:center;font-family:var(--src-font-family-body);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(--src-font-family-body);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--src-text-body-secondary, #6b7280)}.resume-box__text .resume-box__heading{color:var(--src-text-body-main, #1f2937);text-align:center;font-family:var(--src-font-family-body);font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"] }]
|
|
5599
5224
|
}] });
|
|
5600
5225
|
|
|
5601
5226
|
class FreezeFrameComponent {
|
|
@@ -5605,12 +5230,12 @@ class FreezeFrameComponent {
|
|
|
5605
5230
|
this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
|
|
5606
5231
|
}
|
|
5607
5232
|
#store;
|
|
5608
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5609
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5233
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5234
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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 }); }
|
|
5610
5235
|
}
|
|
5611
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FreezeFrameComponent, decorators: [{
|
|
5612
5237
|
type: Component,
|
|
5613
|
-
args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\
|
|
5238
|
+
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"] }]
|
|
5614
5239
|
}] });
|
|
5615
5240
|
|
|
5616
5241
|
class SafePipe {
|
|
@@ -5636,10 +5261,10 @@ class SafePipe {
|
|
|
5636
5261
|
throw new Error(`Invalid safe type specified: ${type}`);
|
|
5637
5262
|
}
|
|
5638
5263
|
}
|
|
5639
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5640
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.
|
|
5264
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5265
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
|
|
5641
5266
|
}
|
|
5642
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5267
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: SafePipe, decorators: [{
|
|
5643
5268
|
type: Pipe,
|
|
5644
5269
|
args: [{
|
|
5645
5270
|
name: 'safe',
|
|
@@ -5651,12 +5276,12 @@ class LowBandwidthModalComponent {
|
|
|
5651
5276
|
close(value) {
|
|
5652
5277
|
this.#dialogRef.close(value || false);
|
|
5653
5278
|
}
|
|
5654
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5655
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
5279
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LowBandwidthModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5280
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: LowBandwidthModalComponent, isStandalone: true, selector: "app-low-bandwidth-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'low-bandwidth'\" class=\"src-modal src-modal--lbm\">\n <header class=\"src-modal__header\">\n <h6 [attr.data-testid]=\"'title'\" class=\"src-modal__title\">\n Unstable Connection\n </h6>\n </header>\n <section class=\"src-modal__body\">\n <div\n [innerHtml]=\"\n 'Fluid Interactivity Modes were disabled due to an unstable connection. Showcase Gallery Mode is enabled. To regain full functionality, switch to Interactive Mode.'\n | safe: 'html'\n \"\n class=\"src-modal__scroll-box\"\n ></div>\n </section>\n <footer class=\"src-modal__footer\">\n <div class=\"src-modal__buttons\">\n <src-button\n (onClick)=\"close(true)\"\n [data-testid]=\"'switch-to-interactive-mode'\"\n >\n Switch\n </src-button>\n\n <src-button\n (onClick)=\"close()\"\n [data-testid]=\"'close-lbm-modal'\"\n weight=\"primary\"\n >\n Ok\n </src-button>\n </div>\n </footer>\n</div>\n", styles: [".src-modal--lbm{width:360px}.src-modal--lbm .src-modal__body{font-size:14px;line-height:24px}.src-modal--lbm .src-modal__buttons{display:flex;gap:8px}\n"], dependencies: [{ kind: "component", type: SourceButtonComponent, selector: "src-button", inputs: ["type", "appearance", "weight", "size", "context", "customClass", "isFullWidth", "isPressed", "isDisabled", "isLoading", "isInverted", "srcButtonConfig", "formID", "data-testid", "ariaLabel"], outputs: ["onClick", "onSubmit"] }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5656
5281
|
}
|
|
5657
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5282
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LowBandwidthModalComponent, decorators: [{
|
|
5658
5283
|
type: Component,
|
|
5659
|
-
args: [{ selector: 'app-low-bandwidth-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SafePipe, SourceButtonComponent], template: "<div [attr.data-testid]=\"'low-bandwidth'\" class=\"src-modal src-modal--lbm\">\
|
|
5284
|
+
args: [{ selector: 'app-low-bandwidth-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SafePipe, SourceButtonComponent], template: "<div [attr.data-testid]=\"'low-bandwidth'\" class=\"src-modal src-modal--lbm\">\n <header class=\"src-modal__header\">\n <h6 [attr.data-testid]=\"'title'\" class=\"src-modal__title\">\n Unstable Connection\n </h6>\n </header>\n <section class=\"src-modal__body\">\n <div\n [innerHtml]=\"\n 'Fluid Interactivity Modes were disabled due to an unstable connection. Showcase Gallery Mode is enabled. To regain full functionality, switch to Interactive Mode.'\n | safe: 'html'\n \"\n class=\"src-modal__scroll-box\"\n ></div>\n </section>\n <footer class=\"src-modal__footer\">\n <div class=\"src-modal__buttons\">\n <src-button\n (onClick)=\"close(true)\"\n [data-testid]=\"'switch-to-interactive-mode'\"\n >\n Switch\n </src-button>\n\n <src-button\n (onClick)=\"close()\"\n [data-testid]=\"'close-lbm-modal'\"\n weight=\"primary\"\n >\n Ok\n </src-button>\n </div>\n </footer>\n</div>\n", styles: [".src-modal--lbm{width:360px}.src-modal--lbm .src-modal__body{font-size:14px;line-height:24px}.src-modal--lbm .src-modal__buttons{display:flex;gap:8px}\n"] }]
|
|
5660
5285
|
}] });
|
|
5661
5286
|
|
|
5662
5287
|
class ImageLoadingSrcComponent {
|
|
@@ -5666,12 +5291,15 @@ class ImageLoadingSrcComponent {
|
|
|
5666
5291
|
this.imageLoadingSrc = this.#store.selectSignal(unrealFeature.selectImageLoadingSrc);
|
|
5667
5292
|
}
|
|
5668
5293
|
#store;
|
|
5669
|
-
|
|
5670
|
-
|
|
5294
|
+
imageError() {
|
|
5295
|
+
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
5296
|
+
}
|
|
5297
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5298
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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)=\"imageError()\"\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:#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 }); }
|
|
5671
5299
|
}
|
|
5672
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5300
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
5673
5301
|
type: Component,
|
|
5674
|
-
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\
|
|
5302
|
+
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)=\"imageError()\"\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:#fff}\n"] }]
|
|
5675
5303
|
}] });
|
|
5676
5304
|
|
|
5677
5305
|
class StatGraphComponent {
|
|
@@ -5745,12 +5373,12 @@ class StatGraphComponent {
|
|
|
5745
5373
|
}
|
|
5746
5374
|
this.draw();
|
|
5747
5375
|
}
|
|
5748
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5749
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.
|
|
5376
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5377
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.10", 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 }); }
|
|
5750
5378
|
}
|
|
5751
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5379
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: StatGraphComponent, decorators: [{
|
|
5752
5380
|
type: Component,
|
|
5753
|
-
args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\
|
|
5381
|
+
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"] }]
|
|
5754
5382
|
}], 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: [{
|
|
5755
5383
|
type: HostListener,
|
|
5756
5384
|
args: ['window:resize']
|
|
@@ -5829,12 +5457,12 @@ class UnrealStatusComponent {
|
|
|
5829
5457
|
// Fails silently if the iframe's content window cannot be accessed
|
|
5830
5458
|
}
|
|
5831
5459
|
}
|
|
5832
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5833
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5460
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5461
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", ngImport: i0, template: "@if (showLoader()) {\n <div class=\"status-box\">\n @if (awsInstance()?.message) {\n <p>{{ awsInstance()?.message }}</p>\n } @else {\n <div class=\"status-box__message\">\n <src-loading\n [size]=\"30\"\n [backgroundStrokeColor]=\"'#E5E7EB'\"\n [progressStrokeColor]=\"'#1F2937'\"\n />\n {{ messagePercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-box{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--src-surface-container-main, #fff);border:none;border-radius:var(--src-border-rounded-full, 9999px);box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814;pointer-events:none}.status-box p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color: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 src-loading{margin-right:12px}\n"], dependencies: [{ kind: "component", type: SourceLoadingComponent, selector: "src-loading", inputs: ["size", "progress", "lineCap", "backgroundStrokeColor", "progressStrokeColor", "strokeWidth", "data-testid", "role", "ariaLabel", "ariaValueNow", "ariaValueMin", "ariaValueMax"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5834
5462
|
}
|
|
5835
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5463
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
5836
5464
|
type: Component,
|
|
5837
|
-
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceLoadingComponent], template: "@if (showLoader()) {\
|
|
5465
|
+
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceLoadingComponent], template: "@if (showLoader()) {\n <div class=\"status-box\">\n @if (awsInstance()?.message) {\n <p>{{ awsInstance()?.message }}</p>\n } @else {\n <div class=\"status-box__message\">\n <src-loading\n [size]=\"30\"\n [backgroundStrokeColor]=\"'#E5E7EB'\"\n [progressStrokeColor]=\"'#1F2937'\"\n />\n {{ messagePercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-box{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--src-surface-container-main, #fff);border:none;border-radius:var(--src-border-rounded-full, 9999px);box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814;pointer-events:none}.status-box p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color: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 src-loading{margin-right:12px}\n"] }]
|
|
5838
5466
|
}] });
|
|
5839
5467
|
|
|
5840
5468
|
class VideoStatsComponent {
|
|
@@ -5961,12 +5589,12 @@ class VideoStatsComponent {
|
|
|
5961
5589
|
elements: this.elementsToShow,
|
|
5962
5590
|
}));
|
|
5963
5591
|
}
|
|
5964
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
5965
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5592
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5593
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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$ | async; track graph) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"(graph.stat | async)!\"\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]=\"ssInfo() | 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: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5966
5594
|
}
|
|
5967
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5595
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
5968
5596
|
type: Component,
|
|
5969
|
-
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, AsyncPipe, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\
|
|
5597
|
+
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, AsyncPipe, 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$ | async; track graph) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"(graph.stat | async)!\"\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]=\"ssInfo() | 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"] }]
|
|
5970
5598
|
}], ctorParameters: () => [] });
|
|
5971
5599
|
|
|
5972
5600
|
class ResumeStreamButtonComponent {
|
|
@@ -6008,12 +5636,12 @@ class ResumeStreamButtonComponent {
|
|
|
6008
5636
|
onDisconnect() {
|
|
6009
5637
|
this.isSecondStart.set(true);
|
|
6010
5638
|
}
|
|
6011
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
6012
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5639
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5640
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", ngImport: i0, template: "@if (isShowResumeButton()) {\n <div class=\"resume-box\">\n @if (isSecondStart()) {\n <div class=\"resume-box__text\">\n Your stream has been paused due to inactivity\n </div>\n }\n\n <src-button\n (onClick)=\"connect()\"\n [isFullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n size=\"lg\"\n weight=\"primary\"\n class=\"connect-button\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </src-button>\n </div>\n}\n", styles: [".resume-box{padding:16px;position:absolute;bottom:0;left:50%;gap:12px;z-index:6;display:flex;transform:translate(-50%,-50%);flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .connect-button{width:100%}.resume-box .resume-box__text{color:var(--src-color-grey-500, #6b7280);text-align:center;font-family:var(--src-font-family-body);font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"], dependencies: [{ kind: "component", type: SourceButtonComponent, selector: "src-button", inputs: ["type", "appearance", "weight", "size", "context", "customClass", "isFullWidth", "isPressed", "isDisabled", "isLoading", "isInverted", "srcButtonConfig", "formID", "data-testid", "ariaLabel"], outputs: ["onClick", "onSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6013
5641
|
}
|
|
6014
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5642
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
6015
5643
|
type: Component,
|
|
6016
|
-
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isShowResumeButton()) {\
|
|
5644
|
+
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isShowResumeButton()) {\n <div class=\"resume-box\">\n @if (isSecondStart()) {\n <div class=\"resume-box__text\">\n Your stream has been paused due to inactivity\n </div>\n }\n\n <src-button\n (onClick)=\"connect()\"\n [isFullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n size=\"lg\"\n weight=\"primary\"\n class=\"connect-button\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </src-button>\n </div>\n}\n", styles: [".resume-box{padding:16px;position:absolute;bottom:0;left:50%;gap:12px;z-index:6;display:flex;transform:translate(-50%,-50%);flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .connect-button{width:100%}.resume-box .resume-box__text{color:var(--src-color-grey-500, #6b7280);text-align:center;font-family:var(--src-font-family-body);font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"] }]
|
|
6017
5645
|
}] });
|
|
6018
5646
|
|
|
6019
5647
|
class IntroSrcComponent {
|
|
@@ -6045,7 +5673,10 @@ class IntroSrcComponent {
|
|
|
6045
5673
|
});
|
|
6046
5674
|
}
|
|
6047
5675
|
createVideo(src, videoContainer) {
|
|
6048
|
-
|
|
5676
|
+
if (typeof src !== 'string') {
|
|
5677
|
+
return;
|
|
5678
|
+
}
|
|
5679
|
+
const matchAbsolutePath = /.*\.(mp4|WebM)(\?.*)?$/i.test(src);
|
|
6049
5680
|
videoContainer.innerHTML = ''; // This will remove all existing content within the layout
|
|
6050
5681
|
const videoElement = document.createElement('video');
|
|
6051
5682
|
videoElement.autoplay = true;
|
|
@@ -6067,15 +5698,19 @@ class IntroSrcComponent {
|
|
|
6067
5698
|
}
|
|
6068
5699
|
sourceElement.type = 'video/mp4';
|
|
6069
5700
|
videoElement.appendChild(sourceElement);
|
|
6070
|
-
videoElement.
|
|
5701
|
+
videoElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
5702
|
+
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
6071
5703
|
videoContainer.appendChild(videoElement);
|
|
6072
5704
|
}
|
|
6073
|
-
|
|
6074
|
-
|
|
5705
|
+
imageError() {
|
|
5706
|
+
this.#store.dispatch(resetIntroSrc());
|
|
5707
|
+
}
|
|
5708
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5709
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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)=\"imageError()\" [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 }); }
|
|
6075
5710
|
}
|
|
6076
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5711
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
6077
5712
|
type: Component,
|
|
6078
|
-
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\
|
|
5713
|
+
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"imageError()\" [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"] }]
|
|
6079
5714
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
6080
5715
|
|
|
6081
5716
|
class UnrealSceneComponent {
|
|
@@ -6096,7 +5731,6 @@ class UnrealSceneComponent {
|
|
|
6096
5731
|
this.changeMouseOverScene.emit(false);
|
|
6097
5732
|
}
|
|
6098
5733
|
constructor() {
|
|
6099
|
-
this.unrealConfig = inject(UNREAL_CONFIG);
|
|
6100
5734
|
this.isStudio = input(false, ...(ngDevMode ? [{ debugName: "isStudio" }] : /* istanbul ignore next */ []));
|
|
6101
5735
|
this.useContainerAsSizeProvider = input(true, ...(ngDevMode ? [{ debugName: "useContainerAsSizeProvider" }] : /* istanbul ignore next */ []));
|
|
6102
5736
|
this.studioResolutionSize = input({
|
|
@@ -6199,16 +5833,7 @@ class UnrealSceneComponent {
|
|
|
6199
5833
|
containerHeight = this.videoElement()?.nativeElement.offsetHeight || 2;
|
|
6200
5834
|
}
|
|
6201
5835
|
const pixelRatio = this.pixelRatio;
|
|
6202
|
-
|
|
6203
|
-
//New Approach
|
|
6204
|
-
return getResizeValuesUniversal({
|
|
6205
|
-
pixelRatio,
|
|
6206
|
-
containerWidth,
|
|
6207
|
-
containerHeight,
|
|
6208
|
-
maxResolution: this.maxResolution,
|
|
6209
|
-
});
|
|
6210
|
-
}
|
|
6211
|
-
return getResizeValuesUniversalOld({
|
|
5836
|
+
return getResizeValuesUniversal({
|
|
6212
5837
|
pixelRatio,
|
|
6213
5838
|
containerWidth,
|
|
6214
5839
|
containerHeight,
|
|
@@ -6216,20 +5841,11 @@ class UnrealSceneComponent {
|
|
|
6216
5841
|
});
|
|
6217
5842
|
}
|
|
6218
5843
|
getResizeStudioValues() {
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
pixelRatio: this.pixelRatio,
|
|
6222
|
-
containerWidth: this.videoElement()?.nativeElement.offsetWidth || 2,
|
|
6223
|
-
containerHeight: this.videoElement()?.nativeElement.offsetHeight || 2,
|
|
6224
|
-
studioWidth: this.width,
|
|
6225
|
-
studioHeight: this.height,
|
|
6226
|
-
maxResolution: this.maxResolution,
|
|
6227
|
-
});
|
|
6228
|
-
}
|
|
6229
|
-
return getResizeStudioValuesOld({
|
|
5844
|
+
const videoElement = this.videoElement()?.nativeElement;
|
|
5845
|
+
return getResizeStudioValues({
|
|
6230
5846
|
pixelRatio: this.pixelRatio,
|
|
6231
|
-
containerWidth:
|
|
6232
|
-
containerHeight:
|
|
5847
|
+
containerWidth: videoElement?.offsetWidth || 2,
|
|
5848
|
+
containerHeight: videoElement?.offsetHeight || 2,
|
|
6233
5849
|
studioWidth: this.width,
|
|
6234
5850
|
studioHeight: this.height,
|
|
6235
5851
|
maxResolution: this.maxResolution,
|
|
@@ -6238,13 +5854,18 @@ class UnrealSceneComponent {
|
|
|
6238
5854
|
sendResize(size) {
|
|
6239
5855
|
this.commandsSender.sendCommandToUnreal({
|
|
6240
5856
|
command: MetaBoxCommand.FChangeResolutionCommand,
|
|
6241
|
-
payload: {
|
|
5857
|
+
payload: {
|
|
5858
|
+
resolution: { x: size.w, y: size.h },
|
|
5859
|
+
payloadVersion: this.isStudio()
|
|
5860
|
+
? EPayloadVersion.disableFovRecalculation
|
|
5861
|
+
: undefined,
|
|
5862
|
+
},
|
|
6242
5863
|
});
|
|
6243
5864
|
}
|
|
6244
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
6245
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, studioResolutionSize: { classPropertyName: "studioResolutionSize", publicName: "studioResolutionSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()" } }, viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer [class.lightModeCursor]=\"lightMode()\" 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 <ng-content select=\"app-low-bandwidth-detector\"></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)}#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)}#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 }); }
|
|
5865
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5866
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, studioResolutionSize: { classPropertyName: "studioResolutionSize", publicName: "studioResolutionSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()" } }, viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer [class.lightModeCursor]=\"lightMode()\" id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-resume-stream-button />\n <app-unreal-status />\n <app-freeze-frame />\n <app-afk-timeout-modal />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n <ng-content select=\"app-low-bandwidth-detector\"></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)}#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)}#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 }); }
|
|
6246
5867
|
}
|
|
6247
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5868
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
6248
5869
|
type: Component,
|
|
6249
5870
|
args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
6250
5871
|
AfkTimeoutModalComponent,
|
|
@@ -6254,7 +5875,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
6254
5875
|
ResumeStreamButtonComponent,
|
|
6255
5876
|
ImageLoadingSrcComponent,
|
|
6256
5877
|
IntroSrcComponent,
|
|
6257
|
-
], template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer [class.lightModeCursor]=\"lightMode()\" 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 <ng-content select=\"app-low-bandwidth-detector\"></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)}#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)}#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"] }]
|
|
5878
|
+
], template: "<div class=\"frame unreal-container\">\n <div #videoContainer [class.lightModeCursor]=\"lightMode()\" id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-resume-stream-button />\n <app-unreal-status />\n <app-freeze-frame />\n <app-afk-timeout-modal />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n <ng-content select=\"app-low-bandwidth-detector\"></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)}#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)}#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"] }]
|
|
6258
5879
|
}], ctorParameters: () => [], propDecorators: { isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], studioResolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "studioResolutionSize", required: false }] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], onMouseOver: [{
|
|
6259
5880
|
type: HostListener,
|
|
6260
5881
|
args: ['mouseover']
|
|
@@ -6283,12 +5904,12 @@ class WebrtcErrorModalComponent {
|
|
|
6283
5904
|
}
|
|
6284
5905
|
this.close();
|
|
6285
5906
|
}
|
|
6286
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
6287
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
5907
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5908
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"src-modal\">\n <header class=\"src-modal__header\"></header>\n <section class=\"src-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"src-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=\"src-modal__footer\">\n <src-button\n (onClick)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </src-button>\n </footer>\n</div>\n", styles: [".src-modal{--modalBodyPadding: 20px 8px 20px 20px;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto}.src-modal__body{width:100%}.src-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}.src-modal__body a{word-wrap:break-word;white-space:normal}\n"], dependencies: [{ kind: "component", type: SourceButtonComponent, selector: "src-button", inputs: ["type", "appearance", "weight", "size", "context", "customClass", "isFullWidth", "isPressed", "isDisabled", "isLoading", "isInverted", "srcButtonConfig", "formID", "data-testid", "ariaLabel"], outputs: ["onClick", "onSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6288
5909
|
}
|
|
6289
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5910
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
|
|
6290
5911
|
type: Component,
|
|
6291
|
-
args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"src-modal\">\
|
|
5912
|
+
args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"src-modal\">\n <header class=\"src-modal__header\"></header>\n <section class=\"src-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"src-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=\"src-modal__footer\">\n <src-button\n (onClick)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </src-button>\n </footer>\n</div>\n", styles: [".src-modal{--modalBodyPadding: 20px 8px 20px 20px;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto}.src-modal__body{width:100%}.src-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}.src-modal__body a{word-wrap:break-word;white-space:normal}\n"] }]
|
|
6292
5913
|
}] });
|
|
6293
5914
|
|
|
6294
5915
|
class FilterSettingsComponent {
|
|
@@ -6332,12 +5953,12 @@ class FilterSettingsComponent {
|
|
|
6332
5953
|
panelOpen: this.settings.panelOpen,
|
|
6333
5954
|
});
|
|
6334
5955
|
}
|
|
6335
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
6336
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
5956
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FilterSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5957
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: FilterSettingsComponent, isStandalone: true, selector: "app-filter-settings", ngImport: i0, template: "<div class=\"settings-container\">\n <button (click)=\"togglePanel()\" class=\"gear-button\">LBM</button>\n @if (settings.panelOpen) {\n <div class=\"settings-panel\">\n <h3>LBM Trigger Settings</h3>\n <h5>Data Flow Monitor</h5>\n <form>\n <label>\n Monitoring delay:\n <input\n [(ngModel)]=\"settings.monitoringDelayTime\"\n [placeholder]=\"defaultFilterModel.monitoringDelayTime\"\n type=\"number\"\n name=\"monitoringDelayTime\"\n />\n </label>\n\n <label>\n Minimum Bitrate (kbit/s):\n <input\n [(ngModel)]=\"settings.minimumBitrate\"\n [placeholder]=\"defaultFilterModel.minimumBitrate\"\n type=\"number\"\n name=\"minimumBitrate\"\n />\n </label>\n <label>\n Yellow Flag (%):\n <input\n [(ngModel)]=\"settings.yellowFlag\"\n [placeholder]=\"defaultFilterModel.yellowFlag\"\n type=\"number\"\n name=\"yellowFlag\"\n />\n </label>\n <label>\n Red Flag (%):\n <input\n [(ngModel)]=\"settings.redFlag\"\n [placeholder]=\"defaultFilterModel.redFlag\"\n type=\"number\"\n name=\"redFlag\"\n />\n </label>\n <label>\n Minimum FPS:\n <input\n [(ngModel)]=\"settings.minimumFps\"\n [placeholder]=\"defaultFilterModel.minimumFps\"\n type=\"number\"\n name=\"minimumFps\"\n />\n </label>\n <hr />\n <h5>Kalman Filter</h5>\n <label>\n Initial Bitrate Estimate (kbit/s):\n <input\n [(ngModel)]=\"settings.initialBitrateEstimate\"\n [placeholder]=\"defaultFilterModel.initialBitrateEstimate\"\n type=\"number\"\n name=\"initialBitrateEstimate\"\n />\n </label>\n <label>\n Initial Error Covariance:\n <input\n [(ngModel)]=\"settings.initialErrorCovariance\"\n [placeholder]=\"defaultFilterModel.initialErrorCovariance\"\n type=\"number\"\n name=\"initialErrorCovariance\"\n />\n </label>\n <label>\n Process Noise (Q):\n <input\n [(ngModel)]=\"settings.processNoise\"\n [placeholder]=\"defaultFilterModel.processNoise\"\n type=\"number\"\n name=\"processNoise\"\n />\n </label>\n <label>\n Measurement Noise (R):\n <input\n [(ngModel)]=\"settings.measurementNoise\"\n [placeholder]=\"defaultFilterModel.measurementNoise\"\n type=\"number\"\n name=\"measurementNoise\"\n />\n </label>\n </form>\n <br />\n <br />\n <div class=\"apply-button-container\">\n <button (click)=\"reset()\">Reset</button>\n <button (click)=\"saveSettings()\">Apply</button>\n </div>\n </div>\n }\n</div>\n", styles: [".settings-container{position:absolute;top:65px;right:10px;z-index:1000}.gear-button{right:0;width:50px;position:absolute;cursor:pointer;font-size:10px;background:none;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#e6f419;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}.settings-panel{font-size:13px;background:#fff;border:1px solid #ccc;padding:15px;margin-top:25px;border-radius:4px;box-shadow:0 2px 8px #0003}.settings-panel h3{margin-top:0}.settings-panel form{display:flex;flex-direction:column}.settings-panel label{margin-bottom:10px;display:flex;flex-direction:column}.settings-panel input{padding:4px;margin-top:4px;border:1px solid #ccc;border-radius:2px}.apply-button-container{position:absolute;bottom:15px;right:15px}.apply-button-container button{padding:6px 12px;border:none;background-color:#1976d2;color:#fff;border-radius:4px;cursor:pointer;margin:2px}.apply-button-container button:hover{background-color:#1565c0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6337
5958
|
}
|
|
6338
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
5959
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: FilterSettingsComponent, decorators: [{
|
|
6339
5960
|
type: Component,
|
|
6340
|
-
args: [{ selector: 'app-filter-settings', imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"settings-container\">\
|
|
5961
|
+
args: [{ selector: 'app-filter-settings', imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"settings-container\">\n <button (click)=\"togglePanel()\" class=\"gear-button\">LBM</button>\n @if (settings.panelOpen) {\n <div class=\"settings-panel\">\n <h3>LBM Trigger Settings</h3>\n <h5>Data Flow Monitor</h5>\n <form>\n <label>\n Monitoring delay:\n <input\n [(ngModel)]=\"settings.monitoringDelayTime\"\n [placeholder]=\"defaultFilterModel.monitoringDelayTime\"\n type=\"number\"\n name=\"monitoringDelayTime\"\n />\n </label>\n\n <label>\n Minimum Bitrate (kbit/s):\n <input\n [(ngModel)]=\"settings.minimumBitrate\"\n [placeholder]=\"defaultFilterModel.minimumBitrate\"\n type=\"number\"\n name=\"minimumBitrate\"\n />\n </label>\n <label>\n Yellow Flag (%):\n <input\n [(ngModel)]=\"settings.yellowFlag\"\n [placeholder]=\"defaultFilterModel.yellowFlag\"\n type=\"number\"\n name=\"yellowFlag\"\n />\n </label>\n <label>\n Red Flag (%):\n <input\n [(ngModel)]=\"settings.redFlag\"\n [placeholder]=\"defaultFilterModel.redFlag\"\n type=\"number\"\n name=\"redFlag\"\n />\n </label>\n <label>\n Minimum FPS:\n <input\n [(ngModel)]=\"settings.minimumFps\"\n [placeholder]=\"defaultFilterModel.minimumFps\"\n type=\"number\"\n name=\"minimumFps\"\n />\n </label>\n <hr />\n <h5>Kalman Filter</h5>\n <label>\n Initial Bitrate Estimate (kbit/s):\n <input\n [(ngModel)]=\"settings.initialBitrateEstimate\"\n [placeholder]=\"defaultFilterModel.initialBitrateEstimate\"\n type=\"number\"\n name=\"initialBitrateEstimate\"\n />\n </label>\n <label>\n Initial Error Covariance:\n <input\n [(ngModel)]=\"settings.initialErrorCovariance\"\n [placeholder]=\"defaultFilterModel.initialErrorCovariance\"\n type=\"number\"\n name=\"initialErrorCovariance\"\n />\n </label>\n <label>\n Process Noise (Q):\n <input\n [(ngModel)]=\"settings.processNoise\"\n [placeholder]=\"defaultFilterModel.processNoise\"\n type=\"number\"\n name=\"processNoise\"\n />\n </label>\n <label>\n Measurement Noise (R):\n <input\n [(ngModel)]=\"settings.measurementNoise\"\n [placeholder]=\"defaultFilterModel.measurementNoise\"\n type=\"number\"\n name=\"measurementNoise\"\n />\n </label>\n </form>\n <br />\n <br />\n <div class=\"apply-button-container\">\n <button (click)=\"reset()\">Reset</button>\n <button (click)=\"saveSettings()\">Apply</button>\n </div>\n </div>\n }\n</div>\n", styles: [".settings-container{position:absolute;top:65px;right:10px;z-index:1000}.gear-button{right:0;width:50px;position:absolute;cursor:pointer;font-size:10px;background:none;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#e6f419;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}.settings-panel{font-size:13px;background:#fff;border:1px solid #ccc;padding:15px;margin-top:25px;border-radius:4px;box-shadow:0 2px 8px #0003}.settings-panel h3{margin-top:0}.settings-panel form{display:flex;flex-direction:column}.settings-panel label{margin-bottom:10px;display:flex;flex-direction:column}.settings-panel input{padding:4px;margin-top:4px;border:1px solid #ccc;border-radius:2px}.apply-button-container{position:absolute;bottom:15px;right:15px}.apply-button-container button{padding:6px 12px;border:none;background-color:#1976d2;color:#fff;border-radius:4px;cursor:pointer;margin:2px}.apply-button-container button:hover{background-color:#1565c0}\n"] }]
|
|
6341
5962
|
}] });
|
|
6342
5963
|
|
|
6343
5964
|
class LowBandwidthDetectorComponent {
|
|
@@ -6440,12 +6061,12 @@ class LowBandwidthDetectorComponent {
|
|
|
6440
6061
|
this.store.dispatch(changeLowBandwidth({ lowBandwidth: false }));
|
|
6441
6062
|
});
|
|
6442
6063
|
}
|
|
6443
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
6444
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
6064
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LowBandwidthDetectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6065
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: LowBandwidthDetectorComponent, isStandalone: true, selector: "app-low-bandwidth-detector", ngImport: i0, template: "@if (isReducedQuality() || isLowBandwidth()) {\n <div\n [class.expanded]=\"isIndicatorExpanded() && isLowBandwidth()\"\n class=\"lbm-indicator freeze-loader\"\n >\n <div (click)=\"toggleIndicator(true)\" class=\"lbm-icon\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 20 20\">\n <path\n fill=\"#85888E\"\n d=\"M7.189 3.605c-.73.145-1.438.35-2.126.614A14.412 14.412 0 0 0 .896 6.666a1.08 1.08 0 0 0-.375.844c0 .34.118.629.354.865s.524.36.865.375c.34.014.65-.09.927-.313a11.89 11.89 0 0 1 3.385-1.916 10.94 10.94 0 0 1 1.235-.375l-.098-2.541ZM7.385 8.708a9.107 9.107 0 0 0-2.906 1.48c-.264.194-.402.464-.416.812-.014.347.104.646.354.896.236.236.524.364.864.385.34.02.664-.073.97-.281.422-.29.878-.53 1.368-.721a2.545 2.545 0 0 1-.166-.814l-.068-1.757ZM12.386 11.267c.094-.25.15-.52.161-.802l.068-1.755a9.019 9.019 0 0 1 2.927 1.52c.264.193.4.46.406.801.007.34-.114.635-.364.885a1.213 1.213 0 0 1-.865.365A1.614 1.614 0 0 1 13.77 12a6.574 6.574 0 0 0-1.385-.733ZM12.713 6.146l.098-2.542c.73.146 1.438.351 2.127.615 1.541.59 2.93 1.406 4.166 2.447.25.223.379.5.386.834.007.333-.115.625-.365.875a1.253 1.253 0 0 1-.864.375c-.34.014-.65-.09-.927-.313a11.892 11.892 0 0 0-3.386-1.916 10.94 10.94 0 0 0-1.235-.375ZM8.813 16.187c.32.32.715.48 1.187.48.472 0 .868-.16 1.188-.48.32-.32.479-.715.479-1.187 0-.473-.16-.868-.48-1.188-.319-.32-.715-.479-1.187-.479-.472 0-.868.16-1.187.48-.32.319-.48.714-.48 1.187 0 .472.16.868.48 1.187Z\"\n />\n <path\n fill=\"#fff\"\n fill-rule=\"evenodd\"\n d=\"M10 .833c-.91 0-1.637.756-1.602 1.665l.304 7.92a1.299 1.299 0 0 0 2.596 0l.305-7.92A1.604 1.604 0 0 0 10 .833ZM8.813 16.187c.32.32.715.48 1.187.48.472 0 .868-.16 1.188-.48.32-.32.479-.715.479-1.187 0-.473-.16-.868-.48-1.188-.319-.32-.715-.479-1.187-.479-.472 0-.868.16-1.187.48-.32.319-.48.714-.48 1.187 0 .472.16.868.48 1.187Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n\n <div\n [class.lbm-message--open]=\"isLowBandwidth() && isIndicatorExpanded()\"\n class=\"lbm-message\"\n >\n <p class=\"lbm-description\">\n Fluid Interactivity Modes were disabled due to an unstable connection.\n\n <button\n (click)=\"openLBMDialog()\"\n [attr.data-testid]=\"'learn-more-lbm'\"\n type=\"button\"\n class=\"lbm-learn-more\"\n >\n Learn more\n </button>\n </p>\n <button\n (click)=\"toggleIndicator(false)\"\n [attr.data-testid]=\"'close-lbm-indicator'\"\n type=\"button\"\n class=\"lbm-close\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M10.0001 11.2289L6.68618 14.5428C6.51951 14.7095 6.31818 14.7895 6.08218 14.7828C5.84618 14.7755 5.64485 14.6885 5.47818 14.5218C5.31151 14.3552 5.22818 14.1505 5.22818 13.9078C5.22818 13.6645 5.31151 13.4595 5.47818 13.2928L8.77107 9.99992L5.45718 6.68603C5.29051 6.51936 5.21051 6.3147 5.21718 6.07203C5.22451 5.8287 5.31151 5.6237 5.47818 5.45703C5.64485 5.29036 5.84951 5.20703 6.09218 5.20703C6.33551 5.20703 6.54051 5.29036 6.70718 5.45703L10.0001 8.77092L13.314 5.45703C13.4806 5.29036 13.6853 5.20703 13.928 5.20703C14.1713 5.20703 14.3763 5.29036 14.543 5.45703C14.7096 5.6237 14.793 5.8287 14.793 6.07203C14.793 6.3147 14.7096 6.51936 14.543 6.68603L11.2291 9.99992L14.543 13.3138C14.7096 13.4805 14.793 13.6818 14.793 13.9178C14.793 14.1538 14.7096 14.3552 14.543 14.5218C14.3763 14.6885 14.1713 14.7718 13.928 14.7718C13.6853 14.7718 13.4806 14.6885 13.314 14.5218L10.0001 11.2289Z\"\n fill=\"white\"\n />\n </svg>\n </button>\n </div>\n </div>\n}\n\n@if (isDevMode) {\n <app-filter-settings />\n}\n", styles: [".freeze-loader,.lbm-indicator{--lbmPositionTop: 18px;--lbmPositionLeft: 18px;--lbmPositionRight: 18px;--lbmIndicatorSize: 36px;--lbmIndicatorBorderRadius: 8px;--lbmIndicatorCloseSize: 20px;--lbmPadding: 10px;--lbmTextSize: 13px;--lbmLineHeight: 20px;--lbmTextColor: #ffffff;--lbmBackgroundColor: rgba(17, 24, 39, .7);position:absolute;top:var(--lbmPositionTop);left:var(--lbmPositionLeft);z-index:10;display:flex;justify-content:center;align-items:flex-start;min-width:var(--lbmIndicatorSize);min-height:var(--lbmIndicatorSize);overflow:hidden}.freeze-loader.expanded,.lbm-indicator.expanded{--lbmPositionTop: 8px;--lbmPositionLeft: 8px;--lbmPositionRight: 8px;width:auto;max-width:calc(100% - var(--lbmPositionLeft) - var(--lbmPositionRight));padding:var(--lbmPadding);background:var(--lbmBackgroundColor);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--lbmIndicatorBorderRadius);gap:12px}.freeze-loader .lbm-icon,.lbm-indicator .lbm-icon{display:flex;width:var(--lbmIndicatorSize);height:var(--lbmIndicatorSize);padding:8px;color:#fff;background-color:var(--lbmBackgroundColor);border-radius:50%;flex-shrink:0;cursor:pointer}.freeze-loader .lbm-icon svg,.freeze-loader .lbm-icon img,.lbm-indicator .lbm-icon svg,.lbm-indicator .lbm-icon img{width:100%;height:100%}.freeze-loader .lbm-close,.lbm-indicator .lbm-close{position:absolute;top:0;right:0;width:var(--lbmIndicatorCloseSize);height:var(--lbmIndicatorCloseSize);background-color:transparent;border:none;padding:0;cursor:pointer}.freeze-loader .lbm-message,.lbm-indicator .lbm-message{position:relative;opacity:0;height:0;max-width:0;padding-right:24px;pointer-events:none;visibility:hidden;animation:closeMessage .3s forwards}.freeze-loader .lbm-message--open,.lbm-indicator .lbm-message--open{position:relative;visibility:visible;display:flex;align-items:center;align-self:center;pointer-events:all;gap:12px;max-width:fit-content;height:auto;opacity:1;animation:openMessage .3s forwards}.freeze-loader .lbm-description,.lbm-indicator .lbm-description{margin:0;font-size:var(--lbmTextSize);font-weight:400;line-height:var(--lbmLineHeight);color:var(--lbmTextColor)}.freeze-loader .lbm-learn-more,.lbm-indicator .lbm-learn-more{display:inline-flex;padding:0;font-size:var(--lbmTextSize);font-weight:400;line-height:var(--lbmLineHeight);color:var(--lbmTextColor);text-decoration-line:underline;background-color:transparent;border:none;cursor:pointer}.freeze-loader .lbm-learn-more:hover,.lbm-indicator .lbm-learn-more:hover{text-decoration:none}@keyframes openMessage{0%{opacity:0;max-width:0;height:0}10%{height:auto;max-width:fit-content}to{opacity:1;height:auto;max-width:fit-content}}@keyframes closeMessage{0%{opacity:1;max-width:fit-content}to{opacity:0;max-width:0}}\n"], dependencies: [{ kind: "component", type: FilterSettingsComponent, selector: "app-filter-settings" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6445
6066
|
}
|
|
6446
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
6067
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LowBandwidthDetectorComponent, decorators: [{
|
|
6447
6068
|
type: Component,
|
|
6448
|
-
args: [{ selector: 'app-low-bandwidth-detector', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FilterSettingsComponent], template: "@if (isReducedQuality() || isLowBandwidth()) {\
|
|
6069
|
+
args: [{ selector: 'app-low-bandwidth-detector', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FilterSettingsComponent], template: "@if (isReducedQuality() || isLowBandwidth()) {\n <div\n [class.expanded]=\"isIndicatorExpanded() && isLowBandwidth()\"\n class=\"lbm-indicator freeze-loader\"\n >\n <div (click)=\"toggleIndicator(true)\" class=\"lbm-icon\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 20 20\">\n <path\n fill=\"#85888E\"\n d=\"M7.189 3.605c-.73.145-1.438.35-2.126.614A14.412 14.412 0 0 0 .896 6.666a1.08 1.08 0 0 0-.375.844c0 .34.118.629.354.865s.524.36.865.375c.34.014.65-.09.927-.313a11.89 11.89 0 0 1 3.385-1.916 10.94 10.94 0 0 1 1.235-.375l-.098-2.541ZM7.385 8.708a9.107 9.107 0 0 0-2.906 1.48c-.264.194-.402.464-.416.812-.014.347.104.646.354.896.236.236.524.364.864.385.34.02.664-.073.97-.281.422-.29.878-.53 1.368-.721a2.545 2.545 0 0 1-.166-.814l-.068-1.757ZM12.386 11.267c.094-.25.15-.52.161-.802l.068-1.755a9.019 9.019 0 0 1 2.927 1.52c.264.193.4.46.406.801.007.34-.114.635-.364.885a1.213 1.213 0 0 1-.865.365A1.614 1.614 0 0 1 13.77 12a6.574 6.574 0 0 0-1.385-.733ZM12.713 6.146l.098-2.542c.73.146 1.438.351 2.127.615 1.541.59 2.93 1.406 4.166 2.447.25.223.379.5.386.834.007.333-.115.625-.365.875a1.253 1.253 0 0 1-.864.375c-.34.014-.65-.09-.927-.313a11.892 11.892 0 0 0-3.386-1.916 10.94 10.94 0 0 0-1.235-.375ZM8.813 16.187c.32.32.715.48 1.187.48.472 0 .868-.16 1.188-.48.32-.32.479-.715.479-1.187 0-.473-.16-.868-.48-1.188-.319-.32-.715-.479-1.187-.479-.472 0-.868.16-1.187.48-.32.319-.48.714-.48 1.187 0 .472.16.868.48 1.187Z\"\n />\n <path\n fill=\"#fff\"\n fill-rule=\"evenodd\"\n d=\"M10 .833c-.91 0-1.637.756-1.602 1.665l.304 7.92a1.299 1.299 0 0 0 2.596 0l.305-7.92A1.604 1.604 0 0 0 10 .833ZM8.813 16.187c.32.32.715.48 1.187.48.472 0 .868-.16 1.188-.48.32-.32.479-.715.479-1.187 0-.473-.16-.868-.48-1.188-.319-.32-.715-.479-1.187-.479-.472 0-.868.16-1.187.48-.32.319-.48.714-.48 1.187 0 .472.16.868.48 1.187Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n\n <div\n [class.lbm-message--open]=\"isLowBandwidth() && isIndicatorExpanded()\"\n class=\"lbm-message\"\n >\n <p class=\"lbm-description\">\n Fluid Interactivity Modes were disabled due to an unstable connection.\n\n <button\n (click)=\"openLBMDialog()\"\n [attr.data-testid]=\"'learn-more-lbm'\"\n type=\"button\"\n class=\"lbm-learn-more\"\n >\n Learn more\n </button>\n </p>\n <button\n (click)=\"toggleIndicator(false)\"\n [attr.data-testid]=\"'close-lbm-indicator'\"\n type=\"button\"\n class=\"lbm-close\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M10.0001 11.2289L6.68618 14.5428C6.51951 14.7095 6.31818 14.7895 6.08218 14.7828C5.84618 14.7755 5.64485 14.6885 5.47818 14.5218C5.31151 14.3552 5.22818 14.1505 5.22818 13.9078C5.22818 13.6645 5.31151 13.4595 5.47818 13.2928L8.77107 9.99992L5.45718 6.68603C5.29051 6.51936 5.21051 6.3147 5.21718 6.07203C5.22451 5.8287 5.31151 5.6237 5.47818 5.45703C5.64485 5.29036 5.84951 5.20703 6.09218 5.20703C6.33551 5.20703 6.54051 5.29036 6.70718 5.45703L10.0001 8.77092L13.314 5.45703C13.4806 5.29036 13.6853 5.20703 13.928 5.20703C14.1713 5.20703 14.3763 5.29036 14.543 5.45703C14.7096 5.6237 14.793 5.8287 14.793 6.07203C14.793 6.3147 14.7096 6.51936 14.543 6.68603L11.2291 9.99992L14.543 13.3138C14.7096 13.4805 14.793 13.6818 14.793 13.9178C14.793 14.1538 14.7096 14.3552 14.543 14.5218C14.3763 14.6885 14.1713 14.7718 13.928 14.7718C13.6853 14.7718 13.4806 14.6885 13.314 14.5218L10.0001 11.2289Z\"\n fill=\"white\"\n />\n </svg>\n </button>\n </div>\n </div>\n}\n\n@if (isDevMode) {\n <app-filter-settings />\n}\n", styles: [".freeze-loader,.lbm-indicator{--lbmPositionTop: 18px;--lbmPositionLeft: 18px;--lbmPositionRight: 18px;--lbmIndicatorSize: 36px;--lbmIndicatorBorderRadius: 8px;--lbmIndicatorCloseSize: 20px;--lbmPadding: 10px;--lbmTextSize: 13px;--lbmLineHeight: 20px;--lbmTextColor: #ffffff;--lbmBackgroundColor: rgba(17, 24, 39, .7);position:absolute;top:var(--lbmPositionTop);left:var(--lbmPositionLeft);z-index:10;display:flex;justify-content:center;align-items:flex-start;min-width:var(--lbmIndicatorSize);min-height:var(--lbmIndicatorSize);overflow:hidden}.freeze-loader.expanded,.lbm-indicator.expanded{--lbmPositionTop: 8px;--lbmPositionLeft: 8px;--lbmPositionRight: 8px;width:auto;max-width:calc(100% - var(--lbmPositionLeft) - var(--lbmPositionRight));padding:var(--lbmPadding);background:var(--lbmBackgroundColor);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--lbmIndicatorBorderRadius);gap:12px}.freeze-loader .lbm-icon,.lbm-indicator .lbm-icon{display:flex;width:var(--lbmIndicatorSize);height:var(--lbmIndicatorSize);padding:8px;color:#fff;background-color:var(--lbmBackgroundColor);border-radius:50%;flex-shrink:0;cursor:pointer}.freeze-loader .lbm-icon svg,.freeze-loader .lbm-icon img,.lbm-indicator .lbm-icon svg,.lbm-indicator .lbm-icon img{width:100%;height:100%}.freeze-loader .lbm-close,.lbm-indicator .lbm-close{position:absolute;top:0;right:0;width:var(--lbmIndicatorCloseSize);height:var(--lbmIndicatorCloseSize);background-color:transparent;border:none;padding:0;cursor:pointer}.freeze-loader .lbm-message,.lbm-indicator .lbm-message{position:relative;opacity:0;height:0;max-width:0;padding-right:24px;pointer-events:none;visibility:hidden;animation:closeMessage .3s forwards}.freeze-loader .lbm-message--open,.lbm-indicator .lbm-message--open{position:relative;visibility:visible;display:flex;align-items:center;align-self:center;pointer-events:all;gap:12px;max-width:fit-content;height:auto;opacity:1;animation:openMessage .3s forwards}.freeze-loader .lbm-description,.lbm-indicator .lbm-description{margin:0;font-size:var(--lbmTextSize);font-weight:400;line-height:var(--lbmLineHeight);color:var(--lbmTextColor)}.freeze-loader .lbm-learn-more,.lbm-indicator .lbm-learn-more{display:inline-flex;padding:0;font-size:var(--lbmTextSize);font-weight:400;line-height:var(--lbmLineHeight);color:var(--lbmTextColor);text-decoration-line:underline;background-color:transparent;border:none;cursor:pointer}.freeze-loader .lbm-learn-more:hover,.lbm-indicator .lbm-learn-more:hover{text-decoration:none}@keyframes openMessage{0%{opacity:0;max-width:0;height:0}10%{height:auto;max-width:fit-content}to{opacity:1;height:auto;max-width:fit-content}}@keyframes closeMessage{0%{opacity:1;max-width:fit-content}to{opacity:0;max-width:0}}\n"] }]
|
|
6449
6070
|
}] });
|
|
6450
6071
|
|
|
6451
6072
|
function provideUnrealModule() {
|
|
@@ -6469,15 +6090,7 @@ function provideUnrealModule() {
|
|
|
6469
6090
|
SignallingService,
|
|
6470
6091
|
StreamStatusTelemetryService,
|
|
6471
6092
|
FpsMonitorService,
|
|
6472
|
-
|
|
6473
|
-
provide: WebRtcPlayerService,
|
|
6474
|
-
useFactory: () => {
|
|
6475
|
-
const config = inject(UNREAL_CONFIG, { optional: true });
|
|
6476
|
-
return config?.newWebRtcConnector
|
|
6477
|
-
? new WebRtcPlayerService2()
|
|
6478
|
-
: new WebRtcPlayerService();
|
|
6479
|
-
},
|
|
6480
|
-
},
|
|
6093
|
+
WebRtcPlayerService,
|
|
6481
6094
|
provideEnvironmentInitializer(() => {
|
|
6482
6095
|
inject(AggregatorService);
|
|
6483
6096
|
inject(InputService);
|
|
@@ -6495,5 +6108,5 @@ function provideUnrealModule() {
|
|
|
6495
6108
|
* Generated bundle index. Do not edit.
|
|
6496
6109
|
*/
|
|
6497
6110
|
|
|
6498
|
-
export { AFKService, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CONSOLE_COMMAND_DISABLE_MESSAGES, CONSOLE_COMMAND_ENABLE_MESSAGES, CONSOLE_COMMAND_PIXEL_QUALITY, CommandTelemetryService, CommandsEffects, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MessageType, MouseButton, MouseButtonsMask, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, 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_TIMEOUT, WebRtcPlayerService,
|
|
6111
|
+
export { AFKService, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CONSOLE_COMMAND_DISABLE_MESSAGES, CONSOLE_COMMAND_ENABLE_MESSAGES, CONSOLE_COMMAND_PIXEL_QUALITY, CommandTelemetryService, CommandsEffects, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MessageType, MouseButton, MouseButtonsMask, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, 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_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, changeLowBandwidth, changeStatusMainVideoOnScene, changeStreamResolutionAction, changeStreamResolutionSuccessAction, commandCompleted, commandStarted, commandsFeature, commandsReducer, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeStudioValuesOld, getResizeValuesUniversal, getResizeValuesUniversalOld, getRtcErrorMessage, iceConnectionFailed, initSignalling, keepMaxUntilReset, makeEven, provideUnrealModule, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetWarnTimeout, saveAnalyticsEvent, selectClientAndViewIds, selectCommandProgress, selectCommandsInProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setDataChannelConnected, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setKalmanSettings, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setViewportNotReady, setViewportReady, showUnrealErrorMessage, smoothTransition, startStream, trackMixpanelEvent, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
6499
6112
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|