@raydiant/playlist-window-manager 0.29.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/IFrameRenderer.d.ts +1 -0
- package/build/IFrameRenderer.js +14 -0
- package/build/IFrameRenderer.test.d.ts +1 -0
- package/build/IFrameRenderer.test.js +70 -0
- package/build/PlaylistWindowManager.d.ts +7 -0
- package/build/PlaylistWindowManager.js +186 -65
- package/build/PlaylistWindowManager.test.d.ts +1 -0
- package/build/PlaylistWindowManager.test.js +1763 -0
- package/build/PresentationWindow.d.ts +37 -1
- package/build/PresentationWindow.js +601 -31
- package/build/PresentationWindow.test.js +509 -0
- package/build/SurfaceBroker.d.ts +30 -0
- package/build/SurfaceBroker.js +311 -0
- package/build/SurfaceBroker.test.d.ts +1 -0
- package/build/SurfaceBroker.test.js +432 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/surfaces.d.ts +52 -0
- package/build/surfaces.js +15 -0
- package/build/testUtils.d.ts +56 -0
- package/build/testUtils.js +327 -5
- package/build/types.d.ts +1 -0
- package/package.json +2 -1
- package/src/IFrameRenderer.test.ts +88 -0
- package/src/IFrameRenderer.ts +21 -0
- package/src/PlaylistWindowManager.test.ts +1466 -0
- package/src/PlaylistWindowManager.ts +164 -20
- package/src/PresentationWindow.test.ts +371 -0
- package/src/PresentationWindow.ts +712 -4
- package/src/SurfaceBroker.test.ts +278 -0
- package/src/SurfaceBroker.ts +281 -0
- package/src/__snapshots__/PlaylistWindowManager.test.ts.snap +26 -0
- package/src/index.ts +1 -0
- package/src/surfaces.ts +82 -0
- package/src/testUtils.ts +335 -1
- package/src/types.ts +5 -0
|
@@ -14,6 +14,7 @@ export default class IFrameRenderer implements PresentationWindowRenderer {
|
|
|
14
14
|
sendMessageObject(windowId: string, type: string, payload?: any): void;
|
|
15
15
|
muteWindow(windowId: string): void;
|
|
16
16
|
unMuteWindow(windowId: string): void;
|
|
17
|
+
setWindowBackground(windowId: string, color: string): void;
|
|
17
18
|
destroy(): void;
|
|
18
19
|
private getWindow;
|
|
19
20
|
private globalMessageHandler;
|
package/build/IFrameRenderer.js
CHANGED
|
@@ -36,6 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
var surfaces_1 = require("./surfaces");
|
|
39
40
|
var namespace = 'raydiant';
|
|
40
41
|
var IFrameRenderer = /** @class */ (function () {
|
|
41
42
|
function IFrameRenderer(container) {
|
|
@@ -55,6 +56,12 @@ var IFrameRenderer = /** @class */ (function () {
|
|
|
55
56
|
if (!window_1) {
|
|
56
57
|
throw new Error("Failed add receive message callback to window, window with window id: '".concat(windowId, "' was not found"));
|
|
57
58
|
}
|
|
59
|
+
// A surface costs a hardware decoder, so only the window's own frame may
|
|
60
|
+
// ask for one; any frame can post here and name any window.
|
|
61
|
+
if (surfaces_1.VIDEO_REQUESTS.indexOf(type) !== -1 &&
|
|
62
|
+
event.source !== window_1.frame.contentWindow) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
58
65
|
if (window_1.receiveMessageCallback) {
|
|
59
66
|
window_1.receiveMessageCallback(type, payload);
|
|
60
67
|
}
|
|
@@ -218,6 +225,13 @@ var IFrameRenderer = /** @class */ (function () {
|
|
|
218
225
|
// There is no mute/unmute API for iframes so we rely on the window manager overriding any
|
|
219
226
|
// mute presentation properties.
|
|
220
227
|
};
|
|
228
|
+
IFrameRenderer.prototype.setWindowBackground = function (windowId, color) {
|
|
229
|
+
var window = this.getWindow(windowId);
|
|
230
|
+
if (!window) {
|
|
231
|
+
throw new Error("Failed to set window background, missing window id '".concat(windowId, "'"));
|
|
232
|
+
}
|
|
233
|
+
window.frame.style.backgroundColor = color;
|
|
234
|
+
};
|
|
221
235
|
IFrameRenderer.prototype.destroy = function () {
|
|
222
236
|
window.removeEventListener('message', this.globalMessageHandler, false);
|
|
223
237
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var IFrameRenderer_1 = __importDefault(require("./IFrameRenderer"));
|
|
7
|
+
function setup() {
|
|
8
|
+
var container = document.createElement('div');
|
|
9
|
+
document.body.appendChild(container);
|
|
10
|
+
var renderer = new IFrameRenderer_1.default(container);
|
|
11
|
+
var received = [];
|
|
12
|
+
renderer.createWindow({
|
|
13
|
+
windowId: 'w1',
|
|
14
|
+
backgroundColor: '#000000',
|
|
15
|
+
receiveMessageCallback: function (type, payload) { return received.push([type, payload]); },
|
|
16
|
+
errorCallback: function () { return undefined; },
|
|
17
|
+
});
|
|
18
|
+
var frame = container.querySelector('iframe');
|
|
19
|
+
var post = function (type, source) {
|
|
20
|
+
window.dispatchEvent(new MessageEvent('message', {
|
|
21
|
+
data: "raydiant:".concat(JSON.stringify({ windowId: 'w1', type: type })),
|
|
22
|
+
source: source,
|
|
23
|
+
}));
|
|
24
|
+
};
|
|
25
|
+
var teardown = function () {
|
|
26
|
+
renderer.destroy();
|
|
27
|
+
document.body.removeChild(container);
|
|
28
|
+
};
|
|
29
|
+
return { renderer: renderer, frame: frame, received: received, post: post, teardown: teardown };
|
|
30
|
+
}
|
|
31
|
+
describe('only the window’s own frame asks for a video surface', function () {
|
|
32
|
+
test.each(['open_video', 'video_bounds', 'video_hole_open', 'close_video'])("%s from another frame's source is dropped", function (type) {
|
|
33
|
+
var _a = setup(), frame = _a.frame, received = _a.received, post = _a.post, teardown = _a.teardown;
|
|
34
|
+
var other = document.createElement('iframe');
|
|
35
|
+
document.body.appendChild(other);
|
|
36
|
+
post(type, other.contentWindow);
|
|
37
|
+
expect(received).toEqual([]);
|
|
38
|
+
post(type, frame.contentWindow);
|
|
39
|
+
expect(received).toEqual([[type, undefined]]);
|
|
40
|
+
document.body.removeChild(other);
|
|
41
|
+
teardown();
|
|
42
|
+
});
|
|
43
|
+
test("every other message keeps today's routing by window id", function () {
|
|
44
|
+
var _a = setup(), received = _a.received, post = _a.post, teardown = _a.teardown;
|
|
45
|
+
post('presentation_ready', null);
|
|
46
|
+
expect(received).toEqual([['presentation_ready', undefined]]);
|
|
47
|
+
teardown();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('the frame background', function () {
|
|
51
|
+
test('setWindowBackground sets the frame’s inline background', function () {
|
|
52
|
+
var _a = setup(), renderer = _a.renderer, frame = _a.frame, teardown = _a.teardown;
|
|
53
|
+
expect(frame.style.backgroundColor).toBe('rgb(0, 0, 0)');
|
|
54
|
+
renderer.setWindowBackground('w1', 'transparent');
|
|
55
|
+
expect(frame.style.backgroundColor).toBe('transparent');
|
|
56
|
+
renderer.setWindowBackground('w1', '#000000');
|
|
57
|
+
expect(frame.style.backgroundColor).toBe('rgb(0, 0, 0)');
|
|
58
|
+
teardown();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('no colour scheme', function () {
|
|
62
|
+
test('a created frame declares no color-scheme', function () {
|
|
63
|
+
var _a = setup(), frame = _a.frame, renderer = _a.renderer, teardown = _a.teardown;
|
|
64
|
+
renderer.showWindow('w1', false);
|
|
65
|
+
renderer.setWindowBackground('w1', 'transparent');
|
|
66
|
+
expect(frame.style.getPropertyValue('color-scheme')).toBe('');
|
|
67
|
+
expect(frame.getAttribute('style')).not.toMatch(/color-scheme/);
|
|
68
|
+
teardown();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -2,6 +2,7 @@ import * as RE from '@raydiant/playlist-rule-engine';
|
|
|
2
2
|
import EventEmitter from 'eventemitter3';
|
|
3
3
|
import { PresentationWindowRenderer, Device, WindowBounds, Theme, Logger, WorkerState, Charge, ChargeResponse, Terminal } from './types';
|
|
4
4
|
import PlaylistWindowManagerState from './PlaylistWindowManagerState';
|
|
5
|
+
import { SurfaceHost } from './surfaces';
|
|
5
6
|
export interface PlaylistWindowManagerOptions {
|
|
6
7
|
ruleEngine: RE.RuleEngine;
|
|
7
8
|
state: PlaylistWindowManagerState;
|
|
@@ -22,6 +23,7 @@ export interface PlaylistWindowManagerOptions {
|
|
|
22
23
|
onDisableInterruptLock?: () => void;
|
|
23
24
|
getTerminal?: () => Terminal | null;
|
|
24
25
|
getOnlineStatus?: () => boolean;
|
|
26
|
+
surfaces?: SurfaceHost;
|
|
25
27
|
}
|
|
26
28
|
export default class PlaylistWindowManager extends EventEmitter {
|
|
27
29
|
private options;
|
|
@@ -45,6 +47,8 @@ export default class PlaylistWindowManager extends EventEmitter {
|
|
|
45
47
|
private forceMute;
|
|
46
48
|
private isFocused;
|
|
47
49
|
private workerState;
|
|
50
|
+
private surfaceBroker;
|
|
51
|
+
private pendingPreload;
|
|
48
52
|
constructor(options: PlaylistWindowManagerOptions);
|
|
49
53
|
private currentPresentationId;
|
|
50
54
|
private nextPresentationId;
|
|
@@ -84,6 +88,8 @@ export default class PlaylistWindowManager extends EventEmitter {
|
|
|
84
88
|
sendTerminal(terminal: Terminal | null): void;
|
|
85
89
|
sendOnlineStatus(isOnline: boolean): void;
|
|
86
90
|
private createWindow;
|
|
91
|
+
private showAfterRevealMs;
|
|
92
|
+
private surfaceSwapDelayMs;
|
|
87
93
|
private loadCurrentWindow;
|
|
88
94
|
private shouldPreload;
|
|
89
95
|
private preloadNextWindow;
|
|
@@ -94,6 +100,7 @@ export default class PlaylistWindowManager extends EventEmitter {
|
|
|
94
100
|
private removeCurrentWindow;
|
|
95
101
|
private removeNextWindow;
|
|
96
102
|
private swapWindows;
|
|
103
|
+
private swapWithSurfaces;
|
|
97
104
|
private evalRuleEngine;
|
|
98
105
|
private handleEnableInterruptLock;
|
|
99
106
|
private handleDisableInterruptLock;
|
|
@@ -25,6 +25,29 @@ var __assign = (this && this.__assign) || function () {
|
|
|
25
25
|
};
|
|
26
26
|
return __assign.apply(this, arguments);
|
|
27
27
|
};
|
|
28
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
29
|
+
if (k2 === undefined) k2 = k;
|
|
30
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
31
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
32
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
33
|
+
}
|
|
34
|
+
Object.defineProperty(o, k2, desc);
|
|
35
|
+
}) : (function(o, m, k, k2) {
|
|
36
|
+
if (k2 === undefined) k2 = k;
|
|
37
|
+
o[k2] = m[k];
|
|
38
|
+
}));
|
|
39
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
40
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
41
|
+
}) : function(o, v) {
|
|
42
|
+
o["default"] = v;
|
|
43
|
+
});
|
|
44
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
28
51
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
29
52
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
30
53
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -71,6 +94,7 @@ var PresentationWindow_1 = __importDefault(require("./PresentationWindow"));
|
|
|
71
94
|
var WindowUnresponsiveError_1 = __importDefault(require("./WindowUnresponsiveError"));
|
|
72
95
|
var WindowTimeoutError_1 = __importDefault(require("./WindowTimeoutError"));
|
|
73
96
|
var WindowLoadError_1 = __importDefault(require("./WindowLoadError"));
|
|
97
|
+
var SurfaceBroker_1 = __importStar(require("./SurfaceBroker"));
|
|
74
98
|
// Wait at least 3 seconds before restarting or moving onto the next window
|
|
75
99
|
// to prevent log spam causing devices to become unresponsive.
|
|
76
100
|
var minTimeBetweenCompletes = 3000;
|
|
@@ -97,6 +121,10 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
97
121
|
_this.forceMute = false;
|
|
98
122
|
_this.isFocused = false;
|
|
99
123
|
_this.workerState = {};
|
|
124
|
+
_this.surfaceBroker = null;
|
|
125
|
+
// The surface swap the next window's preload waits to finish. A newer
|
|
126
|
+
// preload or the next window's removal clears it, cancelling that preload.
|
|
127
|
+
_this.pendingPreload = null;
|
|
100
128
|
_this.handleEnableInterruptLock = function () {
|
|
101
129
|
var onEnableInterruptLock = _this.options.onEnableInterruptLock;
|
|
102
130
|
if (onEnableInterruptLock) {
|
|
@@ -164,6 +192,12 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
164
192
|
}
|
|
165
193
|
// Clear current window error flag.
|
|
166
194
|
this.currentWindowError = null;
|
|
195
|
+
// A complete while the next window's preload waits for its surface swap
|
|
196
|
+
// preloads it now, and the current window restarts while it loads, as
|
|
197
|
+
// for any next window not yet ready.
|
|
198
|
+
if (this.pendingPreload && this.nextPresentation) {
|
|
199
|
+
this.preloadNextWindow();
|
|
200
|
+
}
|
|
167
201
|
if (!(!this.isLocked() &&
|
|
168
202
|
!this.restartCurrentWindowOnEnd &&
|
|
169
203
|
this.currentWindow &&
|
|
@@ -318,6 +352,9 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
318
352
|
_this.bounds = options.bounds;
|
|
319
353
|
_this.themeOverride = options.themeOverride;
|
|
320
354
|
_this.forceMute = options.forceMute || false;
|
|
355
|
+
if (options.surfaces) {
|
|
356
|
+
_this.surfaceBroker = new SurfaceBroker_1.default(options.surfaces, options.logger);
|
|
357
|
+
}
|
|
321
358
|
return _this;
|
|
322
359
|
}
|
|
323
360
|
PlaylistWindowManager.prototype.currentPresentationId = function () {
|
|
@@ -546,7 +583,14 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
546
583
|
return [4 /*yield*/, Promise.all([this.removeCurrentWindow(), this.removeNextWindow()])];
|
|
547
584
|
case 1:
|
|
548
585
|
_a.sent();
|
|
549
|
-
return [
|
|
586
|
+
if (!this.surfaceBroker) return [3 /*break*/, 3];
|
|
587
|
+
// Also closes a surface whose window is still leaving a swap.
|
|
588
|
+
return [4 /*yield*/, this.surfaceBroker.closeAll()];
|
|
589
|
+
case 2:
|
|
590
|
+
// Also closes a surface whose window is still leaving a swap.
|
|
591
|
+
_a.sent();
|
|
592
|
+
_a.label = 3;
|
|
593
|
+
case 3: return [2 /*return*/];
|
|
550
594
|
}
|
|
551
595
|
});
|
|
552
596
|
});
|
|
@@ -702,35 +746,24 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
702
746
|
var presentation = this.state.getPresentation(presentationId);
|
|
703
747
|
var applicationVersion = this.state.getApplicationVersion(presentation.applicationDeploymentId);
|
|
704
748
|
var windowId = (0, uuid_1.v4)();
|
|
705
|
-
return new PresentationWindow_1.default({
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
appRendererOfflineSupport: appRendererOfflineSupport,
|
|
724
|
-
bounds: this.bounds,
|
|
725
|
-
backgroundColor: backgroundColor,
|
|
726
|
-
playlistWindowManagerState: this.state,
|
|
727
|
-
ruleEngineState: this.ruleEngine.state,
|
|
728
|
-
globalRule: this.ruleEngine.globalRule,
|
|
729
|
-
isPreview: isPreview,
|
|
730
|
-
workerState: this.workerState,
|
|
731
|
-
getTerminal: this.options.getTerminal,
|
|
732
|
-
getOnlineStatus: this.options.getOnlineStatus,
|
|
733
|
-
});
|
|
749
|
+
return new PresentationWindow_1.default(__assign({ windowManager: this, renderer: this.renderer, logger: logger, windowId: windowId, windowName: windowName, parentWindowId: parentWindowId, presentation: presentation, applicationVersion: applicationVersion, device: device, playlistId: pr.playlistId, playlistName: this.ruleEngine.state.playlist(pr.playlistId).name, rule: pr.rule, publishedAt: this.state.getPublishedAt(), theme: this.getTheme(presentationId), forceMute: this.forceMute, readyTimeoutDurationSeconds: readyTimeoutDurationSeconds, appRendererUrl: appRendererUrl, appRendererOfflineSupport: appRendererOfflineSupport, bounds: this.bounds, backgroundColor: backgroundColor, playlistWindowManagerState: this.state, ruleEngineState: this.ruleEngine.state, globalRule: this.ruleEngine.globalRule, isPreview: isPreview, workerState: this.workerState, getTerminal: this.options.getTerminal, getOnlineStatus: this.options.getOnlineStatus }, (this.surfaceBroker
|
|
750
|
+
? {
|
|
751
|
+
surfaceBroker: this.surfaceBroker,
|
|
752
|
+
surfaceShowDeadlineMs: this.surfaceSwapDelayMs(),
|
|
753
|
+
}
|
|
754
|
+
: {})));
|
|
755
|
+
};
|
|
756
|
+
PlaylistWindowManager.prototype.showAfterRevealMs = function () {
|
|
757
|
+
var surfaces = this.options.surfaces;
|
|
758
|
+
return surfaces && surfaces.showAfterRevealMs !== undefined
|
|
759
|
+
? surfaces.showAfterRevealMs
|
|
760
|
+
: SurfaceBroker_1.DEFAULT_SHOW_AFTER_REVEAL_MS;
|
|
761
|
+
};
|
|
762
|
+
PlaylistWindowManager.prototype.surfaceSwapDelayMs = function () {
|
|
763
|
+
var closeWindowDelayMs = this.options.closeWindowDelayMs;
|
|
764
|
+
return closeWindowDelayMs !== undefined
|
|
765
|
+
? closeWindowDelayMs
|
|
766
|
+
: SurfaceBroker_1.DEFAULT_SURFACE_SWAP_DELAY_MS;
|
|
734
767
|
};
|
|
735
768
|
PlaylistWindowManager.prototype.loadCurrentWindow = function () {
|
|
736
769
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -784,6 +817,9 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
784
817
|
switch (_a.label) {
|
|
785
818
|
case 0:
|
|
786
819
|
logger = this.options.logger;
|
|
820
|
+
// A publish, a preview change or a complete preloads now, in place of a
|
|
821
|
+
// preload still waiting for its surface swap.
|
|
822
|
+
this.pendingPreload = null;
|
|
787
823
|
if (!this.nextPresentation) {
|
|
788
824
|
logger.warn("Attempted to preload next window but nextPresentation not set");
|
|
789
825
|
return [2 /*return*/];
|
|
@@ -889,6 +925,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
889
925
|
return __generator(this, function (_a) {
|
|
890
926
|
switch (_a.label) {
|
|
891
927
|
case 0:
|
|
928
|
+
this.pendingPreload = null;
|
|
892
929
|
if (!this.nextWindow) return [3 /*break*/, 2];
|
|
893
930
|
return [4 /*yield*/, this.nextWindow.remove()];
|
|
894
931
|
case 1:
|
|
@@ -904,7 +941,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
904
941
|
};
|
|
905
942
|
PlaylistWindowManager.prototype.swapWindows = function () {
|
|
906
943
|
return __awaiter(this, void 0, void 0, function () {
|
|
907
|
-
var nextPreviewPresentationId, preview, result, nextPresentation, shouldPreload, closeWindowPromise;
|
|
944
|
+
var nextPreviewPresentationId, preview, result, nextPresentation, shouldPreload, isSurfaceSwap, closeWindowPromise, windowToClose_1, incomingWindow_1, closeWindowDelayMs_1, preloadAfterSwap;
|
|
908
945
|
var _this = this;
|
|
909
946
|
return __generator(this, function (_a) {
|
|
910
947
|
switch (_a.label) {
|
|
@@ -935,40 +972,56 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
935
972
|
}
|
|
936
973
|
// Clear the pending interrupt whenever we swap the current window for the next one.
|
|
937
974
|
this.hasPendingInterrupt = false;
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
if (
|
|
975
|
+
isSurfaceSwap = !!this.surfaceBroker &&
|
|
976
|
+
((!!this.currentWindow && this.currentWindow.holdsSurface()) ||
|
|
977
|
+
(!!this.nextWindow && this.nextWindow.holdsSurface()));
|
|
978
|
+
if (isSurfaceSwap) {
|
|
979
|
+
closeWindowPromise = this.swapWithSurfaces(this.currentWindow, this.nextWindow);
|
|
980
|
+
}
|
|
981
|
+
else if (this.nextWindow) {
|
|
982
|
+
// Next window is ready, show the next one, hide the current window, and
|
|
983
|
+
// then remove the current window. Show the next window before hiding the
|
|
984
|
+
// current to avoid flashes when rendering with BrowserWindows on device.
|
|
942
985
|
this.nextWindow.show(this.isFocused);
|
|
943
986
|
}
|
|
944
|
-
if (!this.currentWindow) return [3 /*break*/, 3];
|
|
987
|
+
if (!(!isSurfaceSwap && this.currentWindow)) return [3 /*break*/, 3];
|
|
945
988
|
if (!(this.options.closeWindowDelayMs !== undefined)) return [3 /*break*/, 1];
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
989
|
+
windowToClose_1 = this.currentWindow;
|
|
990
|
+
incomingWindow_1 = this.nextWindow;
|
|
991
|
+
closeWindowDelayMs_1 = this.options.closeWindowDelayMs;
|
|
992
|
+
// The outgoing window stays on screen only as a visual backdrop from
|
|
993
|
+
// here on: stop delivering its events (a late complete or error must
|
|
994
|
+
// not end the incoming presentation) and mute it so audio does not
|
|
995
|
+
// bleed into the incoming presentation during the overlap.
|
|
996
|
+
windowToClose_1.detachCallbacks();
|
|
997
|
+
windowToClose_1.mute();
|
|
998
|
+
closeWindowPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
999
|
+
return __generator(this, function (_a) {
|
|
1000
|
+
switch (_a.label) {
|
|
1001
|
+
case 0:
|
|
1002
|
+
if (!incomingWindow_1) return [3 /*break*/, 2];
|
|
1003
|
+
return [4 /*yield*/, incomingWindow_1.waitForFirstPaint(closeWindowDelayMs_1)];
|
|
1004
|
+
case 1:
|
|
1005
|
+
_a.sent();
|
|
1006
|
+
return [3 /*break*/, 4];
|
|
1007
|
+
case 2: return [4 /*yield*/, new Promise(function (resolve) {
|
|
1008
|
+
return setTimeout(resolve, closeWindowDelayMs_1);
|
|
1009
|
+
})];
|
|
1010
|
+
case 3:
|
|
1011
|
+
_a.sent();
|
|
1012
|
+
_a.label = 4;
|
|
1013
|
+
case 4:
|
|
1014
|
+
// We can't use this.removeCurrentWindow because the currentWindow
|
|
1015
|
+
// reference has already changed by the time the wait finishes.
|
|
1016
|
+
return [4 /*yield*/, windowToClose_1.remove()];
|
|
1017
|
+
case 5:
|
|
1018
|
+
// We can't use this.removeCurrentWindow because the currentWindow
|
|
1019
|
+
// reference has already changed by the time the wait finishes.
|
|
1020
|
+
_a.sent();
|
|
1021
|
+
return [2 /*return*/];
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
}); })();
|
|
972
1025
|
return [3 /*break*/, 3];
|
|
973
1026
|
case 1:
|
|
974
1027
|
this.currentWindow.hide();
|
|
@@ -994,8 +1047,17 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
994
1047
|
}
|
|
995
1048
|
// Play new current window.
|
|
996
1049
|
this.playCurrentWindow();
|
|
997
|
-
|
|
998
|
-
if (shouldPreload) {
|
|
1050
|
+
preloadAfterSwap = null;
|
|
1051
|
+
if (shouldPreload && isSurfaceSwap) {
|
|
1052
|
+
// Once the swap has finished, so the next surface's decoder does not
|
|
1053
|
+
// start during it: on the Stick a preload started in the swap held the
|
|
1054
|
+
// outgoing clip's last frame for about 70 ms. The next window is the
|
|
1055
|
+
// current one now.
|
|
1056
|
+
this.nextWindow = null;
|
|
1057
|
+
preloadAfterSwap = closeWindowPromise;
|
|
1058
|
+
this.pendingPreload = preloadAfterSwap;
|
|
1059
|
+
}
|
|
1060
|
+
else if (shouldPreload) {
|
|
999
1061
|
this.preloadNextWindow();
|
|
1000
1062
|
}
|
|
1001
1063
|
else {
|
|
@@ -1009,11 +1071,70 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
1009
1071
|
case 4:
|
|
1010
1072
|
_a.sent();
|
|
1011
1073
|
_a.label = 5;
|
|
1012
|
-
case 5:
|
|
1074
|
+
case 5:
|
|
1075
|
+
if (preloadAfterSwap && this.pendingPreload === preloadAfterSwap) {
|
|
1076
|
+
this.preloadNextWindow();
|
|
1077
|
+
}
|
|
1078
|
+
return [2 /*return*/];
|
|
1013
1079
|
}
|
|
1014
1080
|
});
|
|
1015
1081
|
});
|
|
1016
1082
|
};
|
|
1083
|
+
// The swap when either window holds a video surface. The outgoing surface
|
|
1084
|
+
// is muted and marked leaving here, in the swap's own task; the rest runs
|
|
1085
|
+
// on the two windows held here, so a publish, a preview check or a preload
|
|
1086
|
+
// error during its waits acts on the new next window, never these two.
|
|
1087
|
+
PlaylistWindowManager.prototype.swapWithSurfaces = function (outgoing, incoming) {
|
|
1088
|
+
var _this = this;
|
|
1089
|
+
var delayMs = this.surfaceSwapDelayMs();
|
|
1090
|
+
if (outgoing) {
|
|
1091
|
+
// A late complete or error from the outgoing window must not end the
|
|
1092
|
+
// incoming presentation, and two surfaces never sound at once.
|
|
1093
|
+
outgoing.detachCallbacks();
|
|
1094
|
+
outgoing.muteSurfaceOrFrame();
|
|
1095
|
+
}
|
|
1096
|
+
return (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1097
|
+
var isOutgoingHidden;
|
|
1098
|
+
return __generator(this, function (_a) {
|
|
1099
|
+
switch (_a.label) {
|
|
1100
|
+
case 0:
|
|
1101
|
+
isOutgoingHidden = false;
|
|
1102
|
+
if (!incoming) return [3 /*break*/, 3];
|
|
1103
|
+
// The new is shown before the old is hidden: an incoming surface's
|
|
1104
|
+
// frame is revealed over its open hole and the outgoing frame hidden
|
|
1105
|
+
// in that same task, so neither the outgoing paint-over nor its theme
|
|
1106
|
+
// shows through the incoming hole.
|
|
1107
|
+
return [4 /*yield*/, incoming.show(this.isFocused, function () {
|
|
1108
|
+
if (outgoing) {
|
|
1109
|
+
outgoing.hide();
|
|
1110
|
+
isOutgoingHidden = true;
|
|
1111
|
+
}
|
|
1112
|
+
}, this.showAfterRevealMs())];
|
|
1113
|
+
case 1:
|
|
1114
|
+
// The new is shown before the old is hidden: an incoming surface's
|
|
1115
|
+
// frame is revealed over its open hole and the outgoing frame hidden
|
|
1116
|
+
// in that same task, so neither the outgoing paint-over nor its theme
|
|
1117
|
+
// shows through the incoming hole.
|
|
1118
|
+
_a.sent();
|
|
1119
|
+
if (!(outgoing && !incoming.wasRemoved())) return [3 /*break*/, 3];
|
|
1120
|
+
return [4 /*yield*/, incoming.waitForFirstPaint(delayMs)];
|
|
1121
|
+
case 2:
|
|
1122
|
+
_a.sent();
|
|
1123
|
+
_a.label = 3;
|
|
1124
|
+
case 3:
|
|
1125
|
+
if (!outgoing) return [3 /*break*/, 5];
|
|
1126
|
+
if (!isOutgoingHidden) {
|
|
1127
|
+
outgoing.hide();
|
|
1128
|
+
}
|
|
1129
|
+
return [4 /*yield*/, outgoing.remove()];
|
|
1130
|
+
case 4:
|
|
1131
|
+
_a.sent();
|
|
1132
|
+
_a.label = 5;
|
|
1133
|
+
case 5: return [2 /*return*/];
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}); })();
|
|
1137
|
+
};
|
|
1017
1138
|
PlaylistWindowManager.prototype.evalRuleEngine = function (warnIfPreloadMismatch) {
|
|
1018
1139
|
if (warnIfPreloadMismatch === void 0) { warnIfPreloadMismatch = true; }
|
|
1019
1140
|
var logger = this.options.logger;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|