@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
|
@@ -80,8 +80,47 @@ var embeddedApps_1 = __importDefault(require("./embeddedApps"));
|
|
|
80
80
|
var PlaylistWindowManager_1 = __importDefault(require("./PlaylistWindowManager"));
|
|
81
81
|
var WindowTimeoutError_1 = __importDefault(require("./WindowTimeoutError"));
|
|
82
82
|
var WindowLoadError_1 = __importDefault(require("./WindowLoadError"));
|
|
83
|
+
var SurfaceBroker_1 = require("./SurfaceBroker");
|
|
83
84
|
// TODO: Automatically inject latest version when building in CI.
|
|
84
|
-
var defaultAppRendererUrl = 'https://apps.raydiant.com/3.1.
|
|
85
|
+
var defaultAppRendererUrl = 'https://apps.raydiant.com/3.1.1/index.html';
|
|
86
|
+
// The urls a window may open a surface for besides its content url: the
|
|
87
|
+
// Videos app probes for these renditions beside the original.
|
|
88
|
+
var RENDITION_SUFFIXES = ['_4K', '_720p', '_480p'];
|
|
89
|
+
var isValidRect = function (value) {
|
|
90
|
+
return value &&
|
|
91
|
+
typeof value === 'object' &&
|
|
92
|
+
isFiniteNumber(value.x) &&
|
|
93
|
+
isFiniteNumber(value.y) &&
|
|
94
|
+
isFiniteNumber(value.width) &&
|
|
95
|
+
isFiniteNumber(value.height);
|
|
96
|
+
};
|
|
97
|
+
var isFiniteNumber = function (value) {
|
|
98
|
+
return typeof value === 'number' && isFinite(value);
|
|
99
|
+
};
|
|
100
|
+
var roundRect = function (rect) { return ({
|
|
101
|
+
x: Math.round(rect.x),
|
|
102
|
+
y: Math.round(rect.y),
|
|
103
|
+
width: Math.round(rect.width),
|
|
104
|
+
height: Math.round(rect.height),
|
|
105
|
+
}); };
|
|
106
|
+
// Every string held under a `url` key, at any depth.
|
|
107
|
+
var collectUrls = function (value, urls) {
|
|
108
|
+
if (urls === void 0) { urls = []; }
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
value.forEach(function (item) { return collectUrls(item, urls); });
|
|
111
|
+
}
|
|
112
|
+
else if (value && typeof value === 'object') {
|
|
113
|
+
Object.keys(value).forEach(function (key) {
|
|
114
|
+
if (key === 'url' && typeof value[key] === 'string') {
|
|
115
|
+
urls.push(value[key]);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
collectUrls(value[key], urls);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return urls;
|
|
123
|
+
};
|
|
85
124
|
var isValidNumber = function (value) {
|
|
86
125
|
return typeof value === 'number' && !isNaN(value);
|
|
87
126
|
};
|
|
@@ -140,6 +179,8 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
140
179
|
this.disableInterruptLockCallback = null;
|
|
141
180
|
this.analyticsEventCallback = null;
|
|
142
181
|
this.chargeRequestCallback = null;
|
|
182
|
+
this.didPaintSinceLastPlay = false;
|
|
183
|
+
this.firstPaintResolvers = [];
|
|
143
184
|
this.forceMute = false;
|
|
144
185
|
this.error = null;
|
|
145
186
|
this.workerState = {};
|
|
@@ -152,6 +193,17 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
152
193
|
this.createObjectURLTimeouts = {};
|
|
153
194
|
this.interruptLocks = {};
|
|
154
195
|
this.previouslyLocked = false;
|
|
196
|
+
this.surface = null;
|
|
197
|
+
// Once a window has been shown without a ready surface, or has given one
|
|
198
|
+
// up, it is offered none from then on and its app keeps <video>.
|
|
199
|
+
this.surfaceWithdrawn = false;
|
|
200
|
+
this.surfaceShow = null;
|
|
201
|
+
this.wakeSurfaceShow = [];
|
|
202
|
+
this.holeOpenWaiter = null;
|
|
203
|
+
this.playingWaiter = null;
|
|
204
|
+
this.isPlayHeld = false;
|
|
205
|
+
this.isRemoved = false;
|
|
206
|
+
this.frameBackground = '#000000';
|
|
155
207
|
this.handleEmbeddedMessage = function (type, payload) { return __awaiter(_this, void 0, void 0, function () {
|
|
156
208
|
var windowId, workerState, lock, lock, lock;
|
|
157
209
|
return __generator(this, function (_a) {
|
|
@@ -359,6 +411,11 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
359
411
|
}
|
|
360
412
|
break;
|
|
361
413
|
}
|
|
414
|
+
case 'open_video': {
|
|
415
|
+
// An embedded app is never offered a video surface.
|
|
416
|
+
this.refuseVideo('not_offered');
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
362
419
|
default: {
|
|
363
420
|
this.logWarning("Received unknown embedded message type: ".concat(type));
|
|
364
421
|
}
|
|
@@ -367,7 +424,7 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
367
424
|
});
|
|
368
425
|
}); };
|
|
369
426
|
this.handleLegacyMessage = function (type, payload) { return __awaiter(_this, void 0, void 0, function () {
|
|
370
|
-
var _a, windowId, onPresentationProperties;
|
|
427
|
+
var _a, windowId, onPresentationProperties, surface;
|
|
371
428
|
return __generator(this, function (_b) {
|
|
372
429
|
_a = this.options, windowId = _a.windowId, onPresentationProperties = _a.onPresentationProperties;
|
|
373
430
|
if (type === 'loaded') {
|
|
@@ -382,6 +439,11 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
382
439
|
this.logInfo("Received 'presentation_complete' from window '".concat(windowId, "'"));
|
|
383
440
|
this.handleComplete();
|
|
384
441
|
}
|
|
442
|
+
if (type === 'first_painted') {
|
|
443
|
+
this.logDebug("Received 'first_painted' from window '".concat(windowId, "'"));
|
|
444
|
+
this.didPaintSinceLastPlay = true;
|
|
445
|
+
this.resolveFirstPaintWaiters();
|
|
446
|
+
}
|
|
385
447
|
if (type === 'enable_interrupt_lock') {
|
|
386
448
|
this.logInfo("Received 'enable_interrupt_lock' from window '".concat(windowId, "'"));
|
|
387
449
|
this.enableInteruptLock();
|
|
@@ -404,6 +466,33 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
404
466
|
this.logWarning("Invalid payload received for 'open_child_window', ignoring");
|
|
405
467
|
}
|
|
406
468
|
}
|
|
469
|
+
if (type === 'open_video') {
|
|
470
|
+
this.handleOpenVideo(payload);
|
|
471
|
+
}
|
|
472
|
+
if (type === 'video_bounds') {
|
|
473
|
+
this.handleVideoBounds(payload);
|
|
474
|
+
}
|
|
475
|
+
if (type === 'video_hole_open') {
|
|
476
|
+
this.logInfo("Received 'video_hole_open' from window '".concat(windowId, "'"));
|
|
477
|
+
surface = this.surface;
|
|
478
|
+
if (this.holeOpenWaiter) {
|
|
479
|
+
this.holeOpenWaiter();
|
|
480
|
+
}
|
|
481
|
+
else if (surface &&
|
|
482
|
+
surface.firstFrame &&
|
|
483
|
+
!surface.holeOpen &&
|
|
484
|
+
!this.surfaceShow) {
|
|
485
|
+
// Opened before the window is shown, so a swap may play and reveal
|
|
486
|
+
// it before showing its surface.
|
|
487
|
+
surface.isHolePreopened = true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (type === 'close_video') {
|
|
491
|
+
this.logInfo("Received 'close_video' from window '".concat(windowId, "'"));
|
|
492
|
+
if (this.surface) {
|
|
493
|
+
this.dropSurface(this.surface);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
407
496
|
if (type === 'close_child_window') {
|
|
408
497
|
// TODO: Validate close_child_window message payload.
|
|
409
498
|
this.logInfo("Received 'close_child_window', windowId=".concat(payload.windowId));
|
|
@@ -449,9 +538,40 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
449
538
|
}
|
|
450
539
|
return this.loadLegacyApp();
|
|
451
540
|
};
|
|
452
|
-
|
|
541
|
+
// Shows the window. A window holding a surface with its first frame and
|
|
542
|
+
// bounds shows the surface first and reveals its frame only once the app
|
|
543
|
+
// has opened its hole; onReveal then runs in the reveal's task. Given
|
|
544
|
+
// showAfterRevealMs by a swap, a surface whose app opened its hole while
|
|
545
|
+
// hidden is played, then revealed, then shown instead. The promise
|
|
546
|
+
// resolves once the frame is revealed and any such show has settled, or
|
|
547
|
+
// the window is removed.
|
|
548
|
+
PresentationWindow.prototype.show = function (isFocused, onReveal, showAfterRevealMs) {
|
|
453
549
|
var _this = this;
|
|
454
550
|
if (isFocused === void 0) { isFocused = true; }
|
|
551
|
+
if (this.surfaceShow) {
|
|
552
|
+
return this.surfaceShow;
|
|
553
|
+
}
|
|
554
|
+
var surface = this.surface;
|
|
555
|
+
if (surface && surface.holeOpen) {
|
|
556
|
+
this.showFrame(isFocused);
|
|
557
|
+
return Promise.resolve();
|
|
558
|
+
}
|
|
559
|
+
if (surface && this.isSurfaceReady(surface)) {
|
|
560
|
+
var showing = showAfterRevealMs !== undefined && surface.isHolePreopened
|
|
561
|
+
? this.showSurfaceAfterReveal(surface, isFocused, showAfterRevealMs, onReveal)
|
|
562
|
+
: this.showSurface(surface, isFocused, onReveal);
|
|
563
|
+
this.surfaceShow = showing.then(function () {
|
|
564
|
+
_this.surfaceShow = null;
|
|
565
|
+
});
|
|
566
|
+
return this.surfaceShow;
|
|
567
|
+
}
|
|
568
|
+
// Shown before its surface was ready: the app keeps <video>.
|
|
569
|
+
this.withdrawSurface();
|
|
570
|
+
this.showFrame(isFocused);
|
|
571
|
+
return Promise.resolve();
|
|
572
|
+
};
|
|
573
|
+
PresentationWindow.prototype.showFrame = function (isFocused) {
|
|
574
|
+
var _this = this;
|
|
455
575
|
var _a = this.options, windowId = _a.windowId, renderer = _a.renderer;
|
|
456
576
|
// Show the main window and focus it before any child windows. Showing a child
|
|
457
577
|
// window that requires focus will move focus from the main window to the child.
|
|
@@ -488,7 +608,7 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
488
608
|
};
|
|
489
609
|
PresentationWindow.prototype.remove = function () {
|
|
490
610
|
return __awaiter(this, void 0, void 0, function () {
|
|
491
|
-
var _a, windowId, renderer, err_1;
|
|
611
|
+
var _a, windowId, renderer, surface, surfaceBroker, err_1;
|
|
492
612
|
return __generator(this, function (_b) {
|
|
493
613
|
switch (_b.label) {
|
|
494
614
|
case 0:
|
|
@@ -510,23 +630,43 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
510
630
|
clearTimeout(this.configurableDurationTimeout);
|
|
511
631
|
this.configurableDurationTimeout = null;
|
|
512
632
|
}
|
|
633
|
+
// Release anything waiting on a paint signal so callers never hang on a
|
|
634
|
+
// window that is going away.
|
|
635
|
+
this.resolveFirstPaintWaiters();
|
|
636
|
+
// Release a surface show in progress; a removed window is never revealed.
|
|
637
|
+
this.isRemoved = true;
|
|
638
|
+
this.isPlayHeld = false;
|
|
639
|
+
this.wakeSurfaceShowWaiters();
|
|
513
640
|
// Remove any child window managers.
|
|
514
641
|
Object.values(this.windowManagers).forEach(function (wm) {
|
|
515
642
|
wm.destroy();
|
|
516
643
|
});
|
|
517
|
-
|
|
644
|
+
surface = this.surface;
|
|
645
|
+
surfaceBroker = this.options.surfaceBroker;
|
|
646
|
+
if (!(surface && surfaceBroker)) return [3 /*break*/, 2];
|
|
647
|
+
this.surface = null;
|
|
648
|
+
if (surface.handle) {
|
|
649
|
+
this.sendVideoMessage('video_closing');
|
|
650
|
+
}
|
|
651
|
+
return [4 /*yield*/, surfaceBroker.close(windowId)];
|
|
518
652
|
case 1:
|
|
519
|
-
_b.
|
|
520
|
-
|
|
653
|
+
_b.sent();
|
|
654
|
+
if (surface.holeOpen) {
|
|
655
|
+
surfaceBroker.onHole(false);
|
|
656
|
+
}
|
|
657
|
+
_b.label = 2;
|
|
521
658
|
case 2:
|
|
659
|
+
_b.trys.push([2, 4, , 5]);
|
|
660
|
+
return [4 /*yield*/, renderer.removeWindow(windowId)];
|
|
661
|
+
case 3:
|
|
522
662
|
_b.sent();
|
|
523
663
|
this.logInfo("Removed window '".concat(windowId, "'"));
|
|
524
|
-
return [3 /*break*/,
|
|
525
|
-
case
|
|
664
|
+
return [3 /*break*/, 5];
|
|
665
|
+
case 4:
|
|
526
666
|
err_1 = _b.sent();
|
|
527
667
|
this.logError("Failed to remove window '".concat(windowId, "' with '").concat(err_1.message, "'"));
|
|
528
|
-
return [3 /*break*/,
|
|
529
|
-
case
|
|
668
|
+
return [3 /*break*/, 5];
|
|
669
|
+
case 5: return [2 /*return*/];
|
|
530
670
|
}
|
|
531
671
|
});
|
|
532
672
|
});
|
|
@@ -540,6 +680,17 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
540
680
|
PresentationWindow.prototype.play = function () {
|
|
541
681
|
var _this = this;
|
|
542
682
|
var _a = this.options, applicationVersion = _a.applicationVersion, presentation = _a.presentation;
|
|
683
|
+
// A window holding a surface plays only once its frame is revealed over
|
|
684
|
+
// an open hole, so its first paint follows the hole opening.
|
|
685
|
+
var surface = this.surface;
|
|
686
|
+
if (surface && !surface.holeOpen) {
|
|
687
|
+
this.isPlayHeld = true;
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
this.isPlayHeld = false;
|
|
691
|
+
// Each play starts a new paint cycle; 'first_painted' arrives once the
|
|
692
|
+
// window has presented a frame after this play.
|
|
693
|
+
this.didPaintSinceLastPlay = false;
|
|
543
694
|
if (applicationVersion.configurableDuration) {
|
|
544
695
|
var durationMs = Math.max(presentation.duration * 1000, 5000);
|
|
545
696
|
if (this.configurableDurationTimeout) {
|
|
@@ -553,6 +704,20 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
553
704
|
}
|
|
554
705
|
if (!this.isEmbeddedApp()) {
|
|
555
706
|
this.sendMessageString('play');
|
|
707
|
+
// A replay seeks to the start rather than reopening, which would cost
|
|
708
|
+
// a new first frame with nothing in the hole meanwhile.
|
|
709
|
+
if (surface && surface.handle) {
|
|
710
|
+
if (surface.isPlayingAhead) {
|
|
711
|
+
surface.isPlayingAhead = false;
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
if (surface.plays > 0) {
|
|
715
|
+
surface.handle.seek(0);
|
|
716
|
+
}
|
|
717
|
+
surface.handle.play();
|
|
718
|
+
surface.plays += 1;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
556
721
|
// Play any child window managers.
|
|
557
722
|
Object.values(this.windowManagers).forEach(function (wm) {
|
|
558
723
|
// We only want to trigger play on child windows the first play of the main window or if
|
|
@@ -579,6 +744,75 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
579
744
|
PresentationWindow.prototype.reset = function () {
|
|
580
745
|
this.didReceiveComplete = false;
|
|
581
746
|
};
|
|
747
|
+
// Resolves when the window reports its first painted frame after the most
|
|
748
|
+
// recent play, or after timeoutMs, whichever comes first. Only app-renderer
|
|
749
|
+
// windows emit the paint signal; anything else exits via the timeout.
|
|
750
|
+
PresentationWindow.prototype.waitForFirstPaint = function (timeoutMs) {
|
|
751
|
+
var _this = this;
|
|
752
|
+
if (this.didPaintSinceLastPlay) {
|
|
753
|
+
return Promise.resolve();
|
|
754
|
+
}
|
|
755
|
+
return new Promise(function (resolve) {
|
|
756
|
+
var settled = false;
|
|
757
|
+
var settle = function () {
|
|
758
|
+
if (settled)
|
|
759
|
+
return;
|
|
760
|
+
settled = true;
|
|
761
|
+
clearTimeout(timer);
|
|
762
|
+
var index = _this.firstPaintResolvers.indexOf(settle);
|
|
763
|
+
if (index !== -1) {
|
|
764
|
+
_this.firstPaintResolvers.splice(index, 1);
|
|
765
|
+
}
|
|
766
|
+
resolve();
|
|
767
|
+
};
|
|
768
|
+
var timer = setTimeout(settle, timeoutMs);
|
|
769
|
+
_this.firstPaintResolvers.push(settle);
|
|
770
|
+
});
|
|
771
|
+
};
|
|
772
|
+
// Stop delivering this window's events (complete, error, analytics, charge,
|
|
773
|
+
// interrupt locks) to the window manager. Used when the outgoing window is
|
|
774
|
+
// kept on screen only as a visual backdrop during a swap overlap — a late
|
|
775
|
+
// event from it must not be attributed to the incoming window.
|
|
776
|
+
PresentationWindow.prototype.detachCallbacks = function () {
|
|
777
|
+
this.readyCallback = null;
|
|
778
|
+
this.completeCallback = null;
|
|
779
|
+
this.errorCallback = null;
|
|
780
|
+
this.enableInterruptLockCallback = null;
|
|
781
|
+
this.disableInterruptLockCallback = null;
|
|
782
|
+
this.analyticsEventCallback = null;
|
|
783
|
+
this.chargeRequestCallback = null;
|
|
784
|
+
};
|
|
785
|
+
// Mute the window's audio channel. On the IFrameRenderer this is best-effort
|
|
786
|
+
// (iframes expose no mute API); BrowserWindow renderers mute for real.
|
|
787
|
+
PresentationWindow.prototype.mute = function () {
|
|
788
|
+
var _a = this.options, windowId = _a.windowId, renderer = _a.renderer;
|
|
789
|
+
renderer.muteWindow(windowId);
|
|
790
|
+
};
|
|
791
|
+
PresentationWindow.prototype.wasRemoved = function () {
|
|
792
|
+
return this.isRemoved;
|
|
793
|
+
};
|
|
794
|
+
// The window holds a video surface, opened or still opening.
|
|
795
|
+
PresentationWindow.prototype.holdsSurface = function () {
|
|
796
|
+
return this.surface !== null;
|
|
797
|
+
};
|
|
798
|
+
// A swap is taking this window off screen: mute its surface and tell the
|
|
799
|
+
// broker its close follows, or mute the window as today when it has none.
|
|
800
|
+
PresentationWindow.prototype.muteSurfaceOrFrame = function () {
|
|
801
|
+
var _a = this.options, windowId = _a.windowId, surfaceBroker = _a.surfaceBroker;
|
|
802
|
+
var surface = this.surface;
|
|
803
|
+
if (surface && surface.handle && surfaceBroker) {
|
|
804
|
+
surface.handle.setMuted(true);
|
|
805
|
+
surfaceBroker.leaving(windowId);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
this.mute();
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
PresentationWindow.prototype.resolveFirstPaintWaiters = function () {
|
|
812
|
+
var resolvers = this.firstPaintResolvers;
|
|
813
|
+
this.firstPaintResolvers = [];
|
|
814
|
+
resolvers.forEach(function (resolve) { return resolve(); });
|
|
815
|
+
};
|
|
582
816
|
PresentationWindow.prototype.onComplete = function (callback) {
|
|
583
817
|
this.completeCallback = callback;
|
|
584
818
|
};
|
|
@@ -604,6 +838,12 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
604
838
|
if (this.isEmbeddedApp()) {
|
|
605
839
|
return this.didEmbeddedAppLoad;
|
|
606
840
|
}
|
|
841
|
+
// A window holding a surface is ready only once its first frame has
|
|
842
|
+
// arrived and the app has sized its hole from it.
|
|
843
|
+
var surface = this.surface;
|
|
844
|
+
if (surface && !this.isSurfaceReady(surface)) {
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
607
847
|
return this.didReceiveReady && this.allChildWindowManagersReady();
|
|
608
848
|
};
|
|
609
849
|
PresentationWindow.prototype.isComplete = function () {
|
|
@@ -844,12 +1084,12 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
844
1084
|
case 0:
|
|
845
1085
|
_a = this.options, windowId = _a.windowId, _b = _a.appRendererUrl, appRendererUrl = _b === void 0 ? defaultAppRendererUrl : _b, appRendererOfflineSupport = _a.appRendererOfflineSupport, backgroundColor = _a.backgroundColor;
|
|
846
1086
|
this.logInfo("Create window '".concat(windowId, "'"));
|
|
1087
|
+
this.frameBackground = backgroundColor || '#000000'; // Default to black bg for Raydiant apps
|
|
847
1088
|
return [4 /*yield*/, this.createAndLoadWindow(this.getFullAppRendererUrl({
|
|
848
1089
|
appRendererUrl: appRendererUrl,
|
|
849
1090
|
windowId: windowId,
|
|
850
1091
|
appRendererOfflineSupport: appRendererOfflineSupport,
|
|
851
|
-
}),
|
|
852
|
-
this.handleLegacyMessage)];
|
|
1092
|
+
}), this.frameBackground, this.handleLegacyMessage)];
|
|
853
1093
|
case 1:
|
|
854
1094
|
_c.sent();
|
|
855
1095
|
return [4 /*yield*/, this.waitForPesentationReady()];
|
|
@@ -976,31 +1216,20 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
976
1216
|
return nextTheme;
|
|
977
1217
|
};
|
|
978
1218
|
PresentationWindow.prototype.sendRenderMessage = function () {
|
|
979
|
-
var _a = this.options, applicationVersion = _a.applicationVersion, isPreview = _a.isPreview, device = _a.device;
|
|
1219
|
+
var _a = this.options, applicationVersion = _a.applicationVersion, isPreview = _a.isPreview, device = _a.device, surfaceBroker = _a.surfaceBroker;
|
|
1220
|
+
// The offer of a video surface; app renderer 3.2.0 gives the app its
|
|
1221
|
+
// miraVideo prop only when this is set.
|
|
1222
|
+
var surfaceOffer = surfaceBroker ? { nativeVideo: true } : {};
|
|
980
1223
|
// IFrames do not have a mute/unmute API so we are overriding any mute properties
|
|
981
1224
|
// to support muting MZ zones when using the IFrameRenderer (SecondScreen).
|
|
982
1225
|
if (this.forceMute) {
|
|
983
|
-
this.sendMessageString('render', {
|
|
984
|
-
builderState: this.builderState,
|
|
985
|
-
presentation: __assign(__assign({}, this.presentation), { applicationVariables: __assign(__assign({}, this.presentation.applicationVariables), {
|
|
1226
|
+
this.sendMessageString('render', __assign({ builderState: this.builderState, presentation: __assign(__assign({}, this.presentation), { applicationVariables: __assign(__assign({}, this.presentation.applicationVariables), {
|
|
986
1227
|
// TODO: We need a better way to identify mute properties (ie. PropType.mute())
|
|
987
1228
|
// Force mute the presentation, existing apps use either mute or muted.
|
|
988
|
-
mute: true, muted: true }) }),
|
|
989
|
-
theme: this.buildTheme(),
|
|
990
|
-
applicationVersion: applicationVersion,
|
|
991
|
-
device: device,
|
|
992
|
-
isPreview: isPreview,
|
|
993
|
-
});
|
|
1229
|
+
mute: true, muted: true }) }), theme: this.buildTheme(), applicationVersion: applicationVersion, device: device, isPreview: isPreview }, surfaceOffer));
|
|
994
1230
|
}
|
|
995
1231
|
else {
|
|
996
|
-
this.sendMessageString('render', {
|
|
997
|
-
builderState: this.builderState,
|
|
998
|
-
presentation: this.presentation,
|
|
999
|
-
theme: this.buildTheme(),
|
|
1000
|
-
applicationVersion: applicationVersion,
|
|
1001
|
-
device: device,
|
|
1002
|
-
isPreview: isPreview,
|
|
1003
|
-
});
|
|
1232
|
+
this.sendMessageString('render', __assign({ builderState: this.builderState, presentation: this.presentation, theme: this.buildTheme(), applicationVersion: applicationVersion, device: device, isPreview: isPreview }, surfaceOffer));
|
|
1004
1233
|
}
|
|
1005
1234
|
};
|
|
1006
1235
|
PresentationWindow.prototype.openChildWindow = function (windowName, playlistId, bounds, forceMute, isFocused, themeOverride) {
|
|
@@ -1185,6 +1414,347 @@ var PresentationWindow = /** @class */ (function () {
|
|
|
1185
1414
|
appRendererOfflineSupport: appRendererOfflineSupport,
|
|
1186
1415
|
});
|
|
1187
1416
|
};
|
|
1417
|
+
PresentationWindow.prototype.handleOpenVideo = function (payload) {
|
|
1418
|
+
var _this = this;
|
|
1419
|
+
var _a = this.options, windowId = _a.windowId, surfaceBroker = _a.surfaceBroker, presentation = _a.presentation;
|
|
1420
|
+
this.logInfo("Received 'open_video' from window '".concat(windowId, "', url=").concat(payload && payload.url));
|
|
1421
|
+
if (!surfaceBroker || this.surfaceWithdrawn || this.isEmbeddedApp()) {
|
|
1422
|
+
this.refuseVideo('not_offered');
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
if (this.surface) {
|
|
1426
|
+
this.logWarning("Ignoring 'open_video' from window '".concat(windowId, "', it already holds a surface"));
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
if (!payload ||
|
|
1430
|
+
typeof payload !== 'object' ||
|
|
1431
|
+
typeof payload.url !== 'string' ||
|
|
1432
|
+
!isValidRect(payload.bounds) ||
|
|
1433
|
+
!this.isOfferedVideoUrl(payload.url)) {
|
|
1434
|
+
this.refuseVideo('not_offered');
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
var surface = {
|
|
1438
|
+
handle: null,
|
|
1439
|
+
wantsSound: payload.muted === false,
|
|
1440
|
+
firstFrame: false,
|
|
1441
|
+
bounds: null,
|
|
1442
|
+
holeOpen: false,
|
|
1443
|
+
isHolePreopened: false,
|
|
1444
|
+
isPlayingAhead: false,
|
|
1445
|
+
plays: 0,
|
|
1446
|
+
};
|
|
1447
|
+
this.surface = surface;
|
|
1448
|
+
surfaceBroker
|
|
1449
|
+
.open(windowId, {
|
|
1450
|
+
url: payload.url,
|
|
1451
|
+
bounds: roundRect(payload.bounds),
|
|
1452
|
+
// Always opened muted; sound waits for the show.
|
|
1453
|
+
muted: true,
|
|
1454
|
+
label: presentation.id,
|
|
1455
|
+
}, function (event) { return _this.handleSurfaceEvent(surface, event); }, function (reason) {
|
|
1456
|
+
if (_this.surface !== surface)
|
|
1457
|
+
return;
|
|
1458
|
+
_this.sendVideoMessage('video_refused', { reason: reason });
|
|
1459
|
+
_this.dropSurface(surface);
|
|
1460
|
+
})
|
|
1461
|
+
.then(function (handle) {
|
|
1462
|
+
if (_this.surface !== surface)
|
|
1463
|
+
return;
|
|
1464
|
+
surface.handle = handle;
|
|
1465
|
+
_this.sendVideoMessage('video_opened');
|
|
1466
|
+
}, function (err) {
|
|
1467
|
+
if (_this.surface !== surface)
|
|
1468
|
+
return;
|
|
1469
|
+
var reason = err instanceof SurfaceBroker_1.SurfaceRefusal ? err.reason : 'unsupported';
|
|
1470
|
+
// The broker has logged its refusal.
|
|
1471
|
+
if (reason !== 'closed') {
|
|
1472
|
+
_this.sendVideoMessage('video_refused', { reason: reason });
|
|
1473
|
+
}
|
|
1474
|
+
_this.dropSurface(surface);
|
|
1475
|
+
});
|
|
1476
|
+
};
|
|
1477
|
+
PresentationWindow.prototype.handleVideoBounds = function (payload) {
|
|
1478
|
+
var surface = this.surface;
|
|
1479
|
+
if (!surface || !surface.handle)
|
|
1480
|
+
return;
|
|
1481
|
+
if (!payload || !isValidRect(payload.bounds)) {
|
|
1482
|
+
this.logWarning("Invalid payload received for 'video_bounds', ignoring");
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
var bounds = roundRect(payload.bounds);
|
|
1486
|
+
surface.handle.setBounds(bounds);
|
|
1487
|
+
if (surface.firstFrame) {
|
|
1488
|
+
var wasSized = surface.bounds !== null;
|
|
1489
|
+
surface.bounds = bounds;
|
|
1490
|
+
if (!wasSized) {
|
|
1491
|
+
this.checkIsReadyCallback();
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
PresentationWindow.prototype.handleSurfaceEvent = function (surface, event) {
|
|
1496
|
+
if (this.surface !== surface)
|
|
1497
|
+
return;
|
|
1498
|
+
// A stall is the host's to ride out, but it reaches the app: an app that
|
|
1499
|
+
// times its own complete holds that timer until the next 'playing'.
|
|
1500
|
+
if (event.type === 'first_frame') {
|
|
1501
|
+
surface.firstFrame = true;
|
|
1502
|
+
}
|
|
1503
|
+
this.sendVideoMessage('video_event', event);
|
|
1504
|
+
if (event.type === 'playing' && this.playingWaiter) {
|
|
1505
|
+
this.playingWaiter();
|
|
1506
|
+
}
|
|
1507
|
+
if (event.type === 'error') {
|
|
1508
|
+
this.dropSurface(surface);
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
PresentationWindow.prototype.isSurfaceReady = function (surface) {
|
|
1512
|
+
return !!surface.handle && surface.firstFrame && surface.bounds !== null;
|
|
1513
|
+
};
|
|
1514
|
+
// Only an http(s) url the presentation holds, or one of its renditions,
|
|
1515
|
+
// opens a surface: it is the url the app would give <video>.
|
|
1516
|
+
PresentationWindow.prototype.isOfferedVideoUrl = function (url) {
|
|
1517
|
+
if (!/^https?:\/\//i.test(url))
|
|
1518
|
+
return false;
|
|
1519
|
+
return collectUrls(this.presentation.applicationVariables).some(function (offered) {
|
|
1520
|
+
return url === offered ||
|
|
1521
|
+
RENDITION_SUFFIXES.some(function (suffix) { return url === "".concat(offered).concat(suffix); });
|
|
1522
|
+
});
|
|
1523
|
+
};
|
|
1524
|
+
// Shows a ready surface: the host's show() is awaited, the app is told to
|
|
1525
|
+
// open its hole, and the frame is revealed once it has. One deadline covers
|
|
1526
|
+
// both waits; past it the app keeps <video> and the frame shows as today.
|
|
1527
|
+
PresentationWindow.prototype.showSurface = function (surface, isFocused, onReveal) {
|
|
1528
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1529
|
+
var _a, surfaceShowDeadlineMs, handle, passDeadline, deadline, timer, wake, woken, holeOpen, finish, outcome;
|
|
1530
|
+
var _this = this;
|
|
1531
|
+
return __generator(this, function (_b) {
|
|
1532
|
+
switch (_b.label) {
|
|
1533
|
+
case 0:
|
|
1534
|
+
_a = this.options.surfaceShowDeadlineMs, surfaceShowDeadlineMs = _a === void 0 ? SurfaceBroker_1.DEFAULT_SURFACE_SWAP_DELAY_MS : _a;
|
|
1535
|
+
handle = surface.handle;
|
|
1536
|
+
passDeadline = function () { return undefined; };
|
|
1537
|
+
deadline = new Promise(function (resolve) {
|
|
1538
|
+
passDeadline = resolve;
|
|
1539
|
+
});
|
|
1540
|
+
timer = setTimeout(function () { return passDeadline('deadline'); }, surfaceShowDeadlineMs);
|
|
1541
|
+
wake = function () { return undefined; };
|
|
1542
|
+
woken = new Promise(function (resolve) {
|
|
1543
|
+
wake = function () { return resolve('woken'); };
|
|
1544
|
+
});
|
|
1545
|
+
this.wakeSurfaceShow.push(wake);
|
|
1546
|
+
holeOpen = new Promise(function (resolve) {
|
|
1547
|
+
_this.holeOpenWaiter = function () { return resolve('hole_open'); };
|
|
1548
|
+
});
|
|
1549
|
+
finish = function () {
|
|
1550
|
+
clearTimeout(timer);
|
|
1551
|
+
_this.holeOpenWaiter = null;
|
|
1552
|
+
_this.wakeSurfaceShow = _this.wakeSurfaceShow.filter(function (w) { return w !== wake; });
|
|
1553
|
+
};
|
|
1554
|
+
return [4 /*yield*/, Promise.race([
|
|
1555
|
+
handle.show().then(function () { return 'shown'; }, function () { return 'failed'; }),
|
|
1556
|
+
deadline,
|
|
1557
|
+
woken,
|
|
1558
|
+
])];
|
|
1559
|
+
case 1:
|
|
1560
|
+
outcome = _b.sent();
|
|
1561
|
+
if (!(outcome === 'shown' && this.surface === surface && !this.isRemoved)) return [3 /*break*/, 3];
|
|
1562
|
+
if (surface.wantsSound && !this.forceMute) {
|
|
1563
|
+
handle.setMuted(false);
|
|
1564
|
+
}
|
|
1565
|
+
this.sendVideoMessage('video_shown');
|
|
1566
|
+
return [4 /*yield*/, Promise.race([holeOpen, deadline, woken])];
|
|
1567
|
+
case 2:
|
|
1568
|
+
outcome = _b.sent();
|
|
1569
|
+
_b.label = 3;
|
|
1570
|
+
case 3:
|
|
1571
|
+
finish();
|
|
1572
|
+
if (this.isRemoved) {
|
|
1573
|
+
return [2 /*return*/];
|
|
1574
|
+
}
|
|
1575
|
+
if (outcome === 'hole_open' && this.surface === surface) {
|
|
1576
|
+
this.revealOverHole(surface, isFocused, onReveal);
|
|
1577
|
+
return [2 /*return*/];
|
|
1578
|
+
}
|
|
1579
|
+
// A show the host rejected falls back as a missed deadline does, under
|
|
1580
|
+
// the host's own answer.
|
|
1581
|
+
if ((outcome === 'deadline' || outcome === 'failed') &&
|
|
1582
|
+
this.surface === surface) {
|
|
1583
|
+
this.refuseVideo(outcome === 'failed' ? 'unsupported' : 'deadline');
|
|
1584
|
+
this.dropSurface(surface);
|
|
1585
|
+
}
|
|
1586
|
+
// The surface is gone: the frame shows and plays as today.
|
|
1587
|
+
this.showFrame(isFocused);
|
|
1588
|
+
this.releaseHeldPlay();
|
|
1589
|
+
return [2 /*return*/];
|
|
1590
|
+
}
|
|
1591
|
+
});
|
|
1592
|
+
});
|
|
1593
|
+
};
|
|
1594
|
+
// A swap's incoming surface whose app opened its hole while hidden. It
|
|
1595
|
+
// plays first, still hidden and muted, and the frame is revealed over the
|
|
1596
|
+
// outgoing surface once it reports playing, so the picture is moving when
|
|
1597
|
+
// it appears and no first frame is held. The surface is shown
|
|
1598
|
+
// showAfterRevealMs later: it reaches the screen sooner than the frame
|
|
1599
|
+
// does, so the two land together. Sound waits for the show, so it never
|
|
1600
|
+
// overlaps the outgoing surface's. A surface that never reports playing is
|
|
1601
|
+
// revealed at the show deadline; past a second deadline on the show the
|
|
1602
|
+
// app keeps <video> in the frame already revealed.
|
|
1603
|
+
PresentationWindow.prototype.showSurfaceAfterReveal = function (surface, isFocused, showAfterRevealMs, onReveal) {
|
|
1604
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1605
|
+
var _a, surfaceShowDeadlineMs, handle, timers, after, wake, woken, isHeld, playing, isRevealed, outcome;
|
|
1606
|
+
var _this = this;
|
|
1607
|
+
return __generator(this, function (_b) {
|
|
1608
|
+
switch (_b.label) {
|
|
1609
|
+
case 0:
|
|
1610
|
+
_a = this.options.surfaceShowDeadlineMs, surfaceShowDeadlineMs = _a === void 0 ? SurfaceBroker_1.DEFAULT_SURFACE_SWAP_DELAY_MS : _a;
|
|
1611
|
+
handle = surface.handle;
|
|
1612
|
+
timers = [];
|
|
1613
|
+
after = function (ms, value) {
|
|
1614
|
+
return new Promise(function (resolve) {
|
|
1615
|
+
timers.push(setTimeout(function () { return resolve(value); }, ms));
|
|
1616
|
+
});
|
|
1617
|
+
};
|
|
1618
|
+
wake = function () { return undefined; };
|
|
1619
|
+
woken = new Promise(function (resolve) {
|
|
1620
|
+
wake = function () { return resolve('woken'); };
|
|
1621
|
+
});
|
|
1622
|
+
this.wakeSurfaceShow.push(wake);
|
|
1623
|
+
isHeld = function () { return !_this.isRemoved && _this.surface === surface; };
|
|
1624
|
+
playing = new Promise(function (resolve) {
|
|
1625
|
+
_this.playingWaiter = function () { return resolve('playing'); };
|
|
1626
|
+
});
|
|
1627
|
+
handle.play();
|
|
1628
|
+
surface.plays += 1;
|
|
1629
|
+
surface.isPlayingAhead = true;
|
|
1630
|
+
isRevealed = false;
|
|
1631
|
+
return [4 /*yield*/, Promise.race([
|
|
1632
|
+
playing,
|
|
1633
|
+
after(surfaceShowDeadlineMs, 'no_playing'),
|
|
1634
|
+
woken,
|
|
1635
|
+
])];
|
|
1636
|
+
case 1:
|
|
1637
|
+
outcome = _b.sent();
|
|
1638
|
+
this.playingWaiter = null;
|
|
1639
|
+
if (outcome === 'no_playing') {
|
|
1640
|
+
this.logWarning("No 'playing' from the surface of window '".concat(this.options.windowId, "', revealing it anyway"));
|
|
1641
|
+
}
|
|
1642
|
+
if (!((outcome === 'playing' || outcome === 'no_playing') && isHeld())) return [3 /*break*/, 3];
|
|
1643
|
+
isRevealed = true;
|
|
1644
|
+
this.revealOverHole(surface, isFocused, onReveal);
|
|
1645
|
+
return [4 /*yield*/, Promise.race([
|
|
1646
|
+
after(showAfterRevealMs, 'show'),
|
|
1647
|
+
woken,
|
|
1648
|
+
])];
|
|
1649
|
+
case 2:
|
|
1650
|
+
outcome = _b.sent();
|
|
1651
|
+
_b.label = 3;
|
|
1652
|
+
case 3:
|
|
1653
|
+
if (!(outcome === 'show' && isHeld())) return [3 /*break*/, 5];
|
|
1654
|
+
return [4 /*yield*/, Promise.race([
|
|
1655
|
+
handle.show().then(function () { return 'shown'; }, function () { return 'failed'; }),
|
|
1656
|
+
after(surfaceShowDeadlineMs, 'deadline'),
|
|
1657
|
+
woken,
|
|
1658
|
+
])];
|
|
1659
|
+
case 4:
|
|
1660
|
+
outcome = _b.sent();
|
|
1661
|
+
_b.label = 5;
|
|
1662
|
+
case 5:
|
|
1663
|
+
timers.forEach(function (timer) { return clearTimeout(timer); });
|
|
1664
|
+
this.wakeSurfaceShow = this.wakeSurfaceShow.filter(function (w) { return w !== wake; });
|
|
1665
|
+
if (this.isRemoved) {
|
|
1666
|
+
return [2 /*return*/];
|
|
1667
|
+
}
|
|
1668
|
+
if (outcome === 'shown' && this.surface === surface) {
|
|
1669
|
+
if (surface.wantsSound && !this.forceMute) {
|
|
1670
|
+
handle.setMuted(false);
|
|
1671
|
+
}
|
|
1672
|
+
this.sendVideoMessage('video_shown');
|
|
1673
|
+
return [2 /*return*/];
|
|
1674
|
+
}
|
|
1675
|
+
if ((outcome === 'deadline' || outcome === 'failed') &&
|
|
1676
|
+
this.surface === surface) {
|
|
1677
|
+
this.refuseVideo(outcome === 'failed' ? 'unsupported' : 'deadline');
|
|
1678
|
+
this.dropSurface(surface);
|
|
1679
|
+
}
|
|
1680
|
+
// The surface went before its reveal: the frame shows and plays as today.
|
|
1681
|
+
if (!isRevealed) {
|
|
1682
|
+
this.showFrame(isFocused);
|
|
1683
|
+
this.releaseHeldPlay();
|
|
1684
|
+
}
|
|
1685
|
+
return [2 /*return*/];
|
|
1686
|
+
}
|
|
1687
|
+
});
|
|
1688
|
+
});
|
|
1689
|
+
};
|
|
1690
|
+
// Reveals the frame over its surface's open hole, and runs the caller's
|
|
1691
|
+
// onReveal and any held play in that same task.
|
|
1692
|
+
PresentationWindow.prototype.revealOverHole = function (surface, isFocused, onReveal) {
|
|
1693
|
+
var _a = this.options, windowId = _a.windowId, renderer = _a.renderer, surfaceBroker = _a.surfaceBroker;
|
|
1694
|
+
surface.holeOpen = true;
|
|
1695
|
+
surfaceBroker.onHole(true);
|
|
1696
|
+
if (renderer.setWindowBackground) {
|
|
1697
|
+
renderer.setWindowBackground(windowId, 'transparent');
|
|
1698
|
+
}
|
|
1699
|
+
this.showFrame(isFocused);
|
|
1700
|
+
if (onReveal)
|
|
1701
|
+
onReveal();
|
|
1702
|
+
this.releaseHeldPlay();
|
|
1703
|
+
};
|
|
1704
|
+
// Shown before its surface was ready: any surface it holds closes and the
|
|
1705
|
+
// window is offered none from then on.
|
|
1706
|
+
PresentationWindow.prototype.withdrawSurface = function () {
|
|
1707
|
+
this.surfaceWithdrawn = true;
|
|
1708
|
+
var surface = this.surface;
|
|
1709
|
+
if (surface) {
|
|
1710
|
+
this.refuseVideo('not_offered');
|
|
1711
|
+
this.dropSurface(surface);
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
// The window gives its surface up: closed through the broker, its hole
|
|
1715
|
+
// reported closed and its frame background restored. It holds none from
|
|
1716
|
+
// then on, and counts ready and swaps as any other window.
|
|
1717
|
+
PresentationWindow.prototype.dropSurface = function (surface) {
|
|
1718
|
+
var _a = this.options, windowId = _a.windowId, renderer = _a.renderer, surfaceBroker = _a.surfaceBroker;
|
|
1719
|
+
if (this.surface !== surface || !surfaceBroker)
|
|
1720
|
+
return;
|
|
1721
|
+
this.surface = null;
|
|
1722
|
+
this.surfaceWithdrawn = true;
|
|
1723
|
+
surfaceBroker.close(windowId);
|
|
1724
|
+
if (surface.holeOpen) {
|
|
1725
|
+
surface.holeOpen = false;
|
|
1726
|
+
surfaceBroker.onHole(false);
|
|
1727
|
+
if (renderer.setWindowBackground) {
|
|
1728
|
+
renderer.setWindowBackground(windowId, this.frameBackground);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
this.wakeSurfaceShowWaiters();
|
|
1732
|
+
this.checkIsReadyCallback();
|
|
1733
|
+
};
|
|
1734
|
+
PresentationWindow.prototype.wakeSurfaceShowWaiters = function () {
|
|
1735
|
+
var waiters = this.wakeSurfaceShow;
|
|
1736
|
+
this.wakeSurfaceShow = [];
|
|
1737
|
+
waiters.forEach(function (wake) { return wake(); });
|
|
1738
|
+
};
|
|
1739
|
+
PresentationWindow.prototype.releaseHeldPlay = function () {
|
|
1740
|
+
if (this.isPlayHeld) {
|
|
1741
|
+
this.isPlayHeld = false;
|
|
1742
|
+
this.play();
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1745
|
+
PresentationWindow.prototype.refuseVideo = function (reason) {
|
|
1746
|
+
this.logWarning("Sending 'video_refused' to window '".concat(this.options.windowId, "', reason=").concat(reason));
|
|
1747
|
+
this.sendVideoMessage('video_refused', { reason: reason });
|
|
1748
|
+
};
|
|
1749
|
+
// Every video message rides the string channel the app renderer reads.
|
|
1750
|
+
PresentationWindow.prototype.sendVideoMessage = function (type, payload) {
|
|
1751
|
+
try {
|
|
1752
|
+
this.sendMessageString(type, payload);
|
|
1753
|
+
}
|
|
1754
|
+
catch (err) {
|
|
1755
|
+
this.logWarning("Failed to send '".concat(type, "' with '").concat(err.message, "'"));
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1188
1758
|
PresentationWindow.prototype.handleReady = function () {
|
|
1189
1759
|
this.didReceiveReady = true;
|
|
1190
1760
|
this.checkIsReadyCallback();
|