senza-sdk 4.2.55-e39d067.0 → 4.2.55
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/package.json +1 -1
- package/src/lifecycle.js +6 -15
- package/src/remotePlayer.js +33 -376
- package/src/senzaShakaPlayer.js +80 -23
package/package.json
CHANGED
package/src/lifecycle.js
CHANGED
|
@@ -710,24 +710,15 @@ class Lifecycle extends EventTarget {
|
|
|
710
710
|
* Failure to process the moveToBackground command will result in the promise being rejected.
|
|
711
711
|
*/
|
|
712
712
|
moveToBackground() {
|
|
713
|
-
if (
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (remotePlayer._isSeekingByApplication) {
|
|
713
|
+
if (remotePlayer._isSeekingByApplication) {
|
|
714
|
+
if (window.cefQuery) {
|
|
715
|
+
if (this._inTransition || this._state === this.UiState.BACKGROUND || this._state === this.UiState.IN_TRANSITION_TO_BACKGROUND) {
|
|
716
|
+
sdkLogger.warn(`lifecycle moveToBackground: No need to transition to background, state: ${this._state} transition: ${this._inTransition}`);
|
|
717
|
+
return Promise.resolve(false);
|
|
718
|
+
}
|
|
720
719
|
remotePlayer._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
721
720
|
return Promise.resolve(true);
|
|
722
721
|
}
|
|
723
|
-
if (remotePlayer._isSetSubtitlesInProgress) {
|
|
724
|
-
remotePlayer._targetSetSubtitlePlayingState = TargetPlayingState.PLAYING_ABR;
|
|
725
|
-
return Promise.resolve(true);
|
|
726
|
-
}
|
|
727
|
-
if (remotePlayer._isSetAudioInProgress) {
|
|
728
|
-
remotePlayer._targetSetAudioPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
729
|
-
return Promise.resolve(true);
|
|
730
|
-
}
|
|
731
722
|
}
|
|
732
723
|
return this._moveToBackground();
|
|
733
724
|
}
|
package/src/remotePlayer.js
CHANGED
|
@@ -694,7 +694,7 @@ class RemotePlayer extends EventTarget {
|
|
|
694
694
|
return Promise.resolve(undefined);
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
-
_play(
|
|
697
|
+
_play() {
|
|
698
698
|
if (window.cefQuery) {
|
|
699
699
|
const FCID = getFCID();
|
|
700
700
|
const logger = sdkLogger.withFields({ FCID });
|
|
@@ -714,10 +714,16 @@ class RemotePlayer extends EventTarget {
|
|
|
714
714
|
playbackPosition: this.currentTime
|
|
715
715
|
};
|
|
716
716
|
let waitForResponse = false;
|
|
717
|
+
this._changePlayMode(true);
|
|
717
718
|
if (this._remotePlayerApiVersion >= 2) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
719
|
+
if (this._isAudioSyncEnabled()) {
|
|
720
|
+
message.switchMode = SwitchMode.SEAMLESS;
|
|
721
|
+
message.streamType = StreamType.AUDIO;
|
|
722
|
+
waitForResponse = true;
|
|
723
|
+
} else {
|
|
724
|
+
logger.log("remotePlayer play request ignored and will be sent with the lifecycle.moveToBackground()");
|
|
725
|
+
return Promise.resolve();
|
|
726
|
+
}
|
|
721
727
|
}
|
|
722
728
|
const request = { target: "TC", waitForResponse: waitForResponse, message: JSON.stringify(message) };
|
|
723
729
|
return new Promise((resolve, reject) => {
|
|
@@ -756,6 +762,7 @@ class RemotePlayer extends EventTarget {
|
|
|
756
762
|
|
|
757
763
|
_pause() {
|
|
758
764
|
if (window.cefQuery) {
|
|
765
|
+
this._changePlayMode(false);
|
|
759
766
|
const isForegroundState = lifecycle.state === lifecycle.UiState.FOREGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_FOREGROUND;
|
|
760
767
|
if (this._remotePlayerApiVersion >= 2 && !this._isAudioSyncEnabled() && isForegroundState) {
|
|
761
768
|
sdkLogger.info("remotePlayer pause: application in foreground, remote player is not playing.");
|
|
@@ -809,51 +816,6 @@ class RemotePlayer extends EventTarget {
|
|
|
809
816
|
return Promise.resolve(undefined);
|
|
810
817
|
}
|
|
811
818
|
|
|
812
|
-
_stop(streamType) {
|
|
813
|
-
if (window.cefQuery) {
|
|
814
|
-
const FCID = getFCID();
|
|
815
|
-
const logger = sdkLogger.withFields({ FCID });
|
|
816
|
-
logger.log(`remotePlayer stop: sending stop action for streamType ${streamType}`);
|
|
817
|
-
const message = {
|
|
818
|
-
type: "remotePlayer.stop",
|
|
819
|
-
class: "remotePlayer",
|
|
820
|
-
action: "stop",
|
|
821
|
-
streamType: streamType,
|
|
822
|
-
fcid: FCID
|
|
823
|
-
};
|
|
824
|
-
const request = { target: "TC", waitForResponse: true, message: JSON.stringify(message) };
|
|
825
|
-
return new Promise((resolve, reject) => {
|
|
826
|
-
let timerId = 0;
|
|
827
|
-
const timeBeforeSendingRequest = Date.now();
|
|
828
|
-
const queryId = window.cefQuery({
|
|
829
|
-
request: JSON.stringify(request),
|
|
830
|
-
persistent: false,
|
|
831
|
-
onSuccess: () => {
|
|
832
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
833
|
-
logger.withFields({ duration }).log(`stop completed successfully after ${duration} ms`);
|
|
834
|
-
timerId = clearTimer(timerId);
|
|
835
|
-
resolve();
|
|
836
|
-
},
|
|
837
|
-
onFailure: (code, msg) => {
|
|
838
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
839
|
-
logger.withFields({ duration }).log(`stop failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
|
|
840
|
-
timerId = clearTimer(timerId);
|
|
841
|
-
reject(new RemotePlayerError(code, msg));
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
logger.log(`window.cefQuery for stop returned query id ${queryId}`);
|
|
845
|
-
const timeout = this._remotePlayerConfirmationTimeout + 1000;
|
|
846
|
-
timerId = setTimeout(() => {
|
|
847
|
-
logger.log(`stop reached timeout of ${timeout} ms, canceling query id ${queryId}`);
|
|
848
|
-
window.cefQueryCancel(queryId);
|
|
849
|
-
reject(new RemotePlayerError(6000, `stop reached timeout of ${timeout} ms`));
|
|
850
|
-
}, timeout, queryId);
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
sdkLogger.error("remotePlayer stop: window.cefQuery is undefined");
|
|
854
|
-
return Promise.resolve(undefined);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
819
|
/** In order to support a seamless switch between the video in the UI and ABR, the web application must
|
|
858
820
|
* register the video element being used for the currently played video before calling the load and play apis.
|
|
859
821
|
* @param {object} video The video element currently playing video in the web application
|
|
@@ -929,8 +891,6 @@ class RemotePlayer extends EventTarget {
|
|
|
929
891
|
if (this._loadMode === this.LoadMode.LOADING || this._loadMode === this.LoadMode.UNLOADING) {
|
|
930
892
|
throw new RemotePlayerError(6501, "Cannot call load() while previous load/unload is still in progress");
|
|
931
893
|
}
|
|
932
|
-
this._abortSetAudioLanguage = true;
|
|
933
|
-
this._abortSetSubtitleLanguage = true;
|
|
934
894
|
this._abortSeeking = true;
|
|
935
895
|
if (reset) {
|
|
936
896
|
this._reset();
|
|
@@ -1104,20 +1064,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1104
1064
|
}
|
|
1105
1065
|
}
|
|
1106
1066
|
|
|
1107
|
-
this._changePlayMode(true);
|
|
1108
|
-
|
|
1109
|
-
if (this._isSetAudioInProgress) {
|
|
1110
|
-
sdkLogger.info("application requesting play during setAudioLanguage");
|
|
1111
|
-
this._targetSetAudioPlayingState = TargetPlayingState.PLAYING_UI;
|
|
1112
|
-
return Promise.resolve(true);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
if (this._isSetSubtitlesInProgress) {
|
|
1116
|
-
sdkLogger.info("application requesting play during setSubtitleLanguage");
|
|
1117
|
-
this._targetSetSubtitlePlayingState = TargetPlayingState.PLAYING_UI;
|
|
1118
|
-
return Promise.resolve(true);
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
1067
|
// If seeking in progress, wait for seek to complete before playing
|
|
1122
1068
|
if (this._isSeekingByApplication) {
|
|
1123
1069
|
sdkLogger.info("application requesting play during seek");
|
|
@@ -1132,13 +1078,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1132
1078
|
this._seek(this._videoElement.currentTime, false);
|
|
1133
1079
|
}
|
|
1134
1080
|
}*/
|
|
1135
|
-
|
|
1136
|
-
if (this._remotePlayerApiVersion >= 2 && !this._isAudioSyncEnabled()) {
|
|
1137
|
-
sdkLogger.info("play was called but _isAudioSyncEnabled is disabled, ignoring.");
|
|
1138
|
-
return Promise.resolve(true);
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
return this._play(StreamType.AUDIO);
|
|
1081
|
+
return this._play();
|
|
1142
1082
|
}
|
|
1143
1083
|
|
|
1144
1084
|
/** Pauses the currently playing audio or video
|
|
@@ -1158,24 +1098,11 @@ class RemotePlayer extends EventTarget {
|
|
|
1158
1098
|
throw new RemotePlayerError(6001, "Cannot call pause() if player is not loaded");
|
|
1159
1099
|
}
|
|
1160
1100
|
}
|
|
1161
|
-
|
|
1162
|
-
this._changePlayMode(false);
|
|
1163
|
-
|
|
1164
1101
|
if (this._isSeekingByApplication) {
|
|
1165
1102
|
sdkLogger.info("application requesting pause during seek");
|
|
1166
1103
|
this._targetSeekPlayingState = TargetPlayingState.PAUSED;
|
|
1167
1104
|
return Promise.resolve(true);
|
|
1168
1105
|
}
|
|
1169
|
-
if (this._isSetAudioInProgress) {
|
|
1170
|
-
sdkLogger.info("application requesting pause during setAudioLanguage");
|
|
1171
|
-
this._targetSetAudioPlayingState = TargetPlayingState.PAUSED;
|
|
1172
|
-
return Promise.resolve(true);
|
|
1173
|
-
}
|
|
1174
|
-
if (this._isSetSubtitlesInProgress) {
|
|
1175
|
-
sdkLogger.info("application requesting pause during setSubtitleLanguage");
|
|
1176
|
-
this._targetSetSubtitlePlayingState = TargetPlayingState.PAUSED;
|
|
1177
|
-
return Promise.resolve(true);
|
|
1178
|
-
}
|
|
1179
1106
|
return this._pause();
|
|
1180
1107
|
}
|
|
1181
1108
|
|
|
@@ -1263,6 +1190,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1263
1190
|
const prevSelectedAudioTrack = this._selectedAudioTrack;
|
|
1264
1191
|
for (const track of this.getAudioTracks()) {
|
|
1265
1192
|
if (track.id === audioTrackId) {
|
|
1193
|
+
this._selectedAudioTrack = audioTrackId;
|
|
1266
1194
|
found = true;
|
|
1267
1195
|
break;
|
|
1268
1196
|
}
|
|
@@ -1271,33 +1199,19 @@ class RemotePlayer extends EventTarget {
|
|
|
1271
1199
|
sdkLogger.warn(`Invalid audioTrackId ${audioTrackId}`);
|
|
1272
1200
|
return Promise.resolve();
|
|
1273
1201
|
}
|
|
1274
|
-
if (this.
|
|
1202
|
+
if (this._remotePlayerApiVersion < 2) {
|
|
1203
|
+
return Promise.resolve(); // Resolve immediately for older versions
|
|
1204
|
+
}
|
|
1205
|
+
if (prevSelectedAudioTrack === this._selectedAudioTrack) {
|
|
1275
1206
|
return Promise.resolve(); // Audio language already selected
|
|
1276
1207
|
}
|
|
1277
1208
|
|
|
1278
|
-
|
|
1279
|
-
case 0:
|
|
1280
|
-
case 1:
|
|
1281
|
-
this._selectedAudioTrack = audioTrackId;
|
|
1282
|
-
return Promise.resolve(); // Resolve immediately for older versions
|
|
1283
|
-
case 2:
|
|
1284
|
-
return this._selectAudioTrackV2(audioTrackId, prevSelectedAudioTrack);
|
|
1285
|
-
default:
|
|
1286
|
-
return this._atomicSetAudioLanguage(audioTrackId, prevSelectedAudioTrack);
|
|
1287
|
-
}
|
|
1209
|
+
return this._selectAudioTrack(audioTrackId, prevSelectedAudioTrack);
|
|
1288
1210
|
}
|
|
1289
1211
|
|
|
1290
|
-
|
|
1291
|
-
* Handles the asynchronous selection of an audio track.
|
|
1292
|
-
* If the player is playing, it pauses before changing the track and resumes playback if necessary.
|
|
1293
|
-
*
|
|
1294
|
-
* @param {string} audioTrackId - The ID of the audio track to select.
|
|
1295
|
-
* @param {string} prevSelectedAudioTrack - The previously selected audio track ID.
|
|
1296
|
-
* @returns {Promise<void>} Resolves when the operation is complete.
|
|
1297
|
-
* */
|
|
1298
|
-
async _selectAudioTrackV2(audioTrackId, prevSelectedAudioTrack) {
|
|
1212
|
+
async _selectAudioTrack(audioTrackId, prevSelectedAudioTrack) {
|
|
1299
1213
|
const prevIsPlaying = this._isPlaying;
|
|
1300
|
-
sdkLogger.log(`remotePlayer
|
|
1214
|
+
sdkLogger.log(`remotePlayer _selectAudioTrack: prevAudioTrack=${prevSelectedAudioTrack} audioTrackId=${audioTrackId} isPlaying=${this._isPlaying}`);
|
|
1301
1215
|
try {
|
|
1302
1216
|
if (this._isPlaying) await this.pause();
|
|
1303
1217
|
let position = this.currentTime;
|
|
@@ -1305,9 +1219,9 @@ class RemotePlayer extends EventTarget {
|
|
|
1305
1219
|
position = this._videoElement.currentTime;
|
|
1306
1220
|
}
|
|
1307
1221
|
await this._load(this._loadedUrl, position, audioTrackId, undefined, false);
|
|
1308
|
-
this._selectedAudioTrack = audioTrackId;
|
|
1309
1222
|
} catch (e) {
|
|
1310
|
-
// Do NOT reject - just log
|
|
1223
|
+
// Do NOT reject - just log and revert selection
|
|
1224
|
+
this._selectedAudioTrack = prevSelectedAudioTrack;
|
|
1311
1225
|
sdkLogger.warn(`Failed to select audio track ${audioTrackId}: ${e.message}`);
|
|
1312
1226
|
return;
|
|
1313
1227
|
}
|
|
@@ -1324,62 +1238,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1324
1238
|
}
|
|
1325
1239
|
}
|
|
1326
1240
|
|
|
1327
|
-
/**
|
|
1328
|
-
* Handles the asynchronous selection of an audio track.
|
|
1329
|
-
* If the player is playing, it stops audio streamType before changing the track and resumes audio streamType playback if necessary.
|
|
1330
|
-
* Available only from v3 and on
|
|
1331
|
-
*
|
|
1332
|
-
* @param {string} audioTrackId - The ID of the audio track to select.
|
|
1333
|
-
* @returns {Promise<void>} Resolves when the operation is complete.
|
|
1334
|
-
* */
|
|
1335
|
-
async _selectAudioTrackV3(audioTrackId) {
|
|
1336
|
-
sdkLogger.log(`remotePlayer _selectAudioTrackV3: audioTrackId=${audioTrackId} isPlaying=${this._isPlaying}`);
|
|
1337
|
-
if (window.cefQuery) {
|
|
1338
|
-
const FCID = getFCID();
|
|
1339
|
-
const logger = sdkLogger.withFields({ FCID });
|
|
1340
|
-
logger.log("remotePlayer _selectAudioTrackV3: sending setAudioLanguage action");
|
|
1341
|
-
const message = {
|
|
1342
|
-
type: "remotePlayer.setAudioLanguage",
|
|
1343
|
-
class: "remotePlayer",
|
|
1344
|
-
action: "setAudioLanguage",
|
|
1345
|
-
fcid: FCID,
|
|
1346
|
-
language: audioTrackId
|
|
1347
|
-
};
|
|
1348
|
-
const request = { target: "TC", waitForResponse: true, message: JSON.stringify(message) };
|
|
1349
|
-
return new Promise((resolve, reject) => {
|
|
1350
|
-
let timerId = 0;
|
|
1351
|
-
const timeBeforeSendingRequest = Date.now();
|
|
1352
|
-
const queryId = window.cefQuery({
|
|
1353
|
-
request: JSON.stringify(request),
|
|
1354
|
-
persistent: false,
|
|
1355
|
-
onSuccess: () => {
|
|
1356
|
-
this._selectedAudioTrack = audioTrackId;
|
|
1357
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
1358
|
-
logger.withFields({ duration }).log(`setAudioLanguage completed successfully after ${duration} ms`);
|
|
1359
|
-
timerId = clearTimer(timerId);
|
|
1360
|
-
resolve();
|
|
1361
|
-
},
|
|
1362
|
-
onFailure: (code, msg) => {
|
|
1363
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
1364
|
-
logger.withFields({ duration }).log(`setAudioLanguage failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
|
|
1365
|
-
timerId = clearTimer(timerId);
|
|
1366
|
-
reject(new RemotePlayerError(code, msg));
|
|
1367
|
-
}
|
|
1368
|
-
});
|
|
1369
|
-
logger.log(`window.cefQuery for setAudioLanguage returned query id ${queryId}`);
|
|
1370
|
-
const timeout = this._remotePlayerConfirmationTimeout + 1000;
|
|
1371
|
-
timerId = setTimeout(() => {
|
|
1372
|
-
logger.log(`setAudioLanguage reached timeout of ${timeout} ms, canceling query id ${queryId}`);
|
|
1373
|
-
window.cefQueryCancel(queryId);
|
|
1374
|
-
reject(new RemotePlayerError(6000, `setAudioLanguage reached timeout of ${timeout} ms`));
|
|
1375
|
-
}, timeout, queryId);
|
|
1376
|
-
});
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
sdkLogger.error("remotePlayer _selectAudioTrackV3: window.cefQuery is undefined");
|
|
1380
|
-
return Promise.resolve(undefined);
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
1241
|
/** Select a specific text (subtitle) track.
|
|
1384
1242
|
* Track id should come from a call to getTextTracks.
|
|
1385
1243
|
* If no tracks exist - this is a no-op.
|
|
@@ -1399,6 +1257,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1399
1257
|
const prevSelectedTextTrack = this._selectedSubtitlesTrack;
|
|
1400
1258
|
for (const track of this.getTextTracks()) {
|
|
1401
1259
|
if (track.id === textTrackId) {
|
|
1260
|
+
this._selectedSubtitlesTrack = textTrackId;
|
|
1402
1261
|
found = true;
|
|
1403
1262
|
break;
|
|
1404
1263
|
}
|
|
@@ -1407,20 +1266,14 @@ class RemotePlayer extends EventTarget {
|
|
|
1407
1266
|
sdkLogger.warn(`Invalid textTrackId ${textTrackId}`);
|
|
1408
1267
|
return Promise.resolve();
|
|
1409
1268
|
}
|
|
1410
|
-
if (this.
|
|
1269
|
+
if (this._remotePlayerApiVersion < 2) {
|
|
1270
|
+
return Promise.resolve(); // Resolve immediately for older versions
|
|
1271
|
+
}
|
|
1272
|
+
if (prevSelectedTextTrack === this._selectedSubtitlesTrack) {
|
|
1411
1273
|
return Promise.resolve(); // Subtitle language already selected
|
|
1412
1274
|
}
|
|
1413
1275
|
|
|
1414
|
-
|
|
1415
|
-
case 0:
|
|
1416
|
-
case 1:
|
|
1417
|
-
this._selectedSubtitlesTrack = textTrackId;
|
|
1418
|
-
return Promise.resolve(); // Resolve immediately for older versions
|
|
1419
|
-
case 2:
|
|
1420
|
-
return this._selectTextTrackV2(textTrackId, prevSelectedTextTrack);
|
|
1421
|
-
default:
|
|
1422
|
-
return this._atomicSetSubtitleLanguage(textTrackId, prevSelectedTextTrack);
|
|
1423
|
-
}
|
|
1276
|
+
return this._selectTextTrack(textTrackId, prevSelectedTextTrack);
|
|
1424
1277
|
}
|
|
1425
1278
|
|
|
1426
1279
|
/**
|
|
@@ -1431,9 +1284,9 @@ class RemotePlayer extends EventTarget {
|
|
|
1431
1284
|
* @param {string} prevSelectedTextTrack - The previously selected text track ID.
|
|
1432
1285
|
* @returns {Promise<void>} Resolves when the operation is complete.
|
|
1433
1286
|
* */
|
|
1434
|
-
async
|
|
1287
|
+
async _selectTextTrack(textTrackId, prevSelectedTextTrack) {
|
|
1435
1288
|
const prevIsPlaying = this._isPlaying;
|
|
1436
|
-
sdkLogger.log(`remotePlayer
|
|
1289
|
+
sdkLogger.log(`remotePlayer _selectTextTrack: prevTextTrack=${prevSelectedTextTrack} textTrackId=${textTrackId} isPlaying=${this._isPlaying}`);
|
|
1437
1290
|
try {
|
|
1438
1291
|
if (this._isPlaying) await this.pause();
|
|
1439
1292
|
let position = this.currentTime;
|
|
@@ -1441,9 +1294,9 @@ class RemotePlayer extends EventTarget {
|
|
|
1441
1294
|
position = this._videoElement.currentTime;
|
|
1442
1295
|
}
|
|
1443
1296
|
await this._load(this._loadedUrl, position, undefined, textTrackId, false);
|
|
1444
|
-
this._selectedSubtitlesTrack = textTrackId;
|
|
1445
1297
|
} catch (e) {
|
|
1446
|
-
// Do NOT reject - just log
|
|
1298
|
+
// Do NOT reject - just log and revert selection
|
|
1299
|
+
this._selectedSubtitlesTrack = prevSelectedTextTrack;
|
|
1447
1300
|
sdkLogger.warn(`Failed to select text track ${textTrackId}: ${e.message}`);
|
|
1448
1301
|
return;
|
|
1449
1302
|
}
|
|
@@ -1460,60 +1313,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1460
1313
|
}
|
|
1461
1314
|
}
|
|
1462
1315
|
|
|
1463
|
-
/**
|
|
1464
|
-
* Handles the asynchronous selection of a text track.
|
|
1465
|
-
* If the player is playing, it stops subtitle streamType before changing the track and resumes subtitle streamType playback if necessary.
|
|
1466
|
-
* Available only from v3 and on
|
|
1467
|
-
*
|
|
1468
|
-
* @param {string} textTrackId - The ID of the text track to select.
|
|
1469
|
-
* @returns {Promise<void>} Resolves when the operation is complete.
|
|
1470
|
-
* */
|
|
1471
|
-
async _selectTextTrackV3(textTrackId) {
|
|
1472
|
-
if (window.cefQuery) {
|
|
1473
|
-
const FCID = getFCID();
|
|
1474
|
-
const logger = sdkLogger.withFields({ FCID });
|
|
1475
|
-
logger.log("remotePlayer _selectTextTrackV3: sending setSubtitleLanguage action");
|
|
1476
|
-
const message = {
|
|
1477
|
-
type: "remotePlayer.setSubtitleLanguage",
|
|
1478
|
-
class: "remotePlayer",
|
|
1479
|
-
action: "setSubtitleLanguage",
|
|
1480
|
-
fcid: FCID,
|
|
1481
|
-
language: textTrackId
|
|
1482
|
-
};
|
|
1483
|
-
const request = { target: "TC", waitForResponse: true, message: JSON.stringify(message) };
|
|
1484
|
-
return new Promise((resolve, reject) => {
|
|
1485
|
-
let timerId = 0;
|
|
1486
|
-
const timeBeforeSendingRequest = Date.now();
|
|
1487
|
-
const queryId = window.cefQuery({
|
|
1488
|
-
request: JSON.stringify(request),
|
|
1489
|
-
persistent: false,
|
|
1490
|
-
onSuccess: () => {
|
|
1491
|
-
this._selectedSubtitlesTrack = textTrackId;
|
|
1492
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
1493
|
-
logger.withFields({ duration }).log(`setSubtitleLanguage completed successfully after ${duration} ms`);
|
|
1494
|
-
timerId = clearTimer(timerId);
|
|
1495
|
-
resolve();
|
|
1496
|
-
},
|
|
1497
|
-
onFailure: (code, msg) => {
|
|
1498
|
-
const duration = Date.now() - timeBeforeSendingRequest;
|
|
1499
|
-
logger.withFields({ duration }).log(`setSubtitleLanguage failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
|
|
1500
|
-
timerId = clearTimer(timerId);
|
|
1501
|
-
reject(new RemotePlayerError(code, msg));
|
|
1502
|
-
}
|
|
1503
|
-
});
|
|
1504
|
-
logger.log(`window.cefQuery for setSubtitleLanguage returned query id ${queryId}`);
|
|
1505
|
-
const timeout = this._remotePlayerConfirmationTimeout + 1000;
|
|
1506
|
-
timerId = setTimeout(() => {
|
|
1507
|
-
logger.log(`setSubtitleLanguage reached timeout of ${timeout} ms, canceling query id ${queryId}`);
|
|
1508
|
-
window.cefQueryCancel(queryId);
|
|
1509
|
-
reject(new RemotePlayerError(6000, `setSubtitleLanguage reached timeout of ${timeout} ms`));
|
|
1510
|
-
}, timeout, queryId);
|
|
1511
|
-
});
|
|
1512
|
-
}
|
|
1513
|
-
sdkLogger.error("remotePlayer _selectTextTrackV3: window.cefQuery is undefined");
|
|
1514
|
-
return Promise.resolve(undefined);
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
1316
|
/**
|
|
1518
1317
|
* Enable or disable the subtitles.
|
|
1519
1318
|
* If the player is in an unloaded state, the request will be applied next time content is played.
|
|
@@ -1624,11 +1423,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1624
1423
|
* @private
|
|
1625
1424
|
*/
|
|
1626
1425
|
async _startSeeking(playbackPosition) {
|
|
1627
|
-
if (this._isSetAudioInProgress || this._isSetSubtitlesInProgress) {
|
|
1628
|
-
sdkLogger.info(`Seeking not supported while setAudioLanguage or setSubtitleLanguage are in progress.`);
|
|
1629
|
-
return;
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
1426
|
if (!this._isSeekingByPlatform) {
|
|
1633
1427
|
this._pendingSeekPosition = playbackPosition;
|
|
1634
1428
|
|
|
@@ -1740,11 +1534,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1740
1534
|
// In case where we aborted, we don't want to resume playback.
|
|
1741
1535
|
if (!this._abortSeeking) {
|
|
1742
1536
|
if (this._targetSeekPlayingState === TargetPlayingState.PLAYING_UI) {
|
|
1743
|
-
|
|
1744
|
-
return Promise.resolve(true);
|
|
1745
|
-
}
|
|
1746
|
-
// resume audio play only if _isAudioSyncEnabled
|
|
1747
|
-
this._play(StreamType.AUDIO);
|
|
1537
|
+
this._play();
|
|
1748
1538
|
} else if (this._targetSeekPlayingState === TargetPlayingState.PLAYING_ABR) {
|
|
1749
1539
|
lifecycle._moveToBackground();
|
|
1750
1540
|
}
|
|
@@ -1753,139 +1543,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1753
1543
|
this._isSeekingByApplication = false;
|
|
1754
1544
|
sdkLogger.info("Seeking: local video element seeking end");
|
|
1755
1545
|
}
|
|
1756
|
-
|
|
1757
|
-
async _atomicSetAudioLanguage(audioTrackId, prevSelectedAudioTrack) {
|
|
1758
|
-
if (this._isSetAudioInProgress) {
|
|
1759
|
-
sdkLogger.warn(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} already in progress, ignoring.`);
|
|
1760
|
-
return Promise.resolve();
|
|
1761
|
-
}
|
|
1762
|
-
if (this._isSeekingByApplication) {
|
|
1763
|
-
sdkLogger.warn(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} ignored. seeking is already in progress.`);
|
|
1764
|
-
return Promise.resolve();
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
this._targetSetAudioPlayingState = this._isPlaying ? TargetPlayingState.PLAYING_UI : TargetPlayingState.PAUSED;
|
|
1768
|
-
sdkLogger.log(`remotePlayer _atomicSetAudioLanguage: prevAudioTrack=${prevSelectedAudioTrack} audioTrackId=${audioTrackId} isPlaying=${this._isPlaying} targetState=${this._targetSetAudioPlayingState}`);
|
|
1769
|
-
|
|
1770
|
-
this._abortSetAudioLanguage = false;
|
|
1771
|
-
this._isSetAudioInProgress = true;
|
|
1772
|
-
|
|
1773
|
-
try {
|
|
1774
|
-
await this._stop(StreamType.AUDIO);
|
|
1775
|
-
if (this._abortSetAudioLanguage) {
|
|
1776
|
-
this._isSetAudioInProgress = false;
|
|
1777
|
-
sdkLogger.warn(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} aborted.`);
|
|
1778
|
-
return Promise.resolve();
|
|
1779
|
-
}
|
|
1780
|
-
} catch (error) {
|
|
1781
|
-
this._isSetAudioInProgress = false;
|
|
1782
|
-
sdkLogger.warn(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} failed on stop. aborting.`);
|
|
1783
|
-
return Promise.reject(error);
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
let setLanguageError;
|
|
1787
|
-
try {
|
|
1788
|
-
await this._selectAudioTrackV3(audioTrackId);
|
|
1789
|
-
} catch (error) {
|
|
1790
|
-
sdkLogger.error(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} failed with error ${error.message}.`);
|
|
1791
|
-
if (!this._abortSetAudioLanguage) {
|
|
1792
|
-
setLanguageError = error;
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
// check if load/unload were called
|
|
1797
|
-
if (this._abortSetAudioLanguage) {
|
|
1798
|
-
this._isSetAudioInProgress = false;
|
|
1799
|
-
sdkLogger.warn(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} aborted.`);
|
|
1800
|
-
return Promise.resolve();
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
try {
|
|
1804
|
-
if (this._targetSetAudioPlayingState === TargetPlayingState.PLAYING_UI) {
|
|
1805
|
-
if (!this._isAudioSyncEnabled()) {
|
|
1806
|
-
this._isSetAudioInProgress = false;
|
|
1807
|
-
return Promise.resolve(true);
|
|
1808
|
-
}
|
|
1809
|
-
// resume audio play only if _isAudioSyncEnabled
|
|
1810
|
-
await this._play(StreamType.AUDIO);
|
|
1811
|
-
} else if (this._targetSetAudioPlayingState === TargetPlayingState.PLAYING_ABR) {
|
|
1812
|
-
await lifecycle._moveToBackground();
|
|
1813
|
-
}
|
|
1814
|
-
} catch(error) {
|
|
1815
|
-
sdkLogger.error(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} play failed with error ${error.message}.`);
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
this._isSetAudioInProgress = false;
|
|
1819
|
-
sdkLogger.log(`remotePlayer _atomicSetAudioLanguage: audioTrackId=${audioTrackId} ended.`);
|
|
1820
|
-
return setLanguageError ? Promise.reject(setLanguageError) : Promise.resolve();
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
|
-
async _atomicSetSubtitleLanguage(textTrackId, prevSelectedTextTrack) {
|
|
1824
|
-
if (this._isSetSubtitlesInProgress) {
|
|
1825
|
-
sdkLogger.warn(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} already in progress., ignoring.`);
|
|
1826
|
-
return Promise.resolve();
|
|
1827
|
-
}
|
|
1828
|
-
if (this._isSeekingByApplication) {
|
|
1829
|
-
sdkLogger.warn(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} ignored. seeking is already in progress.`);
|
|
1830
|
-
return Promise.resolve();
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
this._targetSetSubtitlePlayingState = this._isPlaying ? TargetPlayingState.PLAYING_UI : TargetPlayingState.PAUSED;
|
|
1834
|
-
sdkLogger.log(`remotePlayer _atomicSetSubtitleLanguage: prevTextTrack=${prevSelectedTextTrack} textTrackId=${textTrackId} isPlaying=${this._isPlaying} targetState=${this._targetSetSubtitlePlayingState}`);
|
|
1835
|
-
|
|
1836
|
-
this._abortSetSubtitleLanguage = false;
|
|
1837
|
-
this._isSetSubtitlesInProgress = true;
|
|
1838
|
-
|
|
1839
|
-
try {
|
|
1840
|
-
await this._stop(StreamType.SUBTITLE);
|
|
1841
|
-
if (this._abortSetSubtitleLanguage) {
|
|
1842
|
-
this._isSetSubtitlesInProgress = false;
|
|
1843
|
-
sdkLogger.warn(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} aborted.`);
|
|
1844
|
-
return Promise.resolve();
|
|
1845
|
-
}
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
this._isSetSubtitlesInProgress = false;
|
|
1848
|
-
sdkLogger.warn(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} failed on stop. aborting.`);
|
|
1849
|
-
return Promise.reject(error);
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
let setLanguageError;
|
|
1853
|
-
try {
|
|
1854
|
-
await this._selectTextTrackV3(textTrackId);
|
|
1855
|
-
} catch (error) {
|
|
1856
|
-
sdkLogger.error(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} failed with error ${error.message}.`);
|
|
1857
|
-
if (!this._abortSetSubtitleLanguage) {
|
|
1858
|
-
setLanguageError = error;
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
|
|
1862
|
-
// check if load/unload were called
|
|
1863
|
-
if (this._abortSetSubtitleLanguage) {
|
|
1864
|
-
this._isSetSubtitlesInProgress = false;
|
|
1865
|
-
sdkLogger.warn(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} aborted.`);
|
|
1866
|
-
return Promise.resolve();
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1869
|
-
try {
|
|
1870
|
-
if (this._targetSetSubtitlePlayingState === TargetPlayingState.PLAYING_UI) {
|
|
1871
|
-
if (!this._isAudioSyncEnabled()) {
|
|
1872
|
-
this._isSetSubtitlesInProgress = false;
|
|
1873
|
-
return Promise.resolve(true);
|
|
1874
|
-
}
|
|
1875
|
-
// resume audio play only if _isAudioSyncEnabled
|
|
1876
|
-
await this._play(StreamType.AUDIO);
|
|
1877
|
-
} else if (this._targetSetSubtitlePlayingState === TargetPlayingState.PLAYING_ABR) {
|
|
1878
|
-
await lifecycle._moveToBackground();
|
|
1879
|
-
}
|
|
1880
|
-
} catch (error) {
|
|
1881
|
-
sdkLogger.error(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} play failed with error ${error.message}.`);
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
this._isSetSubtitlesInProgress = false;
|
|
1885
|
-
sdkLogger.log(`remotePlayer _atomicSetSubtitleLanguage: textTrackId=${textTrackId} ended.`);
|
|
1886
|
-
return setLanguageError ? Promise.reject(setLanguageError) : Promise.resolve();
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
1546
|
}
|
|
1890
1547
|
/**
|
|
1891
1548
|
*
|