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