@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.
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.SurfaceRefusal = exports.DEFAULT_SHOW_AFTER_REVEAL_MS = exports.DEFAULT_SURFACE_SWAP_DELAY_MS = exports.MAX_LIVE_SURFACES = exports.SURFACE_FIRST_FRAME_DEADLINE_MS = exports.SURFACE_OPEN_DEADLINE_MS = void 0;
55
+ // How long the host's openVideo may take to resolve.
56
+ exports.SURFACE_OPEN_DEADLINE_MS = 2000;
57
+ // From openVideo resolving to first_frame. Inside the 30-second ready timeout,
58
+ // with time left for the app to fall back to <video> and still be ready.
59
+ exports.SURFACE_FIRST_FRAME_DEADLINE_MS = 10000;
60
+ // One playing and one prepared.
61
+ exports.MAX_LIVE_SURFACES = 2;
62
+ // How long a surface swap waits for the incoming window's first paint, and
63
+ // how long showing a surface may take, when closeWindowDelayMs is not set:
64
+ // 1000 ms, the closeWindowDelayMs the player passes.
65
+ exports.DEFAULT_SURFACE_SWAP_DELAY_MS = 1000;
66
+ // SurfaceHost.showAfterRevealMs when the player sets none. On the Signage
67
+ // Stick (Fire OS 8.4, Amazon WebView 136, portrait) the WebView takes about
68
+ // 80-120 ms longer than a surface to put a reveal on screen: 60 ms left the
69
+ // theme trailing the picture by up to 35 ms, and 100 ms put it ahead by up
70
+ // to 54 ms.
71
+ exports.DEFAULT_SHOW_AFTER_REVEAL_MS = 80;
72
+ // Rejects an open. `closed` means the window gave the surface up before the
73
+ // open finished, which needs no answer to the app.
74
+ var SurfaceRefusal = /** @class */ (function (_super) {
75
+ __extends(SurfaceRefusal, _super);
76
+ function SurfaceRefusal(reason) {
77
+ var _this = _super.call(this, "Video surface refused: ".concat(reason)) || this;
78
+ _this.reason = reason;
79
+ _this.name = 'SurfaceRefusal';
80
+ Object.setPrototypeOf(_this, SurfaceRefusal.prototype);
81
+ return _this;
82
+ }
83
+ return SurfaceRefusal;
84
+ }(Error));
85
+ exports.SurfaceRefusal = SurfaceRefusal;
86
+ // The host rejects with an Error whose message is a short machine code.
87
+ var reasonOf = function (err) {
88
+ if (err instanceof SurfaceRefusal && err.reason !== 'closed') {
89
+ return err.reason;
90
+ }
91
+ var code = typeof err === 'string'
92
+ ? err
93
+ : err && typeof err === 'object'
94
+ ? err.message
95
+ : undefined;
96
+ return code === 'no_decoder' ? 'no_decoder' : 'unsupported';
97
+ };
98
+ // Holds every video surface one window manager has open, so the manager never
99
+ // asks the host for more than two at once and opens the next only after the
100
+ // outgoing one has closed, leaving the host an idle decoder to reuse.
101
+ var SurfaceBroker = /** @class */ (function () {
102
+ function SurfaceBroker(host, logger) {
103
+ this.host = host;
104
+ this.logger = logger;
105
+ this.entries = {};
106
+ }
107
+ // Resolves once the host has opened a hidden surface. Rejects with a
108
+ // SurfaceRefusal. A first frame later than its deadline closes the surface
109
+ // and reports it through onRefused instead.
110
+ SurfaceBroker.prototype.open = function (windowId, opts, onEvent, onRefused) {
111
+ return __awaiter(this, void 0, void 0, function () {
112
+ var markClosed, closed, entry, pending_1, surface, retried, err_1, reason, pending_2;
113
+ var _this = this;
114
+ return __generator(this, function (_a) {
115
+ switch (_a.label) {
116
+ case 0:
117
+ markClosed = function () { return undefined; };
118
+ closed = new Promise(function (resolve) {
119
+ markClosed = resolve;
120
+ });
121
+ entry = {
122
+ windowId: windowId,
123
+ label: opts.label,
124
+ surface: null,
125
+ state: 'opening',
126
+ leaving: false,
127
+ firstFrameTimer: null,
128
+ closePromise: null,
129
+ closed: closed,
130
+ markClosed: markClosed,
131
+ };
132
+ this.entries[windowId] = entry;
133
+ _a.label = 1;
134
+ case 1:
135
+ this.throwIfGivenUp(entry);
136
+ pending_1 = this.pendingCloses(entry);
137
+ if (!(pending_1.length > 0)) return [3 /*break*/, 3];
138
+ return [4 /*yield*/, Promise.all(pending_1)];
139
+ case 2:
140
+ _a.sent();
141
+ return [3 /*break*/, 4];
142
+ case 3:
143
+ if (this.liveOthers(entry).length >= exports.MAX_LIVE_SURFACES) {
144
+ throw this.refuse(entry, 'no_decoder');
145
+ }
146
+ return [3 /*break*/, 5];
147
+ case 4: return [3 /*break*/, 1];
148
+ case 5:
149
+ retried = false;
150
+ _a.label = 6;
151
+ case 6:
152
+ this.throwIfGivenUp(entry);
153
+ _a.label = 7;
154
+ case 7:
155
+ _a.trys.push([7, 9, , 12]);
156
+ return [4 /*yield*/, this.openWithDeadline(opts)];
157
+ case 8:
158
+ surface = _a.sent();
159
+ return [3 /*break*/, 13];
160
+ case 9:
161
+ err_1 = _a.sent();
162
+ this.throwIfGivenUp(entry);
163
+ reason = reasonOf(err_1);
164
+ pending_2 = this.pendingCloses(entry);
165
+ if (!(reason === 'no_decoder' && !retried && pending_2.length > 0)) return [3 /*break*/, 11];
166
+ retried = true;
167
+ return [4 /*yield*/, Promise.all(pending_2)];
168
+ case 10:
169
+ _a.sent();
170
+ return [3 /*break*/, 12];
171
+ case 11: throw this.refuse(entry, reason);
172
+ case 12: return [3 /*break*/, 6];
173
+ case 13:
174
+ if (entry.state === 'closed') {
175
+ surface.close();
176
+ throw new SurfaceRefusal('closed');
177
+ }
178
+ entry.surface = surface;
179
+ entry.state = 'open';
180
+ entry.firstFrameTimer = setTimeout(function () {
181
+ entry.firstFrameTimer = null;
182
+ _this.warnRefusal(entry, 'deadline');
183
+ _this.close(windowId);
184
+ onRefused('deadline');
185
+ }, exports.SURFACE_FIRST_FRAME_DEADLINE_MS);
186
+ surface.onEvent(function (e) {
187
+ if (entry.state !== 'open')
188
+ return;
189
+ if (e.type === 'first_frame') {
190
+ if (!entry.firstFrameTimer)
191
+ return;
192
+ clearTimeout(entry.firstFrameTimer);
193
+ entry.firstFrameTimer = null;
194
+ }
195
+ onEvent(e);
196
+ });
197
+ return [2 /*return*/, surface];
198
+ }
199
+ });
200
+ });
201
+ };
202
+ // A swap has started for this window's surface; its close follows.
203
+ SurfaceBroker.prototype.leaving = function (windowId) {
204
+ var entry = this.entries[windowId];
205
+ if (entry)
206
+ entry.leaving = true;
207
+ };
208
+ // Closes the window's surface, or gives up its open. Idempotent.
209
+ SurfaceBroker.prototype.close = function (windowId) {
210
+ var _this = this;
211
+ var entry = this.entries[windowId];
212
+ if (!entry)
213
+ return Promise.resolve();
214
+ if (entry.closePromise)
215
+ return entry.closePromise;
216
+ if (entry.firstFrameTimer) {
217
+ clearTimeout(entry.firstFrameTimer);
218
+ entry.firstFrameTimer = null;
219
+ }
220
+ var surface = entry.surface;
221
+ if (!surface) {
222
+ // Still opening: open() closes a handle that resolves from here on.
223
+ this.forget(entry);
224
+ return Promise.resolve();
225
+ }
226
+ entry.state = 'closing';
227
+ entry.closePromise = surface
228
+ .close()
229
+ .catch(function (err) {
230
+ _this.logger.warn("Failed to close video surface for window '".concat(windowId, "' with '").concat(err && err.message, "'"), { windowId: windowId, presentationId: entry.label });
231
+ })
232
+ .then(function () { return _this.forget(entry); });
233
+ return entry.closePromise;
234
+ };
235
+ SurfaceBroker.prototype.closeAll = function () {
236
+ return __awaiter(this, void 0, void 0, function () {
237
+ var _this = this;
238
+ return __generator(this, function (_a) {
239
+ switch (_a.label) {
240
+ case 0: return [4 /*yield*/, Promise.all(Object.keys(this.entries).map(function (id) { return _this.close(id); }))];
241
+ case 1:
242
+ _a.sent();
243
+ return [2 /*return*/];
244
+ }
245
+ });
246
+ });
247
+ };
248
+ // A window's hole opened or closed.
249
+ SurfaceBroker.prototype.onHole = function (open) {
250
+ this.host.onHole(open);
251
+ };
252
+ SurfaceBroker.prototype.openWithDeadline = function (opts) {
253
+ var _this = this;
254
+ return new Promise(function (resolve, reject) {
255
+ var settled = false;
256
+ var timer = setTimeout(function () {
257
+ settled = true;
258
+ reject(new SurfaceRefusal('deadline'));
259
+ }, exports.SURFACE_OPEN_DEADLINE_MS);
260
+ new Promise(function (r) { return r(_this.host.openVideo(opts)); }).then(function (surface) {
261
+ if (settled) {
262
+ // A late handle never holds a decoder nobody uses.
263
+ surface.close();
264
+ return;
265
+ }
266
+ settled = true;
267
+ clearTimeout(timer);
268
+ resolve(surface);
269
+ }, function (err) {
270
+ if (settled)
271
+ return;
272
+ settled = true;
273
+ clearTimeout(timer);
274
+ reject(err);
275
+ });
276
+ });
277
+ };
278
+ SurfaceBroker.prototype.throwIfGivenUp = function (entry) {
279
+ if (entry.state === 'closed') {
280
+ throw new SurfaceRefusal('closed');
281
+ }
282
+ };
283
+ SurfaceBroker.prototype.liveOthers = function (entry) {
284
+ var _this = this;
285
+ return Object.keys(this.entries)
286
+ .map(function (id) { return _this.entries[id]; })
287
+ .filter(function (e) { return e !== entry && e.state !== 'closed'; });
288
+ };
289
+ SurfaceBroker.prototype.pendingCloses = function (entry) {
290
+ return this.liveOthers(entry)
291
+ .filter(function (e) { return e.state === 'closing' || e.leaving; })
292
+ .map(function (e) { return e.closed; });
293
+ };
294
+ SurfaceBroker.prototype.refuse = function (entry, reason) {
295
+ this.forget(entry);
296
+ this.warnRefusal(entry, reason);
297
+ return new SurfaceRefusal(reason);
298
+ };
299
+ SurfaceBroker.prototype.warnRefusal = function (entry, reason) {
300
+ this.logger.warn("Sending 'video_refused' to window '".concat(entry.windowId, "', reason=").concat(reason), { windowId: entry.windowId, presentationId: entry.label, reason: reason });
301
+ };
302
+ SurfaceBroker.prototype.forget = function (entry) {
303
+ entry.state = 'closed';
304
+ if (this.entries[entry.windowId] === entry) {
305
+ delete this.entries[entry.windowId];
306
+ }
307
+ entry.markClosed();
308
+ };
309
+ return SurfaceBroker;
310
+ }());
311
+ exports.default = SurfaceBroker;
@@ -0,0 +1 @@
1
+ export {};