senza-sdk 4.2.65-d2761c0.0 → 4.3.1-ca3d96f.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.
Files changed (27) hide show
  1. package/dist/bundle.js +1 -1
  2. package/package.json +17 -8
  3. package/src/api.js +258 -327
  4. package/src/{alarmManager.js → implementation/alarmManager.js} +15 -52
  5. package/src/implementation/api.js +363 -0
  6. package/src/{deviceManager.js → implementation/deviceManager.js} +6 -78
  7. package/src/{lifecycle.js → implementation/lifecycle.js} +37 -225
  8. package/src/implementation/messageManager.js +55 -0
  9. package/src/{platformManager.js → implementation/platformManager.js} +5 -23
  10. package/src/{remotePlayer.js → implementation/remotePlayer.js} +35 -237
  11. package/src/{senzaShakaPlayer.js → implementation/senzaShakaPlayer.js} +92 -125
  12. package/src/{utils.js → implementation/utils.js} +15 -6
  13. package/src/interface/alarmManager.js +76 -0
  14. package/src/interface/api.js +8 -0
  15. package/src/{devSequence.js → interface/devSequence.js} +35 -0
  16. package/src/interface/deviceManager.js +142 -0
  17. package/src/interface/lifecycle.js +283 -0
  18. package/src/interface/messageManager.js +53 -0
  19. package/src/interface/platformManager.js +41 -0
  20. package/src/interface/remotePlayer.js +470 -0
  21. package/src/interface/senzaShakaPlayer.js +168 -0
  22. package/src/interface/utils.js +45 -0
  23. package/src/messageManager.js +0 -88
  24. /package/src/{SessionInfo.js → implementation/SessionInfo.js} +0 -0
  25. /package/src/{devHelper.js → implementation/devHelper.js} +0 -0
  26. /package/src/{eventListenersManager.js → implementation/eventListenersManager.js} +0 -0
  27. /package/src/{subtitlesUtils.js → implementation/subtitlesUtils.js} +0 -0
@@ -1,6 +1,9 @@
1
- import * as shaka from "shaka-player";
1
+ import { SenzaShakaPlayer as SenzaShakaInterface, shaka } from "../interface/senzaShakaPlayer";
2
+
2
3
  import { remotePlayer, lifecycle, getPlatformInfo } from "./api";
3
4
  import { sdkLogger, iso6393to1 } from "./utils";
5
+ import moment from "moment";
6
+
4
7
 
5
8
  // Define custom error category
6
9
  shaka.util.Error.Category.SENZA_PLAYER_ERROR = 50;
@@ -30,31 +33,7 @@ class SenzaError extends shaka.util.Error {
30
33
  }
31
34
 
32
35
 
33
- // Copy the shaka module and replace the Player class with SenzaShakaPlayer
34
- // if we don't Copy the shaka module, the Player class will be replaced for all the other modules that import shaka
35
- const senzaShaka = { ...shaka };
36
-
37
-
38
- /**
39
- * SenzaShakaPlayer subclass of Shaka that handles both local and remote playback.
40
- *
41
- * @class SenzaShakaPlayer
42
- *
43
- * @example
44
- * import { SenzaShakaPlayer } from "./senzaShakaPlayer.js";
45
- *
46
- * try {
47
- * const videoElement = document.getElementById("video");
48
- * const player = new SenzaShakaPlayer(videoElement);
49
- * await player.load("http://playable.url/file.mpd");
50
- * await videoElement.play(); // will start the playback
51
- *
52
- * } catch (err) {
53
- * console.error("SenzaShakaPlayer failed with error", err);
54
- * }
55
- */
56
-
57
- export class SenzaShakaPlayer extends shaka.Player {
36
+ export class SenzaShakaPlayer extends SenzaShakaInterface {
58
37
  /** @private {SenzaShakaPlayer|null} Previous instance of the player */
59
38
  static _prevInstance = null;
60
39
 
@@ -76,7 +55,7 @@ export class SenzaShakaPlayer extends shaka.Player {
76
55
  * @private
77
56
  * @type {number}
78
57
  * @description Timeout in milliseconds to wait for playing event
79
- * @default 3000
58
+ * @default 4000
80
59
  */
81
60
  _playingTimeout = 4000;
82
61
 
@@ -139,7 +118,7 @@ export class SenzaShakaPlayer extends shaka.Player {
139
118
  });
140
119
  }
141
120
  },
142
- "pause" : () => {
121
+ "pause": () => {
143
122
  this._resetPlayPromise();
144
123
  this.remotePlayer.pause()
145
124
  .catch(error => {
@@ -185,7 +164,7 @@ export class SenzaShakaPlayer extends shaka.Player {
185
164
  originatesFromRemotePlayer: true
186
165
  };
187
166
 
188
- const response = await this.getNetworkingEngine().request(senzaShaka.net.NetworkingEngine.RequestType.LICENSE, request).promise;
167
+ const response = await this.getNetworkingEngine().request(shaka.net.NetworkingEngine.RequestType.LICENSE, request).promise;
189
168
 
190
169
  let responseBody = response.data;
191
170
  if (response.status < 200 || response.status >= 300) {
@@ -306,13 +285,44 @@ export class SenzaShakaPlayer extends shaka.Player {
306
285
  }
307
286
 
308
287
  /**
309
- * Creates an instance of SenzaShakaPlayer, which is a subclass of shaka.Player.
310
- *
311
- * @param {HTMLVideoElement} videoElement - The video element to be used for local playback. This parameter is optional. If not provided, the video element can be attached later using the attach method.
312
- * @param {HTMLElement=} videoContainer - The videoContainer to construct UITextDisplayer
313
- * @param {function(shaka.Player)=} dependencyInjector Optional callback
314
- * which is called to inject mocks into the Player. Used for testing.
288
+ * @private
289
+ * @type {number}
290
+ * @description Minimum suggested presentation delay in seconds
291
+ * @default 15
315
292
  */
293
+ _minSuggestedPresentationDelay = 15;
294
+
295
+ /**
296
+ * Modifies the suggestedPresentationDelay in the manifest text
297
+ * @private
298
+ * @param {string} manifestText - The MPD manifest text
299
+ * @returns {string} - Modified manifest text , or undefined if no modification was done
300
+ */
301
+ _updateManifestDelayIfBelowMinimum(manifestText) {
302
+ // Look for suggestedPresentationDelay attribute
303
+ const match = manifestText.match(/suggestedPresentationDelay="([^"]+)"/);
304
+ if (match) {
305
+ const durationString = match[1];
306
+ const duration = moment.duration(durationString);
307
+ const currentDelay = duration.asSeconds();
308
+
309
+ sdkLogger.info(`Found suggestedPresentationDelay in manifest: ${currentDelay.toFixed(3)}s`);
310
+
311
+ if (currentDelay < this._minSuggestedPresentationDelay) {
312
+ // Replace the value in the manifest text with 3 decimal places
313
+ manifestText = manifestText.replace(
314
+ /suggestedPresentationDelay="[^"]+"/,
315
+ `suggestedPresentationDelay="PT${this._minSuggestedPresentationDelay.toFixed(3)}S"`
316
+ );
317
+ sdkLogger.info(`Updated manifest suggestedPresentationDelay to ${this._minSuggestedPresentationDelay.toFixed(3)}s`);
318
+ return manifestText;
319
+ }
320
+ } else {
321
+ sdkLogger.info("suggestedPresentationDelay is not defined at the manifest");
322
+ }
323
+ return undefined;
324
+ }
325
+
316
326
  constructor(videoElement, videoContainer, dependencyInjector) {
317
327
  super(videoElement, videoContainer, dependencyInjector);
318
328
 
@@ -330,7 +340,14 @@ export class SenzaShakaPlayer extends shaka.Player {
330
340
  this._addRemotePlayerEventListeners();
331
341
  SenzaShakaPlayer._prevInstance = this;
332
342
  const playTimeout = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"]?.playingEventTimeout;
333
- this._playingTimeout = (playTimeout >= 0) ? playTimeout*1000 : this._playingTimeout;
343
+ this._playingTimeout = (playTimeout >= 0) ? playTimeout * 1000 : this._playingTimeout;
344
+
345
+ // Initialize minSuggestedPresentationDelay from UI settings or use default
346
+ const uiSettings = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"];
347
+ if (uiSettings?.minSuggestedPresentationDelay !== undefined) {
348
+ this._minSuggestedPresentationDelay = uiSettings.minSuggestedPresentationDelay;
349
+ sdkLogger.info(`Using configured minSuggestedPresentationDelay: ${this._minSuggestedPresentationDelay}s`);
350
+ }
334
351
 
335
352
  // if video element is provided, add the listeres here. In this case ,there is no need to call attach.
336
353
  if (videoElement) {
@@ -338,8 +355,25 @@ export class SenzaShakaPlayer extends shaka.Player {
338
355
  sdkLogger.warn("SenzaShakaPlayer constructor Adding videoElement in the constructor is going to be deprecated in the future. Please use attach method instead.");
339
356
  }
340
357
 
358
+ this.configure({
359
+ manifest: {
360
+ defaultPresentationDelay: this._minSuggestedPresentationDelay // in seconds
361
+ }
362
+ });
363
+
364
+ remotePlayer.configure({
365
+ minSuggestedPresentationDelay: this._minSuggestedPresentationDelay
366
+ });
367
+
368
+ this.addEventListener("buffering", () => {
369
+ if (this.videoElement) {
370
+ sdkLogger.info("Buffering at time:", this.videoElement.currentTime);
371
+ }
372
+ });
373
+
341
374
  }
342
375
 
376
+
343
377
  _attach(videoElement) {
344
378
  this.videoElement = videoElement;
345
379
 
@@ -386,27 +420,11 @@ export class SenzaShakaPlayer extends shaka.Player {
386
420
  this._attachVideoElementToRemotePlayer();
387
421
  }
388
422
 
389
- /**
390
- * Overrides the attach method of shaka.Player to attach the video element.
391
- *
392
- * @param {HTMLVideoElement} videoElement - The video element to be used for local playback.
393
- * @param {boolean} [initializeMediaSource=true] - Whether to initialize the media source.
394
- */
395
423
  async attach(videoElement, initializeMediaSource = true) {
396
424
  await super.attach(videoElement, initializeMediaSource);
397
425
  this._attach(videoElement);
398
426
  }
399
427
 
400
- /**
401
- * Detach the player from the current media element. Leaves the player in a
402
- * state where it cannot play media, until it has been attached to something
403
- * else.
404
- *
405
- * @param {boolean=} keepAdManager
406
- *
407
- * @return {!Promise}
408
- * @export
409
- */
410
428
  async detach(keepAdManager = false) {
411
429
  // Clear any pending timeout
412
430
  this._resetPlayPromise();
@@ -437,14 +455,6 @@ export class SenzaShakaPlayer extends shaka.Player {
437
455
  this.videoElement = null;
438
456
  }
439
457
 
440
- /**
441
- * Unloads the currently playing stream, if any.
442
- *
443
- * @param {boolean=} initializeMediaSource
444
- * @param {boolean=} keepAdManager
445
- * @return {!Promise}
446
- * @export
447
- */
448
458
  async unload(initializeMediaSource = true, keepAdManager = false) {
449
459
  // Call the remote player's unload method
450
460
  try {
@@ -459,27 +469,14 @@ export class SenzaShakaPlayer extends shaka.Player {
459
469
  await super.unload(initializeMediaSource, keepAdManager);
460
470
  }
461
471
 
462
- /**
463
- * Overrides the getTextTracks method to use the remote player's text tracks.
464
- * @returns {Array} An array of text tracks.
465
- */
466
472
  getTextLanguages() {
467
473
  return Object.keys(this._textTracksMap);
468
474
  }
469
475
 
470
- /**
471
- * Overrides the getAudioTracks method to use the remote player's audio tracks.
472
- * @returns {Array} An array of audio tracks.
473
- */
474
476
  getAudioLanguages() {
475
477
  return Object.keys(this._audioTracksMap);
476
478
  }
477
479
 
478
- /**
479
- * Overrides the selectAudioLanguage method to use the remote player's audio track selection.
480
- * @param {string} language - The language to select.
481
- * @param {string=} role - The role of the track to select. (e.g. 'main', 'caption', or 'commentary')
482
- */
483
480
  selectAudioLanguage(language, role) {
484
481
  sdkLogger.log("Selecting audio language:", language, "with role: ", role);
485
482
  if (this._audioTracksMap[language]) {
@@ -490,11 +487,6 @@ export class SenzaShakaPlayer extends shaka.Player {
490
487
  super.selectAudioLanguage(language, role);
491
488
  }
492
489
 
493
- /**
494
- * Overrides the selectTextLanguage method to use the remote player's text track selection.
495
- * @param {string} language - The language to select.
496
- * @param {string=} role - The role of the track to select.
497
- */
498
490
  selectTextLanguage(language, role) {
499
491
  sdkLogger.log("Selecting text language:", language, "with role:", role);
500
492
  if (this._textTracksMap[language]) {
@@ -505,20 +497,12 @@ export class SenzaShakaPlayer extends shaka.Player {
505
497
  super.selectTextLanguage(language, role);
506
498
  }
507
499
 
508
- /**
509
- * Overrides the setTextTrackVisibility method to use the remote player's text track visibility settings.
510
- * @param {boolean} visible - Whether the text tracks should be visible.
511
- */
512
500
  setTextTrackVisibility(visible) {
513
501
  sdkLogger.log("Setting text track visibility to:", visible);
514
502
  remotePlayer.setTextTrackVisibility(visible);
515
503
  super.setTextTrackVisibility(visible);
516
504
  }
517
505
 
518
- /**
519
- * Helper function that makes it easier to check if lifecycle.state is
520
- * either background or inTransitionToBackground.
521
- */
522
506
  get isInRemotePlayback() {
523
507
  return lifecycle.state === lifecycle.UiState.BACKGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_BACKGROUND;
524
508
  }
@@ -584,12 +568,6 @@ export class SenzaShakaPlayer extends shaka.Player {
584
568
  this.dispatchEvent(new shaka.util.FakeEvent("error", errorMap));
585
569
  }
586
570
 
587
- /**
588
- * Loads a media URL into both local and remote players.
589
- *
590
- * @param {string} url - The URL of the media to load.
591
- * @returns {Promise<void>}
592
- */
593
571
  async load(url, startTime, mimeType) {
594
572
 
595
573
  // Create a promise that will resolve when _remotePlayerLoad is called
@@ -618,16 +596,30 @@ export class SenzaShakaPlayer extends shaka.Player {
618
596
 
619
597
  // This callbakc will be activated when the manifest is loaded. It will trigger load of the remote player.
620
598
  // This will ensure that the remote player is loaded only after the manifest is loaded by local player.
621
- const responseFilterCallback = async (type) => {
622
- if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST && !manifestLoadHandled) {
623
- manifestLoadHandled = true;
599
+ const responseFilterCallback = async (type, response) => {
600
+ if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST) {
624
601
  try {
625
- await this._remotePlayerLoad(url, startTime);
626
- remoteLoadResolver();
602
+ if (response.data && this._minSuggestedPresentationDelay > 0) {
603
+ const manifestText = new TextDecoder().decode(response.data);
604
+ const modifiedText = this._updateManifestDelayIfBelowMinimum(manifestText);
605
+ if (modifiedText) {
606
+ const responseData = new TextEncoder().encode(modifiedText).buffer;
607
+ response.data = responseData;
608
+ }
609
+ }
627
610
  } catch (error) {
628
- remoteLoadRejecter(error);
611
+ sdkLogger.error("Error processing manifest:", error);
629
612
  }
630
613
 
614
+ if (!manifestLoadHandled) {
615
+ manifestLoadHandled = true;
616
+ try {
617
+ await this._remotePlayerLoad(url, startTime);
618
+ remoteLoadResolver();
619
+ } catch (error) {
620
+ remoteLoadRejecter(error);
621
+ }
622
+ }
631
623
  }
632
624
  };
633
625
 
@@ -662,13 +654,6 @@ export class SenzaShakaPlayer extends shaka.Player {
662
654
 
663
655
  }
664
656
 
665
- /***
666
- *
667
- * Configure the Player instance.
668
- * @param {Object} config the configuration object
669
- * @returns {Boolean}
670
- */
671
-
672
657
  async destroy() {
673
658
  await lifecycle.moveToForeground();
674
659
  SenzaShakaPlayer._prevInstance = null;
@@ -676,10 +661,6 @@ export class SenzaShakaPlayer extends shaka.Player {
676
661
  return super.destroy();
677
662
  }
678
663
 
679
- /**
680
- * A temporary override for older versions of Shaka.
681
- * Senza doesn't support out-of-band subtitles
682
- */
683
664
  addTextTrack(uri, language, kind, mimeType, codec, label, forced = false) {
684
665
  sdkLogger.warn("addTextTrack is deprecated, please use addTextTrackAsync");
685
666
  super.addTextTrackAsync(uri, language, kind, mimeType, codec, label, forced).then(subs => {
@@ -687,20 +668,6 @@ export class SenzaShakaPlayer extends shaka.Player {
687
668
  });
688
669
  }
689
670
 
690
- /**
691
- * Override the configure method to add custom configuration handling
692
- * Supports the following additional configuration options:
693
- * - shouldStopOnRemotePlayerError: boolean - If true, local player will be stopped on remote player error
694
- *
695
- * @override
696
- * @param {Object} config - Configuration object to be merged with existing config
697
- * @param {boolean} [config.shouldStopOnRemotePlayerError=true] - Whether to stop local player on remote player error
698
- * @example
699
- * player.configure({
700
- * shouldStopOnRemotePlayerError: false, // Don't stop local playback on remote player error
701
- * // ... other shaka configurations
702
- * });
703
- */
704
671
  configure(config) {
705
672
  sdkLogger.log("configure player with: ", JSON.stringify(config));
706
673
 
@@ -810,5 +777,5 @@ export class SenzaShakaPlayer extends shaka.Player {
810
777
 
811
778
  }
812
779
 
813
- senzaShaka.Player = SenzaShakaPlayer;
814
- export { senzaShaka as shaka };
780
+ shaka.Player = SenzaShakaPlayer;
781
+ export { shaka };
@@ -1,10 +1,15 @@
1
1
  import { getPlatformInfo } from "./api";
2
- import pack from "../package.json";
3
2
  import { sessionInfo } from "./SessionInfo";
4
- const { version } = pack;
5
3
 
6
4
  const REST_RESPONSE_TIMEOUT_SECONDS = 5;
7
5
 
6
+ export function getVersion() {
7
+ return typeof IMPLEMENTATION_VERSION !== "undefined"
8
+ // eslint-disable-next-line no-undef
9
+ ? IMPLEMENTATION_VERSION
10
+ : "unknown";
11
+ };
12
+
8
13
  export function getFCID() {
9
14
  return Math.round(Math.random() * 100000) + "-" + getPlatformInfo().sessionInfo?.connectionId;
10
15
  }
@@ -42,7 +47,7 @@ class SdkLogger {
42
47
  console.info(`[hs-sdk] [metrics] ${JSON.stringify(metricObj)}`);
43
48
  }
44
49
  withFields(logFields) {
45
- return new SdkLogger({...this.logFields, ...logFields});
50
+ return new SdkLogger({ ...this.logFields, ...logFields });
46
51
  }
47
52
  formatLogString(data) {
48
53
  let logString = "[hs-sdk] " + data.join(" ");
@@ -51,9 +56,13 @@ class SdkLogger {
51
56
  }
52
57
  return logString;
53
58
  }
59
+ addfields(fields) {
60
+ this.logFields = { ...this.logFields, ...fields };
61
+ return this;
62
+ }
54
63
  }
55
64
 
56
- export const sdkLogger = new SdkLogger({sdkVersion: version, url: window?.location?.href ?? ""});
65
+ export const sdkLogger = new SdkLogger({ sdkVersion: getVersion(), url: window?.location?.href ?? "" });
57
66
 
58
67
  export async function getRestResponse(messageName) {
59
68
 
@@ -64,14 +73,14 @@ export async function getRestResponse(messageName) {
64
73
 
65
74
  return new Promise((resolve, reject) => {
66
75
  const FCID = getFCID();
67
- const logger = sdkLogger.withFields({FCID});
76
+ const logger = sdkLogger.withFields({ FCID });
68
77
  const message = {
69
78
  type: "restRequest",
70
79
  name: messageName,
71
80
  method: "GET",
72
81
  fcid: FCID
73
82
  };
74
- const request = {target: "TC", waitForResponse: true, message: JSON.stringify(message)};
83
+ const request = { target: "TC", waitForResponse: true, message: JSON.stringify(message) };
75
84
  let timeoutHandler = 0;
76
85
  const queryId = window.cefQuery({
77
86
  request: JSON.stringify(request),
@@ -0,0 +1,76 @@
1
+ import { noop } from "./utils";
2
+
3
+ /**
4
+ * alarm event
5
+ *
6
+ * @event AlarmManager#MyAlarm
7
+ * @description Fired when time of 'MyAlarm' arrives. If this alarm triggers the application load and the application doesn't call
8
+ * lifecycle.moveToForeground() in the alarm callback (i.e. the application remains in the background after the callback is completed),
9
+ * the application will be unloaded.
10
+ * NOTE: If you perform async operations in the callback (without moving to foreground), you must wait for the async
11
+ * operation to finish before returning from the callback, otherwise the application will be unloaded before the async operation is finished.<br>
12
+ * @example
13
+ * alarmManager.addEventListener("MyAlarm", async (e) => {
14
+ * console.log("alarm MyAlarm arrived with data", e.detail);
15
+ * await fetch("http://www.example.com");
16
+ * });
17
+ * alarmManager.addAlarm("MyAlarm", Date.now() + 60*60*1000, "MyData");
18
+ */
19
+
20
+ /**
21
+ * AlarmManager is a singleton class that manages the alarms in the application. It fires events whose types are the names of the alarms.
22
+ * @fires MyAlarm
23
+ */
24
+ export class AlarmManager extends EventTarget {
25
+
26
+ addEventListener(type, callback) {
27
+ noop("AlarmManager.addEventListener", type, callback);
28
+ }
29
+
30
+ removeEventListener(type, callback) {
31
+ noop("AlarmManager.removeEventListener", type, callback);
32
+ }
33
+
34
+ /** Set alarm to be fired at the specified time, event when ui is released
35
+ * @param {string} alarmName unique name for the alarm
36
+ * @param {number} alarmTime target time for the alarm to be fired, represented by the number of milliseconds elapsed since the epoch
37
+ * @param {string} [data] data to be passed back when the alarm is fired
38
+ * */
39
+ addAlarm(alarmName, alarmTime, data = "", toleranceBefore = 0, toleranceAfter = 0) {
40
+ noop("AlarmManager.addAlarm", alarmName, alarmTime, data, toleranceBefore, toleranceAfter);
41
+ }
42
+
43
+ /** Delete the specified alarm
44
+ * @param {string} alarmName name of alarm to be deleted
45
+ *
46
+ * */
47
+ deleteAlarm(alarmName) {
48
+ noop("AlarmManager.deleteAlarm", alarmName);
49
+ }
50
+
51
+ /** Delete all alarms
52
+ *
53
+ * */
54
+ deleteAllAlarms() {
55
+ noop("AlarmManager.deleteAllAlarms");
56
+ }
57
+
58
+ /** Async function that asks for all active alarms
59
+ * @returns {Promise} when resolved, returns an array of objects containing alarmName and alarmTime fields
60
+ * @throws {string} error string in case of an error
61
+ *
62
+ * */
63
+ getActiveAlarms() {
64
+ return noop("AlarmManager.getActiveAlarms");
65
+ }
66
+ }
67
+
68
+ /**
69
+ * @module
70
+ * @type {AlarmManager}
71
+ * @example
72
+ * import { alarmManager } from "senza-sdk";
73
+ *
74
+ * @return {AlarmManager} pointer to the AlarmManager singleton
75
+ */
76
+ "needed for the module doc comment to be recognized";
@@ -0,0 +1,8 @@
1
+ export { Lifecycle } from "./lifecycle.js";
2
+ export { DeviceManager } from "./deviceManager.js";
3
+ export { PlatformManager } from "./platformManager.js";
4
+ export { AlarmManager } from "./alarmManager.js";
5
+ export { MessageManager } from "./messageManager.js";
6
+ export { RemotePlayer } from "./remotePlayer.js";
7
+ export { SenzaShakaPlayer as ShakaPlayer, shaka } from "./senzaShakaPlayer.js";
8
+ export { showSequence, initSequence } from "./devSequence.js";
@@ -204,6 +204,7 @@ const setupSequence = (components, items) => {
204
204
  };
205
205
  methodInject(components, inject, (name) => name.startsWith("_") || name.startsWith("get"));
206
206
  handleKeys(items);
207
+ playersEvents(components, items);
207
208
  sdkLogger.log("Sequence initialized.");
208
209
  };
209
210
 
@@ -257,3 +258,37 @@ export const showSequence = (visible = true) => {
257
258
  }
258
259
  container.style.visibility = visible ? "visible" : "hidden";
259
260
  };
261
+ function playersEvents(components, items) {
262
+ components.remotePlayer.addEventListener("videoelementattached", () => {
263
+ const video = components.remotePlayer._videoElement;
264
+ if (video && !video._devSequenceRateChangeHandler) {
265
+ video._devSequenceRateChangeHandler = () => {
266
+ items.push({
267
+ component: "localPlayer",
268
+ id: "ratechange=" + video.playbackRate,
269
+ time: performance.now() - currentTime
270
+ });
271
+ };
272
+ video.addEventListener("ratechange", video._devSequenceRateChangeHandler);
273
+ }
274
+
275
+ if (video && !video._devSequencePlayingHandler) {
276
+ video._devSequencePlayingHandler = () => {
277
+ items.push({
278
+ component: "localPlayer",
279
+ id: "playing event",
280
+ time: performance.now() - currentTime
281
+ });
282
+ };
283
+ video.addEventListener("playing", video._devSequencePlayingHandler);
284
+ }
285
+ });
286
+ components.remotePlayer.addEventListener("playing", () => {
287
+ items.push({
288
+ component: "remotePlayer",
289
+ id: "playing event",
290
+ time: performance.now() - currentTime
291
+ });
292
+ });
293
+ }
294
+