senza-sdk 4.5.1 → 4.5.2
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/dist/bundle.js +1 -1
- package/dist/implementation.bundle.js +1 -1
- package/package.json +1 -1
- package/src/implementation/overlay.js +143 -36
- package/src/interface/overlay.js +12 -10
- package/src/interface/version.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { Overlay as OverlayInterface } from "../interface/overlay.js";
|
|
2
2
|
import { getFCID, sdkLogger, SenzaError } from "./utils";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Named overlay capture plans. Each step: `{ quality, conditional, delay }`.
|
|
6
|
+
* Steps run when refresh() is called; `delay` is ms after the previous step in the batch.
|
|
7
|
+
* `conditional`: when true, capture only if overlay content changed since the last
|
|
8
|
+
* required (non-conditional) capture in this batch; when false, always capture on that step.
|
|
9
|
+
* Set per step by the plan author; the SDK does not derive it.
|
|
10
|
+
*/
|
|
11
|
+
const OVERLAY_CAPTURE_PRESETS = {
|
|
12
|
+
default: [
|
|
13
|
+
{ quality: "low", conditional: false, delay: 0 },
|
|
14
|
+
{ quality: "low", conditional: true, delay: 150 },
|
|
15
|
+
{ quality: "low", conditional: true, delay: 300 },
|
|
16
|
+
{ quality: "high", conditional: false, delay: 600 }
|
|
17
|
+
],
|
|
18
|
+
once: [
|
|
19
|
+
{ quality: "high", conditional: true, delay: 0 }
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const DEFAULT_CAPTURE_PRESET = "default";
|
|
24
|
+
const VALID_QUALITIES = new Set(["low", "mid", "high"]);
|
|
25
|
+
|
|
4
26
|
class Overlay extends OverlayInterface {
|
|
5
27
|
constructor() {
|
|
6
28
|
super();
|
|
@@ -8,51 +30,102 @@ class Overlay extends OverlayInterface {
|
|
|
8
30
|
this._element = null;
|
|
9
31
|
this._configuration = {
|
|
10
32
|
useTransparency: true,
|
|
11
|
-
|
|
33
|
+
overlayCapturePreset: DEFAULT_CAPTURE_PRESET,
|
|
34
|
+
overlayCapturePlan: null
|
|
12
35
|
};
|
|
36
|
+
this._activeCapturePlan = OVERLAY_CAPTURE_PRESETS[DEFAULT_CAPTURE_PRESET];
|
|
13
37
|
this._retryGeneration = 0;
|
|
14
|
-
this.
|
|
38
|
+
this._planTimerId = null;
|
|
39
|
+
this._currentBatchId = null;
|
|
15
40
|
}
|
|
16
41
|
|
|
17
42
|
_isTransparencyEnabled() {
|
|
18
43
|
return this._configuration.useTransparency !== false;
|
|
19
44
|
}
|
|
20
45
|
|
|
46
|
+
_clearPlanTimer() {
|
|
47
|
+
if (this._planTimerId != null) {
|
|
48
|
+
clearTimeout(this._planTimerId);
|
|
49
|
+
this._planTimerId = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
21
53
|
_clearRetryTimers() {
|
|
22
54
|
this._retryGeneration++;
|
|
23
|
-
|
|
24
|
-
this._retryTimerId = null;
|
|
55
|
+
this._clearPlanTimer();
|
|
25
56
|
}
|
|
26
57
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
_validateCapturePlan(plan) {
|
|
59
|
+
if (!Array.isArray(plan) || plan.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < plan.length; i++) {
|
|
63
|
+
const step = plan[i];
|
|
64
|
+
if (!step || typeof step !== "object") {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (!VALID_QUALITIES.has(step.quality)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (typeof step.conditional !== "boolean") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (typeof step.delay !== "number" || !Number.isFinite(step.delay) || step.delay < 0) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
31
79
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
80
|
+
_resolveCapturePlan() {
|
|
81
|
+
if (this._configuration.overlayCapturePlan != null) {
|
|
82
|
+
return structuredClone(this._configuration.overlayCapturePlan);
|
|
83
|
+
}
|
|
84
|
+
const presetName = this._configuration.overlayCapturePreset ?? DEFAULT_CAPTURE_PRESET;
|
|
85
|
+
const preset = OVERLAY_CAPTURE_PRESETS[presetName];
|
|
86
|
+
if (!preset) {
|
|
87
|
+
throw new Error(`Overlay: unknown overlayCapturePreset "${presetName}"`);
|
|
88
|
+
}
|
|
89
|
+
return structuredClone(preset);
|
|
90
|
+
}
|
|
36
91
|
|
|
37
|
-
|
|
38
|
-
|
|
92
|
+
_scheduleCapturePlanFromStep(batchId, plan, generation, startIndex) {
|
|
93
|
+
const scheduleStep = (index) => {
|
|
94
|
+
if (this._retryGeneration !== generation) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const step = plan[index];
|
|
98
|
+
if (!step) {
|
|
99
|
+
sdkLogger.error(`Overlay: missing capture plan step at index ${index} (plan length ${plan.length})`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this._clearPlanTimer();
|
|
103
|
+
this._planTimerId = setTimeout(async () => {
|
|
104
|
+
if (this._retryGeneration !== generation) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
39
107
|
try {
|
|
40
|
-
await this._renderFrame(
|
|
108
|
+
await this._renderFrame(batchId, step, index);
|
|
41
109
|
} catch (err) {
|
|
42
|
-
sdkLogger.
|
|
110
|
+
sdkLogger.error("Overlay: capture plan step error:", err);
|
|
111
|
+
}
|
|
112
|
+
if (index + 1 < plan.length && this._retryGeneration === generation) {
|
|
113
|
+
scheduleStep(index + 1);
|
|
43
114
|
}
|
|
44
|
-
|
|
45
|
-
scheduleNext();
|
|
46
|
-
}, delay);
|
|
115
|
+
}, step.delay);
|
|
47
116
|
};
|
|
48
117
|
|
|
49
|
-
|
|
118
|
+
scheduleStep(startIndex);
|
|
50
119
|
}
|
|
51
120
|
|
|
52
|
-
|
|
121
|
+
/**
|
|
122
|
+
* @param {boolean} conditional - When true, capture only if overlay content changed since
|
|
123
|
+
* the last required capture in this batch; when false, always capture on this step.
|
|
124
|
+
*/
|
|
125
|
+
_sendFrame(x, y, width, height, batchId, quality, conditional, stepIndex = 0) {
|
|
53
126
|
if (window.cefQuery) {
|
|
54
127
|
return new Promise((resolve, reject) => {
|
|
55
|
-
const FCID = getFCID()
|
|
128
|
+
const FCID = `${stepIndex}-${getFCID()}`;
|
|
56
129
|
const message = {
|
|
57
130
|
type: "displayOverlay",
|
|
58
131
|
x,
|
|
@@ -61,8 +134,11 @@ class Overlay extends OverlayInterface {
|
|
|
61
134
|
height,
|
|
62
135
|
useTransparency: this._isTransparencyEnabled(),
|
|
63
136
|
fcid: FCID,
|
|
137
|
+
batchId,
|
|
138
|
+
quality,
|
|
64
139
|
conditional
|
|
65
140
|
};
|
|
141
|
+
sdkLogger.log(`Overlay: rendering frame x=${x} y=${y} width=${width} height=${height} fcid=${FCID} (batchId=${batchId}, quality=${quality}, conditional=${conditional})`);
|
|
66
142
|
const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
|
|
67
143
|
window.cefQuery({
|
|
68
144
|
request: JSON.stringify(request),
|
|
@@ -79,7 +155,7 @@ class Overlay extends OverlayInterface {
|
|
|
79
155
|
return Promise.reject("Overlay is not supported if NOT running e2e");
|
|
80
156
|
}
|
|
81
157
|
|
|
82
|
-
_renderFrame(conditional =
|
|
158
|
+
_renderFrame(batchId, captureStep = { quality: "high", conditional: false }, stepIndex = 0) {
|
|
83
159
|
if (!this._element) {
|
|
84
160
|
return Promise.reject("No element configured");
|
|
85
161
|
}
|
|
@@ -91,9 +167,10 @@ class Overlay extends OverlayInterface {
|
|
|
91
167
|
return Promise.resolve(false);
|
|
92
168
|
}
|
|
93
169
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
170
|
+
const id = batchId ?? this._currentBatchId ?? getFCID();
|
|
171
|
+
|
|
172
|
+
return this._sendFrame(frame.x, frame.y, frame.width, frame.height, id, captureStep.quality, captureStep.conditional, stepIndex).then(() => {
|
|
173
|
+
if (!captureStep.conditional) {
|
|
97
174
|
const refreshEvent = new Event("refresh");
|
|
98
175
|
refreshEvent.frame = frame;
|
|
99
176
|
this.dispatchEvent(refreshEvent);
|
|
@@ -108,7 +185,7 @@ class Overlay extends OverlayInterface {
|
|
|
108
185
|
const x = Math.round(toFiniteNumber(rect.x));
|
|
109
186
|
const y = Math.round(toFiniteNumber(rect.y));
|
|
110
187
|
const width = Math.round(toFiniteNumber(rect.width));
|
|
111
|
-
const height =Math.round(toFiniteNumber(rect.height));
|
|
188
|
+
const height = Math.round(toFiniteNumber(rect.height));
|
|
112
189
|
|
|
113
190
|
return { x, y, width, height };
|
|
114
191
|
}
|
|
@@ -116,16 +193,41 @@ class Overlay extends OverlayInterface {
|
|
|
116
193
|
_applyConfiguration(configuration) {
|
|
117
194
|
const normalizedConfiguration = { ...configuration };
|
|
118
195
|
|
|
196
|
+
if (
|
|
197
|
+
Object.prototype.hasOwnProperty.call(normalizedConfiguration, "overlayCapturePreset") ||
|
|
198
|
+
Object.prototype.hasOwnProperty.call(normalizedConfiguration, "overlayCapturePlan")
|
|
199
|
+
) {
|
|
200
|
+
this._clearRetryTimers();
|
|
201
|
+
}
|
|
202
|
+
|
|
119
203
|
if (Object.prototype.hasOwnProperty.call(normalizedConfiguration, "useTransparency")) {
|
|
120
204
|
normalizedConfiguration.useTransparency = normalizedConfiguration.useTransparency !== false;
|
|
121
205
|
}
|
|
122
206
|
|
|
123
|
-
if (Object.prototype.hasOwnProperty.call(normalizedConfiguration, "
|
|
124
|
-
const
|
|
125
|
-
|
|
207
|
+
if (Object.prototype.hasOwnProperty.call(normalizedConfiguration, "overlayCapturePreset")) {
|
|
208
|
+
const preset = normalizedConfiguration.overlayCapturePreset;
|
|
209
|
+
if (typeof preset === "string" && OVERLAY_CAPTURE_PRESETS[preset]) {
|
|
210
|
+
normalizedConfiguration.overlayCapturePreset = preset;
|
|
211
|
+
} else if (preset != null) {
|
|
212
|
+
sdkLogger.warn(`Overlay: invalid overlayCapturePreset "${preset}", keeping previous preset`);
|
|
213
|
+
delete normalizedConfiguration.overlayCapturePreset;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (Object.prototype.hasOwnProperty.call(normalizedConfiguration, "overlayCapturePlan")) {
|
|
218
|
+
const plan = normalizedConfiguration.overlayCapturePlan;
|
|
219
|
+
if (plan == null) {
|
|
220
|
+
normalizedConfiguration.overlayCapturePlan = null;
|
|
221
|
+
} else if (this._validateCapturePlan(plan)) {
|
|
222
|
+
normalizedConfiguration.overlayCapturePlan = structuredClone(plan);
|
|
223
|
+
} else {
|
|
224
|
+
sdkLogger.warn("Overlay: invalid overlayCapturePlan, keeping previous plan");
|
|
225
|
+
delete normalizedConfiguration.overlayCapturePlan;
|
|
226
|
+
}
|
|
126
227
|
}
|
|
127
228
|
|
|
128
229
|
this._configuration = { ...this._configuration, ...normalizedConfiguration };
|
|
230
|
+
this._activeCapturePlan = this._resolveCapturePlan();
|
|
129
231
|
}
|
|
130
232
|
|
|
131
233
|
async addElement(element) {
|
|
@@ -171,14 +273,19 @@ class Overlay extends OverlayInterface {
|
|
|
171
273
|
return Promise.reject(errorMsg);
|
|
172
274
|
}
|
|
173
275
|
this._clearRetryTimers();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
276
|
+
this._currentBatchId = getFCID();
|
|
277
|
+
const batchId = this._currentBatchId;
|
|
278
|
+
const generation = this._retryGeneration;
|
|
279
|
+
const plan = this._activeCapturePlan;
|
|
280
|
+
if (plan[0].delay === 0) {
|
|
281
|
+
const result = await this._renderFrame(batchId, plan[0], 0);
|
|
282
|
+
if (result === true && plan.length > 1) {
|
|
283
|
+
this._scheduleCapturePlanFromStep(batchId, plan, generation, 1);
|
|
179
284
|
}
|
|
285
|
+
return result;
|
|
180
286
|
}
|
|
181
|
-
|
|
287
|
+
this._scheduleCapturePlanFromStep(batchId, plan, generation, 0);
|
|
288
|
+
return true;
|
|
182
289
|
}
|
|
183
290
|
|
|
184
291
|
async removeAllElements() {
|
package/src/interface/overlay.js
CHANGED
|
@@ -46,13 +46,11 @@ class Overlay extends EventTarget {
|
|
|
46
46
|
* This is useful when the element's content or position has changed.
|
|
47
47
|
* The overlay must have an element registered before calling refresh.
|
|
48
48
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* Pending retries are cancelled by a subsequent call to refresh(), hideOverlay(),
|
|
55
|
-
* or removeElement().
|
|
49
|
+
* Runs the configured overlay capture plan after each call. The `default` preset sends
|
|
50
|
+
* low-quality captures with relative delays, ending with a high-quality capture.
|
|
51
|
+
* The `once` preset runs one high-quality conditional step immediately.
|
|
52
|
+
* All steps in one refresh share the same `batchId` (from `getFCID()`). Pending plan
|
|
53
|
+
* steps are cancelled by a subsequent call to refresh(), hideOverlay(), or removeElement().
|
|
56
54
|
*
|
|
57
55
|
* @returns {Promise<boolean>} Resolves to true if successful, rejects with error if failed.
|
|
58
56
|
*/
|
|
@@ -85,9 +83,13 @@ class Overlay extends EventTarget {
|
|
|
85
83
|
* @param {Object} configuration - The new configuration to apply.
|
|
86
84
|
* @param {boolean} [configuration.useTransparency=true] - Controls whether the overlay should be rendered with transparency.
|
|
87
85
|
* When set to `true`, the value is forwarded to UI-Streamer in `displayOverlay` requests.
|
|
88
|
-
* @param {
|
|
89
|
-
*
|
|
90
|
-
*
|
|
86
|
+
* @param {string} [configuration.overlayCapturePreset="default"] - Named capture plan preset:
|
|
87
|
+
* `default` (progressive low→high captures) or `once` (one immediate high-quality conditional step).
|
|
88
|
+
* @param {Array<{quality: "low"|"mid"|"high", conditional: boolean, delay: number}>} [configuration.overlayCapturePlan]
|
|
89
|
+
* Explicit capture plan; overrides preset. Steps run on refresh(); each step's `delay` is ms after
|
|
90
|
+
* the previous step in the batch. Set `conditional` per step (the SDK does not derive it):
|
|
91
|
+
* when `true`, capture only if overlay content changed since the last required (non-conditional)
|
|
92
|
+
* capture in this batch; when `false`, always capture on that step.
|
|
91
93
|
*/
|
|
92
94
|
configure(configuration) {
|
|
93
95
|
noop(configuration);
|
package/src/interface/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "4.5.
|
|
1
|
+
export const version = "4.5.2";
|