rx-player 3.28.0-dev.2022061700 → 3.28.0-dev.2022062000

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/CHANGELOG.md CHANGED
@@ -1,27 +1,28 @@
1
1
  # Changelog
2
2
 
3
- ## v3.28.0-dev.2022061700 (2022-06-17)
3
+ ## v3.28.0
4
4
 
5
5
  ### Features
6
6
 
7
7
  - Add `label` to audio, video and text track APIs (such as `getAvailableAudioTracks`) which gives a human-readable description of the corresponding track, if available in the Manifest [#1105, #1109]
8
8
  - Automatically set the LogLevel to `"DEBUG"` if a global `__RX_PLAYER_DEBUG_MODE__` constant is set to `true`, to simplify debugging [#1115]
9
- - TTML: Add support for percent based thickness for textOutline in TTML Subtitles [#1108]
10
9
 
11
10
  ### Bug fixes
12
11
 
13
12
  - Use the first **compatible** codec of the current AdaptationSet when creating a SourceBuffer [#1094]
14
13
  - DASH/DRM: Fix potential infinite rebuffering when a KID is not anounced in the MPD [#1113]
14
+ - DRM: Fix quality fallback when loading a content whose license has been cached under an extended `singleLicensePer` setting and when starting (and staying) with a quality whose key id is not in it [#1133]
15
15
  - DASH: Avoid infinite loop due to rounding errors while parsing multi-Periods MPDs [#1111, #1110]
16
+ - After a `RELOADING` state, stay in `PAUSED` if the media element was paused synchronously before the side-effect which triggered the reloading (usually coming from the API) was perform [#1132]
16
17
  - Fix issue with `maxVideoBufferSize` setting which could lead to too much data being buffered [#1125]
17
18
  - Prevent possibility of requests loops and infinite rebuffering when a pushed segment is always completely and immediately garbage collected by the browser [#1123]
18
19
  - DASH: Fix issues that could arise if a segment is calculated to start at a negative position [#1122]
19
20
  - DASH: Fix possibility of wrong segments being requested when a SegmentTimeline in a given Period (whose Period@end is set) had an S@r set to `-1` at its end [#1098]
20
21
  - DASH: If the first `<S>` has its S@t attribute not set, make as if it is set to `0` [#1118]
21
- - Reload in the paused state when the action that lead to reloading was performed directly as the RxPlayer went into the `PAUSED` state [#1132]
22
22
 
23
23
  ### Other improvements
24
24
 
25
+ - TTML: Add support for percent based thickness for textOutline in TTML Subtitles [#1108]
25
26
  - If seeking after the last potential position, load last segments before ending [#1097]
26
27
  - The duration set on the media element is now only relative to the current chosen tracks (it was previously relative to all potential track). This allows to seek later when switching e.g. to a longer video track [#1102]
27
28
  - Errors coming from an HTMLMediaElement now have the browser's error message if it exists [#1112]
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.28.0-dev.2022061700
1
+ 3.28.0-dev.2022062000
package/appveyor.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # Test against the latest version of this Node.js version
2
2
  environment:
3
- nodejs_version: "12"
3
+ nodejs_version: "16"
4
4
 
5
5
  branches:
6
6
  only:
@@ -23,8 +23,10 @@ import { IPendingRequestStoreBegin, IPendingRequestStoreProgress } from "./utils
23
23
  /**
24
24
  * Select the most adapted Representation according to the network and buffer
25
25
  * metrics it receives.
26
+ *
26
27
  * @param {Object} options - Initial configuration (see type definition)
27
- * @returns {Object} - Interface allowing to select a Representation
28
+ * @returns {Object} - Interface allowing to select a Representation.
29
+ * @see IRepresentationEstimator
28
30
  */
29
31
  export default function createAdaptiveRepresentationSelector(options: IAdaptiveRepresentationSelectorArguments): IRepresentationEstimator;
30
32
  /**
@@ -175,11 +177,7 @@ export interface IABRFiltersObject {
175
177
  */
176
178
  width?: number;
177
179
  }
178
- /**
179
- * Callbacks returned by `getEstimateReference`.
180
- * Those needs to be called as soon as the corresponding events to obtain
181
- * coherent Representation estimates.
182
- */
180
+ /** Callbacks returned by `getEstimateReference`. */
183
181
  export interface IRepresentationEstimatorCallbacks {
184
182
  /** Callback to call when a segment has been completely pushed to the buffer. */
185
183
  addedSegment(val: IAddedSegmentCallbackPayload): void;
@@ -303,14 +301,37 @@ export interface IRepresentationEstimatorArguments {
303
301
  * Type of the function returned by `createAdaptiveRepresentationSelector`,
304
302
  * allowing to estimate the most adapted `Representation`.
305
303
  */
306
- export declare type IRepresentationEstimator = (context: {
304
+ export declare type IRepresentationEstimator = (
305
+ /** Information on the content for which a Representation will be chosen */
306
+ context: {
307
307
  manifest: Manifest;
308
308
  period: Period;
309
309
  adaptation: Adaptation;
310
- }, currentRepresentation: IReadOnlySharedReference<Representation | null>, representations: IReadOnlySharedReference<Representation[]>, playbackObserver: IReadOnlyPlaybackObserver<IRepresentationEstimatorPlaybackObservation>, cancellationSignal: CancellationSignal) => [
311
- IReadOnlySharedReference<IABREstimate>,
312
- IRepresentationEstimatorCallbacks
313
- ];
310
+ },
311
+ /** Reference emitting the Representation currently loaded. */
312
+ currentRepresentation: IReadOnlySharedReference<Representation | null>,
313
+ /** Reference emitting the list of available Representations to choose from. */
314
+ representations: IReadOnlySharedReference<Representation[]>,
315
+ /** Regularly emits playback conditions */
316
+ playbackObserver: IReadOnlyPlaybackObserver<IRepresentationEstimatorPlaybackObservation>,
317
+ /**
318
+ * After this `CancellationSignal` emits, resources will be disposed and
319
+ * estimates will stop to be emitted.
320
+ */
321
+ stopAllEstimates: CancellationSignal) => IRepresentationEstimatorResponse;
322
+ /** Value returned by an `IRepresentationEstimator` */
323
+ export interface IRepresentationEstimatorResponse {
324
+ /**
325
+ * Regularly produces estimates of the best Representation to play (from the
326
+ * list given).
327
+ */
328
+ estimates: IReadOnlySharedReference<IABREstimate>;
329
+ /**
330
+ * Callback which need to be called as soon as the corresponding events to
331
+ * obtain accurate Representation estimates.
332
+ */
333
+ callbacks: IRepresentationEstimatorCallbacks;
334
+ }
314
335
  /** Arguments received by `createAdaptiveRepresentationSelector`. */
315
336
  export interface IAdaptiveRepresentationSelectorArguments {
316
337
  /** Initial bitrate chosen, per type (minimum if not set) */
@@ -32,8 +32,10 @@ import selectOptimalRepresentation from "./utils/select_optimal_representation";
32
32
  /**
33
33
  * Select the most adapted Representation according to the network and buffer
34
34
  * metrics it receives.
35
+ *
35
36
  * @param {Object} options - Initial configuration (see type definition)
36
- * @returns {Object} - Interface allowing to select a Representation
37
+ * @returns {Object} - Interface allowing to select a Representation.
38
+ * @see IRepresentationEstimator
37
39
  */
38
40
  export default function createAdaptiveRepresentationSelector(options) {
39
41
  /**
@@ -45,17 +47,16 @@ export default function createAdaptiveRepresentationSelector(options) {
45
47
  /**
46
48
  * Returns Object emitting Representation estimates as well as callbacks
47
49
  * allowing to helping it produce them.
50
+ *
51
+ * @see IRepresentationEstimator
48
52
  * @param {Object} context
49
- * @param {Object} currentRepresentation - Reference emitting the
50
- * Representation currently loaded.
51
- * @param {Object} representations - Reference emitting the list of available
52
- * Representations to choose from.
53
- * @param {Object} playbackObserver - Emits regularly playback conditions
54
- * @param {Object} cancellationSignal - After this `CancellationSignal` emits,
55
- * estimates will stop to be emitted.
53
+ * @param {Object} currentRepresentation
54
+ * @param {Object} representations
55
+ * @param {Object} playbackObserver
56
+ * @param {Object} stopAllEstimates
56
57
  * @returns {Array.<Object>}
57
58
  */
58
- return function getEstimates(context, currentRepresentation, representations, playbackObserver, cancellationSignal) {
59
+ return function getEstimates(context, currentRepresentation, representations, playbackObserver, stopAllEstimates) {
59
60
  var type = context.adaptation.type;
60
61
  var bandwidthEstimator = _getBandwidthEstimator(type);
61
62
  var manualBitrate = takeFirstSet(manualBitrates[type], createSharedReference(-1));
@@ -66,7 +67,7 @@ export default function createAdaptiveRepresentationSelector(options) {
66
67
  limitWidth: takeFirstSet(throttlers.limitWidth[type], createSharedReference(undefined)),
67
68
  throttleBitrate: takeFirstSet(throttlers.throttleBitrate[type], throttlers.throttle[type], createSharedReference(Infinity)),
68
69
  };
69
- return getEstimateReference({ bandwidthEstimator: bandwidthEstimator, context: context, currentRepresentation: currentRepresentation, filters: filters, initialBitrate: initialBitrate, manualBitrate: manualBitrate, minAutoBitrate: minAutoBitrate, maxAutoBitrate: maxAutoBitrate, playbackObserver: playbackObserver, representations: representations, lowLatencyMode: lowLatencyMode }, cancellationSignal);
70
+ return getEstimateReference({ bandwidthEstimator: bandwidthEstimator, context: context, currentRepresentation: currentRepresentation, filters: filters, initialBitrate: initialBitrate, manualBitrate: manualBitrate, minAutoBitrate: minAutoBitrate, maxAutoBitrate: maxAutoBitrate, playbackObserver: playbackObserver, representations: representations, lowLatencyMode: lowLatencyMode }, stopAllEstimates);
70
71
  };
71
72
  /**
72
73
  * Returns interface allowing to estimate network throughtput for a given type.
@@ -100,10 +101,10 @@ export default function createAdaptiveRepresentationSelector(options) {
100
101
  * events to help it doing those estimates.
101
102
  *
102
103
  * @param {Object} args
103
- * @param {Object} cancellationSignal
104
+ * @param {Object} stopAllEstimates
104
105
  * @returns {Array.<Object>}
105
106
  */
106
- function getEstimateReference(_a, cancellationSignal) {
107
+ function getEstimateReference(_a, stopAllEstimates) {
107
108
  var bandwidthEstimator = _a.bandwidthEstimator, context = _a.context, currentRepresentation = _a.currentRepresentation, filters = _a.filters, initialBitrate = _a.initialBitrate, lowLatencyMode = _a.lowLatencyMode, manualBitrate = _a.manualBitrate, maxAutoBitrate = _a.maxAutoBitrate, minAutoBitrate = _a.minAutoBitrate, playbackObserver = _a.playbackObserver, representationsRef = _a.representations;
108
109
  var scoreCalculator = new RepresentationScoreCalculator();
109
110
  var networkAnalyzer = new NetworkAnalyzer(initialBitrate !== null && initialBitrate !== void 0 ? initialBitrate : 0, lowLatencyMode);
@@ -121,15 +122,12 @@ function getEstimateReference(_a, cancellationSignal) {
121
122
  * This TaskCanceller is used both for restarting estimates with a new
122
123
  * configuration and to cancel them altogether.
123
124
  */
124
- var currentEstimatesCanceller = new TaskCanceller();
125
- cancellationSignal.register(function () {
126
- currentEstimatesCanceller.cancel();
127
- });
125
+ var currentEstimatesCanceller = new TaskCanceller({ cancelOn: stopAllEstimates });
128
126
  // Create `ISharedReference` on which estimates will be emitted.
129
127
  var estimateRef = createEstimateReference(manualBitrate.getValue(), representationsRef.getValue(), currentEstimatesCanceller.signal);
130
- manualBitrate.onUpdate(restartEstimatesProductionFromCurrentConditions, { clearSignal: currentEstimatesCanceller.signal });
131
- representationsRef.onUpdate(restartEstimatesProductionFromCurrentConditions, { clearSignal: currentEstimatesCanceller.signal });
132
- return [estimateRef, callbacks];
128
+ manualBitrate.onUpdate(restartEstimatesProductionFromCurrentConditions, { clearSignal: stopAllEstimates });
129
+ representationsRef.onUpdate(restartEstimatesProductionFromCurrentConditions, { clearSignal: stopAllEstimates });
130
+ return { estimates: estimateRef, callbacks: callbacks };
133
131
  function createEstimateReference(manualBitrateVal, representations, innerCancellationSignal) {
134
132
  if (manualBitrateVal >= 0) {
135
133
  // A manual bitrate has been set. Just choose Representation according to it.
@@ -319,7 +317,7 @@ function getEstimateReference(_a, cancellationSignal) {
319
317
  var manualBitrateVal = manualBitrate.getValue();
320
318
  var representations = representationsRef.getValue();
321
319
  currentEstimatesCanceller.cancel();
322
- currentEstimatesCanceller = new TaskCanceller();
320
+ currentEstimatesCanceller = new TaskCanceller({ cancelOn: stopAllEstimates });
323
321
  var newRef = createEstimateReference(manualBitrateVal, representations, currentEstimatesCanceller.signal);
324
322
  newRef.onUpdate(function onNewEstimate(newEstimate) {
325
323
  estimateRef.setValue(newEstimate);
@@ -88,7 +88,7 @@ var Player = /** @class */ (function (_super) {
88
88
  // Workaround to support Firefox autoplay on FF 42.
89
89
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
90
90
  videoElement.preload = "auto";
91
- _this.version = /* PLAYER_VERSION */ "3.28.0-dev.2022061700";
91
+ _this.version = /* PLAYER_VERSION */ "3.28.0-dev.2022062000";
92
92
  _this.log = log;
93
93
  _this.state = "STOPPED";
94
94
  _this.videoElement = videoElement;
@@ -2295,5 +2295,5 @@ var Player = /** @class */ (function (_super) {
2295
2295
  };
2296
2296
  return Player;
2297
2297
  }(EventEmitter));
2298
- Player.version = /* PLAYER_VERSION */ "3.28.0-dev.2022061700";
2298
+ Player.version = /* PLAYER_VERSION */ "3.28.0-dev.2022062000";
2299
2299
  export default Player;
@@ -428,18 +428,7 @@ var ContentDecryptor = /** @class */ (function (_super) {
428
428
  _this.trigger("warning", evt.value);
429
429
  return;
430
430
  }
431
- var linkedKeys;
432
- if (sessionInfo.source === "created-session" /* MediaKeySessionLoadingType.Created */) {
433
- // When the license has been fetched, there might be implicit key ids
434
- // linked to the session depending on the `singleLicensePer` option.
435
- linkedKeys = getFetchedLicenseKeysInfo(initializationData, options.singleLicensePer, evt.value.whitelistedKeyIds, evt.value.blacklistedKeyIDs);
436
- }
437
- else {
438
- // When the MediaKeySession is just a cached/persisted one, we don't
439
- // have any concept of "implicit key id".
440
- linkedKeys = { whitelisted: evt.value.whitelistedKeyIds,
441
- blacklisted: evt.value.blacklistedKeyIDs };
442
- }
431
+ var linkedKeys = getKeyIdsLinkedToSession(initializationData, sessionInfo.record, options.singleLicensePer, sessionInfo.source === "created-session" /* MediaKeySessionLoadingType.Created */, evt.value.whitelistedKeyIds, evt.value.blacklistedKeyIDs);
443
432
  sessionInfo.record.associateKeyIds(linkedKeys.whitelisted);
444
433
  sessionInfo.record.associateKeyIds(linkedKeys.blacklisted);
445
434
  sessionInfo.keyStatuses = { whitelisted: linkedKeys.whitelisted,
@@ -758,26 +747,63 @@ export var ContentDecryptorState;
758
747
  ContentDecryptorState[ContentDecryptorState["Disposed"] = 4] = "Disposed";
759
748
  })(ContentDecryptorState || (ContentDecryptorState = {}));
760
749
  /**
761
- * Returns information on all keys - explicit or implicit - that are linked to
762
- * a loaded license.
750
+ * Returns set of all usable and unusable keys - explicit or implicit - that are
751
+ * linked to a `MediaKeySession`.
763
752
  *
764
753
  * In the RxPlayer, there is a concept of "explicit" key ids, which are key ids
765
754
  * found in a license whose status can be known through the `keyStatuses`
766
755
  * property from a `MediaKeySession`, and of "implicit" key ids, which are key
767
756
  * ids which were expected to be in a fetched license, but apparently weren't.
768
- * @param {Object} initializationData
769
- * @param {string|undefined} singleLicensePer
770
- * @param {Array.<Uint8Array>} usableKeyIds
771
- * @param {Array.<Uint8Array>} unusableKeyIds
772
- * @returns {Object}
757
+ *
758
+ * @param {Object} initializationData - Initialization data object used to make
759
+ * the request for the current license.
760
+ * @param {Object} keySessionRecord - The `KeySessionRecord` associated with the
761
+ * session that has been loaded. It might give supplementary information on
762
+ * keys implicitly linked to the license.
763
+ * @param {string|undefined} singleLicensePer - Setting allowing to indicate the
764
+ * scope a given license should have.
765
+ * @param {boolean} isCurrentLicense - If `true` the license has been fetched
766
+ * especially for the current content.
767
+ *
768
+ * Knowing this allows to determine that if decryption keys that should have
769
+ * been referenced in the fetched license (according to the `singleLicensePer`
770
+ * setting) are missing, then the keys surely must have been voluntarly
771
+ * removed from the license.
772
+ *
773
+ * If it is however set to `false`, it means that the license is an older
774
+ * license that might have been linked to another content, thus we cannot make
775
+ * that assumption.
776
+ * @param {Array.<Uint8Array>} usableKeyIds - Key ids that are present in the
777
+ * license and can be used.
778
+ * @param {Array.<Uint8Array>} unusableKeyIds - Key ids that are present in the
779
+ * license yet cannot be used.
780
+ * @returns {Object} - Returns an object with the following properties:
781
+ * - `whitelisted`: Array of key ids for keys that are known to be usable
782
+ * - `blacklisted`: Array of key ids for keys that are considered unusable.
783
+ * The qualities linked to those keys should not be played.
773
784
  */
774
- function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableKeyIds, unusableKeyIds) {
785
+ function getKeyIdsLinkedToSession(initializationData, keySessionRecord, singleLicensePer, isCurrentLicense, usableKeyIds, unusableKeyIds) {
775
786
  var _a;
776
787
  /**
777
788
  * Every key id associated with the MediaKeySession, starting with
778
789
  * whitelisted ones.
779
790
  */
780
791
  var associatedKeyIds = __spreadArray(__spreadArray([], usableKeyIds, true), unusableKeyIds, true);
792
+ // Add all key ids associated to the `KeySessionRecord` yet not in
793
+ // `usableKeyIds` nor in `unusableKeyIds`
794
+ var allKnownKeyIds = keySessionRecord.getAssociatedKeyIds();
795
+ var _loop_2 = function (kid) {
796
+ if (!associatedKeyIds.some(function (ak) { return areKeyIdsEqual(ak, kid); })) {
797
+ if (log.hasLevel("DEBUG")) {
798
+ log.debug("DRM: KeySessionRecord's key missing in the license, blacklisting it", bytesToHex(kid));
799
+ }
800
+ associatedKeyIds.push(kid);
801
+ }
802
+ };
803
+ for (var _i = 0, allKnownKeyIds_1 = allKnownKeyIds; _i < allKnownKeyIds_1.length; _i++) {
804
+ var kid = allKnownKeyIds_1[_i];
805
+ _loop_2(kid);
806
+ }
781
807
  if (singleLicensePer !== undefined && singleLicensePer !== "init-data") {
782
808
  // We want to add the current key ids in the blacklist if it is
783
809
  // not already there.
@@ -798,24 +824,27 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
798
824
  return !associatedKeyIds.some(function (k) { return areKeyIdsEqual(k, expected); });
799
825
  });
800
826
  if (missingKeyIds.length > 0) {
827
+ if (log.hasLevel("DEBUG")) {
828
+ log.debug("DRM: init data keys missing in the license, blacklisting them", missingKeyIds.map(function (m) { return bytesToHex(m); }).join(", "));
829
+ }
801
830
  associatedKeyIds.push.apply(associatedKeyIds, missingKeyIds);
802
831
  }
803
832
  }
804
- if (content !== undefined) {
833
+ if (isCurrentLicense && content !== undefined) {
805
834
  if (singleLicensePer === "content") {
806
835
  // Put it in a Set to automatically filter out duplicates (by ref)
807
836
  var contentKeys = new Set();
808
837
  var manifest = content.manifest;
809
- for (var _i = 0, _b = manifest.periods; _i < _b.length; _i++) {
810
- var period = _b[_i];
838
+ for (var _b = 0, _c = manifest.periods; _b < _c.length; _b++) {
839
+ var period = _c[_b];
811
840
  addKeyIdsFromPeriod(contentKeys, period);
812
841
  }
813
842
  mergeKeyIdSetIntoArray(contentKeys, associatedKeyIds);
814
843
  }
815
844
  else if (singleLicensePer === "periods") {
816
845
  var manifest = content.manifest;
817
- for (var _c = 0, _d = manifest.periods; _c < _d.length; _c++) {
818
- var period = _d[_c];
846
+ for (var _d = 0, _e = manifest.periods; _d < _e.length; _d++) {
847
+ var period = _e[_d];
819
848
  var periodKeys = new Set();
820
849
  addKeyIdsFromPeriod(periodKeys, period);
821
850
  if (((_a = initializationData.content) === null || _a === void 0 ? void 0 : _a.period.id) === period.id) {
@@ -823,16 +852,16 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
823
852
  }
824
853
  else {
825
854
  var periodKeysArr = Array.from(periodKeys);
826
- var _loop_2 = function (kid) {
855
+ var _loop_3 = function (kid) {
827
856
  var isFound = associatedKeyIds.some(function (k) { return areKeyIdsEqual(k, kid); });
828
857
  if (isFound) {
829
858
  mergeKeyIdSetIntoArray(periodKeys, associatedKeyIds);
830
859
  return "break";
831
860
  }
832
861
  };
833
- for (var _e = 0, periodKeysArr_3 = periodKeysArr; _e < periodKeysArr_3.length; _e++) {
834
- var kid = periodKeysArr_3[_e];
835
- var state_2 = _loop_2(kid);
862
+ for (var _f = 0, periodKeysArr_3 = periodKeysArr; _f < periodKeysArr_3.length; _f++) {
863
+ var kid = periodKeysArr_3[_f];
864
+ var state_2 = _loop_3(kid);
836
865
  if (state_2 === "break")
837
866
  break;
838
867
  }
@@ -847,7 +876,7 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
847
876
  }
848
877
  function mergeKeyIdSetIntoArray(set, arr) {
849
878
  var setArr = Array.from(set.values());
850
- var _loop_3 = function (kid) {
879
+ var _loop_4 = function (kid) {
851
880
  var isFound = arr.some(function (k) { return areKeyIdsEqual(k, kid); });
852
881
  if (!isFound) {
853
882
  arr.push(kid);
@@ -855,7 +884,7 @@ function mergeKeyIdSetIntoArray(set, arr) {
855
884
  };
856
885
  for (var _i = 0, setArr_1 = setArr; _i < setArr_1.length; _i++) {
857
886
  var kid = setArr_1[_i];
858
- _loop_3(kid);
887
+ _loop_4(kid);
859
888
  }
860
889
  }
861
890
  function addKeyIdsFromPeriod(set, period) {
@@ -39,7 +39,7 @@ export default function getRepresentationEstimate(content, representationEstimat
39
39
  updateRepresentationsReference();
40
40
  manifest.addEventListener("decipherabilityUpdate", updateRepresentationsReference);
41
41
  var unregisterCleanUp = cancellationSignal.register(cleanUp);
42
- var _a = representationEstimator(content, currentRepresentation, representations, playbackObserver, cancellationSignal), estimateRef = _a[0], abrCallbacks = _a[1];
42
+ var _a = representationEstimator(content, currentRepresentation, representations, playbackObserver, cancellationSignal), estimateRef = _a.estimates, abrCallbacks = _a.callbacks;
43
43
  return { abrCallbacks: abrCallbacks, estimateRef: estimateRef };
44
44
  function updateRepresentationsReference() {
45
45
  /** Representations for which a `RepresentationStream` can be created. */
@@ -52,10 +52,24 @@ import { CancellationSignal } from "./task_canceller";
52
52
  * those use cases makes the intent of the corresponding code clearer.
53
53
  */
54
54
  export interface ISharedReference<T> {
55
- /** Get the last set value for this shared reference. */
55
+ /**
56
+ * Get the last set value for this shared reference.
57
+ * @returns {*}
58
+ */
56
59
  getValue(): T;
57
- /** Update the value of this shared reference. */
60
+ /**
61
+ * Update the value of this shared reference.
62
+ * @param {*} newVal
63
+ */
58
64
  setValue(newVal: T): void;
65
+ /**
66
+ * Update the value of this shared reference only if the value changed.
67
+ *
68
+ * Note that this function only performs a strict equality reference through
69
+ * the "===" operator. Different objects that are structurally the same will
70
+ * thus be considered different.
71
+ * @param {*} newVal
72
+ */
59
73
  setValueIfChanged(newVal: T): void;
60
74
  /**
61
75
  * Returns an Observable which synchronously emits the current value (unless
@@ -65,21 +79,6 @@ export interface ISharedReference<T> {
65
79
  * @returns {Observable}
66
80
  */
67
81
  asObservable(skipCurrentValue?: boolean): Observable<T>;
68
- /**
69
- * Triggers a callback each time this reference's value is updated.
70
- *
71
- * Can be given several options as argument:
72
- * - clearSignal: When the attach `CancellationSignal` emits, the given
73
- * callback will not be called anymore on reference updates.
74
- * - emitCurrentValue: If `true`, the callback will be called directly and
75
- * synchronously on this call with its current value.
76
- * @param {Function} cb
77
- * @param {Object} [options]
78
- */
79
- onUpdate(cb: (val: T) => void, options?: {
80
- clearSignal?: CancellationSignal;
81
- emitCurrentValue?: boolean;
82
- }): void;
83
82
  /**
84
83
  * Allows to register a callback to be called each time the value inside the
85
84
  * reference is updated.
@@ -160,5 +159,16 @@ export interface IReadOnlySharedReference<T> {
160
159
  * @returns {Observable}
161
160
  */
162
161
  export declare function createSharedReference<T>(initialValue: T): ISharedReference<T>;
162
+ /**
163
+ * Create a new `ISharedReference` based on another one by mapping over its
164
+ * referenced value each time it is updated.
165
+ * @param {Object} originalRef - The Original `ISharedReference` you wish to map
166
+ * over.
167
+ * @param {Function} mappingFn - The mapping function which will receives
168
+ * `originalRef`'s value and outputs this new reference's value.
169
+ * @param {Object | undefined} [cancellationSignal] - Optionally, a
170
+ * `CancellationSignal` which will finish that reference when it emits.
171
+ * @returns {Object} - The new, mapped, reference.
172
+ */
163
173
  export declare function createMappedReference<T, U>(originalRef: IReadOnlySharedReference<T>, mappingFn: (x: T) => U, cancellationSignal?: CancellationSignal): IReadOnlySharedReference<U>;
164
174
  export default createSharedReference;
@@ -53,7 +53,7 @@ export function createSharedReference(initialValue) {
53
53
  },
54
54
  /**
55
55
  * Update the value of this shared reference.
56
- * @param {*}
56
+ * @param {*} newVal
57
57
  */
58
58
  setValue: function (newVal) {
59
59
  if (isFinished) {
@@ -81,6 +81,10 @@ export function createSharedReference(initialValue) {
81
81
  }
82
82
  }
83
83
  },
84
+ /**
85
+ * Update the value of this shared reference only if it changed.
86
+ * @param {*} newVal
87
+ */
84
88
  setValueIfChanged: function (newVal) {
85
89
  if (newVal !== value) {
86
90
  this.setValue(newVal);
@@ -181,6 +185,17 @@ export function createSharedReference(initialValue) {
181
185
  },
182
186
  };
183
187
  }
188
+ /**
189
+ * Create a new `ISharedReference` based on another one by mapping over its
190
+ * referenced value each time it is updated.
191
+ * @param {Object} originalRef - The Original `ISharedReference` you wish to map
192
+ * over.
193
+ * @param {Function} mappingFn - The mapping function which will receives
194
+ * `originalRef`'s value and outputs this new reference's value.
195
+ * @param {Object | undefined} [cancellationSignal] - Optionally, a
196
+ * `CancellationSignal` which will finish that reference when it emits.
197
+ * @returns {Object} - The new, mapped, reference.
198
+ */
184
199
  export function createMappedReference(originalRef, mappingFn, cancellationSignal) {
185
200
  var newRef = createSharedReference(mappingFn(originalRef.getValue()));
186
201
  originalRef.onUpdate(function mapOriginalReference(x) {