@3dsource/angular-unreal-module 0.0.113-dev.0 → 0.0.113-dev.1
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.
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, inject, ChangeDetectionStrategy, Component, Injectable, DestroyRef, effect, untracked, signal, computed, Pipe, input, ElementRef, viewChild, afterNextRender, HostListener, output, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
|
|
3
3
|
import { SourceButtonComponent, SourceLoadingComponent } from '@3dsource/source-ui-native';
|
|
4
|
-
import { merge, map, scan, concatMap, of, animationFrameScheduler, interval, Observable, switchMap, timer, take, timeout, mergeMap, EMPTY,
|
|
4
|
+
import { merge, map, scan, concatMap, of, animationFrameScheduler, interval, Observable, skip, switchMap, concat, delay, debounceTime, timer, take, timeout, mergeMap, EMPTY, Subject, share, from, fromEvent, throwError, defer, retry, tap as tap$1, takeUntil as takeUntil$1, NEVER, startWith, throttleTime, asyncScheduler, filter as filter$1, withLatestFrom as withLatestFrom$1, pairwise, Subscription, bufferTime, combineLatestWith, distinctUntilChanged as distinctUntilChanged$1 } from 'rxjs';
|
|
5
5
|
import { createAction, props, createReducer, on, createFeature, createSelector, Store, provideState } from '@ngrx/store';
|
|
6
6
|
import { Actions, createEffect, ofType, provideEffects } from '@ngrx/effects';
|
|
7
|
-
import { map as map$1, distinctUntilChanged, takeWhile, filter, tap, takeUntil, catchError, withLatestFrom, exhaustMap, switchMap as switchMap$1, timeout as timeout$1, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1
|
|
7
|
+
import { map as map$1, distinctUntilChanged, takeWhile, filter, tap, takeUntil, catchError, withLatestFrom, exhaustMap, switchMap as switchMap$1, timeout as timeout$1, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
|
|
8
8
|
import { Logger, calculateMedian, clampf, lerp, getCanvasCached, getSnapshot, fitIntoRectangle, whereNot, Truthy, tapLog, Falsy, generateUuid, COLOR_CODES, where, KeyboardNumericCode, InvertedKeyMap, Semaphore, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
9
9
|
import { concatLatestFrom } from '@ngrx/operators';
|
|
10
10
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
11
11
|
import { HttpClient } from '@angular/common/http';
|
|
12
12
|
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
13
13
|
import { MetaBoxCommand, EPayloadVersion } from '@3dsource/types-unreal';
|
|
14
|
-
import { toSignal,
|
|
14
|
+
import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
15
15
|
import { v4 } from 'uuid';
|
|
16
16
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
17
17
|
import { NgOptimizedImage, AsyncPipe, JsonPipe } from '@angular/common';
|
|
@@ -197,8 +197,11 @@ const DESTROY_DISCONNECT_REASONS = [
|
|
|
197
197
|
|
|
198
198
|
const DEBOUNCE_TO_MANY_RESIZE_CALLS = 100;
|
|
199
199
|
const SAME_SIZE_THRESHOLD = 1.01;
|
|
200
|
+
// Minimum container dimension in px — prevents division by zero in resize calculations
|
|
201
|
+
const MIN_CONTAINER_SIZE = 2;
|
|
200
202
|
const MINIMAL_FPS = 6;
|
|
201
203
|
const STREAMING_VIDEO_ID = 'streamingVideo';
|
|
204
|
+
const STREAMING_AUDIO_ID = 'streamingAudio';
|
|
202
205
|
const CONSOLE_COMMAND_ENABLE_MESSAGES = 'EnableAllScreenMessages';
|
|
203
206
|
const CONSOLE_COMMAND_DISABLE_MESSAGES = 'DisableAllScreenMessages';
|
|
204
207
|
const CONSOLE_COMMAND_PIXEL_QUALITY = 'PixelStreaming.FreezeFrameQuality 95';
|
|
@@ -208,7 +211,7 @@ const WS_TIMEOUT = 2000;
|
|
|
208
211
|
const POLLING_TIME = 4000;
|
|
209
212
|
const WS_OPEN_STATE = 1;
|
|
210
213
|
const DEFAULT_AFK_TIMEOUT_PERIOD = 15;
|
|
211
|
-
const DEFAULT_AFK_TIMEOUT =
|
|
214
|
+
const DEFAULT_AFK_TIMEOUT = 10;
|
|
212
215
|
const DATA_CHANNEL_CONNECTION_TIMEOUT = 8000; //ms;
|
|
213
216
|
const SIGNALLING_PERCENT_VALUE = 56;
|
|
214
217
|
const SCREEN_LOCKER_CONTAINER_ID = '3dsource_start_screen';
|
|
@@ -310,11 +313,7 @@ const setAfkTimerVisible = createAction(scoped `set afk timer visible`);
|
|
|
310
313
|
const setAfkTimerHide = createAction(scoped `set afk timer hide`);
|
|
311
314
|
const setAfkTimerCountdown = createAction(scoped `set afk timer count down`, props());
|
|
312
315
|
const showUnrealErrorMessage = createAction(scoped `show unreal error message`, props());
|
|
313
|
-
const initSignalling = createAction(scoped `init signalling`, (
|
|
314
|
-
resetDisconnectionReason: true,
|
|
315
|
-
}) => ({
|
|
316
|
-
resetDisconnectionReason: data.resetDisconnectionReason,
|
|
317
|
-
}));
|
|
316
|
+
const initSignalling = createAction(scoped `init signalling`, (resetDisconnectionReason = true) => ({ resetDisconnectionReason }));
|
|
318
317
|
const startStream = createAction(scoped `startStream`, props());
|
|
319
318
|
const resetConfig = createAction(scoped `reset config`);
|
|
320
319
|
const resetAfk = createAction(scoped `reset afk action`);
|
|
@@ -339,8 +338,9 @@ const dropDC = createAction(scoped `drop data channel`);
|
|
|
339
338
|
const dropPC = createAction(scoped `drop peer connection`);
|
|
340
339
|
const showLoadingProgress = createAction(scoped `show loading progress`, props());
|
|
341
340
|
const showResumeStreamPopup = createAction(scoped `show resume stream popup`, props());
|
|
342
|
-
const
|
|
343
|
-
const
|
|
341
|
+
const showUserInactivityTimeoutPopup = createAction(scoped `show user inactivity timeout popup`, props());
|
|
342
|
+
const setUserInactivityTimeout = createAction(scoped `set user inactivity timeout`, props());
|
|
343
|
+
const resetUserInactivityTimeout = createAction(scoped `reset user inactivity timeout`);
|
|
344
344
|
|
|
345
345
|
const initialState$1 = {
|
|
346
346
|
streamRequestContext: null,
|
|
@@ -372,7 +372,7 @@ const initialState$1 = {
|
|
|
372
372
|
autoStart: true,
|
|
373
373
|
warnTimeout: DEFAULT_AFK_TIMEOUT,
|
|
374
374
|
},
|
|
375
|
-
|
|
375
|
+
userInactivityTimeout: DEFAULT_AFK_TIMEOUT,
|
|
376
376
|
matchUrls: [],
|
|
377
377
|
streamClientCompanyId: '',
|
|
378
378
|
streamViewId: 'default',
|
|
@@ -385,9 +385,18 @@ const initialState$1 = {
|
|
|
385
385
|
showAfkTimeoutPopup: true,
|
|
386
386
|
};
|
|
387
387
|
const unrealReducer = createReducer(initialState$1, on(changeStatusMainVideoOnScene, (state, { isVideoPlaying }) => {
|
|
388
|
-
return { ...state, isVideoPlaying
|
|
388
|
+
return { ...state, isVideoPlaying };
|
|
389
389
|
}), on(setAwsInstance, (state, { instanceName, wsUrl, pollingUrl }) => {
|
|
390
|
-
return {
|
|
390
|
+
return {
|
|
391
|
+
...state,
|
|
392
|
+
awsInstance: {
|
|
393
|
+
...state.awsInstance,
|
|
394
|
+
instanceName,
|
|
395
|
+
wsUrl,
|
|
396
|
+
pollingUrl,
|
|
397
|
+
progressComplete: 0,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
391
400
|
}), on(setViewportReady, (state) => {
|
|
392
401
|
return {
|
|
393
402
|
...state,
|
|
@@ -414,15 +423,11 @@ const unrealReducer = createReducer(initialState$1, on(changeStatusMainVideoOnSc
|
|
|
414
423
|
},
|
|
415
424
|
};
|
|
416
425
|
}), on(disconnectStream, (state, errorMessage) => {
|
|
417
|
-
|
|
418
|
-
state.disconnectReason === DisconnectReason.Destroy
|
|
426
|
+
const alreadyHandled = state.dataChannelConnected ||
|
|
427
|
+
state.disconnectReason === DisconnectReason.Destroy;
|
|
428
|
+
if (alreadyHandled)
|
|
419
429
|
return state;
|
|
420
|
-
}
|
|
421
|
-
return {
|
|
422
|
-
...state,
|
|
423
|
-
errorMessage,
|
|
424
|
-
statusMessage: null,
|
|
425
|
-
};
|
|
430
|
+
return { ...state, errorMessage, statusMessage: null };
|
|
426
431
|
}), on(setFreezeFrameFromVideo, (state, freezeFrameFromVideo) => {
|
|
427
432
|
return {
|
|
428
433
|
...state,
|
|
@@ -449,14 +454,17 @@ const unrealReducer = createReducer(initialState$1, on(changeStatusMainVideoOnSc
|
|
|
449
454
|
}), on(resetWarnTimeout, (state) => {
|
|
450
455
|
return {
|
|
451
456
|
...state,
|
|
452
|
-
streamConfig: {
|
|
457
|
+
streamConfig: {
|
|
458
|
+
...state.streamConfig,
|
|
459
|
+
warnTimeout: state.userInactivityTimeout,
|
|
460
|
+
},
|
|
453
461
|
};
|
|
454
462
|
}), on(resetConfig, (state) => {
|
|
455
463
|
return {
|
|
456
464
|
...state,
|
|
457
465
|
streamConfig: {
|
|
458
466
|
...initialState$1.streamConfig,
|
|
459
|
-
warnTimeout: state.
|
|
467
|
+
warnTimeout: state.userInactivityTimeout,
|
|
460
468
|
},
|
|
461
469
|
};
|
|
462
470
|
}), on(initSignalling, (state, { resetDisconnectionReason = true }) => {
|
|
@@ -537,12 +545,12 @@ const unrealReducer = createReducer(initialState$1, on(changeStatusMainVideoOnSc
|
|
|
537
545
|
return { ...state, showLoadingProgress: visible };
|
|
538
546
|
}), on(showResumeStreamPopup, (state, { visible }) => {
|
|
539
547
|
return { ...state, showResumeStreamPopup: visible };
|
|
540
|
-
}), on(
|
|
548
|
+
}), on(showUserInactivityTimeoutPopup, (state, { visible }) => {
|
|
541
549
|
return { ...state, showAfkTimeoutPopup: visible };
|
|
542
|
-
}), on(
|
|
550
|
+
}), on(setUserInactivityTimeout, (state, { timeout }) => {
|
|
543
551
|
return {
|
|
544
552
|
...state,
|
|
545
|
-
|
|
553
|
+
userInactivityTimeout: timeout,
|
|
546
554
|
streamConfig: { ...state.streamConfig, warnTimeout: timeout },
|
|
547
555
|
};
|
|
548
556
|
}), on(setCirrusDisconnected, (state) => {
|
|
@@ -560,7 +568,7 @@ const unrealReducer = createReducer(initialState$1, on(changeStatusMainVideoOnSc
|
|
|
560
568
|
environmentId: state.environmentId,
|
|
561
569
|
streamRequestContext: state.streamRequestContext,
|
|
562
570
|
streamConfig: state.streamConfig,
|
|
563
|
-
|
|
571
|
+
userInactivityTimeout: state.userInactivityTimeout,
|
|
564
572
|
};
|
|
565
573
|
}), on(dropConnection, (state) => {
|
|
566
574
|
return { ...state, establishingConnection: false };
|
|
@@ -1079,63 +1087,6 @@ function getResizeValuesUniversal(params) {
|
|
|
1079
1087
|
return { w: makeEven(w), h: makeEven(h), x: 0, y: 0, scale: w / maxSpace.w };
|
|
1080
1088
|
}
|
|
1081
1089
|
|
|
1082
|
-
//TODO: Remove this legacy method after confirming that `getResizeValuesUniversal`
|
|
1083
|
-
// works well in all scenarios and updating any dependent code to use it instead.
|
|
1084
|
-
function getResizeValuesUniversalOld(params) {
|
|
1085
|
-
const { pixelRatio, containerWidth, containerHeight, maxResolution } = params;
|
|
1086
|
-
const maxSpace = {
|
|
1087
|
-
w: containerWidth * pixelRatio,
|
|
1088
|
-
h: containerHeight * pixelRatio,
|
|
1089
|
-
};
|
|
1090
|
-
const isVertical = containerWidth < containerHeight;
|
|
1091
|
-
let maxH = FULL_HD_HEIGHT;
|
|
1092
|
-
let maxW = FULL_HD_WIDTH;
|
|
1093
|
-
if (maxResolution) {
|
|
1094
|
-
maxH = FULL_HD_HEIGHT * 2;
|
|
1095
|
-
maxW = FULL_HD_WIDTH * 2;
|
|
1096
|
-
}
|
|
1097
|
-
const maxLimits = isVertical
|
|
1098
|
-
? { w: maxH, h: maxW, x: 0, y: 0 }
|
|
1099
|
-
: { w: maxW, h: maxH, x: 0, y: 0 };
|
|
1100
|
-
const props = fitIntoRectangle({ x: 0, y: 0, w: containerWidth, h: containerHeight }, { x: 0, y: 0, ...maxSpace });
|
|
1101
|
-
let out = { ...props };
|
|
1102
|
-
const fitIntoMax = fitIntoRectangle(props, maxLimits);
|
|
1103
|
-
if (fitIntoMax.scale < 1) {
|
|
1104
|
-
// If reducing size to 1920x1080 is required, do it
|
|
1105
|
-
out = fitIntoMax;
|
|
1106
|
-
}
|
|
1107
|
-
else {
|
|
1108
|
-
// Otherwise, use the lowest resolution because the layout size is smaller than 1920x1080
|
|
1109
|
-
out.scale = 1;
|
|
1110
|
-
}
|
|
1111
|
-
/**
|
|
1112
|
-
* Ensure that the size is always even.
|
|
1113
|
-
*/
|
|
1114
|
-
out.w = makeEven(out.w);
|
|
1115
|
-
out.h = makeEven(out.h);
|
|
1116
|
-
return { ...out };
|
|
1117
|
-
}
|
|
1118
|
-
function getResizeStudioValuesOld(params) {
|
|
1119
|
-
const { pixelRatio, containerWidth, containerHeight, studioWidth, studioHeight, } = params;
|
|
1120
|
-
const maxSpace = {
|
|
1121
|
-
w: containerWidth * pixelRatio,
|
|
1122
|
-
h: containerHeight * pixelRatio,
|
|
1123
|
-
};
|
|
1124
|
-
const videoSizePixelPerfect = fitIntoRectangle({ x: 0, y: 0, w: studioWidth, h: studioHeight }, { x: 0, y: 0, ...maxSpace });
|
|
1125
|
-
const out = fitIntoRectangle(videoSizePixelPerfect, {
|
|
1126
|
-
x: 0,
|
|
1127
|
-
y: 0,
|
|
1128
|
-
w: Math.min(maxSpace.w, FULL_HD_WIDTH),
|
|
1129
|
-
h: Math.min(maxSpace.h, FULL_HD_HEIGHT),
|
|
1130
|
-
});
|
|
1131
|
-
/**
|
|
1132
|
-
* Ensure that the size is always even.
|
|
1133
|
-
*/
|
|
1134
|
-
out.w = makeEven(out.w);
|
|
1135
|
-
out.h = makeEven(out.h);
|
|
1136
|
-
return out;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
1090
|
const removeExileCommands = (state, idToRemove) => {
|
|
1140
1091
|
const exileTimeout = 10000;
|
|
1141
1092
|
const out = { ...state };
|
|
@@ -1143,11 +1094,11 @@ const removeExileCommands = (state, idToRemove) => {
|
|
|
1143
1094
|
out.totalCommandsCompleted++;
|
|
1144
1095
|
const time = new Date().getTime();
|
|
1145
1096
|
const markForDelete = [];
|
|
1146
|
-
|
|
1097
|
+
for (const { id, timeStamp } of out.commandsInProgress) {
|
|
1147
1098
|
if (time - timeStamp > exileTimeout) {
|
|
1148
1099
|
markForDelete.push(id);
|
|
1149
1100
|
}
|
|
1150
|
-
}
|
|
1101
|
+
}
|
|
1151
1102
|
out.totalCommandsCompleted += markForDelete.length;
|
|
1152
1103
|
out.commandsInProgress = out.commandsInProgress.filter((command) => !markForDelete.includes(command.id));
|
|
1153
1104
|
return out;
|
|
@@ -1194,8 +1145,8 @@ const selectStreamConfig = createSelector(unrealFeature.selectStreamConfig, (con
|
|
|
1194
1145
|
const selectWarnTimeout = createSelector(selectStreamConfig, (config) => config?.warnTimeout || DEFAULT_AFK_TIMEOUT);
|
|
1195
1146
|
const selectIsExistMatchUrls = createSelector(unrealFeature.selectMatchUrls, (urls) => urls?.length > 0);
|
|
1196
1147
|
const selectIsAutostart = createSelector(selectStreamConfig, (config) => config?.autoStart);
|
|
1197
|
-
const selectShowReconnectPopup = createSelector(unrealFeature.selectCirrusConnected, unrealFeature.selectEstablishingConnection, (
|
|
1198
|
-
const selectShowLoader = createSelector(selectShowReconnectPopup, unrealFeature.selectViewportReady,
|
|
1148
|
+
const selectShowReconnectPopup = createSelector(unrealFeature.selectCirrusConnected, unrealFeature.selectEstablishingConnection, (cirrusConnected, establishingConnection) => !cirrusConnected && !establishingConnection);
|
|
1149
|
+
const selectShowLoader = createSelector(selectShowReconnectPopup, unrealFeature.selectViewportReady, (showPopup, viewportReady) => !showPopup && !viewportReady);
|
|
1199
1150
|
const selectIsVideoPlayingAndDataChannelConnected = createSelector(unrealFeature.selectIsVideoPlaying, unrealFeature.selectDataChannelConnected, (isVideoPlaying, isDataChannelConnected) => isVideoPlaying && isDataChannelConnected);
|
|
1200
1151
|
const selectSignalingParameters = createSelector(unrealFeature.selectSsData, unrealFeature.selectAwsInstance, (data, instance) => {
|
|
1201
1152
|
const info = [];
|
|
@@ -1209,29 +1160,37 @@ const selectSignalingParameters = createSelector(unrealFeature.selectSsData, unr
|
|
|
1209
1160
|
return info.join('<br>');
|
|
1210
1161
|
});
|
|
1211
1162
|
const selectClientAndViewIds = createSelector(unrealFeature.selectStreamClientCompanyId, unrealFeature.selectStreamViewId, (clientId, viewId) => ({ clientId, viewId }));
|
|
1212
|
-
const
|
|
1163
|
+
const selectIsFullyConnected = createSelector(unrealFeature.selectViewportReady, unrealFeature.selectDataChannelConnected, unrealFeature.selectCirrusConnected, (viewportReady, dataChannelConnected, cirrusConnected) => viewportReady && dataChannelConnected && cirrusConnected);
|
|
1164
|
+
const selectIsLoaderScreenVisible = createSelector(selectIsFullyConnected, (fullyConnected) => !fullyConnected);
|
|
1213
1165
|
const selectCirrusConnectionId = createSelector(unrealFeature.selectSsData, (data) => data?.connectionId);
|
|
1214
1166
|
/**
|
|
1215
|
-
* Returns Scene load progress as a float value
|
|
1167
|
+
* Returns Scene load progress as a float value between 0 and 1.
|
|
1168
|
+
*
|
|
1169
|
+
* Progress is split into two phases:
|
|
1170
|
+
* 1. **Signaling** (0 → ~56%): connection polling or orchestration progress.
|
|
1171
|
+
* Starts at 0.1%, so the bar is never visually empty while connecting.
|
|
1172
|
+
* 2. **Commands** (~56% → 100%): Unreal command progress after the data channel connects.
|
|
1173
|
+
*
|
|
1174
|
+
* The split point bumps by +1% once the WebSocket URL is known,
|
|
1175
|
+
* producing a small visual step that indicates the WS handshake succeeded.
|
|
1216
1176
|
*/
|
|
1217
1177
|
const selectTotalProgress = createSelector(unrealFeature.selectStatusPercentSignallingServer, selectCommandProgress, unrealFeature.selectAwsInstance, unrealFeature.selectDataChannelConnected, (statusPercentSignallingServer, commandProgress, awsInstance, dataChannelConnected) => {
|
|
1218
|
-
// TODO make better mechanism to detect is new orchestration
|
|
1219
|
-
const isNewOrchestration = String(awsInstance?.wsUrl).match(/^wss:\/\/orchestration-websocket/i);
|
|
1220
|
-
const newOrchestrationProgressComplete = dataChannelConnected
|
|
1221
|
-
? 100
|
|
1222
|
-
: (awsInstance?.progressComplete || 0) * 100;
|
|
1223
|
-
/**
|
|
1224
|
-
* Set 57% {@link SIGNALLING_PERCENT_VALUE} immediately when signalingServer?.signalingUrl is available
|
|
1225
|
-
* Up to 56% {@link SIGNALLING_PERCENT_VALUE} - 1 of the progress is reserved for signaling server polling
|
|
1226
|
-
*/
|
|
1227
|
-
const signalingPercentValue = isNewOrchestration
|
|
1228
|
-
? newOrchestrationProgressComplete
|
|
1229
|
-
: statusPercentSignallingServer;
|
|
1230
1178
|
const SIGNALLING_MAX = SIGNALLING_PERCENT_VALUE / 100;
|
|
1179
|
+
const ORCHESTRATION_WS_PATTERN = /^wss:\/\/orchestration-websocket/i;
|
|
1180
|
+
const isNewOrchestration = ORCHESTRATION_WS_PATTERN.test(awsInstance?.wsUrl ?? '');
|
|
1181
|
+
// Orchestration progress is 0–1 from the backend; map to 0–1 directly.
|
|
1182
|
+
// Once the data channel is connected, signaling is fully complete (1.0).
|
|
1183
|
+
const signalingProgress = isNewOrchestration
|
|
1184
|
+
? dataChannelConnected
|
|
1185
|
+
? 1
|
|
1186
|
+
: (awsInstance?.progressComplete ?? 0)
|
|
1187
|
+
: (statusPercentSignallingServer ?? 0) / 100;
|
|
1188
|
+
// +1% bump once WS URL is known (visual step for WS handshake)
|
|
1231
1189
|
const splitPoint = awsInstance?.wsUrl
|
|
1232
1190
|
? SIGNALLING_MAX + 0.01
|
|
1233
1191
|
: SIGNALLING_MAX;
|
|
1234
|
-
|
|
1192
|
+
// 0.001 minimum so the bar is never completely empty while loading
|
|
1193
|
+
const progressSignaling = lerp(0.001, splitPoint, signalingProgress);
|
|
1235
1194
|
const progressRest = lerp(0, 1 - splitPoint, commandProgress);
|
|
1236
1195
|
return clampf(0, 1, progressSignaling + progressRest);
|
|
1237
1196
|
});
|
|
@@ -1286,12 +1245,9 @@ class UnrealEffects {
|
|
|
1286
1245
|
};
|
|
1287
1246
|
this.disconnectReasonHandling$ = createEffect(() => {
|
|
1288
1247
|
return this.actions$.pipe(ofType(disconnectStream), filter(({ reason }) => {
|
|
1289
|
-
// Skip DataChannelClosed if peer reconnection
|
|
1290
|
-
// The peer reconnection effect will handle this case
|
|
1248
|
+
// Skip DataChannelClosed if peer reconnection will handle this case
|
|
1291
1249
|
if (reason === DisconnectReason.DataChannelClosed &&
|
|
1292
|
-
this.
|
|
1293
|
-
this.reconnectConfig.onDataChannelClose &&
|
|
1294
|
-
this.signallingService.isConnected()) {
|
|
1250
|
+
this.canPeerReconnect()) {
|
|
1295
1251
|
Logger.info('[Reconnect] Skipping destroy for DataChannelClosed - peer reconnection will handle');
|
|
1296
1252
|
return false;
|
|
1297
1253
|
}
|
|
@@ -1323,11 +1279,25 @@ class UnrealEffects {
|
|
|
1323
1279
|
})));
|
|
1324
1280
|
});
|
|
1325
1281
|
this.resetAfk$ = createEffect(() => {
|
|
1326
|
-
return this.actions$.pipe(ofType(setConfig,
|
|
1282
|
+
return this.actions$.pipe(ofType(setConfig, setUserInactivityTimeout, resetWarnTimeout, resetConfig), map(() => resetAfk()));
|
|
1327
1283
|
});
|
|
1328
1284
|
this.abortEstablishingConnection$ = createEffect(() => {
|
|
1329
|
-
return merge(this.store.select(unrealFeature.selectViewportReady).pipe(filter(Truthy)), this.actions$.pipe(ofType(setCirrusDisconnected, destroyUnrealScene, dropConnection))).pipe(
|
|
1285
|
+
return merge(this.store.select(unrealFeature.selectViewportReady).pipe(filter(Truthy)), this.actions$.pipe(ofType(setCirrusDisconnected, destroyUnrealScene, dropConnection))).pipe(map(() => abortEstablishingConnection()));
|
|
1330
1286
|
});
|
|
1287
|
+
this.iframeMessaging$ = createEffect(() => {
|
|
1288
|
+
const cirrusConnected$ = this.store
|
|
1289
|
+
.select(unrealFeature.selectCirrusConnected)
|
|
1290
|
+
.pipe(skip(1));
|
|
1291
|
+
// On disconnect: immediately show 'Connection closed.', nullify after 2s
|
|
1292
|
+
const cirrusStatus$ = cirrusConnected$.pipe(switchMap((connected) => connected
|
|
1293
|
+
? of('Creating Socket...')
|
|
1294
|
+
: concat(of('Connection closed.'), of(null).pipe(delay(2000)))));
|
|
1295
|
+
// Skip initial false; emit null on every viewport state change
|
|
1296
|
+
const viewportReset$ = this.store
|
|
1297
|
+
.select(unrealFeature.selectViewportReady)
|
|
1298
|
+
.pipe(skip(1), delay(500), map(() => null));
|
|
1299
|
+
return merge(cirrusStatus$, this.store.select(unrealFeature.selectStatusMessage), viewportReset$).pipe(debounceTime(0), distinctUntilChanged(), tapLog('STATUS=>'), tap((status) => this.postToScreenLocker(status)));
|
|
1300
|
+
}, { dispatch: false });
|
|
1331
1301
|
this.setSignalingTo100$ = createEffect(() => {
|
|
1332
1302
|
return this.actions$.pipe(ofType(setAwsInstance), map(() => setStatusPercentSignallingServer({ percent: 100 })));
|
|
1333
1303
|
});
|
|
@@ -1404,7 +1374,7 @@ class UnrealEffects {
|
|
|
1404
1374
|
});
|
|
1405
1375
|
this.commandTelemetryService.trackStartCommand('EXT-SetViewportReady');
|
|
1406
1376
|
}), switchMap(() =>
|
|
1407
|
-
// Wait for initial commands to be sent before sending loopback.
|
|
1377
|
+
// Wait for initial commands to be sent before sending the loopback.
|
|
1408
1378
|
// commandStarted fires for each sent command; debounce ensures
|
|
1409
1379
|
// we proceed only after no more commands are started for 100 ms.
|
|
1410
1380
|
this.actions$.pipe(ofType(commandStarted), debounceTime(100), take(1), switchMap(() => this.unrealCallbackService.observeCommandResponse({ command: MetaBoxCommand.FLoopBackCommand }, (data) => this.commandsSender.sendCommandToUnreal(data))), switchMap(() => this.videoService.videoStats$), filter(({ aggregatedStats: s }) => !!s.framesPerSecond &&
|
|
@@ -1417,6 +1387,9 @@ class UnrealEffects {
|
|
|
1417
1387
|
this.startStream$ = createEffect(() => {
|
|
1418
1388
|
return this.actions$.pipe(ofType(startStream), map(() => initSignalling()));
|
|
1419
1389
|
});
|
|
1390
|
+
this.resetAfkOnVideoStart$ = createEffect(() => {
|
|
1391
|
+
return this.actions$.pipe(ofType(videoStreamInitialized), filter(() => !!this.videoService.video?.paused), tap(() => Logger.info('Simulate Press Play')), map(() => resetAfk()));
|
|
1392
|
+
});
|
|
1420
1393
|
/**
|
|
1421
1394
|
* Effect: `forceViewportNotReady$`
|
|
1422
1395
|
*
|
|
@@ -1444,9 +1417,7 @@ class UnrealEffects {
|
|
|
1444
1417
|
*/
|
|
1445
1418
|
this.handleDataChannelClosed$ = createEffect(() => {
|
|
1446
1419
|
return this.actions$.pipe(ofType(disconnectStream), filter(({ reason }) => reason === DisconnectReason.DataChannelClosed &&
|
|
1447
|
-
this.
|
|
1448
|
-
this.reconnectConfig.onDataChannelClose &&
|
|
1449
|
-
this.signallingService.isConnected()), tap(() => {
|
|
1420
|
+
this.canPeerReconnect()), tap(() => {
|
|
1450
1421
|
Logger.warn('[Reconnect] DataChannel closed, initiating peer reconnection');
|
|
1451
1422
|
}), map(() => reconnectPeer({
|
|
1452
1423
|
attempt: 1,
|
|
@@ -1557,16 +1528,21 @@ class UnrealEffects {
|
|
|
1557
1528
|
// Ensure a single in-flight request per attempt.
|
|
1558
1529
|
exhaustMap((urls) => this.signallingService.connectToSignaling(urls)));
|
|
1559
1530
|
}, { dispatch: false });
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1531
|
+
}
|
|
1532
|
+
canPeerReconnect() {
|
|
1533
|
+
return (this.reconnectConfig.enabled &&
|
|
1534
|
+
this.reconnectConfig.onDataChannelClose &&
|
|
1535
|
+
this.signallingService.isConnected());
|
|
1536
|
+
}
|
|
1537
|
+
postToScreenLocker(text) {
|
|
1538
|
+
try {
|
|
1539
|
+
const el = document.getElementById(this.unrealInitialConfig?.screenLockerContainerId ??
|
|
1540
|
+
SCREEN_LOCKER_CONTAINER_ID);
|
|
1541
|
+
el?.contentWindow?.postMessage(text, '*');
|
|
1542
|
+
}
|
|
1543
|
+
catch {
|
|
1544
|
+
// Fails silently if cross-origin
|
|
1545
|
+
}
|
|
1570
1546
|
}
|
|
1571
1547
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1572
1548
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealEffects }); }
|
|
@@ -1601,7 +1577,7 @@ class SubService {
|
|
|
1601
1577
|
this.disconnect$ = this.store
|
|
1602
1578
|
.select(unrealFeature.selectCirrusConnected)
|
|
1603
1579
|
.pipe(skip(1), filter(Falsy), share());
|
|
1604
|
-
this.
|
|
1580
|
+
this.destroyRef.onDestroy(() => {
|
|
1605
1581
|
this.destroy$.next();
|
|
1606
1582
|
this.destroy$.complete();
|
|
1607
1583
|
});
|
|
@@ -1612,7 +1588,7 @@ class AFKService extends SubService {
|
|
|
1612
1588
|
constructor() {
|
|
1613
1589
|
super();
|
|
1614
1590
|
this.active = false; // Whether the AFK system is currently looking for inactivity.
|
|
1615
|
-
this.countdown = 0;
|
|
1591
|
+
this.countdown = 0;
|
|
1616
1592
|
this.warnTimeout = this.store.selectSignal(selectWarnTimeout);
|
|
1617
1593
|
this.isViewportReady = this.store.selectSignal(unrealFeature.selectViewportReady);
|
|
1618
1594
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
@@ -1620,6 +1596,8 @@ class AFKService extends SubService {
|
|
|
1620
1596
|
this.afkResetTrigger = toSignal(merge(this.store.select(selectWarnTimeout), this.actions$.pipe(ofType(resetAfk))));
|
|
1621
1597
|
/** Ticks when cirrus disconnects */
|
|
1622
1598
|
this.disconnected = toSignal(this.disconnect$);
|
|
1599
|
+
/** Ticks when resetUserInactivityTimeout action fires */
|
|
1600
|
+
this.resetUserInactivityTrigger = toSignal(this.actions$.pipe(ofType(resetUserInactivityTimeout)));
|
|
1623
1601
|
this.destroyRef.onDestroy(() => this.clearTimers());
|
|
1624
1602
|
if (this.unrealConfig?.playwright) {
|
|
1625
1603
|
return;
|
|
@@ -1647,6 +1625,11 @@ class AFKService extends SubService {
|
|
|
1647
1625
|
untracked(() => this.stop());
|
|
1648
1626
|
}
|
|
1649
1627
|
});
|
|
1628
|
+
// Full reset (hide overlay + restart warning timer) on external request
|
|
1629
|
+
effect(() => {
|
|
1630
|
+
this.resetUserInactivityTrigger();
|
|
1631
|
+
untracked(() => this.reset());
|
|
1632
|
+
});
|
|
1650
1633
|
}
|
|
1651
1634
|
hideOverlay() {
|
|
1652
1635
|
this.store.dispatch(setAfkTimerHide());
|
|
@@ -1724,11 +1707,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1724
1707
|
type: Injectable
|
|
1725
1708
|
}], ctorParameters: () => [] });
|
|
1726
1709
|
|
|
1710
|
+
class LoadingProgressService {
|
|
1711
|
+
constructor() {
|
|
1712
|
+
this.#store = inject(Store);
|
|
1713
|
+
this.loaderVisible = this.#store.selectSignal(selectShowLoader);
|
|
1714
|
+
this.percents = toSignal(this.#store
|
|
1715
|
+
.select(selectTotalProgress)
|
|
1716
|
+
.pipe(keepMaxUntilReset(toObservable(this.loaderVisible).pipe(filter(Falsy))), floatToSmoothPercents(), distinctUntilChanged()));
|
|
1717
|
+
}
|
|
1718
|
+
#store;
|
|
1719
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1720
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: LoadingProgressService }); }
|
|
1721
|
+
}
|
|
1722
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: LoadingProgressService, decorators: [{
|
|
1723
|
+
type: Injectable
|
|
1724
|
+
}] });
|
|
1725
|
+
|
|
1727
1726
|
class FreezeFrameService extends SubService {
|
|
1728
1727
|
constructor() {
|
|
1729
1728
|
super();
|
|
1730
1729
|
this.receiving = false;
|
|
1731
1730
|
this.size = 0;
|
|
1731
|
+
this.jpeg = undefined;
|
|
1732
1732
|
this.freezeFrameOverlay = new Image();
|
|
1733
1733
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
1734
1734
|
this.init();
|
|
@@ -1881,7 +1881,7 @@ class VideoService extends SubService {
|
|
|
1881
1881
|
this.videoTrack$.next({ stream, pcClient });
|
|
1882
1882
|
}
|
|
1883
1883
|
else {
|
|
1884
|
-
|
|
1884
|
+
Logger.error('Video element is not defined.');
|
|
1885
1885
|
}
|
|
1886
1886
|
}
|
|
1887
1887
|
attachAudioStream(stream) {
|
|
@@ -1958,7 +1958,7 @@ class VideoService extends SubService {
|
|
|
1958
1958
|
catch (err) {
|
|
1959
1959
|
// Handle InvalidStateError or any transient WebRTC errors gracefully
|
|
1960
1960
|
if (err instanceof DOMException && err.name === 'InvalidStateError') {
|
|
1961
|
-
|
|
1961
|
+
Logger.warn('Peer connection is closed or unusable, skipping stats.');
|
|
1962
1962
|
return null;
|
|
1963
1963
|
}
|
|
1964
1964
|
throw err;
|
|
@@ -2100,7 +2100,7 @@ class VideoService extends SubService {
|
|
|
2100
2100
|
}
|
|
2101
2101
|
createWebRtcAudio() {
|
|
2102
2102
|
const audio = new Audio();
|
|
2103
|
-
audio.id =
|
|
2103
|
+
audio.id = STREAMING_AUDIO_ID;
|
|
2104
2104
|
this.audio = audio;
|
|
2105
2105
|
}
|
|
2106
2106
|
playAudio(audio) {
|
|
@@ -2573,7 +2573,9 @@ class SignallingService extends SubService {
|
|
|
2573
2573
|
return;
|
|
2574
2574
|
}
|
|
2575
2575
|
this.setHandlersFromStream();
|
|
2576
|
-
this.action
|
|
2576
|
+
this.action$
|
|
2577
|
+
.pipe(ofType(dataChannelReady), takeUntil(this.abort$))
|
|
2578
|
+
.subscribe(() => {
|
|
2577
2579
|
this.send({
|
|
2578
2580
|
type: 'p2pEstablished',
|
|
2579
2581
|
source: 'front',
|
|
@@ -2583,7 +2585,7 @@ class SignallingService extends SubService {
|
|
|
2583
2585
|
this.action$
|
|
2584
2586
|
.pipe(ofType(dataChannelReady), switchMap(() => this.store
|
|
2585
2587
|
.select(unrealFeature.selectViewportReady)
|
|
2586
|
-
.pipe(filter(Truthy), take(1))))
|
|
2588
|
+
.pipe(filter(Truthy), take(1))), takeUntil(this.abort$))
|
|
2587
2589
|
.subscribe(() => {
|
|
2588
2590
|
this.send({
|
|
2589
2591
|
type: 'streamPreparedForUserInteraction',
|
|
@@ -2615,10 +2617,10 @@ class SignallingService extends SubService {
|
|
|
2615
2617
|
},
|
|
2616
2618
|
// count: 10, // Optional: cap the number of attempts.
|
|
2617
2619
|
}),
|
|
2618
|
-
// abort$ sits OUTSIDE retry so it kills the entire retry loop,
|
|
2620
|
+
// abort$ sits OUTSIDE retry, so it kills the entire retry loop,
|
|
2619
2621
|
// not just the current attempt. Each inner createWebSocket also
|
|
2620
2622
|
// receives abort$ independently, so mid-connection attempts are
|
|
2621
|
-
//
|
|
2623
|
+
// canceled too.
|
|
2622
2624
|
takeUntil(this.abort$));
|
|
2623
2625
|
}
|
|
2624
2626
|
startEstablishingConnection() {
|
|
@@ -2644,7 +2646,7 @@ class SignallingService extends SubService {
|
|
|
2644
2646
|
*
|
|
2645
2647
|
* 1. **Telemetry** — Starts a `getSignaling` span for end-to-end timing.
|
|
2646
2648
|
* 2. **Candidate URL selection** — A stateful generator (`urlGen`) is created
|
|
2647
|
-
* from `urlsPool`. Each resubscription (e.g
|
|
2649
|
+
* from `urlsPool`. Each resubscription (e.g., via `retry`) advances to the next URL.
|
|
2648
2650
|
* 3. **Short-circuit for WS URLs** — If the picked candidate already matches
|
|
2649
2651
|
* `ws://` or `wss://`, emit `{ wsUrl, pollingUrl: null, instanceName: null }`
|
|
2650
2652
|
* immediately and complete (no HTTP request).
|
|
@@ -2656,7 +2658,7 @@ class SignallingService extends SubService {
|
|
|
2656
2658
|
* while the request is in flight are **ignored** until completion, preventing overlap.
|
|
2657
2659
|
* 6. **Per-attempt timeout** — `timeout(WS_TIMEOUT)` caps how long we wait for a response.
|
|
2658
2660
|
* On timeout, the attempt errors and the outer `retry` schedules the next URL.
|
|
2659
|
-
* 7. **Response validation
|
|
2661
|
+
* 7. **Response validation and progress reporting** — A `filter`:
|
|
2660
2662
|
* - Calls `TelemetryStop('getSignaling', { ...data, multi: true })` on receipt.
|
|
2661
2663
|
* - If `data.signallingServer === ''` or `data.error`:
|
|
2662
2664
|
* shows a status message, optionally dispatches `setStatusPercentSignallingServer`
|
|
@@ -2673,7 +2675,7 @@ class SignallingService extends SubService {
|
|
|
2673
2675
|
*
|
|
2674
2676
|
* ### Concurrency semantics
|
|
2675
2677
|
*
|
|
2676
|
-
* - `exhaustMap` guarantees a **single** HTTP request per attempt;
|
|
2678
|
+
* - `exhaustMap` guarantees a **single** HTTP request per attempt; later
|
|
2677
2679
|
* `{clientId, viewId}` emissions are ignored until the current request completes.
|
|
2678
2680
|
*
|
|
2679
2681
|
* ### Telemetry semantics
|
|
@@ -2707,7 +2709,7 @@ class SignallingService extends SubService {
|
|
|
2707
2709
|
* @remarks
|
|
2708
2710
|
* - The URL generator (`urlGen`) is created **outside** `defer`, so resubscriptions
|
|
2709
2711
|
* advance the pool. Creating it inside `defer` would restart from the first URL each retry.
|
|
2710
|
-
* - `location.protocol` is used to derive `ws` vs `wss`. If this may run in non-browser
|
|
2712
|
+
* - `location.protocol` is used to derive `ws` vs. `wss`. If this may run in non-browser
|
|
2711
2713
|
* contexts (e.g., SSR), guard or abstract this logic.
|
|
2712
2714
|
* - Consider capping retries with `count` in `retry({ count, delay })` when appropriate.
|
|
2713
2715
|
*
|
|
@@ -2740,7 +2742,7 @@ class SignallingService extends SubService {
|
|
|
2740
2742
|
};
|
|
2741
2743
|
}));
|
|
2742
2744
|
}
|
|
2743
|
-
// Old (HTTP-polling) orchestration flow — mark the
|
|
2745
|
+
// Old (HTTP-polling) orchestration flow — mark the round trip so
|
|
2744
2746
|
// the signaling-phase timeline can show it as a distinct segment.
|
|
2745
2747
|
this.store.dispatch(pollingStarted());
|
|
2746
2748
|
return this.store.select(selectClientAndViewIds).pipe(
|
|
@@ -2914,6 +2916,8 @@ class WebRtcPlayerService extends SubService {
|
|
|
2914
2916
|
constructor() {
|
|
2915
2917
|
super();
|
|
2916
2918
|
this.onDataChannelMessage$ = new Subject();
|
|
2919
|
+
this.pcClient = null;
|
|
2920
|
+
this.dcClient = null;
|
|
2917
2921
|
this.signallingSrv = inject(SignallingService);
|
|
2918
2922
|
this.videoService = inject(VideoService);
|
|
2919
2923
|
this.commandTelemetryService = inject(CommandTelemetryService);
|
|
@@ -2927,29 +2931,37 @@ class WebRtcPlayerService extends SubService {
|
|
|
2927
2931
|
this.iceCandidateBuffer = [];
|
|
2928
2932
|
this.isReconnecting = this.store.selectSignal(unrealFeature.selectIsReconnecting);
|
|
2929
2933
|
this.init();
|
|
2930
|
-
this.actions
|
|
2931
|
-
|
|
2934
|
+
this.actions$
|
|
2935
|
+
.pipe(ofType(dropDC), takeUntil(this.destroy$))
|
|
2936
|
+
.subscribe(() => this.dcClient?.close());
|
|
2937
|
+
this.actions$
|
|
2938
|
+
.pipe(ofType(dropPC), takeUntil(this.destroy$))
|
|
2939
|
+
.subscribe(() => this.pcClient?.close());
|
|
2932
2940
|
}
|
|
2933
2941
|
init() {
|
|
2934
|
-
this.signallingSrv.onConfig
|
|
2942
|
+
this.signallingSrv.onConfig$
|
|
2943
|
+
.pipe(takeUntil(this.destroy$))
|
|
2944
|
+
.subscribe((config) => {
|
|
2935
2945
|
this.videoService.create();
|
|
2936
2946
|
this.setConfig(config);
|
|
2937
2947
|
});
|
|
2938
2948
|
// Server-initiated offer: set remote description and respond with answer
|
|
2939
|
-
this.signallingSrv.onOffer
|
|
2949
|
+
this.signallingSrv.onOffer$
|
|
2950
|
+
.pipe(filter(Truthy), takeUntil(this.destroy$))
|
|
2951
|
+
.subscribe((offer) => {
|
|
2940
2952
|
void this.handleServerOffer(offer);
|
|
2941
2953
|
});
|
|
2942
2954
|
// Answer to a client-initiated offer
|
|
2943
2955
|
this.signallingSrv.onWebRtcAnswer$
|
|
2944
|
-
.pipe(filter(Truthy))
|
|
2956
|
+
.pipe(filter(Truthy), takeUntil(this.destroy$))
|
|
2945
2957
|
.subscribe((answer) => {
|
|
2946
2958
|
void this.handleServerAnswer(answer);
|
|
2947
2959
|
});
|
|
2948
2960
|
// ICE candidates — buffered until remote description is set
|
|
2949
|
-
this.signallingSrv.onWebRtcIce
|
|
2950
|
-
this.
|
|
2951
|
-
|
|
2952
|
-
});
|
|
2961
|
+
this.signallingSrv.onWebRtcIce$
|
|
2962
|
+
.pipe(takeUntil(this.destroy$))
|
|
2963
|
+
.subscribe((candidate) => {
|
|
2964
|
+
this.commandTelemetryService.trackStopCommand('EXT-iceCandidate', true, { multi: true });
|
|
2953
2965
|
if (this.remoteDescriptionSet) {
|
|
2954
2966
|
this.handleCandidateFromServer(candidate);
|
|
2955
2967
|
}
|
|
@@ -2974,11 +2986,15 @@ class WebRtcPlayerService extends SubService {
|
|
|
2974
2986
|
if (!this.pcClient) {
|
|
2975
2987
|
this.setupPeerConnection(this.cfg);
|
|
2976
2988
|
}
|
|
2989
|
+
const pc = this.pcClient;
|
|
2990
|
+
if (!pc) {
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2977
2993
|
// Offer already defines media transceivers — don't add extras
|
|
2978
|
-
await
|
|
2994
|
+
await pc.setRemoteDescription(offer);
|
|
2979
2995
|
this.remoteDescriptionSet = true;
|
|
2980
2996
|
this.flushIceCandidateBuffer();
|
|
2981
|
-
await this.createAnswer(
|
|
2997
|
+
await this.createAnswer(pc);
|
|
2982
2998
|
}
|
|
2983
2999
|
catch (e) {
|
|
2984
3000
|
Logger.error('Failed to handle server offer', e);
|
|
@@ -3023,10 +3039,16 @@ class WebRtcPlayerService extends SubService {
|
|
|
3023
3039
|
if (!this.pcClient) {
|
|
3024
3040
|
this.setupPeerConnection(this.cfg);
|
|
3025
3041
|
}
|
|
3042
|
+
const pc = this.pcClient;
|
|
3043
|
+
if (!pc) {
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3026
3046
|
// Client offers: transceivers first, then DC, then offer
|
|
3027
|
-
await this.setupTransceiversAsync(
|
|
3028
|
-
this.dcClient = this.createDataChannel(
|
|
3029
|
-
|
|
3047
|
+
await this.setupTransceiversAsync(pc);
|
|
3048
|
+
this.dcClient = this.createDataChannel(pc, 'UnrealDcConnection', {
|
|
3049
|
+
ordered: true,
|
|
3050
|
+
});
|
|
3051
|
+
await this.createOffer(pc);
|
|
3030
3052
|
}
|
|
3031
3053
|
catch (e) {
|
|
3032
3054
|
Logger.error('Failed to create WebRTC offer', e);
|
|
@@ -3085,7 +3107,7 @@ class WebRtcPlayerService extends SubService {
|
|
|
3085
3107
|
* RFC 6184 that encodes three H.264 parameters:
|
|
3086
3108
|
* - **Profile IDC** (`XX`) — the H.264 profile.
|
|
3087
3109
|
* - **Profile IOP** (`YY`) — constraint flags that further narrow the profile.
|
|
3088
|
-
* - **Level IDC** (`ZZ`) — the level
|
|
3110
|
+
* - **Level IDC** (`ZZ`) — the level which caps resolution/framerate/bitrate.
|
|
3089
3111
|
*
|
|
3090
3112
|
* ### H.264 profiles relevant to Unreal Engine Pixel Streaming
|
|
3091
3113
|
*
|
|
@@ -3103,12 +3125,12 @@ class WebRtcPlayerService extends SubService {
|
|
|
3103
3125
|
* | `f4001f` | High 4:4:4 Predictive | 3.1 | Lossless capable; rare in browsers |
|
|
3104
3126
|
*
|
|
3105
3127
|
* UE Pixel Streaming defaults to Constrained Baseline (`42e01f`) or High (`6400xx`)
|
|
3106
|
-
* depending on engine version and `WebRTC.H264Profile` CVar.
|
|
3128
|
+
* depending on the engine version and `WebRTC.H264Profile` CVar.
|
|
3107
3129
|
*
|
|
3108
3130
|
* We prioritize `42e01f` because it guarantees hardware decoding on
|
|
3109
3131
|
* virtually all client devices (desktop, mobile, embedded), avoiding
|
|
3110
3132
|
* fallback to software decoding or negotiation of a higher profile
|
|
3111
|
-
* that the client GPU may not
|
|
3133
|
+
* that the client GPU may not speed up.
|
|
3112
3134
|
*/
|
|
3113
3135
|
prioritizeH264Profile(sdp, profileLevelId) {
|
|
3114
3136
|
const lines = sdp.split('\r\n');
|
|
@@ -3517,7 +3539,7 @@ class FileReceiverService extends SubService {
|
|
|
3517
3539
|
}
|
|
3518
3540
|
this.store
|
|
3519
3541
|
.select(unrealFeature.selectViewportReady)
|
|
3520
|
-
.pipe(filter(Truthy))
|
|
3542
|
+
.pipe(filter(Truthy), takeUntil(this.destroy$))
|
|
3521
3543
|
.subscribe(() => this.reset());
|
|
3522
3544
|
}
|
|
3523
3545
|
reset() {
|
|
@@ -3642,7 +3664,7 @@ class AggregatorService extends SubService {
|
|
|
3642
3664
|
initialize() {
|
|
3643
3665
|
this.store
|
|
3644
3666
|
.select(unrealFeature.selectCirrusConnected)
|
|
3645
|
-
.pipe(distinctUntilChanged())
|
|
3667
|
+
.pipe(distinctUntilChanged(), takeUntil(this.destroy$))
|
|
3646
3668
|
.subscribe((connected) => {
|
|
3647
3669
|
this.resetResponseList();
|
|
3648
3670
|
if (connected) {
|
|
@@ -3652,7 +3674,9 @@ class AggregatorService extends SubService {
|
|
|
3652
3674
|
const unlockViewport$ = this.store
|
|
3653
3675
|
.select(unrealFeature.selectViewportReady)
|
|
3654
3676
|
.pipe(filter(Truthy));
|
|
3655
|
-
merge(unlockViewport$, this.disconnect$)
|
|
3677
|
+
merge(unlockViewport$, this.disconnect$)
|
|
3678
|
+
.pipe(takeUntil(this.destroy$))
|
|
3679
|
+
.subscribe(() => {
|
|
3656
3680
|
this.removeLoadScreen();
|
|
3657
3681
|
});
|
|
3658
3682
|
if (!this.selectStreamConfig()?.autoStart ||
|
|
@@ -3664,22 +3688,6 @@ class AggregatorService extends SubService {
|
|
|
3664
3688
|
addResponseEventListener(name, listener) {
|
|
3665
3689
|
this.responseEventListeners.set(name, listener);
|
|
3666
3690
|
}
|
|
3667
|
-
showOnScreenKeyboard(command) {
|
|
3668
|
-
if (command.showOnScreenKeyboard) {
|
|
3669
|
-
// Show the 'edit text' button.
|
|
3670
|
-
//editTextButton.classList.remove('hiddenState');
|
|
3671
|
-
// Place the 'edit text' button near the UE4 input widget.
|
|
3672
|
-
//let pos = unquantizeAndDenormalizeUnsigned(command.x, command.y);
|
|
3673
|
-
//editTextButton.style.top = pos.y.toString() + 'px';
|
|
3674
|
-
//editTextButton.style.left = (pos.x - 40).toString() + 'px';
|
|
3675
|
-
}
|
|
3676
|
-
else {
|
|
3677
|
-
// Hide the 'edit text' button.
|
|
3678
|
-
//editTextButton.classList.add('hiddenState');
|
|
3679
|
-
// Hide the on-screen keyboard.
|
|
3680
|
-
// hiddenInput.blur();
|
|
3681
|
-
}
|
|
3682
|
-
}
|
|
3683
3691
|
removeLoadScreen() {
|
|
3684
3692
|
document
|
|
3685
3693
|
.getElementById(this.unrealConfig?.screenLockerContainerId ||
|
|
@@ -3747,12 +3755,8 @@ class AggregatorService extends SubService {
|
|
|
3747
3755
|
break;
|
|
3748
3756
|
}
|
|
3749
3757
|
case ToClientMessage.Command: {
|
|
3750
|
-
const
|
|
3751
|
-
Logger.colored(...COLOR_CODES.FROM_UNREAL,
|
|
3752
|
-
const command = JSON.parse(commandAsString);
|
|
3753
|
-
if (command.command === 'onScreenKeyboard') {
|
|
3754
|
-
this.showOnScreenKeyboard(command);
|
|
3755
|
-
}
|
|
3758
|
+
const command = JSON.parse(decodeData(anyData));
|
|
3759
|
+
Logger.colored(...COLOR_CODES.FROM_UNREAL, command);
|
|
3756
3760
|
break;
|
|
3757
3761
|
}
|
|
3758
3762
|
case ToClientMessage.FileExtension:
|
|
@@ -3857,7 +3861,7 @@ class ConsoleExtensionsService extends SubService {
|
|
|
3857
3861
|
command: MetaBoxCommand.FChangeResolutionCommand,
|
|
3858
3862
|
payload: { resolution },
|
|
3859
3863
|
});
|
|
3860
|
-
return `
|
|
3864
|
+
return `Resolution set to ${resolution.x}x${resolution.y}`;
|
|
3861
3865
|
};
|
|
3862
3866
|
window.setMaxFps = (maxFps) => {
|
|
3863
3867
|
this.store.dispatch(setMaxFps({ maxFps }));
|
|
@@ -3932,7 +3936,9 @@ class UnrealCommunicatorService {
|
|
|
3932
3936
|
// of the store selector. The selector reads the current state and can fire on
|
|
3933
3937
|
// stale `true` from a previous session when switching components (Angular
|
|
3934
3938
|
// creates the new component before destroying the old one).
|
|
3935
|
-
this.actions
|
|
3939
|
+
this.actions$
|
|
3940
|
+
.pipe(ofType(dataChannelConnected), takeUntil$1(this.destroy$))
|
|
3941
|
+
.subscribe(() => {
|
|
3936
3942
|
this.requestInitialSettings();
|
|
3937
3943
|
this.requestQualityControl();
|
|
3938
3944
|
});
|
|
@@ -4048,7 +4054,15 @@ class InputService extends SubService {
|
|
|
4048
4054
|
KeyboardNumericCode.NumpadDecimal,
|
|
4049
4055
|
];
|
|
4050
4056
|
this.availableKeys = this.defaultKeys;
|
|
4057
|
+
this.options = InputOptions;
|
|
4051
4058
|
this.reInit$ = new Subject();
|
|
4059
|
+
this.deactivatedVideoTrigger$ = NEVER;
|
|
4060
|
+
this.normalizeAndQuantizeUnsigned = (_x, _y) => ({
|
|
4061
|
+
inRange: false,
|
|
4062
|
+
x: 65535,
|
|
4063
|
+
y: 65535,
|
|
4064
|
+
});
|
|
4065
|
+
this.normalizeAndQuantizeSigned = (_x, _y) => ({ x: 0, y: 0 });
|
|
4052
4066
|
this.videoBoundingRect = new DOMRect(0, 0, 1, 1);
|
|
4053
4067
|
this.fingerIds = new Map();
|
|
4054
4068
|
this.maxByteValue = 255;
|
|
@@ -4071,11 +4085,11 @@ class InputService extends SubService {
|
|
|
4071
4085
|
const visibilityVisibleTrigger$ = fromEvent(document, 'visibilitychange').pipe(map$1(() => document.visibilityState === 'visible'), filter(Truthy), startWith(true));
|
|
4072
4086
|
this.deactivatedVideoTrigger$ = merge(this.disconnect$, this.reInit$, visibilityHiddenTrigger$);
|
|
4073
4087
|
merge(visibilityVisibleTrigger$, this.store.select(unrealFeature.selectViewportReady).pipe(filter(Truthy)))
|
|
4074
|
-
.pipe(filter(() => !!this.video))
|
|
4088
|
+
.pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
|
|
4075
4089
|
.subscribe(() => this.setup());
|
|
4076
4090
|
}
|
|
4077
4091
|
useKeyboardKeys(keys) {
|
|
4078
|
-
this.availableKeys = keys
|
|
4092
|
+
this.availableKeys = keys;
|
|
4079
4093
|
}
|
|
4080
4094
|
get video() {
|
|
4081
4095
|
return this.videoService.video;
|
|
@@ -4137,49 +4151,47 @@ class InputService extends SubService {
|
|
|
4137
4151
|
};
|
|
4138
4152
|
}
|
|
4139
4153
|
setupNormalizeAndQuantize(videoElement) {
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
normalizedY > 1.0) {
|
|
4159
|
-
return {
|
|
4160
|
-
inRange: false,
|
|
4161
|
-
x: 65535,
|
|
4162
|
-
y: 65535,
|
|
4163
|
-
};
|
|
4164
|
-
}
|
|
4165
|
-
else {
|
|
4166
|
-
return {
|
|
4167
|
-
inRange: true,
|
|
4168
|
-
x: normalizedX * 65536,
|
|
4169
|
-
y: normalizedY * 65536,
|
|
4170
|
-
};
|
|
4171
|
-
}
|
|
4172
|
-
};
|
|
4173
|
-
// Signed.
|
|
4174
|
-
this.normalizeAndQuantizeSigned = (x, y) => {
|
|
4175
|
-
const normalizedX = x / (0.5 * videoElement.clientWidth);
|
|
4176
|
-
const normalizedY = y / (0.5 * videoElement.clientHeight);
|
|
4154
|
+
this.videoBoundingRect = videoElement.getBoundingClientRect();
|
|
4155
|
+
this.offsetParams = this.getObjectFitOffset(videoElement);
|
|
4156
|
+
// Unsigned XY positions are the ratio (0.0..1.0) along a viewport axis,
|
|
4157
|
+
// quantized into an uint16 (0..65536).
|
|
4158
|
+
// Signed XY deltas are the ratio (-1.0..1.0) along a viewport axis,
|
|
4159
|
+
// quantized into an int16 (-32767..32767).
|
|
4160
|
+
// This allows the browser viewport and client viewport to have a different
|
|
4161
|
+
// size.
|
|
4162
|
+
// Hack: Currently, we set an out-of-range position to an extreme (65535)
|
|
4163
|
+
// as we can't yet accurately detect mouse enter and leave events
|
|
4164
|
+
// precisely inside a video with an aspect ratio which causes mattes.
|
|
4165
|
+
this.normalizeAndQuantizeUnsigned = (x, y) => {
|
|
4166
|
+
const normalizedX = x / videoElement.clientWidth;
|
|
4167
|
+
const normalizedY = y / videoElement.clientHeight;
|
|
4168
|
+
if (normalizedX < 0.0 ||
|
|
4169
|
+
normalizedX > 1.0 ||
|
|
4170
|
+
normalizedY < 0.0 ||
|
|
4171
|
+
normalizedY > 1.0) {
|
|
4177
4172
|
return {
|
|
4178
|
-
|
|
4179
|
-
|
|
4173
|
+
inRange: false,
|
|
4174
|
+
x: 65535,
|
|
4175
|
+
y: 65535,
|
|
4180
4176
|
};
|
|
4177
|
+
}
|
|
4178
|
+
else {
|
|
4179
|
+
return {
|
|
4180
|
+
inRange: true,
|
|
4181
|
+
x: normalizedX * 65536,
|
|
4182
|
+
y: normalizedY * 65536,
|
|
4183
|
+
};
|
|
4184
|
+
}
|
|
4185
|
+
};
|
|
4186
|
+
// Signed.
|
|
4187
|
+
this.normalizeAndQuantizeSigned = (x, y) => {
|
|
4188
|
+
const normalizedX = x / (0.5 * videoElement.clientWidth);
|
|
4189
|
+
const normalizedY = y / (0.5 * videoElement.clientHeight);
|
|
4190
|
+
return {
|
|
4191
|
+
x: normalizedX * 32767,
|
|
4192
|
+
y: normalizedY * 32767,
|
|
4181
4193
|
};
|
|
4182
|
-
}
|
|
4194
|
+
};
|
|
4183
4195
|
}
|
|
4184
4196
|
sendInputData(data) {
|
|
4185
4197
|
this.commandsSender.sendInputData(data);
|
|
@@ -4219,11 +4231,12 @@ class InputService extends SubService {
|
|
|
4219
4231
|
this.fingerIds.set(touch.identifier, finger);
|
|
4220
4232
|
};
|
|
4221
4233
|
const forgetTouch = (touch) => {
|
|
4222
|
-
this.
|
|
4234
|
+
const finger = this.fingerIds.get(touch.identifier);
|
|
4235
|
+
if (finger) {
|
|
4236
|
+
this.fingers.push(finger);
|
|
4237
|
+
}
|
|
4223
4238
|
// Sort array back into descending order. This means if finger '1' were to lift after finger '0', we would ensure that 0 will be the first index to pop
|
|
4224
|
-
this.fingers.sort(
|
|
4225
|
-
return b - a;
|
|
4226
|
-
});
|
|
4239
|
+
this.fingers.sort((a, b) => b - a);
|
|
4227
4240
|
this.fingerIds.delete(touch.identifier);
|
|
4228
4241
|
};
|
|
4229
4242
|
const emitTouchData = (type, touches) => {
|
|
@@ -4234,21 +4247,24 @@ class InputService extends SubService {
|
|
|
4234
4247
|
const touch = touches[t];
|
|
4235
4248
|
const { x, y } = this.getTouchPositionWithOffset(touch);
|
|
4236
4249
|
Logger.info(`F${this.fingerIds.get(touch.identifier)}=(${x}, ${y})`);
|
|
4237
|
-
const
|
|
4250
|
+
const normalizeCoordinates = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4238
4251
|
const data = new DataView(new ArrayBuffer(9));
|
|
4239
4252
|
data.setUint8(0, type);
|
|
4240
4253
|
data.setUint8(1, numTouches);
|
|
4241
|
-
data.setUint16(byte,
|
|
4254
|
+
data.setUint16(byte, normalizeCoordinates.x, true);
|
|
4242
4255
|
byte += 2;
|
|
4243
|
-
data.setUint16(byte,
|
|
4256
|
+
data.setUint16(byte, normalizeCoordinates.y, true);
|
|
4244
4257
|
byte += 2;
|
|
4245
|
-
|
|
4258
|
+
const finger = this.fingerIds.get(touch.identifier);
|
|
4259
|
+
if (finger) {
|
|
4260
|
+
data.setUint8(byte, finger);
|
|
4261
|
+
}
|
|
4246
4262
|
byte += 1;
|
|
4247
4263
|
// force is between 0.0 and 1.0, so quantize into byte.
|
|
4248
4264
|
// iOs bug: Forced to be always 0.5 on all devices as we do not use forced touch any way;/
|
|
4249
4265
|
data.setUint8(byte, this.maxByteValue * 0.5);
|
|
4250
4266
|
byte += 1;
|
|
4251
|
-
data.setUint8(byte,
|
|
4267
|
+
data.setUint8(byte, normalizeCoordinates.inRange ? 1 : 0);
|
|
4252
4268
|
byte += 1;
|
|
4253
4269
|
this.sendInputData(data.buffer);
|
|
4254
4270
|
}
|
|
@@ -4291,42 +4307,42 @@ class InputService extends SubService {
|
|
|
4291
4307
|
window.focus();
|
|
4292
4308
|
}
|
|
4293
4309
|
emitMouseMove(x, y, deltaX, deltaY) {
|
|
4294
|
-
const
|
|
4310
|
+
const normalizeCoordinates = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4295
4311
|
const delta = this.normalizeAndQuantizeSigned(deltaX, deltaY);
|
|
4296
|
-
const
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
this.sendInputData(
|
|
4312
|
+
const data = new DataView(new ArrayBuffer(9));
|
|
4313
|
+
data.setUint8(0, MessageType.MouseMove);
|
|
4314
|
+
data.setUint16(1, normalizeCoordinates.x, true);
|
|
4315
|
+
data.setUint16(3, normalizeCoordinates.y, true);
|
|
4316
|
+
data.setInt16(5, delta.x, true);
|
|
4317
|
+
data.setInt16(7, delta.y, true);
|
|
4318
|
+
this.sendInputData(data.buffer);
|
|
4303
4319
|
}
|
|
4304
4320
|
emitMouseDown(button, x, y) {
|
|
4305
|
-
const
|
|
4306
|
-
const
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
this.sendInputData(
|
|
4321
|
+
const normalizeCoordinates = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4322
|
+
const data = new DataView(new ArrayBuffer(6));
|
|
4323
|
+
data.setUint8(0, MessageType.MouseDown);
|
|
4324
|
+
data.setUint8(1, button);
|
|
4325
|
+
data.setUint16(2, normalizeCoordinates.x, true);
|
|
4326
|
+
data.setUint16(4, normalizeCoordinates.y, true);
|
|
4327
|
+
this.sendInputData(data.buffer);
|
|
4312
4328
|
}
|
|
4313
4329
|
emitMouseUp(button, x, y) {
|
|
4314
|
-
const
|
|
4315
|
-
const
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
this.sendInputData(
|
|
4330
|
+
const normalizeCoordinates = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4331
|
+
const data = new DataView(new ArrayBuffer(6));
|
|
4332
|
+
data.setUint8(0, MessageType.MouseUp);
|
|
4333
|
+
data.setUint8(1, button);
|
|
4334
|
+
data.setUint16(2, normalizeCoordinates.x, true);
|
|
4335
|
+
data.setUint16(4, normalizeCoordinates.y, true);
|
|
4336
|
+
this.sendInputData(data.buffer);
|
|
4321
4337
|
}
|
|
4322
4338
|
emitMouseWheel(delta, x, y) {
|
|
4323
|
-
const
|
|
4324
|
-
const
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
this.sendInputData(
|
|
4339
|
+
const normalizeCoordinates = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4340
|
+
const data = new DataView(new ArrayBuffer(7));
|
|
4341
|
+
data.setUint8(0, MessageType.MouseWheel);
|
|
4342
|
+
data.setInt16(1, delta, true);
|
|
4343
|
+
data.setUint16(3, normalizeCoordinates.x, true);
|
|
4344
|
+
data.setUint16(5, normalizeCoordinates.y, true);
|
|
4345
|
+
this.sendInputData(data.buffer);
|
|
4330
4346
|
}
|
|
4331
4347
|
releaseMouseButtons(buttons, x, y) {
|
|
4332
4348
|
if (buttons & MouseButtonsMask.PrimaryButton) {
|
|
@@ -4345,7 +4361,7 @@ class InputService extends SubService {
|
|
|
4345
4361
|
this.emitMouseUp(MouseButton.FifthButton, x, y);
|
|
4346
4362
|
}
|
|
4347
4363
|
}
|
|
4348
|
-
// If the user has any mouse buttons pressed then press them again.
|
|
4364
|
+
// If the user has any mouse buttons pressed, then press them again.
|
|
4349
4365
|
pressMouseButtons(buttons, x, y) {
|
|
4350
4366
|
if (buttons & MouseButtonsMask.PrimaryButton) {
|
|
4351
4367
|
this.emitMouseDown(MouseButton.MainButton, x, y);
|
|
@@ -4364,58 +4380,53 @@ class InputService extends SubService {
|
|
|
4364
4380
|
}
|
|
4365
4381
|
}
|
|
4366
4382
|
registerHoveringMouseEvents(htmlVideoElement) {
|
|
4367
|
-
htmlVideoElement
|
|
4383
|
+
fromEvent(htmlVideoElement, 'mousemove')
|
|
4384
|
+
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4385
|
+
.subscribe((e) => {
|
|
4368
4386
|
const { x, y } = this.getMousePositionWithOffset(e);
|
|
4369
4387
|
this.emitMouseMove(x, y, e.movementX, e.movementY);
|
|
4370
4388
|
e.preventDefault();
|
|
4371
|
-
};
|
|
4372
|
-
htmlVideoElement
|
|
4389
|
+
});
|
|
4390
|
+
fromEvent(htmlVideoElement, 'mousedown')
|
|
4391
|
+
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4392
|
+
.subscribe((e) => {
|
|
4373
4393
|
const { x, y } = this.getMousePositionWithOffset(e);
|
|
4374
4394
|
this.focusWindow();
|
|
4375
4395
|
this.emitMouseDown(e.button, x, y);
|
|
4376
4396
|
e.preventDefault();
|
|
4377
|
-
};
|
|
4378
|
-
htmlVideoElement
|
|
4397
|
+
});
|
|
4398
|
+
fromEvent(htmlVideoElement, 'mouseup')
|
|
4399
|
+
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4400
|
+
.subscribe((e) => {
|
|
4379
4401
|
const { x, y } = this.getMousePositionWithOffset(e);
|
|
4380
4402
|
this.emitMouseUp(e.button, x, y);
|
|
4381
4403
|
e.preventDefault();
|
|
4382
|
-
};
|
|
4383
|
-
// When the context menu is shown, then it is safest to release the button
|
|
4384
|
-
// pressed when the event happened. This will guarantee we will
|
|
4385
|
-
// get at least one mouse up corresponding to a mouse down event. Otherwise,
|
|
4386
|
-
// the mouse can get stuck.
|
|
4387
|
-
// https://github.com/facebook/react/issues/5531
|
|
4388
|
-
// playerElement.oncontextmenu = (e) => {
|
|
4389
|
-
// e.preventDefault();
|
|
4390
|
-
// this.emitMouseUp(e.button, e.offsetX, e.offsetY);
|
|
4391
|
-
// };
|
|
4404
|
+
});
|
|
4392
4405
|
fromEvent(htmlVideoElement, 'wheel')
|
|
4393
4406
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4394
4407
|
.subscribe((e) => {
|
|
4395
4408
|
this.emitMouseWheel(e.deltaY * -120, e.offsetX, e.offsetY);
|
|
4396
4409
|
e.preventDefault();
|
|
4397
4410
|
});
|
|
4398
|
-
htmlVideoElement.pressMouseButtons = (e) => {
|
|
4399
|
-
this.pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
4400
|
-
};
|
|
4401
|
-
htmlVideoElement.releaseMouseButtons = (e) => {
|
|
4402
|
-
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
4403
|
-
};
|
|
4404
4411
|
}
|
|
4405
4412
|
registerMouseEnterAndLeaveEvents(htmlVideoElement) {
|
|
4406
|
-
htmlVideoElement
|
|
4413
|
+
fromEvent(htmlVideoElement, 'mouseenter')
|
|
4414
|
+
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4415
|
+
.subscribe((e) => {
|
|
4407
4416
|
this.focusWindow();
|
|
4408
|
-
const
|
|
4409
|
-
|
|
4410
|
-
this.sendInputData(
|
|
4411
|
-
|
|
4412
|
-
};
|
|
4413
|
-
htmlVideoElement
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4417
|
+
const data = new DataView(new ArrayBuffer(1));
|
|
4418
|
+
data.setUint8(0, MessageType.MouseEnter);
|
|
4419
|
+
this.sendInputData(data.buffer);
|
|
4420
|
+
this.pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
4421
|
+
});
|
|
4422
|
+
fromEvent(htmlVideoElement, 'mouseleave')
|
|
4423
|
+
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4424
|
+
.subscribe((e) => {
|
|
4425
|
+
const data = new DataView(new ArrayBuffer(1));
|
|
4426
|
+
data.setUint8(0, MessageType.MouseLeave);
|
|
4427
|
+
this.sendInputData(data.buffer);
|
|
4428
|
+
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
4429
|
+
});
|
|
4419
4430
|
}
|
|
4420
4431
|
// Browser keys do not have a charCode so we only need to test keyCode.
|
|
4421
4432
|
isKeyCodeBrowserKey(keyCode) {
|
|
@@ -5432,22 +5443,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
5432
5443
|
}] });
|
|
5433
5444
|
|
|
5434
5445
|
class AnalyticsService extends SubService {
|
|
5435
|
-
#store = inject(Store);
|
|
5436
5446
|
/** Signals monitorMouse inner subscriptions to stop (viewport lost / new session). */
|
|
5437
5447
|
#stopMouse$ = new Subject();
|
|
5438
5448
|
sendEventToMixPanel(name, params = {}) {
|
|
5439
5449
|
Logger.log('Analytics Event:', name, params);
|
|
5440
|
-
this
|
|
5450
|
+
this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
|
|
5441
5451
|
}
|
|
5442
5452
|
constructor() {
|
|
5443
5453
|
super();
|
|
5444
|
-
const abortSignal$ = this
|
|
5454
|
+
const abortSignal$ = this.store
|
|
5445
5455
|
.select(unrealFeature.selectViewportReady)
|
|
5446
5456
|
.pipe(filter$1(Falsy), map(() => void 0));
|
|
5447
|
-
this
|
|
5457
|
+
this.store
|
|
5448
5458
|
.select(unrealFeature.selectViewportReady)
|
|
5449
|
-
.pipe(distinctUntilChanged(), filter$1(Truthy),
|
|
5450
|
-
.subscribe();
|
|
5459
|
+
.pipe(distinctUntilChanged(), filter$1(Truthy), takeUntil$1(this.destroy$))
|
|
5460
|
+
.subscribe(() => this.monitorMouse(abortSignal$));
|
|
5451
5461
|
}
|
|
5452
5462
|
monitorMouse(abortSignal$) {
|
|
5453
5463
|
this.#stopMouse$.next();
|
|
@@ -5920,12 +5930,7 @@ class UnrealCallbackService {
|
|
|
5920
5930
|
* ```
|
|
5921
5931
|
*/
|
|
5922
5932
|
fromUnrealCallback(command) {
|
|
5923
|
-
return this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => {
|
|
5924
|
-
if ('commandCallback' in json) {
|
|
5925
|
-
return json.commandCallback;
|
|
5926
|
-
}
|
|
5927
|
-
return json;
|
|
5928
|
-
}), filter((json) => json.command === command), map$1((data) => ({
|
|
5933
|
+
return this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.command === command), map$1((data) => ({
|
|
5929
5934
|
command: data.command,
|
|
5930
5935
|
payload: 'payload' in data ? data.payload : null,
|
|
5931
5936
|
})));
|
|
@@ -6057,15 +6062,15 @@ class ImageLoadingSrcComponent {
|
|
|
6057
6062
|
this.imageLoadingSrc = this.#store.selectSignal(unrealFeature.selectImageLoadingSrc);
|
|
6058
6063
|
}
|
|
6059
6064
|
#store;
|
|
6060
|
-
|
|
6065
|
+
loadingImageError() {
|
|
6061
6066
|
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
6062
6067
|
}
|
|
6063
6068
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6064
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"
|
|
6069
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:#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 }); }
|
|
6065
6070
|
}
|
|
6066
6071
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
6067
6072
|
type: Component,
|
|
6068
|
-
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"
|
|
6073
|
+
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:#fff}\n"] }]
|
|
6069
6074
|
}] });
|
|
6070
6075
|
|
|
6071
6076
|
class StatGraphComponent {
|
|
@@ -6152,83 +6157,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
6152
6157
|
|
|
6153
6158
|
class UnrealStatusComponent {
|
|
6154
6159
|
constructor() {
|
|
6155
|
-
this
|
|
6156
|
-
this
|
|
6157
|
-
this.
|
|
6158
|
-
this.
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
this.
|
|
6162
|
-
/**
|
|
6163
|
-
* An observable that emits smoothed percentage values from 0 to 100.
|
|
6164
|
-
*/
|
|
6165
|
-
this.messagePercents = toSignal(this.store.select(selectTotalProgress).pipe(keepMaxUntilReset(this.resetPercentageSignal$), floatToSmoothPercents(), distinctUntilChanged(), map$1((progress) => progress || 0)));
|
|
6166
|
-
this.awsInstance = this.store.selectSignal(unrealFeature.selectAwsInstance);
|
|
6167
|
-
}
|
|
6168
|
-
ngOnInit() {
|
|
6169
|
-
/**
|
|
6170
|
-
* A subject that emits null values to trigger nullification.
|
|
6171
|
-
*/
|
|
6172
|
-
const nullify$ = new Subject();
|
|
6173
|
-
/**
|
|
6174
|
-
* An observable that emits null values with a delay of 2000 milliseconds.
|
|
6175
|
-
*/
|
|
6176
|
-
const nullifyObs$ = nullify$
|
|
6177
|
-
.asObservable()
|
|
6178
|
-
.pipe(delay(2000));
|
|
6179
|
-
/**
|
|
6180
|
-
* An observable that emits the status message from the Unreal feature store.
|
|
6181
|
-
*/
|
|
6182
|
-
const signalingStatus$ = this.store.select(unrealFeature.selectStatusMessage);
|
|
6183
|
-
/**
|
|
6184
|
-
* An observable that emits connection status messages based on the Cirrus connection state.
|
|
6185
|
-
* Then call side effect to nullify the message.
|
|
6186
|
-
*/
|
|
6187
|
-
const cirrusConnected$ = this.store
|
|
6188
|
-
.select(unrealFeature.selectCirrusConnected)
|
|
6189
|
-
.pipe(skip(1), switchMap((connected) => connected
|
|
6190
|
-
? of('Creating Socket...')
|
|
6191
|
-
: of('Connection closed.').pipe(tap(() => nullify$.next(null)))));
|
|
6192
|
-
/**
|
|
6193
|
-
* An observable that emits the viewport visibility state.
|
|
6194
|
-
*/
|
|
6195
|
-
const viewportTrigger$ = this.store.select(unrealFeature.selectViewportReady);
|
|
6196
|
-
/**
|
|
6197
|
-
* An observable that will nullify any message displayed after 500 mSec, when viewport changes its state.
|
|
6198
|
-
*/
|
|
6199
|
-
const streamToggle$ = merge(viewportTrigger$.pipe(filter(Falsy), skip(1)), viewportTrigger$.pipe(filter(Truthy))).pipe(delay(500), map$1(() => null));
|
|
6200
|
-
/**
|
|
6201
|
-
* A subscription that merges various status observables and emits debounced status via postMessage.
|
|
6202
|
-
*/
|
|
6203
|
-
merge(nullifyObs$, cirrusConnected$, signalingStatus$, streamToggle$)
|
|
6204
|
-
.pipe(tapLog('STATUS=>'), debounceTime$1(0), takeUntilDestroyed(this.destroyRef))
|
|
6205
|
-
.subscribe((status) => this.sendMessageToIndex(status));
|
|
6206
|
-
}
|
|
6207
|
-
/**
|
|
6208
|
-
* Sends a message to the embedded iframe identified by the default value '3dsource_start_screen' ID.
|
|
6209
|
-
* This function tries to post a message to the iframe's content window. If the content
|
|
6210
|
-
* window is not accessible (e.g., due to cross-origin policies), the function fails silently.
|
|
6211
|
-
*
|
|
6212
|
-
* @param {string} text The message to be sent to the iframe. This could be a status update
|
|
6213
|
-
* or any other relevant information that the iframe needs to process.
|
|
6214
|
-
*/
|
|
6215
|
-
sendMessageToIndex(text) {
|
|
6216
|
-
const objectElement = document.getElementById(this.unrealInitialConfig?.screenLockerContainerId ||
|
|
6217
|
-
SCREEN_LOCKER_CONTAINER_ID);
|
|
6218
|
-
try {
|
|
6219
|
-
const objectDocument = objectElement.contentWindow;
|
|
6220
|
-
objectDocument?.postMessage(text, '*');
|
|
6221
|
-
}
|
|
6222
|
-
catch {
|
|
6223
|
-
// Fails silently if the iframe's content window cannot be accessed
|
|
6224
|
-
}
|
|
6160
|
+
this.#store = inject(Store);
|
|
6161
|
+
this.#loadingProgress = inject(LoadingProgressService);
|
|
6162
|
+
this.awsInstance = this.#store.selectSignal(unrealFeature.selectAwsInstance);
|
|
6163
|
+
this.messagePercents = this.#loadingProgress.percents;
|
|
6164
|
+
this.showLoader = this.#loadingProgress.loaderVisible;
|
|
6165
|
+
this.showLoadingProgress = this.#store.selectSignal(unrealFeature.selectShowLoadingProgress);
|
|
6166
|
+
this.isShowLoadingPercentsPopup = computed(() => this.showLoader() && this.showLoadingProgress(), ...(ngDevMode ? [{ debugName: "isShowLoadingPercentsPopup" }] : /* istanbul ignore next */ []));
|
|
6225
6167
|
}
|
|
6168
|
+
#store;
|
|
6169
|
+
#loadingProgress;
|
|
6226
6170
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6227
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", ngImport: i0, template: "@if (
|
|
6171
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", ngImport: i0, template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\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 }); }
|
|
6228
6172
|
}
|
|
6229
6173
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
6230
6174
|
type: Component,
|
|
6231
|
-
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceLoadingComponent], template: "@if (
|
|
6175
|
+
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SourceLoadingComponent], template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\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"] }]
|
|
6232
6176
|
}] });
|
|
6233
6177
|
|
|
6234
6178
|
class VideoStatsComponent {
|
|
@@ -6240,42 +6184,18 @@ class VideoStatsComponent {
|
|
|
6240
6184
|
this.obs$ = this.videoService.videoStats$;
|
|
6241
6185
|
this.viewportReady = this.store.selectSignal(unrealFeature.selectViewportReady);
|
|
6242
6186
|
this.ssData = this.store.selectSignal(selectSignalingParameters);
|
|
6243
|
-
this.fpsTick = toSignal(this.obs$.pipe(map$1((stat) => ({
|
|
6244
|
-
|
|
6245
|
-
}))));
|
|
6246
|
-
this.
|
|
6247
|
-
|
|
6248
|
-
}))));
|
|
6249
|
-
this.bitrateTick = toSignal(this.obs$.pipe(map$1((stat) => ({
|
|
6250
|
-
value: stat.aggregatedStats.bitrate,
|
|
6251
|
-
}))));
|
|
6252
|
-
this.videoQP = toSignal(this.obs$.pipe(map$1((stat) => ({
|
|
6253
|
-
value: stat.aggregatedStats.VideoEncoderQP,
|
|
6254
|
-
}))));
|
|
6255
|
-
this.bitrateAverageTick = toSignal(this.obs$.pipe(map$1((stat) => ({
|
|
6256
|
-
value: stat.aggregatedStats.avgBitrate,
|
|
6257
|
-
}))));
|
|
6187
|
+
this.fpsTick = toSignal(this.obs$.pipe(map$1((stat) => ({ value: stat.aggregatedStats.framesPerSecond || 0 }))));
|
|
6188
|
+
this.fpsAvgTick = toSignal(this.obs$.pipe(map$1((stat) => ({ value: stat.aggregatedStats.avgFrameRate }))));
|
|
6189
|
+
this.bitrateTick = toSignal(this.obs$.pipe(map$1((stat) => ({ value: stat.aggregatedStats.bitrate }))));
|
|
6190
|
+
this.videoQP = toSignal(this.obs$.pipe(map$1((stat) => ({ value: stat.aggregatedStats.VideoEncoderQP }))));
|
|
6191
|
+
this.bitrateAverageTick = toSignal(this.obs$.pipe(map$1((stat) => ({ value: stat.aggregatedStats.avgBitrate }))));
|
|
6258
6192
|
this.videoStatus = toSignal(this.obs$.pipe(map$1((event) => this.isDevMode &&
|
|
6259
6193
|
{
|
|
6260
6194
|
...event.aggregatedStats,
|
|
6261
6195
|
quality: event.quality,
|
|
6262
|
-
}), filter(Boolean), map$1((data) =>
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
return {
|
|
6266
|
-
key,
|
|
6267
|
-
value: data[key],
|
|
6268
|
-
};
|
|
6269
|
-
})
|
|
6270
|
-
.filter((r) => !this.elementsToShow.includes(r.key));
|
|
6271
|
-
})));
|
|
6272
|
-
this.graphList = [];
|
|
6273
|
-
this.idKey = 'com.source3d.unreal.stat';
|
|
6274
|
-
this.elementsToShow = [];
|
|
6275
|
-
this.trigger$ = new BehaviorSubject(undefined);
|
|
6276
|
-
this.getFields();
|
|
6277
|
-
}
|
|
6278
|
-
ngOnInit() {
|
|
6196
|
+
}), filter(Boolean), map$1((data) => this.fields
|
|
6197
|
+
.map((key) => ({ key, value: data[key] }))
|
|
6198
|
+
.filter((r) => !this.elementsToShow().includes(r.key)))));
|
|
6279
6199
|
this.fields = [
|
|
6280
6200
|
'kalmanBitrate',
|
|
6281
6201
|
'bitrateDrop',
|
|
@@ -6299,26 +6219,21 @@ class VideoStatsComponent {
|
|
|
6299
6219
|
'type',
|
|
6300
6220
|
'codecs',
|
|
6301
6221
|
'selectedPair',
|
|
6302
|
-
//'pliCount',
|
|
6303
|
-
//'sliCount',
|
|
6304
|
-
//'transportId',
|
|
6305
|
-
//'id',
|
|
6306
6222
|
];
|
|
6307
|
-
this.
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
key,
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
this.graphList$ = of(this.graphList).pipe(combineLatestWith(this.trigger$), map$1(([graphList]) => graphList.filter((r) => this.elementsToShow.includes(r.key))));
|
|
6223
|
+
this.elementsToShow = signal([], ...(ngDevMode ? [{ debugName: "elementsToShow" }] : /* istanbul ignore next */ []));
|
|
6224
|
+
this.idKey = 'com.source3d.unreal.stat';
|
|
6225
|
+
this.graphListItems = this.fields.map((key) => ({
|
|
6226
|
+
key,
|
|
6227
|
+
color: '#' +
|
|
6228
|
+
Math.floor(Math.random() * 16777216)
|
|
6229
|
+
.toString(16)
|
|
6230
|
+
.padStart(6, '0'),
|
|
6231
|
+
stat: this.obs$.pipe(map$1((val) => ({
|
|
6232
|
+
value: val.aggregatedStats[key],
|
|
6233
|
+
}))),
|
|
6234
|
+
}));
|
|
6235
|
+
this.graphList = computed(() => this.graphListItems.filter((r) => this.elementsToShow().includes(r.key)), ...(ngDevMode ? [{ debugName: "graphList" }] : /* istanbul ignore next */ []));
|
|
6236
|
+
this.restoreFromStorage();
|
|
6322
6237
|
}
|
|
6323
6238
|
toggle() {
|
|
6324
6239
|
this.collapsed.update((collapsed) => !collapsed);
|
|
@@ -6330,78 +6245,63 @@ class VideoStatsComponent {
|
|
|
6330
6245
|
(typeof value === 'number' && isNaN(value))) {
|
|
6331
6246
|
return;
|
|
6332
6247
|
}
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
else {
|
|
6337
|
-
this.elementsToShow.push(el);
|
|
6338
|
-
}
|
|
6248
|
+
this.elementsToShow.update((current) => current.includes(el)
|
|
6249
|
+
? current.filter((item) => item !== el)
|
|
6250
|
+
: [...current, el]);
|
|
6339
6251
|
this.writeFields();
|
|
6340
|
-
this.trigger$.next();
|
|
6341
6252
|
}
|
|
6342
|
-
|
|
6253
|
+
restoreFromStorage() {
|
|
6343
6254
|
try {
|
|
6344
|
-
const { elements, collapsed } = JSON.parse(localStorage.getItem(this.idKey)) ||
|
|
6345
|
-
this.elementsToShow
|
|
6346
|
-
this.collapsed.set(collapsed);
|
|
6255
|
+
const { elements, collapsed } = JSON.parse(localStorage.getItem(this.idKey)) || {};
|
|
6256
|
+
this.elementsToShow.set(elements || []);
|
|
6257
|
+
this.collapsed.set(collapsed ?? false);
|
|
6347
6258
|
}
|
|
6348
6259
|
catch {
|
|
6349
|
-
this.elementsToShow
|
|
6260
|
+
this.elementsToShow.set([]);
|
|
6350
6261
|
}
|
|
6351
6262
|
}
|
|
6352
6263
|
writeFields() {
|
|
6353
6264
|
localStorage.setItem(this.idKey, JSON.stringify({
|
|
6354
6265
|
collapsed: this.collapsed(),
|
|
6355
|
-
elements: this.elementsToShow,
|
|
6266
|
+
elements: this.elementsToShow(),
|
|
6356
6267
|
}));
|
|
6357
6268
|
}
|
|
6358
6269
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6359
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", 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
|
|
6270
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"(graph.stat | 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 class=\"ssInfo\">\n @for (line of ssData(); track line) {\n <div>{{ line }}</div>\n }\n </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" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6360
6271
|
}
|
|
6361
6272
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
6362
6273
|
type: Component,
|
|
6363
|
-
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, AsyncPipe, JsonPipe
|
|
6274
|
+
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, AsyncPipe, JsonPipe], template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"(graph.stat | 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 class=\"ssInfo\">\n @for (line of ssData(); track line) {\n <div>{{ line }}</div>\n }\n </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"] }]
|
|
6364
6275
|
}], ctorParameters: () => [] });
|
|
6365
6276
|
|
|
6366
6277
|
class ResumeStreamButtonComponent {
|
|
6278
|
+
#store;
|
|
6367
6279
|
constructor() {
|
|
6368
|
-
this.actions$ = inject(Actions);
|
|
6369
6280
|
this.#store = inject(Store);
|
|
6370
|
-
this.#videoService = inject(VideoService);
|
|
6371
|
-
this.#destroyRef = inject(DestroyRef);
|
|
6372
|
-
this.showReconnectPopup = this.#store.selectSignal(selectShowReconnectPopup);
|
|
6373
|
-
this.isLoaderScreenVisible = this.#store.selectSignal(selectIsLoaderScreenVisible);
|
|
6374
6281
|
this.streamConfig = this.#store.selectSignal(selectStreamConfig);
|
|
6282
|
+
this.isSecondStart = signal(!!(this.streamConfig()?.autoStart && location.href.match(/^https/gi)), ...(ngDevMode ? [{ debugName: "isSecondStart" }] : /* istanbul ignore next */ []));
|
|
6283
|
+
this.isLoaderScreenVisible = this.#store.selectSignal(selectIsLoaderScreenVisible);
|
|
6284
|
+
this.showReconnectPopup = this.#store.selectSignal(selectShowReconnectPopup);
|
|
6375
6285
|
this.isExistMatchUrls = this.#store.selectSignal(selectIsExistMatchUrls);
|
|
6376
6286
|
this.showResumeStreamPopup = this.#store.selectSignal(unrealFeature.selectShowResumeStreamPopup);
|
|
6377
|
-
this.isSecondStart = signal(!!(this.streamConfig()?.autoStart && location.href.match(/^https/gi)), ...(ngDevMode ? [{ debugName: "isSecondStart" }] : /* istanbul ignore next */ []));
|
|
6378
6287
|
this.isShowResumeButton = computed(() => this.isLoaderScreenVisible() &&
|
|
6379
6288
|
this.showReconnectPopup() &&
|
|
6380
6289
|
this.isExistMatchUrls() &&
|
|
6381
6290
|
this.showResumeStreamPopup(), ...(ngDevMode ? [{ debugName: "isShowResumeButton" }] : /* istanbul ignore next */ []));
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
.subscribe(() => this.onDisconnect());
|
|
6391
|
-
}
|
|
6392
|
-
ngAfterViewInit() {
|
|
6393
|
-
this.actions$
|
|
6394
|
-
.pipe(ofType(videoStreamInitialized), takeUntilDestroyed(this.#destroyRef), filter(() => !!this.#videoService.video?.paused))
|
|
6395
|
-
.subscribe(() => {
|
|
6396
|
-
Logger.info('Simulate Press Play');
|
|
6397
|
-
this.#videoService.play();
|
|
6398
|
-
this.#store.dispatch(resetAfk());
|
|
6291
|
+
this.cirrusConnected = this.#store.selectSignal(unrealFeature.selectCirrusConnected);
|
|
6292
|
+
let wasConnected = this.cirrusConnected();
|
|
6293
|
+
effect(() => {
|
|
6294
|
+
const connected = this.cirrusConnected();
|
|
6295
|
+
if (!connected && wasConnected) {
|
|
6296
|
+
this.disconnect();
|
|
6297
|
+
}
|
|
6298
|
+
wasConnected = connected;
|
|
6399
6299
|
});
|
|
6400
6300
|
}
|
|
6401
6301
|
connect() {
|
|
6402
6302
|
this.#store.dispatch(startStream({ config: { autoStart: true } }));
|
|
6403
6303
|
}
|
|
6404
|
-
|
|
6304
|
+
disconnect() {
|
|
6405
6305
|
this.isSecondStart.set(true);
|
|
6406
6306
|
}
|
|
6407
6307
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -6410,13 +6310,13 @@ class ResumeStreamButtonComponent {
|
|
|
6410
6310
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
6411
6311
|
type: Component,
|
|
6412
6312
|
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"] }]
|
|
6413
|
-
}] });
|
|
6313
|
+
}], ctorParameters: () => [] });
|
|
6414
6314
|
|
|
6415
6315
|
class IntroSrcComponent {
|
|
6416
6316
|
#store;
|
|
6417
6317
|
constructor() {
|
|
6418
|
-
this.videoElement = viewChild('videoPlayerCover', ...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
|
|
6419
6318
|
this.#store = inject(Store);
|
|
6319
|
+
this.videoElement = viewChild('videoPlayerCover', ...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
|
|
6420
6320
|
this.imageIntroSrc = this.#store.selectSignal(unrealFeature.selectImageIntroSrc);
|
|
6421
6321
|
this.videoIntroSrc = this.#store.selectSignal(unrealFeature.selectVideoIntroSrc);
|
|
6422
6322
|
this.viewportReady = this.#store.selectSignal(unrealFeature.selectViewportReady);
|
|
@@ -6440,6 +6340,9 @@ class IntroSrcComponent {
|
|
|
6440
6340
|
});
|
|
6441
6341
|
});
|
|
6442
6342
|
}
|
|
6343
|
+
loadingImageError() {
|
|
6344
|
+
this.#store.dispatch(resetIntroSrc());
|
|
6345
|
+
}
|
|
6443
6346
|
createVideo(src, videoContainer) {
|
|
6444
6347
|
if (typeof src !== 'string') {
|
|
6445
6348
|
return;
|
|
@@ -6470,15 +6373,12 @@ class IntroSrcComponent {
|
|
|
6470
6373
|
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
6471
6374
|
videoContainer.appendChild(videoElement);
|
|
6472
6375
|
}
|
|
6473
|
-
imageError() {
|
|
6474
|
-
this.#store.dispatch(resetIntroSrc());
|
|
6475
|
-
}
|
|
6476
6376
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6477
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"
|
|
6377
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
6478
6378
|
}
|
|
6479
6379
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
6480
6380
|
type: Component,
|
|
6481
|
-
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"
|
|
6381
|
+
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"] }]
|
|
6482
6382
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
6483
6383
|
|
|
6484
6384
|
class UnrealSceneComponent {
|
|
@@ -6498,19 +6398,19 @@ class UnrealSceneComponent {
|
|
|
6498
6398
|
onMouseOut() {
|
|
6499
6399
|
this.changeMouseOverScene.emit(false);
|
|
6500
6400
|
}
|
|
6401
|
+
onContextMenu(event) {
|
|
6402
|
+
event.preventDefault();
|
|
6403
|
+
}
|
|
6501
6404
|
constructor() {
|
|
6502
|
-
this.isStudio = input(false, ...(ngDevMode ? [{ debugName: "isStudio" }] : /* istanbul ignore next */ []));
|
|
6503
6405
|
this.useContainerAsSizeProvider = input(true, ...(ngDevMode ? [{ debugName: "useContainerAsSizeProvider" }] : /* istanbul ignore next */ []));
|
|
6504
|
-
this.
|
|
6406
|
+
this.isStudio = input(false, ...(ngDevMode ? [{ debugName: "isStudio" }] : /* istanbul ignore next */ []));
|
|
6407
|
+
this.resolutionSize = input({
|
|
6505
6408
|
width: FULL_HD_WIDTH,
|
|
6506
6409
|
height: FULL_HD_HEIGHT,
|
|
6507
|
-
}, ...(ngDevMode ? [{ debugName: "
|
|
6508
|
-
this.studioResolutionValues = toObservable(computed(() => {
|
|
6509
|
-
const values = this.studioResolutionSize();
|
|
6510
|
-
return { width: values.width, height: values.height };
|
|
6511
|
-
}));
|
|
6512
|
-
this.videoElement = viewChild('videoContainer', ...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
|
|
6410
|
+
}, ...(ngDevMode ? [{ debugName: "resolutionSize" }] : /* istanbul ignore next */ []));
|
|
6513
6411
|
this.changeMouseOverScene = output();
|
|
6412
|
+
this.videoElement = viewChild('videoContainer', ...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
|
|
6413
|
+
this.resolutionValues$ = toObservable(this.resolutionSize);
|
|
6514
6414
|
this.width = FULL_HD_WIDTH;
|
|
6515
6415
|
this.height = FULL_HD_HEIGHT;
|
|
6516
6416
|
this.actions$ = inject(Actions);
|
|
@@ -6521,38 +6421,34 @@ class UnrealSceneComponent {
|
|
|
6521
6421
|
this.maxResolution = Truthy(new URLSearchParams(location.search).get('maxresolution'));
|
|
6522
6422
|
this.commandsSender = inject(UnrealCommunicatorService);
|
|
6523
6423
|
this.videoService = inject(VideoService);
|
|
6524
|
-
this.element = inject(ElementRef);
|
|
6525
6424
|
this.destroyRef = inject(DestroyRef);
|
|
6526
6425
|
this.destroyRef.onDestroy(() => this.#store.dispatch(destroyUnrealScene()));
|
|
6527
6426
|
effect(() => {
|
|
6528
6427
|
const videoElement = this.videoElement();
|
|
6529
6428
|
const isExistMatchUrls = this.isExistMatchUrls();
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6429
|
+
untracked(() => {
|
|
6430
|
+
if (videoElement && isExistMatchUrls) {
|
|
6431
|
+
this.#store.dispatch(initSignalling());
|
|
6432
|
+
}
|
|
6433
|
+
});
|
|
6533
6434
|
});
|
|
6534
6435
|
afterNextRender({
|
|
6535
6436
|
read: () => {
|
|
6536
6437
|
const videoElement = this.videoElement();
|
|
6537
6438
|
if (videoElement) {
|
|
6538
6439
|
this.videoService.setContainer(videoElement.nativeElement);
|
|
6539
|
-
if (this.element?.nativeElement) {
|
|
6540
|
-
fromEvent(this.element?.nativeElement, 'contextmenu')
|
|
6541
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
6542
|
-
.subscribe((event) => event.preventDefault());
|
|
6543
|
-
}
|
|
6544
6440
|
this.listenResizeValues();
|
|
6545
6441
|
}
|
|
6546
6442
|
},
|
|
6547
6443
|
});
|
|
6548
6444
|
}
|
|
6549
6445
|
listenResizeValues() {
|
|
6550
|
-
const customSizeInputChanged$ = this.
|
|
6446
|
+
const customSizeInputChanged$ = this.resolutionValues$.pipe(filter(({ width, height }) => this.width !== width || this.height !== height), tap(({ width, height }) => {
|
|
6551
6447
|
this.width = width;
|
|
6552
6448
|
this.height = height;
|
|
6553
6449
|
}));
|
|
6554
6450
|
const resizeRequired$ = merge(this.actions$.pipe(ofType(videoStreamInitialized)), fromEvent(window, 'resize'));
|
|
6555
|
-
const videoStreamSizeChanged$ = this.videoService
|
|
6451
|
+
const videoStreamSizeChanged$ = this.videoService.videoStats$.pipe(filter(() => !this.isFreezeFrameLoading()), map$1((stats) => ({
|
|
6556
6452
|
w: stats.aggregatedStats.frameWidth || 0,
|
|
6557
6453
|
h: stats.aggregatedStats.frameHeight || 0,
|
|
6558
6454
|
})), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
|
|
@@ -6560,12 +6456,17 @@ class UnrealSceneComponent {
|
|
|
6560
6456
|
merge(customSizeInputChanged$, resizeRequired$, videoStreamSizeChanged$)
|
|
6561
6457
|
.pipe(debounceTime(DEBOUNCE_TO_MANY_RESIZE_CALLS), switchMap(() => {
|
|
6562
6458
|
const key = Math.random();
|
|
6563
|
-
//
|
|
6459
|
+
// Poll 3 times to capture late-arriving DOM measurements after layout settles
|
|
6564
6460
|
return timer(0, 300).pipe(take(3), map$1(() => key));
|
|
6565
6461
|
}), map$1((key) => ({ key, ...this.resizeValues })), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
|
|
6566
6462
|
fpIsASameAsB(previous.h, current.h, SAME_SIZE_THRESHOLD) &&
|
|
6567
|
-
previous.key === current.key), tap((size) => this.adaptVideo(size)),
|
|
6568
|
-
|
|
6463
|
+
previous.key === current.key), tap((size) => this.adaptVideo(size)),
|
|
6464
|
+
// Key excluded: only dispatch when actual pixel dimensions change
|
|
6465
|
+
distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
|
|
6466
|
+
fpIsASameAsB(previous.h, current.h, SAME_SIZE_THRESHOLD)),
|
|
6467
|
+
// Holds dispatch until data channel is up; retains true after disconnect
|
|
6468
|
+
// so resizes still reach Unreal — cleanup is handled by destroyUnrealScene
|
|
6469
|
+
combineLatestWith(this.#store
|
|
6569
6470
|
.select(unrealFeature.selectDataChannelConnected)
|
|
6570
6471
|
.pipe(filter(Truthy))), takeUntilDestroyed(this.destroyRef))
|
|
6571
6472
|
.subscribe(([size]) => {
|
|
@@ -6593,11 +6494,13 @@ class UnrealSceneComponent {
|
|
|
6593
6494
|
this.#store.dispatch(videoAdaptedToContainer());
|
|
6594
6495
|
}
|
|
6595
6496
|
getResizeValuesUniversal() {
|
|
6596
|
-
let containerWidth = window.innerWidth ||
|
|
6597
|
-
let containerHeight = window.innerHeight ||
|
|
6497
|
+
let containerWidth = window.innerWidth || MIN_CONTAINER_SIZE;
|
|
6498
|
+
let containerHeight = window.innerHeight || MIN_CONTAINER_SIZE;
|
|
6598
6499
|
if (this.useContainerAsSizeProvider()) {
|
|
6599
|
-
containerWidth =
|
|
6600
|
-
|
|
6500
|
+
containerWidth =
|
|
6501
|
+
this.videoElement()?.nativeElement.offsetWidth || MIN_CONTAINER_SIZE;
|
|
6502
|
+
containerHeight =
|
|
6503
|
+
this.videoElement()?.nativeElement.offsetHeight || MIN_CONTAINER_SIZE;
|
|
6601
6504
|
}
|
|
6602
6505
|
const pixelRatio = this.pixelRatio;
|
|
6603
6506
|
return getResizeValuesUniversal({
|
|
@@ -6611,8 +6514,8 @@ class UnrealSceneComponent {
|
|
|
6611
6514
|
const videoElement = this.videoElement()?.nativeElement;
|
|
6612
6515
|
return getResizeStudioValues({
|
|
6613
6516
|
pixelRatio: this.pixelRatio,
|
|
6614
|
-
containerWidth: videoElement?.offsetWidth ||
|
|
6615
|
-
containerHeight: videoElement?.offsetHeight ||
|
|
6517
|
+
containerWidth: videoElement?.offsetWidth || MIN_CONTAINER_SIZE,
|
|
6518
|
+
containerHeight: videoElement?.offsetHeight || MIN_CONTAINER_SIZE,
|
|
6616
6519
|
studioWidth: this.width,
|
|
6617
6520
|
studioHeight: this.height,
|
|
6618
6521
|
maxResolution: this.maxResolution,
|
|
@@ -6630,7 +6533,7 @@ class UnrealSceneComponent {
|
|
|
6630
6533
|
});
|
|
6631
6534
|
}
|
|
6632
6535
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6633
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", 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 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\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 }); }
|
|
6536
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer 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\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 }); }
|
|
6634
6537
|
}
|
|
6635
6538
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
6636
6539
|
type: Component,
|
|
@@ -6643,12 +6546,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
6643
6546
|
ImageLoadingSrcComponent,
|
|
6644
6547
|
IntroSrcComponent,
|
|
6645
6548
|
], template: "<div class=\"frame unreal-container\">\n <div #videoContainer 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\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"] }]
|
|
6646
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
6549
|
+
}], ctorParameters: () => [], propDecorators: { useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], resolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutionSize", required: false }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], onMouseOver: [{
|
|
6647
6550
|
type: HostListener,
|
|
6648
6551
|
args: ['mouseover']
|
|
6649
6552
|
}], onMouseOut: [{
|
|
6650
6553
|
type: HostListener,
|
|
6651
6554
|
args: ['mouseout']
|
|
6555
|
+
}], onContextMenu: [{
|
|
6556
|
+
type: HostListener,
|
|
6557
|
+
args: ['contextmenu', ['$event']]
|
|
6652
6558
|
}] } });
|
|
6653
6559
|
|
|
6654
6560
|
class WebrtcErrorModalComponent {
|
|
@@ -6659,9 +6565,6 @@ class WebrtcErrorModalComponent {
|
|
|
6659
6565
|
}
|
|
6660
6566
|
#dialogRef;
|
|
6661
6567
|
#store;
|
|
6662
|
-
close() {
|
|
6663
|
-
this.#dialogRef.close();
|
|
6664
|
-
}
|
|
6665
6568
|
closeModalWithCirrusDisconnect() {
|
|
6666
6569
|
if (!this.isCirrusConnected()) {
|
|
6667
6570
|
this.#store.dispatch(disconnectStream({
|
|
@@ -6671,6 +6574,9 @@ class WebrtcErrorModalComponent {
|
|
|
6671
6574
|
}
|
|
6672
6575
|
this.close();
|
|
6673
6576
|
}
|
|
6577
|
+
close() {
|
|
6578
|
+
this.#dialogRef.close();
|
|
6579
|
+
}
|
|
6674
6580
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6675
6581
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", 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 }); }
|
|
6676
6582
|
}
|
|
@@ -6727,12 +6633,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
6727
6633
|
|
|
6728
6634
|
class LowBandwidthDetectorComponent {
|
|
6729
6635
|
constructor() {
|
|
6730
|
-
this
|
|
6636
|
+
this.#store = inject(Store);
|
|
6731
6637
|
this.dialog = inject(Dialog);
|
|
6732
6638
|
this.destroyRef = inject(DestroyRef);
|
|
6733
6639
|
this.videoService = inject(VideoService);
|
|
6734
6640
|
this.isDevMode = inject(DevModeService).isDevMode;
|
|
6735
|
-
this.viewportReady$ = this
|
|
6641
|
+
this.viewportReady$ = this.#store.select(unrealFeature.selectViewportReady);
|
|
6736
6642
|
this.isLowBandwidth$ = of(true);
|
|
6737
6643
|
this.lowBandwidthTrigger$ = this.isLowBandwidth$.pipe(distinctUntilChanged$1(), filter(Truthy));
|
|
6738
6644
|
this.highBandwidthTrigger$ = this.isLowBandwidth$.pipe(distinctUntilChanged$1(), filter(Falsy));
|
|
@@ -6755,6 +6661,7 @@ class LowBandwidthDetectorComponent {
|
|
|
6755
6661
|
this.isIndicatorExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isIndicatorExpanded" }] : /* istanbul ignore next */ []));
|
|
6756
6662
|
this.isIndicatorExpandedTrigger$ = toObservable(this.isIndicatorExpanded).pipe(skip(1), distinctUntilChanged$1(), filter(Falsy));
|
|
6757
6663
|
}
|
|
6664
|
+
#store;
|
|
6758
6665
|
ngOnInit() {
|
|
6759
6666
|
this.lowBandwidthTrigger$
|
|
6760
6667
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
@@ -6853,6 +6760,7 @@ function provideUnrealModule() {
|
|
|
6853
6760
|
StreamStatusTelemetryService2,
|
|
6854
6761
|
FpsMonitorService,
|
|
6855
6762
|
WebRtcPlayerService,
|
|
6763
|
+
LoadingProgressService,
|
|
6856
6764
|
provideEnvironmentInitializer(() => {
|
|
6857
6765
|
inject(AggregatorService);
|
|
6858
6766
|
inject(InputService);
|
|
@@ -6871,5 +6779,5 @@ function provideUnrealModule() {
|
|
|
6871
6779
|
* Generated bundle index. Do not edit.
|
|
6872
6780
|
*/
|
|
6873
6781
|
|
|
6874
|
-
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, DESTROY_DISCONNECT_REASONS, 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, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, changeStreamResolutionSuccessAction, commandCompleted, commandStarted, commandsFeature, commandsReducer, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues,
|
|
6782
|
+
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, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, 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_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, changeStreamResolutionSuccessAction, commandCompleted, commandStarted, commandsFeature, commandsReducer, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectCommandsInProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, smoothTransition, startStream, trackMixpanelEvent, trackTelemetryData, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
6875
6783
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|