@3dsource/angular-unreal-module 0.0.108 → 0.0.109
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 +272 -690
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +1 -1
- package/types/3dsource-angular-unreal-module.d.ts +3 -54
- package/types/3dsource-angular-unreal-module.d.ts.map +0 -1
|
@@ -10,7 +10,7 @@ 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
14
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
15
15
|
import { NgOptimizedImage, AsyncPipe, JsonPipe } from '@angular/common';
|
|
16
16
|
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
@@ -1180,11 +1180,11 @@ class UnrealErrorModalComponent {
|
|
|
1180
1180
|
this.#dialogRef.close();
|
|
1181
1181
|
}
|
|
1182
1182
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1183
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"src-modal src-modal--small\">\
|
|
1183
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", 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
1185
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", 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
|
/**
|
|
@@ -2878,103 +2878,243 @@ class WebRtcPlayerService extends SubService {
|
|
|
2878
2878
|
this.useMic = false;
|
|
2879
2879
|
this.forceTURN = false;
|
|
2880
2880
|
this.forceMonoAudio = false;
|
|
2881
|
+
/** Whether the remote SDP has been applied to the current peer connection */
|
|
2882
|
+
this.remoteDescriptionSet = false;
|
|
2883
|
+
/** ICE candidates received before the remote description was set */
|
|
2884
|
+
this.iceCandidateBuffer = [];
|
|
2881
2885
|
this.isReconnecting = this.store.selectSignal(unrealFeature.selectIsReconnecting);
|
|
2882
2886
|
this.init();
|
|
2883
2887
|
this.actions$.pipe(ofType(dropDC)).subscribe(() => this.dcClient?.close());
|
|
2884
2888
|
this.actions$.pipe(ofType(dropPC)).subscribe(() => this.pcClient?.close());
|
|
2885
2889
|
}
|
|
2886
2890
|
init() {
|
|
2887
|
-
const iceCandidateBuffer = [];
|
|
2888
|
-
const processBuffer = () => {
|
|
2889
|
-
iceCandidateBuffer.forEach((cnd) => {
|
|
2890
|
-
this.handleCandidateFromServer(cnd);
|
|
2891
|
-
});
|
|
2892
|
-
iceCandidateBuffer.length = 0;
|
|
2893
|
-
};
|
|
2894
2891
|
this.signallingSrv.onConfig$.subscribe((config) => {
|
|
2895
2892
|
this.videoService.create();
|
|
2896
2893
|
this.setConfig(config);
|
|
2897
2894
|
});
|
|
2895
|
+
// Server-initiated offer: set remote description and respond with answer
|
|
2896
|
+
this.signallingSrv.onOffer$.pipe(filter(Truthy)).subscribe((offer) => {
|
|
2897
|
+
void this.handleServerOffer(offer);
|
|
2898
|
+
});
|
|
2899
|
+
// Answer to a client-initiated offer
|
|
2898
2900
|
this.signallingSrv.onWebRtcAnswer$
|
|
2899
2901
|
.pipe(filter(Truthy))
|
|
2900
2902
|
.subscribe((answer) => {
|
|
2901
|
-
this.
|
|
2902
|
-
processBuffer();
|
|
2903
|
-
});
|
|
2904
|
-
this.signallingSrv.onOffer$.pipe(filter(Truthy)).subscribe(() => {
|
|
2905
|
-
void this.createWebRtcOffer();
|
|
2903
|
+
void this.handleServerAnswer(answer);
|
|
2906
2904
|
});
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
.
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
if (
|
|
2913
|
-
|
|
2905
|
+
// ICE candidates — buffered until remote description is set
|
|
2906
|
+
this.signallingSrv.onWebRtcIce$.subscribe((candidate) => {
|
|
2907
|
+
this.commandTelemetryService.trackStopCommand('EXT-iceCandidate', true, {
|
|
2908
|
+
multi: true,
|
|
2909
|
+
});
|
|
2910
|
+
if (this.remoteDescriptionSet) {
|
|
2911
|
+
this.handleCandidateFromServer(candidate);
|
|
2912
|
+
}
|
|
2913
|
+
else {
|
|
2914
|
+
this.iceCandidateBuffer.push(candidate);
|
|
2914
2915
|
}
|
|
2915
2916
|
});
|
|
2916
2917
|
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Handles an SDP offer received from the server.
|
|
2920
|
+
* Creates a new peer connection, applies the remote offer,
|
|
2921
|
+
* then responds with an SDP answer.
|
|
2922
|
+
*
|
|
2923
|
+
* The DataChannel is NOT created here — the server creates it,
|
|
2924
|
+
* and we receive it via the `datachannel` event on the peer connection.
|
|
2925
|
+
*/
|
|
2926
|
+
async handleServerOffer(offer) {
|
|
2927
|
+
Logger.info('Received offer from server, creating answer');
|
|
2928
|
+
try {
|
|
2929
|
+
this.remoteDescriptionSet = false;
|
|
2930
|
+
this.iceCandidateBuffer.length = 0;
|
|
2931
|
+
if (!this.pcClient) {
|
|
2932
|
+
this.setupPeerConnection(this.cfg);
|
|
2933
|
+
}
|
|
2934
|
+
// Offer already defines media transceivers — don't add extras
|
|
2935
|
+
await this.pcClient?.setRemoteDescription(offer);
|
|
2936
|
+
this.remoteDescriptionSet = true;
|
|
2937
|
+
this.flushIceCandidateBuffer();
|
|
2938
|
+
await this.createAnswer(this.pcClient);
|
|
2939
|
+
}
|
|
2940
|
+
catch (e) {
|
|
2941
|
+
Logger.error('Failed to handle server offer', e);
|
|
2942
|
+
this.store.dispatch(disconnectStream({
|
|
2943
|
+
reason: DisconnectReason.WebRTCError,
|
|
2944
|
+
message: 'WebRTCError: Failed to handle server offer',
|
|
2945
|
+
}));
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Handles an SDP answer received from the server in response to our offer.
|
|
2950
|
+
* Applies the remote description and flushes any buffered ICE candidates.
|
|
2951
|
+
*/
|
|
2952
|
+
async handleServerAnswer(answer) {
|
|
2953
|
+
Logger.info('Received answer from server');
|
|
2954
|
+
try {
|
|
2955
|
+
await this.pcClient?.setRemoteDescription(answer);
|
|
2956
|
+
this.remoteDescriptionSet = true;
|
|
2957
|
+
this.flushIceCandidateBuffer();
|
|
2958
|
+
}
|
|
2959
|
+
catch (e) {
|
|
2960
|
+
Logger.error('Failed to set remote description from answer', e);
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
/** Drains buffered ICE candidates after the remote description has been set */
|
|
2964
|
+
flushIceCandidateBuffer() {
|
|
2965
|
+
for (const candidate of this.iceCandidateBuffer) {
|
|
2966
|
+
this.handleCandidateFromServer(candidate);
|
|
2967
|
+
}
|
|
2968
|
+
this.iceCandidateBuffer.length = 0;
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* Creates a client-initiated WebRTC offer and sends it to the server.
|
|
2972
|
+
* When the client offers, it also creates the DataChannel.
|
|
2973
|
+
* Used for peer reconnection through the existing signaling connection.
|
|
2974
|
+
*/
|
|
2917
2975
|
async createWebRtcOffer() {
|
|
2918
|
-
Logger.info('Creating offer');
|
|
2919
|
-
let offer;
|
|
2976
|
+
Logger.info('Creating client-initiated offer');
|
|
2920
2977
|
try {
|
|
2921
|
-
|
|
2978
|
+
this.remoteDescriptionSet = false;
|
|
2979
|
+
this.iceCandidateBuffer.length = 0;
|
|
2980
|
+
if (!this.pcClient) {
|
|
2981
|
+
this.setupPeerConnection(this.cfg);
|
|
2982
|
+
}
|
|
2983
|
+
// Client offers: transceivers first, then DC, then offer
|
|
2984
|
+
await this.setupTransceiversAsync(this.pcClient);
|
|
2985
|
+
this.dcClient = this.createDataChannel(this.pcClient, 'UnrealDcConnection', { ordered: true });
|
|
2986
|
+
await this.createOffer(this.pcClient);
|
|
2922
2987
|
}
|
|
2923
|
-
catch {
|
|
2988
|
+
catch (e) {
|
|
2989
|
+
Logger.error('Failed to create WebRTC offer', e);
|
|
2924
2990
|
this.store.dispatch(disconnectStream({
|
|
2925
2991
|
reason: DisconnectReason.WebRTCError,
|
|
2926
2992
|
message: 'WebRTCError: Offer Error',
|
|
2927
2993
|
}));
|
|
2928
2994
|
}
|
|
2929
|
-
|
|
2995
|
+
}
|
|
2996
|
+
/**
|
|
2997
|
+
* Initializes a new RTCPeerConnection with event handlers.
|
|
2998
|
+
* Transceivers are NOT added here — the caller is responsible for adding
|
|
2999
|
+
* them at the correct point depending on the negotiation flow.
|
|
3000
|
+
*/
|
|
3001
|
+
setupPeerConnection(config) {
|
|
3002
|
+
this.closePC();
|
|
3003
|
+
Logger.log('Creating new RTCPeerConnection with config');
|
|
3004
|
+
this.pcClient = new RTCPeerConnection(config);
|
|
3005
|
+
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE gathering');
|
|
3006
|
+
this.commandTelemetryService.trackStartCommand('EXT-Browser ICE connection');
|
|
3007
|
+
this.commandTelemetryService.trackStartCommand('EXT-Signaling state change');
|
|
3008
|
+
this.handlePeerConnectionEvents(this.pcClient);
|
|
3009
|
+
this.disconnect$.pipe(take(1)).subscribe(() => {
|
|
3010
|
+
this.closePC();
|
|
3011
|
+
});
|
|
2930
3012
|
}
|
|
2931
3013
|
createDataChannel(pc, label, options) {
|
|
2932
|
-
// This is the primary data channel code path when we are "offering"
|
|
2933
3014
|
const datachannel = pc.createDataChannel(label, options);
|
|
2934
3015
|
return this.setupDataChannelCallbacks(datachannel);
|
|
2935
3016
|
}
|
|
2936
|
-
receiveAnswer(answer) {
|
|
2937
|
-
this.pcClient?.setRemoteDescription(answer);
|
|
2938
|
-
}
|
|
2939
3017
|
handleCandidateFromServer(iceCandidate) {
|
|
2940
3018
|
try {
|
|
2941
3019
|
const candidate = new RTCIceCandidate(iceCandidate);
|
|
2942
3020
|
Logger.info('[Unreal ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
2943
|
-
//
|
|
3021
|
+
// If forcing TURN, reject any candidates not relay
|
|
2944
3022
|
if (this.forceTURN) {
|
|
2945
|
-
// check if no relay address is found, if so, we are assuming it means no TURN server
|
|
2946
3023
|
if (candidate.candidate.indexOf('relay') < 0) {
|
|
2947
3024
|
Logger.warn('Dropping candidate because it was not TURN relay.', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|');
|
|
2948
3025
|
return;
|
|
2949
3026
|
}
|
|
2950
3027
|
}
|
|
2951
|
-
this.pcClient?.addIceCandidate(candidate).catch(
|
|
2952
|
-
|
|
3028
|
+
this.pcClient?.addIceCandidate(candidate).catch((e) => {
|
|
3029
|
+
Logger.warn('Failed to add ICE candidate', e);
|
|
2953
3030
|
});
|
|
2954
3031
|
}
|
|
2955
3032
|
catch (e) {
|
|
2956
3033
|
Logger.error('Error handleCandidateFromServer', e);
|
|
2957
3034
|
}
|
|
2958
3035
|
}
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3036
|
+
/**
|
|
3037
|
+
* Reorders the `m=video` line in the SDP so that payload types matching
|
|
3038
|
+
* the given H.264 `profile-level-id` appear first, making the browser
|
|
3039
|
+
* prefer that profile during codec negotiation.
|
|
3040
|
+
*
|
|
3041
|
+
* A `profile-level-id` is a 3-byte hex string (`XXYYZZ`) defined in
|
|
3042
|
+
* RFC 6184 that encodes three H.264 parameters:
|
|
3043
|
+
* - **Profile IDC** (`XX`) — the H.264 profile.
|
|
3044
|
+
* - **Profile IOP** (`YY`) — constraint flags that further narrow the profile.
|
|
3045
|
+
* - **Level IDC** (`ZZ`) — the level, which caps resolution/framerate/bitrate.
|
|
3046
|
+
*
|
|
3047
|
+
* ### H.264 profiles relevant to Unreal Engine Pixel Streaming
|
|
3048
|
+
*
|
|
3049
|
+
* | profile-level-id | Profile | Level | Notes |
|
|
3050
|
+
* |------------------|----------------------------|-------|----------------------------------------------|
|
|
3051
|
+
* | `42001f` | Baseline | 3.1 | No B-frames, low latency; legacy devices |
|
|
3052
|
+
* | `42e01f` | Constrained Baseline | 3.1 | Widest HW decode support; **recommended** |
|
|
3053
|
+
* | `4d001f` | Main | 3.1 | B-frames + CABAC; better compression |
|
|
3054
|
+
* | `4d4028` | Main | 4.0 | Up to 1080p60; common desktop target |
|
|
3055
|
+
* | `640028` | High | 4.0 | Best quality/compression; most GPUs support |
|
|
3056
|
+
* | `64002a` | High | 4.2 | Up to 1080p120 or 4K30 |
|
|
3057
|
+
* | `640033` | High | 5.1 | Up to 4K60; requires modern HW |
|
|
3058
|
+
* | `640034` | High | 5.2 | Up to 4K120; high-end HW only |
|
|
3059
|
+
* | `6e001f` | High 10 | 3.1 | 10-bit color; limited browser support |
|
|
3060
|
+
* | `f4001f` | High 4:4:4 Predictive | 3.1 | Lossless capable; rare in browsers |
|
|
3061
|
+
*
|
|
3062
|
+
* UE Pixel Streaming defaults to Constrained Baseline (`42e01f`) or High (`6400xx`)
|
|
3063
|
+
* depending on engine version and `WebRTC.H264Profile` CVar.
|
|
3064
|
+
*
|
|
3065
|
+
* We prioritize `42e01f` because it guarantees hardware decoding on
|
|
3066
|
+
* virtually all client devices (desktop, mobile, embedded), avoiding
|
|
3067
|
+
* fallback to software decoding or negotiation of a higher profile
|
|
3068
|
+
* that the client GPU may not accelerate.
|
|
3069
|
+
*/
|
|
3070
|
+
prioritizeH264Profile(sdp, profileLevelId) {
|
|
3071
|
+
const lines = sdp.split('\r\n');
|
|
3072
|
+
const targetPts = [];
|
|
3073
|
+
for (const line of lines) {
|
|
3074
|
+
if (line.startsWith('a=fmtp:') &&
|
|
3075
|
+
line.toLowerCase().includes(`profile-level-id=${profileLevelId}`)) {
|
|
3076
|
+
const pt = line.split(':')[1]?.split(' ')[0];
|
|
3077
|
+
if (pt)
|
|
3078
|
+
targetPts.push(pt);
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
if (targetPts.length === 0)
|
|
3082
|
+
return sdp;
|
|
3083
|
+
return lines
|
|
3084
|
+
.map((line) => {
|
|
3085
|
+
if (!line.startsWith('m=video'))
|
|
3086
|
+
return line;
|
|
3087
|
+
const parts = line.split(' ');
|
|
3088
|
+
// parts: m=video <port> <proto> <pt1> <pt2> ...
|
|
3089
|
+
const header = parts.slice(0, 3);
|
|
3090
|
+
const pts = parts.slice(3);
|
|
3091
|
+
const prioritized = [
|
|
3092
|
+
...targetPts.filter((pt) => pts.includes(pt)),
|
|
3093
|
+
...pts.filter((pt) => !targetPts.includes(pt)),
|
|
3094
|
+
];
|
|
3095
|
+
return [...header, ...prioritized].join(' ');
|
|
3096
|
+
})
|
|
3097
|
+
.join('\r\n');
|
|
3098
|
+
}
|
|
3099
|
+
mungeSDP(sdp) {
|
|
3100
|
+
let mungedSDP = this.prioritizeH264Profile(sdp, '42e01f');
|
|
3101
|
+
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');
|
|
3102
|
+
// Set max bitrate to highest bitrate Opus supports
|
|
3103
|
+
let audioSDP = 'maxaveragebitrate=510000;';
|
|
2963
3104
|
if (this.useMic) {
|
|
2964
|
-
//
|
|
3105
|
+
// Set the max capture rate to 48khz (so we can send high-quality audio from mic)
|
|
2965
3106
|
audioSDP += 'sprop-maxcapturerate=48000;';
|
|
2966
3107
|
}
|
|
2967
3108
|
// 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
|
|
3109
|
+
audioSDP += this.forceMonoAudio ? 'stereo=0;' : 'stereo=1;';
|
|
3110
|
+
// Enable in-band forward error correction for opus audio
|
|
2972
3111
|
audioSDP += 'useinbandfec=1';
|
|
2973
3112
|
// We use the line 'useinbandfec=1' (which Opus uses) to set our Opus specific audio parameters.
|
|
2974
|
-
|
|
3113
|
+
mungedSDP = mungedSDP?.replace('useinbandfec=1', audioSDP);
|
|
3114
|
+
return mungedSDP;
|
|
2975
3115
|
}
|
|
2976
3116
|
/**
|
|
2977
|
-
* Closes existing PeerConnection
|
|
3117
|
+
* Closes existing PeerConnection and DataChannel, resets negotiation state.
|
|
2978
3118
|
*/
|
|
2979
3119
|
closePC() {
|
|
2980
3120
|
if (this.pcClient) {
|
|
@@ -2987,6 +3127,8 @@ class WebRtcPlayerService extends SubService {
|
|
|
2987
3127
|
}
|
|
2988
3128
|
this.dcClient?.close();
|
|
2989
3129
|
this.dcClient = null;
|
|
3130
|
+
this.remoteDescriptionSet = false;
|
|
3131
|
+
this.iceCandidateBuffer.length = 0;
|
|
2990
3132
|
}
|
|
2991
3133
|
canSend() {
|
|
2992
3134
|
return this.dcClient && this.dcClient.readyState === 'open';
|
|
@@ -3023,9 +3165,9 @@ class WebRtcPlayerService extends SubService {
|
|
|
3023
3165
|
}
|
|
3024
3166
|
}
|
|
3025
3167
|
/**
|
|
3026
|
-
*
|
|
3027
|
-
*
|
|
3028
|
-
* the existing WebSocket connection.
|
|
3168
|
+
* Reconnects only the WebRTC peer connection without re-establishing signaling.
|
|
3169
|
+
* Closes the current PeerConnection and creates a new client-initiated offer
|
|
3170
|
+
* through the existing WebSocket connection.
|
|
3029
3171
|
* @returns true if reconnection was initiated, false if signaling is not connected
|
|
3030
3172
|
*/
|
|
3031
3173
|
reconnectPeer() {
|
|
@@ -3058,11 +3200,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3058
3200
|
this.cfg.bundlePolicy = urlParams.has('ForceMaxBundle')
|
|
3059
3201
|
? 'max-bundle'
|
|
3060
3202
|
: 'balanced';
|
|
3061
|
-
|
|
3062
|
-
//Variables
|
|
3063
|
-
//**********************
|
|
3064
|
-
this.pcClient = null;
|
|
3065
|
-
this.dcClient = null;
|
|
3203
|
+
this.cfg.iceCandidatePoolSize = 1;
|
|
3066
3204
|
// When ?useMic check for SSL or localhost
|
|
3067
3205
|
const isLocalhostConnection = location.hostname === 'localhost' || location.hostname === '127.0.0.1';
|
|
3068
3206
|
const isHttpsConnection = location.protocol === 'https:';
|
|
@@ -3071,23 +3209,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3071
3209
|
Logger.error('Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access.');
|
|
3072
3210
|
Logger.error("For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'");
|
|
3073
3211
|
}
|
|
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);
|
|
3212
|
+
this.setupPeerConnection(this.cfg);
|
|
3091
3213
|
}
|
|
3092
3214
|
handlePeerConnectionEvents(pcClient) {
|
|
3093
3215
|
fromEvent(pcClient, 'signalingstatechange')
|
|
@@ -3116,8 +3238,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3116
3238
|
fromEvent(pcClient, 'icecandidate')
|
|
3117
3239
|
.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
3240
|
.subscribe((candidate) => this.signallingSrv.send({ type: 'iceCandidate', candidate }));
|
|
3241
|
+
// When the server creates the DataChannel (server-offer flow),
|
|
3242
|
+
// we receive it here via the 'datachannel' event
|
|
3119
3243
|
fromEvent(pcClient, 'datachannel')
|
|
3120
|
-
.pipe(tap$1(() => Logger.info(
|
|
3244
|
+
.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
3245
|
.subscribe((datachannel) => {
|
|
3122
3246
|
this.dcClient = this.setupDataChannelCallbacks(datachannel);
|
|
3123
3247
|
});
|
|
@@ -3225,7 +3349,14 @@ class WebRtcPlayerService extends SubService {
|
|
|
3225
3349
|
this.onDataChannelConnected();
|
|
3226
3350
|
});
|
|
3227
3351
|
fromEvent(datachannel, 'message')
|
|
3228
|
-
.pipe(
|
|
3352
|
+
.pipe(
|
|
3353
|
+
/* tap((e: MessageEvent) => {
|
|
3354
|
+
const view = new Uint8Array(e.data);
|
|
3355
|
+
Logger.info(
|
|
3356
|
+
`[DATACHANNEL] Message received on "${datachannel.label}" id=${datachannel.id}, byteCode=${view[0]}, size=${view.byteLength}`,
|
|
3357
|
+
);
|
|
3358
|
+
}),*/
|
|
3359
|
+
map$1((e) => e.data), takeUntil(this.disconnect$))
|
|
3229
3360
|
.subscribe((data) => this.onDataChannelMessage$.next(data));
|
|
3230
3361
|
return datachannel;
|
|
3231
3362
|
}
|
|
@@ -3242,20 +3373,38 @@ class WebRtcPlayerService extends SubService {
|
|
|
3242
3373
|
}
|
|
3243
3374
|
this.store.dispatch(dataChannelConnected({ statusMessage }));
|
|
3244
3375
|
}
|
|
3376
|
+
/**
|
|
3377
|
+
* Creates an SDP offer, applies SDP munging, sets it as a local description,
|
|
3378
|
+
* and sends it to the server via signaling.
|
|
3379
|
+
* Transceivers already configure media directions, so deprecated
|
|
3380
|
+
* offerToReceive* options are not used.
|
|
3381
|
+
*/
|
|
3245
3382
|
async createOffer(pcClient) {
|
|
3246
3383
|
try {
|
|
3247
|
-
const offer = await pcClient.createOffer(
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
});
|
|
3251
|
-
this.mungeSDP(offer);
|
|
3252
|
-
pcClient?.setLocalDescription(offer);
|
|
3384
|
+
const offer = await pcClient.createOffer();
|
|
3385
|
+
offer.sdp = this.mungeSDP(offer.sdp ?? '');
|
|
3386
|
+
await pcClient.setLocalDescription(offer);
|
|
3253
3387
|
this.signallingSrv.send(offer);
|
|
3254
3388
|
}
|
|
3255
3389
|
catch {
|
|
3256
3390
|
Logger.error("Couldn't create offer");
|
|
3257
3391
|
}
|
|
3258
3392
|
}
|
|
3393
|
+
/**
|
|
3394
|
+
* Creates an SDP answer, applies SDP munging, sets it as a local description,
|
|
3395
|
+
* and sends it to the server via signaling.
|
|
3396
|
+
*/
|
|
3397
|
+
async createAnswer(pcClient) {
|
|
3398
|
+
try {
|
|
3399
|
+
const answer = await pcClient.createAnswer();
|
|
3400
|
+
answer.sdp = this.mungeSDP(answer.sdp ?? '');
|
|
3401
|
+
await pcClient.setLocalDescription(answer);
|
|
3402
|
+
this.signallingSrv.send(answer);
|
|
3403
|
+
}
|
|
3404
|
+
catch (e) {
|
|
3405
|
+
Logger.error("Couldn't create answer", e);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3259
3408
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3260
3409
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebRtcPlayerService }); }
|
|
3261
3410
|
}
|
|
@@ -4458,556 +4607,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
4458
4607
|
type: Injectable
|
|
4459
4608
|
}], ctorParameters: () => [] });
|
|
4460
4609
|
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
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
|
-
});
|
|
4855
|
-
}
|
|
4856
|
-
async setupTransceiversAsync(pc) {
|
|
4857
|
-
const hasTransceivers = pc.getTransceivers().length > 0;
|
|
4858
|
-
// Set up a transceiver for getting UE video
|
|
4859
|
-
pc.addTransceiver('video', { direction: 'recvonly' });
|
|
4860
|
-
// Set up a transceiver for sending mic audio to UE and receiving audio from UE
|
|
4861
|
-
if (!this.useMic) {
|
|
4862
|
-
pc.addTransceiver('audio', { direction: 'recvonly' });
|
|
4863
|
-
}
|
|
4864
|
-
else {
|
|
4865
|
-
const audioSendOptions = this.useMic
|
|
4866
|
-
? {
|
|
4867
|
-
autoGainControl: false,
|
|
4868
|
-
channelCount: 1,
|
|
4869
|
-
echoCancellation: false,
|
|
4870
|
-
latency: 0,
|
|
4871
|
-
noiseSuppression: false,
|
|
4872
|
-
sampleRate: 48000,
|
|
4873
|
-
sampleSize: 16,
|
|
4874
|
-
volume: 1.0,
|
|
4875
|
-
}
|
|
4876
|
-
: false;
|
|
4877
|
-
// Note using mic on android chrome requires SSL or chrome://flags/ "unsafely-treat-insecure-origin-as-secure"
|
|
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
|
-
}
|
|
4897
|
-
}
|
|
4898
|
-
else {
|
|
4899
|
-
for (const track of stream.getTracks()) {
|
|
4900
|
-
if (track.kind && track.kind === 'audio') {
|
|
4901
|
-
pc.addTransceiver(track, { direction: 'sendrecv' });
|
|
4902
|
-
}
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
|
-
}
|
|
4906
|
-
else {
|
|
4907
|
-
pc.addTransceiver('audio', { direction: 'recvonly' });
|
|
4908
|
-
}
|
|
4909
|
-
}
|
|
4910
|
-
}
|
|
4911
|
-
setupDataChannelCallbacks(datachannel) {
|
|
4912
|
-
try {
|
|
4913
|
-
Logger.log(`[DATACHANNEL] Setting up datachannel "${datachannel.label}" callbacks...`);
|
|
4914
|
-
this.commandTelemetryService.trackStartCommand('EXT-DataChannel Connection');
|
|
4915
|
-
// Inform browser we would like binary data as an ArrayBuffer (FF chooses Blob by default!)
|
|
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;
|
|
4953
|
-
}
|
|
4954
|
-
catch (e) {
|
|
4955
|
-
Logger.warn('[DATACHANNEL] Datachannel setup caused an exception: ', e);
|
|
4956
|
-
return null;
|
|
4957
|
-
}
|
|
4958
|
-
}
|
|
4959
|
-
onDataChannelConnected() {
|
|
4960
|
-
let statusMessage = 'Session connected, video stream starting.';
|
|
4961
|
-
if (navigator.userAgent.includes('Firefox')) {
|
|
4962
|
-
statusMessage +=
|
|
4963
|
-
'\n If you are experiencing connection problems please try Google Chrome';
|
|
4964
|
-
}
|
|
4965
|
-
this.store.dispatch(dataChannelConnected({ statusMessage }));
|
|
4966
|
-
}
|
|
4967
|
-
/**
|
|
4968
|
-
* Creates an SDP offer, applies SDP munging, sets it as a local description,
|
|
4969
|
-
* and sends it to the server via signaling.
|
|
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");
|
|
4982
|
-
}
|
|
4983
|
-
}
|
|
4984
|
-
/**
|
|
4985
|
-
* Creates an SDP answer, applies SDP munging, sets it as a local description,
|
|
4986
|
-
* and sends it to the server via signaling.
|
|
4987
|
-
*/
|
|
4988
|
-
async createAnswer(pcClient) {
|
|
4989
|
-
try {
|
|
4990
|
-
const answer = await pcClient.createAnswer();
|
|
4991
|
-
answer.sdp = this.mungeSDP(answer.sdp ?? '');
|
|
4992
|
-
await pcClient.setLocalDescription(answer);
|
|
4993
|
-
this.signallingSrv.send(answer);
|
|
4994
|
-
}
|
|
4995
|
-
catch (e) {
|
|
4996
|
-
Logger.error("Couldn't create answer", e);
|
|
4997
|
-
}
|
|
4998
|
-
}
|
|
4999
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebRtcPlayerService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5000
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebRtcPlayerService2 }); }
|
|
5001
|
-
}
|
|
5002
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebRtcPlayerService2, decorators: [{
|
|
5003
|
-
type: Injectable
|
|
5004
|
-
}], ctorParameters: () => [] });
|
|
5005
|
-
|
|
5006
|
-
const ReceivedMimeTypes = {
|
|
5007
|
-
ApplicationJson: 'application/json',
|
|
5008
|
-
};
|
|
5009
|
-
|
|
5010
|
-
class FileHandlerService {
|
|
4610
|
+
const ReceivedMimeTypes = {
|
|
4611
|
+
ApplicationJson: 'application/json',
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
class FileHandlerService {
|
|
5011
4615
|
constructor() {
|
|
5012
4616
|
this.fileService = inject(FileReceiverService);
|
|
5013
4617
|
this.fileHandlers = {
|
|
@@ -5591,11 +5195,11 @@ class AfkTimeoutModalComponent {
|
|
|
5591
5195
|
this.#afkService.reset();
|
|
5592
5196
|
}
|
|
5593
5197
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5594
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", ngImport: i0, template: "@if (isAfkTimerVisible()) {\
|
|
5198
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5199
|
}
|
|
5596
5200
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
|
|
5597
5201
|
type: Component,
|
|
5598
|
-
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isAfkTimerVisible()) {\
|
|
5202
|
+
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
5203
|
}] });
|
|
5600
5204
|
|
|
5601
5205
|
class FreezeFrameComponent {
|
|
@@ -5606,11 +5210,11 @@ class FreezeFrameComponent {
|
|
|
5606
5210
|
}
|
|
5607
5211
|
#store;
|
|
5608
5212
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5609
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: FreezeFrameComponent, isStandalone: true, selector: "app-freeze-frame", ngImport: i0, template: "@let image = combinedFreeze();\
|
|
5213
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5214
|
}
|
|
5611
5215
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FreezeFrameComponent, decorators: [{
|
|
5612
5216
|
type: Component,
|
|
5613
|
-
args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\
|
|
5217
|
+
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
5218
|
}] });
|
|
5615
5219
|
|
|
5616
5220
|
class SafePipe {
|
|
@@ -5652,11 +5256,11 @@ class LowBandwidthModalComponent {
|
|
|
5652
5256
|
this.#dialogRef.close(value || false);
|
|
5653
5257
|
}
|
|
5654
5258
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LowBandwidthModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5655
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: LowBandwidthModalComponent, isStandalone: true, selector: "app-low-bandwidth-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'low-bandwidth'\" class=\"src-modal src-modal--lbm\">\
|
|
5259
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", 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
5260
|
}
|
|
5657
5261
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LowBandwidthModalComponent, decorators: [{
|
|
5658
5262
|
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\">\
|
|
5263
|
+
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
5264
|
}] });
|
|
5661
5265
|
|
|
5662
5266
|
class ImageLoadingSrcComponent {
|
|
@@ -5667,11 +5271,11 @@ class ImageLoadingSrcComponent {
|
|
|
5667
5271
|
}
|
|
5668
5272
|
#store;
|
|
5669
5273
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5670
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\
|
|
5274
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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 [ngSrc]=\"image\" fill loading=\"lazy\" alt=\"image loading src\" />\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
5275
|
}
|
|
5672
5276
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
5673
5277
|
type: Component,
|
|
5674
|
-
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\
|
|
5278
|
+
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 [ngSrc]=\"image\" fill loading=\"lazy\" alt=\"image loading src\" />\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
5279
|
}] });
|
|
5676
5280
|
|
|
5677
5281
|
class StatGraphComponent {
|
|
@@ -5746,11 +5350,11 @@ class StatGraphComponent {
|
|
|
5746
5350
|
this.draw();
|
|
5747
5351
|
}
|
|
5748
5352
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5749
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", 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\">\
|
|
5353
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", 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
5354
|
}
|
|
5751
5355
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StatGraphComponent, decorators: [{
|
|
5752
5356
|
type: Component,
|
|
5753
|
-
args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\
|
|
5357
|
+
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
5358
|
}], 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
5359
|
type: HostListener,
|
|
5756
5360
|
args: ['window:resize']
|
|
@@ -5830,11 +5434,11 @@ class UnrealStatusComponent {
|
|
|
5830
5434
|
}
|
|
5831
5435
|
}
|
|
5832
5436
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5833
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", ngImport: i0, template: "@if (showLoader()) {\
|
|
5437
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5438
|
}
|
|
5835
5439
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
5836
5440
|
type: Component,
|
|
5837
|
-
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceLoadingComponent], template: "@if (showLoader()) {\
|
|
5441
|
+
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
5442
|
}] });
|
|
5839
5443
|
|
|
5840
5444
|
class VideoStatsComponent {
|
|
@@ -5962,11 +5566,11 @@ class VideoStatsComponent {
|
|
|
5962
5566
|
}));
|
|
5963
5567
|
}
|
|
5964
5568
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5965
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\
|
|
5569
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5570
|
}
|
|
5967
5571
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
5968
5572
|
type: Component,
|
|
5969
|
-
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, AsyncPipe, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\
|
|
5573
|
+
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
5574
|
}], ctorParameters: () => [] });
|
|
5971
5575
|
|
|
5972
5576
|
class ResumeStreamButtonComponent {
|
|
@@ -6009,11 +5613,11 @@ class ResumeStreamButtonComponent {
|
|
|
6009
5613
|
this.isSecondStart.set(true);
|
|
6010
5614
|
}
|
|
6011
5615
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6012
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", ngImport: i0, template: "@if (isShowResumeButton()) {\
|
|
5616
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5617
|
}
|
|
6014
5618
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
6015
5619
|
type: Component,
|
|
6016
|
-
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceButtonComponent], template: "@if (isShowResumeButton()) {\
|
|
5620
|
+
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
5621
|
}] });
|
|
6018
5622
|
|
|
6019
5623
|
class IntroSrcComponent {
|
|
@@ -6071,11 +5675,11 @@ class IntroSrcComponent {
|
|
|
6071
5675
|
videoContainer.appendChild(videoElement);
|
|
6072
5676
|
}
|
|
6073
5677
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6074
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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();\
|
|
5678
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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 [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
5679
|
}
|
|
6076
5680
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
6077
5681
|
type: Component,
|
|
6078
|
-
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\
|
|
5682
|
+
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img [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
5683
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
6080
5684
|
|
|
6081
5685
|
class UnrealSceneComponent {
|
|
@@ -6096,7 +5700,6 @@ class UnrealSceneComponent {
|
|
|
6096
5700
|
this.changeMouseOverScene.emit(false);
|
|
6097
5701
|
}
|
|
6098
5702
|
constructor() {
|
|
6099
|
-
this.unrealConfig = inject(UNREAL_CONFIG);
|
|
6100
5703
|
this.isStudio = input(false, ...(ngDevMode ? [{ debugName: "isStudio" }] : /* istanbul ignore next */ []));
|
|
6101
5704
|
this.useContainerAsSizeProvider = input(true, ...(ngDevMode ? [{ debugName: "useContainerAsSizeProvider" }] : /* istanbul ignore next */ []));
|
|
6102
5705
|
this.studioResolutionSize = input({
|
|
@@ -6199,16 +5802,7 @@ class UnrealSceneComponent {
|
|
|
6199
5802
|
containerHeight = this.videoElement()?.nativeElement.offsetHeight || 2;
|
|
6200
5803
|
}
|
|
6201
5804
|
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({
|
|
5805
|
+
return getResizeValuesUniversal({
|
|
6212
5806
|
pixelRatio,
|
|
6213
5807
|
containerWidth,
|
|
6214
5808
|
containerHeight,
|
|
@@ -6216,20 +5810,11 @@ class UnrealSceneComponent {
|
|
|
6216
5810
|
});
|
|
6217
5811
|
}
|
|
6218
5812
|
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({
|
|
5813
|
+
const videoElement = this.videoElement()?.nativeElement;
|
|
5814
|
+
return getResizeStudioValues({
|
|
6230
5815
|
pixelRatio: this.pixelRatio,
|
|
6231
|
-
containerWidth:
|
|
6232
|
-
containerHeight:
|
|
5816
|
+
containerWidth: videoElement?.offsetWidth || 2,
|
|
5817
|
+
containerHeight: videoElement?.offsetHeight || 2,
|
|
6233
5818
|
studioWidth: this.width,
|
|
6234
5819
|
studioHeight: this.height,
|
|
6235
5820
|
maxResolution: this.maxResolution,
|
|
@@ -6238,11 +5823,16 @@ class UnrealSceneComponent {
|
|
|
6238
5823
|
sendResize(size) {
|
|
6239
5824
|
this.commandsSender.sendCommandToUnreal({
|
|
6240
5825
|
command: MetaBoxCommand.FChangeResolutionCommand,
|
|
6241
|
-
payload: {
|
|
5826
|
+
payload: {
|
|
5827
|
+
resolution: { x: size.w, y: size.h },
|
|
5828
|
+
payloadVersion: this.isStudio()
|
|
5829
|
+
? EPayloadVersion.disableFovRecalculation
|
|
5830
|
+
: undefined,
|
|
5831
|
+
},
|
|
6242
5832
|
});
|
|
6243
5833
|
}
|
|
6244
5834
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
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 }); }
|
|
5835
|
+
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\">\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
5836
|
}
|
|
6247
5837
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
6248
5838
|
type: Component,
|
|
@@ -6254,7 +5844,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
6254
5844
|
ResumeStreamButtonComponent,
|
|
6255
5845
|
ImageLoadingSrcComponent,
|
|
6256
5846
|
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"] }]
|
|
5847
|
+
], 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
5848
|
}], 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
5849
|
type: HostListener,
|
|
6260
5850
|
args: ['mouseover']
|
|
@@ -6284,11 +5874,11 @@ class WebrtcErrorModalComponent {
|
|
|
6284
5874
|
this.close();
|
|
6285
5875
|
}
|
|
6286
5876
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6287
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"src-modal\">\
|
|
5877
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", 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
5878
|
}
|
|
6289
5879
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
|
|
6290
5880
|
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\">\
|
|
5881
|
+
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
5882
|
}] });
|
|
6293
5883
|
|
|
6294
5884
|
class FilterSettingsComponent {
|
|
@@ -6333,11 +5923,11 @@ class FilterSettingsComponent {
|
|
|
6333
5923
|
});
|
|
6334
5924
|
}
|
|
6335
5925
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FilterSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6336
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: FilterSettingsComponent, isStandalone: true, selector: "app-filter-settings", ngImport: i0, template: "<div class=\"settings-container\">\
|
|
5926
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
5927
|
}
|
|
6338
5928
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FilterSettingsComponent, decorators: [{
|
|
6339
5929
|
type: Component,
|
|
6340
|
-
args: [{ selector: 'app-filter-settings', imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"settings-container\">\
|
|
5930
|
+
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
5931
|
}] });
|
|
6342
5932
|
|
|
6343
5933
|
class LowBandwidthDetectorComponent {
|
|
@@ -6441,11 +6031,11 @@ class LowBandwidthDetectorComponent {
|
|
|
6441
6031
|
});
|
|
6442
6032
|
}
|
|
6443
6033
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LowBandwidthDetectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6444
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: LowBandwidthDetectorComponent, isStandalone: true, selector: "app-low-bandwidth-detector", ngImport: i0, template: "@if (isReducedQuality() || isLowBandwidth()) {\
|
|
6034
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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
6035
|
}
|
|
6446
6036
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LowBandwidthDetectorComponent, decorators: [{
|
|
6447
6037
|
type: Component,
|
|
6448
|
-
args: [{ selector: 'app-low-bandwidth-detector', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FilterSettingsComponent], template: "@if (isReducedQuality() || isLowBandwidth()) {\
|
|
6038
|
+
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
6039
|
}] });
|
|
6450
6040
|
|
|
6451
6041
|
function provideUnrealModule() {
|
|
@@ -6469,15 +6059,7 @@ function provideUnrealModule() {
|
|
|
6469
6059
|
SignallingService,
|
|
6470
6060
|
StreamStatusTelemetryService,
|
|
6471
6061
|
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
|
-
},
|
|
6062
|
+
WebRtcPlayerService,
|
|
6481
6063
|
provideEnvironmentInitializer(() => {
|
|
6482
6064
|
inject(AggregatorService);
|
|
6483
6065
|
inject(InputService);
|
|
@@ -6495,5 +6077,5 @@ function provideUnrealModule() {
|
|
|
6495
6077
|
* Generated bundle index. Do not edit.
|
|
6496
6078
|
*/
|
|
6497
6079
|
|
|
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,
|
|
6080
|
+
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
6081
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|