senza-sdk 4.4.6 → 4.4.8
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 +2 -2
- package/src/implementation/api.js +9 -0
- package/src/implementation/deviceManager.js +254 -3
- package/src/implementation/lifecycle.js +16 -3
- package/src/implementation/remotePlayer.js +7 -1
- package/src/interface/deviceManager.js +126 -0
- package/src/interface/lifecycle.js +5 -3
- package/src/interface/version.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "senza-sdk",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.8",
|
|
4
4
|
"main": "./src/api.js",
|
|
5
5
|
"description": "API for Senza application",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"eslint-plugin-jest": "^28.11.0",
|
|
35
35
|
"globals": "^16.0.0",
|
|
36
36
|
"jest": "^30.2.0",
|
|
37
|
-
"jest-environment-jsdom"
|
|
37
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
38
38
|
"jsdoc-to-markdown": "^7.1.1",
|
|
39
39
|
"webpack": "^5.72.1",
|
|
40
40
|
"webpack-cli": "^5.1.4"
|
|
@@ -20,6 +20,7 @@ let authToken;
|
|
|
20
20
|
|
|
21
21
|
const API_VERSION = "1.0";
|
|
22
22
|
let interfaceVersion;
|
|
23
|
+
let uiReadyHasBeenCalled = false;
|
|
23
24
|
|
|
24
25
|
/** @namespace auth
|
|
25
26
|
*@example
|
|
@@ -262,6 +263,7 @@ export function isRunningE2E() {
|
|
|
262
263
|
|
|
263
264
|
/** Call this API once after application startup, when the ui is ready to accept keys/events */
|
|
264
265
|
export function uiReady() {
|
|
266
|
+
uiReadyHasBeenCalled = true;
|
|
265
267
|
if (window.cefQuery) {
|
|
266
268
|
window.cefQuery({
|
|
267
269
|
request: "uiReady",
|
|
@@ -278,6 +280,13 @@ export function uiReady() {
|
|
|
278
280
|
}
|
|
279
281
|
}
|
|
280
282
|
|
|
283
|
+
/**
|
|
284
|
+
* @private
|
|
285
|
+
*/
|
|
286
|
+
export function _isUiReady() {
|
|
287
|
+
return uiReadyHasBeenCalled;
|
|
288
|
+
}
|
|
289
|
+
|
|
281
290
|
import "./devHelper.js";
|
|
282
291
|
|
|
283
292
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeviceManager as DeviceManagerInterface
|
|
1
|
+
import { DeviceManager as DeviceManagerInterface} from "../interface/deviceManager";
|
|
2
2
|
import { getFCID, sdkLogger, getRestResponse } from "./utils";
|
|
3
3
|
import { sessionInfo } from "./SessionInfo";
|
|
4
4
|
|
|
@@ -9,6 +9,186 @@ let wifi_status_last_update = 0;
|
|
|
9
9
|
const WIFI_STATUS_CACHE_SECONDS = 5;
|
|
10
10
|
const FACTORY_RESET_TIMEOUT_SECONDS = 5;
|
|
11
11
|
|
|
12
|
+
const byteSize = str => new Blob([str]).size;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* MessageChannel is not extended from the interface as its objects are only instantiated internally.
|
|
16
|
+
* The implementation here needs to match the interface definition which exists purely for documentation.
|
|
17
|
+
*/
|
|
18
|
+
class MessageChannel extends EventTarget {
|
|
19
|
+
constructor(deviceManager, channelType) {
|
|
20
|
+
super();
|
|
21
|
+
switch (channelType) {
|
|
22
|
+
case deviceManager.DeviceMessageChannelType.SZE_HOST_APP:
|
|
23
|
+
this._type = deviceManager.DeviceMessageChannelType.SZE_HOST_APP;
|
|
24
|
+
this._description = "Message channel for bidirectional communication with the Senza Embedded device's host application";
|
|
25
|
+
this._capabilities = {
|
|
26
|
+
send: true,
|
|
27
|
+
receive: true,
|
|
28
|
+
dataTypes: ["string"],
|
|
29
|
+
maxMessageSize: 60 * 1024 // 60KB - to account for SCTP default max message size of 64Kb minus the wrapping object overhead
|
|
30
|
+
};
|
|
31
|
+
break;
|
|
32
|
+
case deviceManager.DeviceMessageChannelType.USB_SERIAL:
|
|
33
|
+
this._type = deviceManager.DeviceMessageChannelType.USB_SERIAL;
|
|
34
|
+
this._description = "Message channel for sending messages to the device's USB serial interface";
|
|
35
|
+
this._capabilities = {
|
|
36
|
+
send: true,
|
|
37
|
+
receive: false,
|
|
38
|
+
dataTypes: ["string"],
|
|
39
|
+
maxMessageSize: 60 * 1024 // 60KB
|
|
40
|
+
};
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
throw new Error("Invalid channel type");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this._open = true;
|
|
47
|
+
this._manager = deviceManager;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Calls EventTarget's addEventListener after checking if channel is open
|
|
52
|
+
*/
|
|
53
|
+
addEventListener(type, callback) {
|
|
54
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
55
|
+
EventTarget.prototype.addEventListener.call(this, type, callback);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Calls EventTarget's removeEventListener after checking if channel is open
|
|
60
|
+
*/
|
|
61
|
+
removeEventListener(type, callback) {
|
|
62
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
63
|
+
EventTarget.prototype.removeEventListener.call(this, type, callback);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Marks channel as closed and not usable anymore. Also removes it from the DeviceManager's createdChannels map.
|
|
68
|
+
*/
|
|
69
|
+
dispose() {
|
|
70
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
71
|
+
this._open = false;
|
|
72
|
+
if (this._manager && typeof this._manager._removeChannel === "function") {
|
|
73
|
+
this._manager._removeChannel(this._type);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the type of this message channel.
|
|
79
|
+
* @returns {DeviceMessageChannelType} The channel type
|
|
80
|
+
*/
|
|
81
|
+
get type() {
|
|
82
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
83
|
+
return this._type;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get the description of this message channel.
|
|
88
|
+
* @returns {string} The channel description
|
|
89
|
+
*/
|
|
90
|
+
get description() {
|
|
91
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
92
|
+
return this._description;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the capabilities of this message channel.
|
|
97
|
+
* @returns {Object} The capabilities object containing send/receive flags, supported data types, etc.
|
|
98
|
+
*/
|
|
99
|
+
get capabilities() {
|
|
100
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
101
|
+
return this._capabilities;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @private
|
|
106
|
+
* Performs checks to see if a message can be sent through this channel.
|
|
107
|
+
* @param {*} message The message to check
|
|
108
|
+
*/
|
|
109
|
+
_checkMessageBeforeSend(message) {
|
|
110
|
+
if (!this._open) throw new Error("Channel is closed");
|
|
111
|
+
if (typeof window === "undefined" || typeof window.cefQuery !== "function") {
|
|
112
|
+
throw new Error("cefQuery is not available");
|
|
113
|
+
}
|
|
114
|
+
if (typeof message !== "string" && !(message instanceof String)) {
|
|
115
|
+
throw new Error("message must be a string");
|
|
116
|
+
}
|
|
117
|
+
// Enforce maxMessageSize limit
|
|
118
|
+
const maxSize = this.capabilities.maxMessageSize;
|
|
119
|
+
const messageSize = byteSize(message);
|
|
120
|
+
if (messageSize > maxSize) {
|
|
121
|
+
throw new Error(`Message size (${messageSize} bytes) exceeds maximum allowed size (${maxSize} bytes)`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Senza Embedded Host App Message Channel
|
|
128
|
+
*/
|
|
129
|
+
class SzeHostAppMessageChannel extends MessageChannel {
|
|
130
|
+
_docListener = (e) => {
|
|
131
|
+
const logger = sdkLogger.withFields({ "FCID": e?.detail?.fcid });
|
|
132
|
+
logger.log("Got hs/deviceMsgSzeHostApp", JSON.stringify(e?.detail));
|
|
133
|
+
|
|
134
|
+
const event = new Event("message");
|
|
135
|
+
event.message = e?.detail?.message || "";
|
|
136
|
+
this.dispatchEvent(event);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
constructor(deviceManager) {
|
|
140
|
+
super(deviceManager, deviceManager.DeviceMessageChannelType.SZE_HOST_APP);
|
|
141
|
+
// Listen for device host app to web app messages and forward to EventTarget listeners
|
|
142
|
+
if (typeof document !== "undefined") {
|
|
143
|
+
document.addEventListener("hs/deviceMsgSzeHostApp", this._docListener);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async sendMessage(message) {
|
|
148
|
+
this._checkMessageBeforeSend(message);
|
|
149
|
+
const tc_message = { type: "deviceMsgSzeHostApp", message: message };
|
|
150
|
+
const request = {
|
|
151
|
+
target: "TC",
|
|
152
|
+
waitForResponse: false,
|
|
153
|
+
message: JSON.stringify(tc_message)
|
|
154
|
+
};
|
|
155
|
+
return new Promise((resolve, reject) => {
|
|
156
|
+
window.cefQuery({
|
|
157
|
+
request: JSON.stringify(request),
|
|
158
|
+
persistent: false,
|
|
159
|
+
onSuccess: () => {
|
|
160
|
+
resolve();
|
|
161
|
+
},
|
|
162
|
+
onFailure: (code, msg) => {
|
|
163
|
+
reject(new Error(`Request failed: ${code} ${msg}`));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
dispose() {
|
|
170
|
+
if (typeof document !== "undefined") {
|
|
171
|
+
document.removeEventListener("hs/deviceMsgSzeHostApp", this._docListener);
|
|
172
|
+
}
|
|
173
|
+
super.dispose();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* USB Serial Message Channel implementation
|
|
179
|
+
*/
|
|
180
|
+
class UsbSerialMessageChannel extends MessageChannel {
|
|
181
|
+
constructor(deviceManager) {
|
|
182
|
+
super(deviceManager, deviceManager.DeviceMessageChannelType.USB_SERIAL);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async sendMessage(message) {
|
|
186
|
+
this._checkMessageBeforeSend(message);
|
|
187
|
+
// Use the existing sendDataToDevice functionality
|
|
188
|
+
return getDeviceManagerInstance().sendDataToDevice(message);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
12
192
|
async function getWifiApData() {
|
|
13
193
|
// Wi-Fi access point data is static, so it needs to be retrieved only once
|
|
14
194
|
if (!wifi_ap_data) {
|
|
@@ -38,6 +218,13 @@ class DeviceManager extends DeviceManagerInterface {
|
|
|
38
218
|
|
|
39
219
|
constructor() {
|
|
40
220
|
super();
|
|
221
|
+
this.availableMessageChannels = [
|
|
222
|
+
// Future enhancement: add available channels based on cfg or some device info
|
|
223
|
+
this.DeviceMessageChannelType.SZE_HOST_APP,
|
|
224
|
+
this.DeviceMessageChannelType.USB_SERIAL
|
|
225
|
+
];
|
|
226
|
+
// Track created channels in a map to enforce one-per-type limit, i.e. only one SZE_HOST_APP channel at a time
|
|
227
|
+
this.createdChannels = new Map();
|
|
41
228
|
}
|
|
42
229
|
|
|
43
230
|
get deviceInfo() {
|
|
@@ -202,10 +389,67 @@ class DeviceManager extends DeviceManagerInterface {
|
|
|
202
389
|
await Promise.all([getWifiApData(), getWifiStatus()]);
|
|
203
390
|
return { ...wifi_ap_data, ...wifi_status };
|
|
204
391
|
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Returns a list of available message channels for the device.
|
|
395
|
+
* @returns {DeviceMessageChannelType[]} An array of DeviceMessageChannelType values representing the available message channels.
|
|
396
|
+
*/
|
|
397
|
+
getAvailableMessageChannels() {
|
|
398
|
+
return this.availableMessageChannels || [];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Create a message channel of the specified type.
|
|
403
|
+
* Only one channel of each type can be created at a time.
|
|
404
|
+
* @param {DeviceMessageChannelType} type The type of message channel to create.
|
|
405
|
+
* @returns {MessageChannel} A MessageChannel object representing the created message channel.
|
|
406
|
+
* @throws {Error} If the specified type is not supported or already exists.
|
|
407
|
+
*/
|
|
408
|
+
createMessageChannel(type) {
|
|
409
|
+
const channelType = this.availableMessageChannels.find(c => c === type);
|
|
410
|
+
const availableTypes = this.availableMessageChannels.join(", ");
|
|
411
|
+
if (!channelType) {
|
|
412
|
+
throw new Error(`Unsupported channel type: ${type}. Available types: ${availableTypes}`);
|
|
413
|
+
}
|
|
414
|
+
// Check if a channel of this type already exists
|
|
415
|
+
if (this.createdChannels.has(type)) {
|
|
416
|
+
throw new Error(`A message channel of type '${type}' already exists. Only one channel per type is allowed.`);
|
|
417
|
+
}
|
|
418
|
+
// Create channel implementation based on type
|
|
419
|
+
let channel;
|
|
420
|
+
if (type === this.DeviceMessageChannelType.SZE_HOST_APP) {
|
|
421
|
+
channel = new SzeHostAppMessageChannel(this);
|
|
422
|
+
} else if (type === this.DeviceMessageChannelType.USB_SERIAL) {
|
|
423
|
+
channel = new UsbSerialMessageChannel(this);
|
|
424
|
+
}
|
|
425
|
+
// else channel type is unsupported, but is already checked above
|
|
426
|
+
|
|
427
|
+
this.createdChannels.set(type, channel);
|
|
428
|
+
return channel;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Remove a message channel of the specified type.
|
|
433
|
+
* @private
|
|
434
|
+
* @param {DeviceMessageChannelType} type The type of message channel to remove.
|
|
435
|
+
*/
|
|
436
|
+
_removeChannel(type) {
|
|
437
|
+
if (!this.createdChannels || !this.createdChannels.has(type)) {
|
|
438
|
+
throw new Error(`No channel of type '${type}' exists.`);
|
|
439
|
+
}
|
|
440
|
+
this.createdChannels.delete(type);
|
|
441
|
+
}
|
|
205
442
|
}
|
|
206
443
|
|
|
207
|
-
|
|
444
|
+
// Create the singleton instance
|
|
445
|
+
const deviceManagerInstance = new DeviceManager();
|
|
446
|
+
|
|
447
|
+
// Function to get the singleton instance (for forward reference)
|
|
448
|
+
function getDeviceManagerInstance() {
|
|
449
|
+
return deviceManagerInstance;
|
|
450
|
+
}
|
|
208
451
|
|
|
452
|
+
/**
|
|
209
453
|
* @module
|
|
210
454
|
* @example
|
|
211
455
|
* import { deviceManager } from "senza-sdk";
|
|
@@ -214,6 +458,13 @@ class DeviceManager extends DeviceManagerInterface {
|
|
|
214
458
|
* await deviceManager.clearWifi();
|
|
215
459
|
* deviceManager.reboot();
|
|
216
460
|
*
|
|
461
|
+
* // Message channels
|
|
462
|
+
* const channels = deviceManager.getAvailableMessageChannels();
|
|
463
|
+
* const channel = deviceManager.createMessageChannel(deviceManager.DeviceMessageChannelType.SZE_HOST_APP);
|
|
464
|
+
* channel.addEventListener('message', (event) => {
|
|
465
|
+
* console.log(`Received: ${event.message}`);
|
|
466
|
+
* });
|
|
467
|
+
*
|
|
217
468
|
* @return {DeviceManager} pointer to the DeviceManager singleton
|
|
218
469
|
*/
|
|
219
|
-
export const deviceManager =
|
|
470
|
+
export const deviceManager = deviceManagerInstance;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Lifecycle as LifecycleInterface } from "../interface/lifecycle.js";
|
|
2
|
-
import { getPlatformInfo } from "./api.js";
|
|
2
|
+
import { getPlatformInfo, _isUiReady } from "./api.js";
|
|
3
3
|
import { alarmManager } from "./alarmManager.js";
|
|
4
4
|
import {
|
|
5
5
|
getFCID,
|
|
@@ -108,6 +108,8 @@ class Lifecycle extends LifecycleInterface {
|
|
|
108
108
|
*/
|
|
109
109
|
this._isSuspendTriggeredByTimer = false;
|
|
110
110
|
|
|
111
|
+
this._isInTransitionToSuspended = false;
|
|
112
|
+
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/**
|
|
@@ -705,7 +707,6 @@ class Lifecycle extends LifecycleInterface {
|
|
|
705
707
|
return this._inTransitionToForeground || this._inTransitionToBackground || this._inTransitionToStandby;
|
|
706
708
|
}
|
|
707
709
|
|
|
708
|
-
|
|
709
710
|
getState() {
|
|
710
711
|
if (window.cefQuery) {
|
|
711
712
|
return new Promise((resolve, reject) => {
|
|
@@ -727,6 +728,13 @@ class Lifecycle extends LifecycleInterface {
|
|
|
727
728
|
}
|
|
728
729
|
|
|
729
730
|
moveToForeground() {
|
|
731
|
+
if (!_isUiReady()) {
|
|
732
|
+
sdkLogger.warn("lifecycle moveToForeground: UI is not ready yet. Make sure to call senza.uiReady() before calling lifecycle.moveToForeground()");
|
|
733
|
+
}
|
|
734
|
+
if (this._isInTransitionToSuspended) {
|
|
735
|
+
sdkLogger.error("lifecycle moveToForeground: Currently in transition to suspend, cannot move to foreground");
|
|
736
|
+
return Promise.resolve(false);
|
|
737
|
+
}
|
|
730
738
|
// Reset activity timestamp when moving to foreground
|
|
731
739
|
this._lastActivityTimestamp = Date.now();
|
|
732
740
|
|
|
@@ -911,7 +919,10 @@ class Lifecycle extends LifecycleInterface {
|
|
|
911
919
|
}
|
|
912
920
|
|
|
913
921
|
moveToBackground(isTriggeredByTimer = false) {
|
|
914
|
-
|
|
922
|
+
if (this._isInTransitionToSuspended) {
|
|
923
|
+
sdkLogger.error("lifecycle moveToBackground: Currently in transition to suspend, cannot move to background");
|
|
924
|
+
return Promise.resolve(false);
|
|
925
|
+
}
|
|
915
926
|
// If the background transition is triggered by the auto background timer, set the flag
|
|
916
927
|
this._isBackgroundTriggeredByTimer = isTriggeredByTimer;
|
|
917
928
|
|
|
@@ -1073,6 +1084,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
1073
1084
|
return Promise.reject(errorMsg);
|
|
1074
1085
|
}
|
|
1075
1086
|
|
|
1087
|
+
this._isInTransitionToSuspended = true;
|
|
1076
1088
|
// Report metrics for time between background and suspend
|
|
1077
1089
|
const duration = (Date.now() - this._backgroundTimestamp) / 1000;
|
|
1078
1090
|
|
|
@@ -1109,6 +1121,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
1109
1121
|
resolve(true);
|
|
1110
1122
|
},
|
|
1111
1123
|
onFailure: (code, msg) => {
|
|
1124
|
+
this._isInTransitionToSuspended = false;
|
|
1112
1125
|
logger.error(`moveToSuspended failed: ${code} ${msg}`);
|
|
1113
1126
|
reject(new SenzaError(code, msg));
|
|
1114
1127
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isAppVersionAboveOrEqual
|
|
16
16
|
} from "./utils";
|
|
17
17
|
import { lifecycle } from "./lifecycle";
|
|
18
|
-
import { writeLicenseResponse } from "./api";
|
|
18
|
+
import { writeLicenseResponse, _isUiReady } from "./api";
|
|
19
19
|
import { mergeAutoTranslationLanguages } from "./subtitlesUtils";
|
|
20
20
|
|
|
21
21
|
// This is the delay we wait for to detect if the web application is seeking multiple times
|
|
@@ -736,6 +736,9 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
736
736
|
*
|
|
737
737
|
* */
|
|
738
738
|
async load(url, position) {
|
|
739
|
+
if (!_isUiReady()) {
|
|
740
|
+
sdkLogger.warn("remotePlayer load: UI is not ready yet. Make sure to call senza.uiReady() before calling remotePlayer.load()");
|
|
741
|
+
}
|
|
739
742
|
return this._load(url, position);
|
|
740
743
|
}
|
|
741
744
|
|
|
@@ -942,6 +945,9 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
942
945
|
* @throws {RemotePlayerError} error object contains code & msg
|
|
943
946
|
*/
|
|
944
947
|
play(autoTune = false) {
|
|
948
|
+
if (!_isUiReady()) {
|
|
949
|
+
sdkLogger.warn("remotePlayer play: UI is not ready yet. Make sure to call senza.uiReady() before calling remotePlayer.play()");
|
|
950
|
+
}
|
|
945
951
|
if (!this._isInitialized) {
|
|
946
952
|
throw new RemotePlayerError(6500, "Cannot call play() if remote player is not initialized");
|
|
947
953
|
}
|
|
@@ -4,6 +4,15 @@ import { sdkLogger, noop } from "./utils.js";
|
|
|
4
4
|
* DeviceManager is a singleton class that manages the device.<br>
|
|
5
5
|
*/
|
|
6
6
|
export class DeviceManager extends EventTarget {
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} DeviceMessageChannelType Defines the types of message channels available for communication with the device.
|
|
9
|
+
* @property {string} SZE_HOST_APP Message channel for bidirectional communication with the Senza Embedded device host application.
|
|
10
|
+
* @property {string} USB_SERIAL Message channel for sending messages to the device's USB serial interface.
|
|
11
|
+
*/
|
|
12
|
+
DeviceMessageChannelType = Object.freeze({
|
|
13
|
+
SZE_HOST_APP: "SZE_HOST_APP",
|
|
14
|
+
USB_SERIAL: "USB_SERIAL"
|
|
15
|
+
});
|
|
7
16
|
|
|
8
17
|
/**
|
|
9
18
|
* @property {object} DeviceInfo
|
|
@@ -97,8 +106,117 @@ export class DeviceManager extends EventTarget {
|
|
|
97
106
|
async getWifiInfo() {
|
|
98
107
|
return Promise.resolve({});
|
|
99
108
|
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Returns a list of available message channels for the device.
|
|
112
|
+
* @returns {DeviceMessageChannelType[]} An array of DeviceMessageChannelType objects representing the available message channels.
|
|
113
|
+
* @example
|
|
114
|
+
* import { deviceManager } from "senza-sdk";
|
|
115
|
+
* const channelType = deviceManager.getAvailableMessageChannels();
|
|
116
|
+
* channels.forEach(channel => {
|
|
117
|
+
* console.log(`Channel Type: ${channel.type}, Description: ${channel.description}`);
|
|
118
|
+
* });
|
|
119
|
+
*/
|
|
120
|
+
getAvailableMessageChannels() {
|
|
121
|
+
return noop("DeviceManager.getAvailableMessageChannels");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create a message channel of the specified type.
|
|
126
|
+
* Only one channel of each type can be created at a time.
|
|
127
|
+
* @param {DeviceMessageChannelType} type The type of message channel to create.
|
|
128
|
+
* @returns {MessageChannel} A MessageChannel object representing the created message channel.
|
|
129
|
+
* @throws {Error} If the specified type is not supported or already exists.
|
|
130
|
+
* @example
|
|
131
|
+
* import { deviceManager } from "senza-sdk";
|
|
132
|
+
* const channel = deviceManager.createMessageChannel(deviceManager.DeviceMessageChannelType.SZE_HOST_APP);
|
|
133
|
+
* channel.sendMessage("Hello Senza Embedded host application");
|
|
134
|
+
*/
|
|
135
|
+
createMessageChannel(type) {
|
|
136
|
+
return noop("DeviceManager.createMessageChannel", type);
|
|
137
|
+
}
|
|
100
138
|
}
|
|
101
139
|
|
|
140
|
+
/**
|
|
141
|
+
* MessageChannel represents a communication channel to the device.
|
|
142
|
+
* Objects of this type are created via DeviceManager.createMessageChannel().
|
|
143
|
+
* Available channel types depend on the device and are queried at runtime via DeviceManager.getAvailableMessageChannels().
|
|
144
|
+
* <pre>
|
|
145
|
+
* type: DeviceMessageChannelType.SZE_HOST_APP
|
|
146
|
+
* description: Message channel for bidirectional communication ...
|
|
147
|
+
* capabilities:
|
|
148
|
+
* send: true
|
|
149
|
+
* receive: true
|
|
150
|
+
* dataTypes: [string] // string messages are supported using the sendMessage() method and 'message' event
|
|
151
|
+
* maxMessageSize: 61440
|
|
152
|
+
* </pre>
|
|
153
|
+
*/
|
|
154
|
+
// eslint-disable-next-line no-unused-vars
|
|
155
|
+
class MessageChannel extends EventTarget {
|
|
156
|
+
/**
|
|
157
|
+
* Send a string message to the device via this message channel.
|
|
158
|
+
* @param {string} message The message to send.
|
|
159
|
+
* @returns {Promise<void>} Promise that resolves when message is sent
|
|
160
|
+
* @example
|
|
161
|
+
* const channel = deviceManager.createMessageChannel(DeviceMessageChannelType.SZE_HOST_APP);
|
|
162
|
+
* await channel.sendMessage("Hello Senza Embedded host application");
|
|
163
|
+
*/
|
|
164
|
+
sendMessage() {
|
|
165
|
+
return noop("MessageChannel.sendMessage");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get the type of this message channel.
|
|
170
|
+
* @returns {DeviceMessageChannelType} The channel type
|
|
171
|
+
*/
|
|
172
|
+
get type() {
|
|
173
|
+
return noop("MessageChannel.get() type");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get the description of this message channel.
|
|
178
|
+
* @returns {string} The channel description
|
|
179
|
+
*/
|
|
180
|
+
get description() {
|
|
181
|
+
return noop("MessageChannel.get() description");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get the capabilities of this message channel.
|
|
186
|
+
* @returns {Object} The capabilities object containing send/receive flags, supported data types, max message size.
|
|
187
|
+
*/
|
|
188
|
+
get capabilities() {
|
|
189
|
+
return noop("MessageChannel.get() capabilities");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Listen for events on this channel.
|
|
194
|
+
* @param {string} type Event type. 'message' is currently the only supported event type.
|
|
195
|
+
* @param {Function} listener The event listener function
|
|
196
|
+
*
|
|
197
|
+
* Events fired:
|
|
198
|
+
* - 'message': Fired when a message is received from the device. The event object has a 'message' property containing the message string.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* // Listen for messages
|
|
202
|
+
* channel.addEventListener('message', (event) => {
|
|
203
|
+
* console.log(`Received message: ${event.message}`);
|
|
204
|
+
* });
|
|
205
|
+
*
|
|
206
|
+
* // remove listener
|
|
207
|
+
* channel.removeEventListener('message', messageHandler);
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
/** dispose of this message channel.
|
|
211
|
+
* After calling dispose(), the channel is no longer usable.
|
|
212
|
+
* You may create a new channel of the same type if needed via the DeviceManager.
|
|
213
|
+
* @example
|
|
214
|
+
* channel.dispose();
|
|
215
|
+
*/
|
|
216
|
+
dispose() {
|
|
217
|
+
return noop("MessageChannel.dispose");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
102
220
|
|
|
103
221
|
/**
|
|
104
222
|
* @module
|
|
@@ -110,6 +228,14 @@ export class DeviceManager extends EventTarget {
|
|
|
110
228
|
* await deviceManager.clearWifi();
|
|
111
229
|
* deviceManager.reboot();
|
|
112
230
|
*
|
|
231
|
+
* // Message channel example
|
|
232
|
+
* const channels = deviceManager.getAvailableMessageChannels();
|
|
233
|
+
* const channel = deviceManager.createMessageChannel(deviceManager.DeviceMessageChannelType.SZE_HOST_APP);
|
|
234
|
+
* channel.addEventListener('message', (event) => {
|
|
235
|
+
* console.log(`Received: ${event.message}`);
|
|
236
|
+
* });
|
|
237
|
+
* await channel.sendMessage("Hello Senza Embedded host application");
|
|
238
|
+
*
|
|
113
239
|
* @return {DeviceManager} pointer to the DeviceManager singleton
|
|
114
240
|
*/
|
|
115
241
|
"needed for the module doc comment to be recognized";
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
/**
|
|
17
17
|
* @event Lifecycle#beforestatechange
|
|
18
18
|
* @description Fired before transitioning to a new state. This event is cancelable.<br>
|
|
19
|
-
* Currently only fired when transitioning to BACKGROUND state (e.g., from autoBackground feature).<br>
|
|
19
|
+
* Currently only fired when transitioning to BACKGROUND and SUSPENDED state (e.g., from autoBackground feature).<br>
|
|
20
20
|
* The actual state transition will occur after all event listeners have completed processing.
|
|
21
|
-
* Can be used to prevent automatic transitions to background state when using autoBackground feature.
|
|
21
|
+
* Can be used to prevent automatic transitions to background state when using autoBackground feature, or for suspneded from autoSuspended feature .
|
|
22
22
|
* @property {UiState} state - Indicates the target state the lifecycle is trying to transition to.
|
|
23
23
|
* @property {boolean} cancelable - true, indicating the event can be cancelled using preventDefault()
|
|
24
24
|
* @example
|
|
@@ -87,13 +87,15 @@ class Lifecycle extends EventTarget {
|
|
|
87
87
|
* @property {string} IN_TRANSITION_TO_FOREGROUND - ui is about to be displayed
|
|
88
88
|
* @property {string} BACKGROUND - remote player is playing (full screen playback is displayed)
|
|
89
89
|
* @property {string} IN_TRANSITION_TO_BACKGROUND - remote player is about to be playing
|
|
90
|
+
* @property {string} SUSPENDED - application is suspended. This state is used for the beforestatechange event only.
|
|
90
91
|
*/
|
|
91
92
|
UiState = Object.freeze({
|
|
92
93
|
UNKNOWN: "unknown",
|
|
93
94
|
FOREGROUND: "foreground",
|
|
94
95
|
IN_TRANSITION_TO_FOREGROUND: "inTransitionToForeground",
|
|
95
96
|
BACKGROUND: "background",
|
|
96
|
-
IN_TRANSITION_TO_BACKGROUND: "inTransitionToBackground"
|
|
97
|
+
IN_TRANSITION_TO_BACKGROUND: "inTransitionToBackground",
|
|
98
|
+
SUSPENDED: "suspended"
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
/**
|
package/src/interface/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "4.4.
|
|
1
|
+
export const version = "4.4.8";
|