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 +4 -3
- package/VERSION +1 -1
- package/appveyor.yml +1 -1
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.d.ts +32 -11
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +18 -20
- package/dist/_esm5.processed/core/api/public_api.js +2 -2
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +60 -31
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.js +1 -1
- package/dist/_esm5.processed/utils/reference.d.ts +27 -17
- package/dist/_esm5.processed/utils/reference.js +16 -1
- package/dist/rx-player.js +119 -62
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/core/adaptive/adaptive_representation_selector.ts +46 -33
- package/src/core/api/public_api.ts +2 -2
- package/src/core/decrypt/content_decryptor.ts +57 -23
- package/src/core/stream/adaptation/create_representation_estimator.ts +6 -6
- package/src/utils/reference.ts +33 -23
package/package.json
CHANGED
package/sonar-project.properties
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
sonar.projectKey=rx-player
|
|
2
2
|
sonar.organization=rx-player
|
|
3
3
|
sonar.projectName=rx-player
|
|
4
|
-
sonar.projectVersion=3.28.0-dev.
|
|
4
|
+
sonar.projectVersion=3.28.0-dev.2022062000
|
|
5
5
|
sonar.sources=./src,./demo,./tests
|
|
6
6
|
sonar.exclusions=demo/full/bundle.js,demo/standalone/lib.js,demo/bundle.js
|
|
7
7
|
sonar.host.url=https://sonarcloud.io
|
|
@@ -52,8 +52,10 @@ import selectOptimalRepresentation from "./utils/select_optimal_representation";
|
|
|
52
52
|
/**
|
|
53
53
|
* Select the most adapted Representation according to the network and buffer
|
|
54
54
|
* metrics it receives.
|
|
55
|
+
*
|
|
55
56
|
* @param {Object} options - Initial configuration (see type definition)
|
|
56
|
-
* @returns {Object} - Interface allowing to select a Representation
|
|
57
|
+
* @returns {Object} - Interface allowing to select a Representation.
|
|
58
|
+
* @see IRepresentationEstimator
|
|
57
59
|
*/
|
|
58
60
|
export default function createAdaptiveRepresentationSelector(
|
|
59
61
|
options : IAdaptiveRepresentationSelectorArguments
|
|
@@ -73,14 +75,13 @@ export default function createAdaptiveRepresentationSelector(
|
|
|
73
75
|
/**
|
|
74
76
|
* Returns Object emitting Representation estimates as well as callbacks
|
|
75
77
|
* allowing to helping it produce them.
|
|
78
|
+
*
|
|
79
|
+
* @see IRepresentationEstimator
|
|
76
80
|
* @param {Object} context
|
|
77
|
-
* @param {Object} currentRepresentation
|
|
78
|
-
*
|
|
79
|
-
* @param {Object}
|
|
80
|
-
*
|
|
81
|
-
* @param {Object} playbackObserver - Emits regularly playback conditions
|
|
82
|
-
* @param {Object} cancellationSignal - After this `CancellationSignal` emits,
|
|
83
|
-
* estimates will stop to be emitted.
|
|
81
|
+
* @param {Object} currentRepresentation
|
|
82
|
+
* @param {Object} representations
|
|
83
|
+
* @param {Object} playbackObserver
|
|
84
|
+
* @param {Object} stopAllEstimates
|
|
84
85
|
* @returns {Array.<Object>}
|
|
85
86
|
*/
|
|
86
87
|
return function getEstimates(
|
|
@@ -92,9 +93,8 @@ export default function createAdaptiveRepresentationSelector(
|
|
|
92
93
|
playbackObserver : IReadOnlyPlaybackObserver<
|
|
93
94
|
IRepresentationEstimatorPlaybackObservation
|
|
94
95
|
>,
|
|
95
|
-
|
|
96
|
-
) :
|
|
97
|
-
IRepresentationEstimatorCallbacks ] {
|
|
96
|
+
stopAllEstimates : CancellationSignal
|
|
97
|
+
) : IRepresentationEstimatorResponse {
|
|
98
98
|
const { type } = context.adaptation;
|
|
99
99
|
const bandwidthEstimator = _getBandwidthEstimator(type);
|
|
100
100
|
const manualBitrate = takeFirstSet<IReadOnlySharedReference<number>>(
|
|
@@ -127,7 +127,7 @@ export default function createAdaptiveRepresentationSelector(
|
|
|
127
127
|
playbackObserver,
|
|
128
128
|
representations,
|
|
129
129
|
lowLatencyMode },
|
|
130
|
-
|
|
130
|
+
stopAllEstimates);
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
/**
|
|
@@ -163,7 +163,7 @@ export default function createAdaptiveRepresentationSelector(
|
|
|
163
163
|
* events to help it doing those estimates.
|
|
164
164
|
*
|
|
165
165
|
* @param {Object} args
|
|
166
|
-
* @param {Object}
|
|
166
|
+
* @param {Object} stopAllEstimates
|
|
167
167
|
* @returns {Array.<Object>}
|
|
168
168
|
*/
|
|
169
169
|
function getEstimateReference(
|
|
@@ -178,10 +178,8 @@ function getEstimateReference(
|
|
|
178
178
|
minAutoBitrate,
|
|
179
179
|
playbackObserver,
|
|
180
180
|
representations : representationsRef } : IRepresentationEstimatorArguments,
|
|
181
|
-
|
|
182
|
-
) :
|
|
183
|
-
IRepresentationEstimatorCallbacks ] {
|
|
184
|
-
|
|
181
|
+
stopAllEstimates : CancellationSignal
|
|
182
|
+
) : IRepresentationEstimatorResponse {
|
|
185
183
|
const scoreCalculator = new RepresentationScoreCalculator();
|
|
186
184
|
const networkAnalyzer = new NetworkAnalyzer(initialBitrate ?? 0, lowLatencyMode);
|
|
187
185
|
const requestsStore = new PendingRequestsStore();
|
|
@@ -200,10 +198,7 @@ function getEstimateReference(
|
|
|
200
198
|
* This TaskCanceller is used both for restarting estimates with a new
|
|
201
199
|
* configuration and to cancel them altogether.
|
|
202
200
|
*/
|
|
203
|
-
let currentEstimatesCanceller = new TaskCanceller();
|
|
204
|
-
cancellationSignal.register(() => {
|
|
205
|
-
currentEstimatesCanceller.cancel();
|
|
206
|
-
});
|
|
201
|
+
let currentEstimatesCanceller = new TaskCanceller({ cancelOn: stopAllEstimates });
|
|
207
202
|
|
|
208
203
|
// Create `ISharedReference` on which estimates will be emitted.
|
|
209
204
|
const estimateRef = createEstimateReference(manualBitrate.getValue(),
|
|
@@ -211,11 +206,11 @@ function getEstimateReference(
|
|
|
211
206
|
currentEstimatesCanceller.signal);
|
|
212
207
|
|
|
213
208
|
manualBitrate.onUpdate(restartEstimatesProductionFromCurrentConditions,
|
|
214
|
-
{ clearSignal:
|
|
209
|
+
{ clearSignal: stopAllEstimates });
|
|
215
210
|
representationsRef.onUpdate(restartEstimatesProductionFromCurrentConditions,
|
|
216
|
-
{ clearSignal:
|
|
211
|
+
{ clearSignal: stopAllEstimates });
|
|
217
212
|
|
|
218
|
-
return
|
|
213
|
+
return { estimates: estimateRef, callbacks };
|
|
219
214
|
|
|
220
215
|
function createEstimateReference(
|
|
221
216
|
manualBitrateVal : number,
|
|
@@ -475,12 +470,13 @@ function getEstimateReference(
|
|
|
475
470
|
const manualBitrateVal = manualBitrate.getValue();
|
|
476
471
|
const representations = representationsRef.getValue();
|
|
477
472
|
currentEstimatesCanceller.cancel();
|
|
478
|
-
currentEstimatesCanceller = new TaskCanceller();
|
|
473
|
+
currentEstimatesCanceller = new TaskCanceller({ cancelOn: stopAllEstimates });
|
|
479
474
|
const newRef = createEstimateReference(
|
|
480
475
|
manualBitrateVal,
|
|
481
476
|
representations,
|
|
482
477
|
currentEstimatesCanceller.signal
|
|
483
478
|
);
|
|
479
|
+
|
|
484
480
|
newRef.onUpdate(function onNewEstimate(newEstimate : IABREstimate) : void {
|
|
485
481
|
estimateRef.setValue(newEstimate);
|
|
486
482
|
}, { clearSignal: currentEstimatesCanceller.signal,
|
|
@@ -700,11 +696,7 @@ export interface IABRFiltersObject {
|
|
|
700
696
|
width?: number;
|
|
701
697
|
}
|
|
702
698
|
|
|
703
|
-
/**
|
|
704
|
-
* Callbacks returned by `getEstimateReference`.
|
|
705
|
-
* Those needs to be called as soon as the corresponding events to obtain
|
|
706
|
-
* coherent Representation estimates.
|
|
707
|
-
*/
|
|
699
|
+
/** Callbacks returned by `getEstimateReference`. */
|
|
708
700
|
export interface IRepresentationEstimatorCallbacks {
|
|
709
701
|
/** Callback to call when a segment has been completely pushed to the buffer. */
|
|
710
702
|
addedSegment(val : IAddedSegmentCallbackPayload) : void;
|
|
@@ -832,17 +824,38 @@ export interface IRepresentationEstimatorArguments {
|
|
|
832
824
|
* allowing to estimate the most adapted `Representation`.
|
|
833
825
|
*/
|
|
834
826
|
export type IRepresentationEstimator = (
|
|
827
|
+
/** Information on the content for which a Representation will be chosen */
|
|
835
828
|
context : { manifest : Manifest;
|
|
836
829
|
period : Period;
|
|
837
830
|
adaptation : Adaptation; },
|
|
831
|
+
/** Reference emitting the Representation currently loaded. */
|
|
838
832
|
currentRepresentation : IReadOnlySharedReference<Representation | null>,
|
|
833
|
+
/** Reference emitting the list of available Representations to choose from. */
|
|
839
834
|
representations : IReadOnlySharedReference<Representation[]>,
|
|
835
|
+
/** Regularly emits playback conditions */
|
|
840
836
|
playbackObserver : IReadOnlyPlaybackObserver<
|
|
841
837
|
IRepresentationEstimatorPlaybackObservation
|
|
842
838
|
>,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
839
|
+
/**
|
|
840
|
+
* After this `CancellationSignal` emits, resources will be disposed and
|
|
841
|
+
* estimates will stop to be emitted.
|
|
842
|
+
*/
|
|
843
|
+
stopAllEstimates : CancellationSignal
|
|
844
|
+
) => IRepresentationEstimatorResponse;
|
|
845
|
+
|
|
846
|
+
/** Value returned by an `IRepresentationEstimator` */
|
|
847
|
+
export interface IRepresentationEstimatorResponse {
|
|
848
|
+
/**
|
|
849
|
+
* Regularly produces estimates of the best Representation to play (from the
|
|
850
|
+
* list given).
|
|
851
|
+
*/
|
|
852
|
+
estimates: IReadOnlySharedReference<IABREstimate>;
|
|
853
|
+
/**
|
|
854
|
+
* Callback which need to be called as soon as the corresponding events to
|
|
855
|
+
* obtain accurate Representation estimates.
|
|
856
|
+
*/
|
|
857
|
+
callbacks: IRepresentationEstimatorCallbacks;
|
|
858
|
+
}
|
|
846
859
|
|
|
847
860
|
/** Arguments received by `createAdaptiveRepresentationSelector`. */
|
|
848
861
|
export interface IAdaptiveRepresentationSelectorArguments {
|
|
@@ -429,7 +429,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
429
429
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
430
430
|
videoElement.preload = "auto";
|
|
431
431
|
|
|
432
|
-
this.version = /* PLAYER_VERSION */"3.28.0-dev.
|
|
432
|
+
this.version = /* PLAYER_VERSION */"3.28.0-dev.2022062000";
|
|
433
433
|
this.log = log;
|
|
434
434
|
this.state = "STOPPED";
|
|
435
435
|
this.videoElement = videoElement;
|
|
@@ -2941,7 +2941,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2941
2941
|
return activeRepresentations[currentPeriod.id];
|
|
2942
2942
|
}
|
|
2943
2943
|
}
|
|
2944
|
-
Player.version = /* PLAYER_VERSION */"3.28.0-dev.
|
|
2944
|
+
Player.version = /* PLAYER_VERSION */"3.28.0-dev.2022062000";
|
|
2945
2945
|
|
|
2946
2946
|
/** Every events sent by the RxPlayer's public API. */
|
|
2947
2947
|
interface IPublicAPIEvent {
|
|
@@ -491,20 +491,13 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
491
491
|
return;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
evt.value.blacklistedKeyIDs);
|
|
502
|
-
} else {
|
|
503
|
-
// When the MediaKeySession is just a cached/persisted one, we don't
|
|
504
|
-
// have any concept of "implicit key id".
|
|
505
|
-
linkedKeys = { whitelisted: evt.value.whitelistedKeyIds,
|
|
506
|
-
blacklisted: evt.value.blacklistedKeyIDs };
|
|
507
|
-
}
|
|
494
|
+
const linkedKeys = getKeyIdsLinkedToSession(
|
|
495
|
+
initializationData,
|
|
496
|
+
sessionInfo.record,
|
|
497
|
+
options.singleLicensePer,
|
|
498
|
+
sessionInfo.source === MediaKeySessionLoadingType.Created,
|
|
499
|
+
evt.value.whitelistedKeyIds,
|
|
500
|
+
evt.value.blacklistedKeyIDs);
|
|
508
501
|
|
|
509
502
|
sessionInfo.record.associateKeyIds(linkedKeys.whitelisted);
|
|
510
503
|
sessionInfo.record.associateKeyIds(linkedKeys.blacklisted);
|
|
@@ -1053,22 +1046,46 @@ interface IAttachedMediaKeysData {
|
|
|
1053
1046
|
}
|
|
1054
1047
|
|
|
1055
1048
|
/**
|
|
1056
|
-
* Returns
|
|
1057
|
-
* a
|
|
1049
|
+
* Returns set of all usable and unusable keys - explicit or implicit - that are
|
|
1050
|
+
* linked to a `MediaKeySession`.
|
|
1058
1051
|
*
|
|
1059
1052
|
* In the RxPlayer, there is a concept of "explicit" key ids, which are key ids
|
|
1060
1053
|
* found in a license whose status can be known through the `keyStatuses`
|
|
1061
1054
|
* property from a `MediaKeySession`, and of "implicit" key ids, which are key
|
|
1062
1055
|
* ids which were expected to be in a fetched license, but apparently weren't.
|
|
1063
|
-
*
|
|
1064
|
-
* @param {
|
|
1065
|
-
*
|
|
1066
|
-
* @param {
|
|
1067
|
-
*
|
|
1056
|
+
*
|
|
1057
|
+
* @param {Object} initializationData - Initialization data object used to make
|
|
1058
|
+
* the request for the current license.
|
|
1059
|
+
* @param {Object} keySessionRecord - The `KeySessionRecord` associated with the
|
|
1060
|
+
* session that has been loaded. It might give supplementary information on
|
|
1061
|
+
* keys implicitly linked to the license.
|
|
1062
|
+
* @param {string|undefined} singleLicensePer - Setting allowing to indicate the
|
|
1063
|
+
* scope a given license should have.
|
|
1064
|
+
* @param {boolean} isCurrentLicense - If `true` the license has been fetched
|
|
1065
|
+
* especially for the current content.
|
|
1066
|
+
*
|
|
1067
|
+
* Knowing this allows to determine that if decryption keys that should have
|
|
1068
|
+
* been referenced in the fetched license (according to the `singleLicensePer`
|
|
1069
|
+
* setting) are missing, then the keys surely must have been voluntarly
|
|
1070
|
+
* removed from the license.
|
|
1071
|
+
*
|
|
1072
|
+
* If it is however set to `false`, it means that the license is an older
|
|
1073
|
+
* license that might have been linked to another content, thus we cannot make
|
|
1074
|
+
* that assumption.
|
|
1075
|
+
* @param {Array.<Uint8Array>} usableKeyIds - Key ids that are present in the
|
|
1076
|
+
* license and can be used.
|
|
1077
|
+
* @param {Array.<Uint8Array>} unusableKeyIds - Key ids that are present in the
|
|
1078
|
+
* license yet cannot be used.
|
|
1079
|
+
* @returns {Object} - Returns an object with the following properties:
|
|
1080
|
+
* - `whitelisted`: Array of key ids for keys that are known to be usable
|
|
1081
|
+
* - `blacklisted`: Array of key ids for keys that are considered unusable.
|
|
1082
|
+
* The qualities linked to those keys should not be played.
|
|
1068
1083
|
*/
|
|
1069
|
-
function
|
|
1084
|
+
function getKeyIdsLinkedToSession(
|
|
1070
1085
|
initializationData : IProcessedProtectionData,
|
|
1086
|
+
keySessionRecord : KeySessionRecord,
|
|
1071
1087
|
singleLicensePer : undefined | "init-data" | "content" | "periods",
|
|
1088
|
+
isCurrentLicense : boolean,
|
|
1072
1089
|
usableKeyIds : Uint8Array[],
|
|
1073
1090
|
unusableKeyIds : Uint8Array[]
|
|
1074
1091
|
) : { whitelisted : Uint8Array[];
|
|
@@ -1081,6 +1098,19 @@ function getFetchedLicenseKeysInfo(
|
|
|
1081
1098
|
const associatedKeyIds = [...usableKeyIds,
|
|
1082
1099
|
...unusableKeyIds];
|
|
1083
1100
|
|
|
1101
|
+
// Add all key ids associated to the `KeySessionRecord` yet not in
|
|
1102
|
+
// `usableKeyIds` nor in `unusableKeyIds`
|
|
1103
|
+
const allKnownKeyIds = keySessionRecord.getAssociatedKeyIds();
|
|
1104
|
+
for (const kid of allKnownKeyIds) {
|
|
1105
|
+
if (!associatedKeyIds.some(ak => areKeyIdsEqual(ak, kid))) {
|
|
1106
|
+
if (log.hasLevel("DEBUG")) {
|
|
1107
|
+
log.debug("DRM: KeySessionRecord's key missing in the license, blacklisting it",
|
|
1108
|
+
bytesToHex(kid));
|
|
1109
|
+
}
|
|
1110
|
+
associatedKeyIds.push(kid);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1084
1114
|
if (singleLicensePer !== undefined && singleLicensePer !== "init-data") {
|
|
1085
1115
|
// We want to add the current key ids in the blacklist if it is
|
|
1086
1116
|
// not already there.
|
|
@@ -1102,11 +1132,15 @@ function getFetchedLicenseKeysInfo(
|
|
|
1102
1132
|
return !associatedKeyIds.some(k => areKeyIdsEqual(k, expected));
|
|
1103
1133
|
});
|
|
1104
1134
|
if (missingKeyIds.length > 0) {
|
|
1135
|
+
if (log.hasLevel("DEBUG")) {
|
|
1136
|
+
log.debug("DRM: init data keys missing in the license, blacklisting them",
|
|
1137
|
+
missingKeyIds.map(m => bytesToHex(m)).join(", "));
|
|
1138
|
+
}
|
|
1105
1139
|
associatedKeyIds.push(...missingKeyIds) ;
|
|
1106
1140
|
}
|
|
1107
1141
|
}
|
|
1108
1142
|
|
|
1109
|
-
if (content !== undefined) {
|
|
1143
|
+
if (isCurrentLicense && content !== undefined) {
|
|
1110
1144
|
if (singleLicensePer === "content") {
|
|
1111
1145
|
// Put it in a Set to automatically filter out duplicates (by ref)
|
|
1112
1146
|
const contentKeys = new Set<Uint8Array>();
|
|
@@ -70,12 +70,12 @@ export default function getRepresentationEstimate(
|
|
|
70
70
|
updateRepresentationsReference();
|
|
71
71
|
manifest.addEventListener("decipherabilityUpdate", updateRepresentationsReference);
|
|
72
72
|
const unregisterCleanUp = cancellationSignal.register(cleanUp);
|
|
73
|
-
const
|
|
74
|
-
abrCallbacks
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const { estimates: estimateRef,
|
|
74
|
+
callbacks: abrCallbacks } = representationEstimator(content,
|
|
75
|
+
currentRepresentation,
|
|
76
|
+
representations,
|
|
77
|
+
playbackObserver,
|
|
78
|
+
cancellationSignal);
|
|
79
79
|
return { abrCallbacks, estimateRef };
|
|
80
80
|
|
|
81
81
|
function updateRepresentationsReference() : void {
|
package/src/utils/reference.ts
CHANGED
|
@@ -57,11 +57,26 @@ import { CancellationSignal } from "./task_canceller";
|
|
|
57
57
|
* those use cases makes the intent of the corresponding code clearer.
|
|
58
58
|
*/
|
|
59
59
|
export interface ISharedReference<T> {
|
|
60
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Get the last set value for this shared reference.
|
|
62
|
+
* @returns {*}
|
|
63
|
+
*/
|
|
61
64
|
getValue() : T;
|
|
62
65
|
|
|
63
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Update the value of this shared reference.
|
|
68
|
+
* @param {*} newVal
|
|
69
|
+
*/
|
|
64
70
|
setValue(newVal : T) : void;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Update the value of this shared reference only if the value changed.
|
|
74
|
+
*
|
|
75
|
+
* Note that this function only performs a strict equality reference through
|
|
76
|
+
* the "===" operator. Different objects that are structurally the same will
|
|
77
|
+
* thus be considered different.
|
|
78
|
+
* @param {*} newVal
|
|
79
|
+
*/
|
|
65
80
|
setValueIfChanged(newVal : T) : void;
|
|
66
81
|
|
|
67
82
|
/**
|
|
@@ -72,25 +87,6 @@ export interface ISharedReference<T> {
|
|
|
72
87
|
* @returns {Observable}
|
|
73
88
|
*/
|
|
74
89
|
asObservable(skipCurrentValue? : boolean) : Observable<T>;
|
|
75
|
-
/**
|
|
76
|
-
* Triggers a callback each time this reference's value is updated.
|
|
77
|
-
*
|
|
78
|
-
* Can be given several options as argument:
|
|
79
|
-
* - clearSignal: When the attach `CancellationSignal` emits, the given
|
|
80
|
-
* callback will not be called anymore on reference updates.
|
|
81
|
-
* - emitCurrentValue: If `true`, the callback will be called directly and
|
|
82
|
-
* synchronously on this call with its current value.
|
|
83
|
-
* @param {Function} cb
|
|
84
|
-
* @param {Object} [options]
|
|
85
|
-
*/
|
|
86
|
-
onUpdate(
|
|
87
|
-
cb : (val : T) => void,
|
|
88
|
-
options? : {
|
|
89
|
-
clearSignal?: CancellationSignal;
|
|
90
|
-
emitCurrentValue?: boolean;
|
|
91
|
-
},
|
|
92
|
-
) : void;
|
|
93
|
-
|
|
94
90
|
/**
|
|
95
91
|
* Allows to register a callback to be called each time the value inside the
|
|
96
92
|
* reference is updated.
|
|
@@ -109,7 +105,6 @@ export interface ISharedReference<T> {
|
|
|
109
105
|
emitCurrentValue?: boolean;
|
|
110
106
|
},
|
|
111
107
|
) : void;
|
|
112
|
-
|
|
113
108
|
/**
|
|
114
109
|
* Indicate that no new values will be emitted.
|
|
115
110
|
* Allows to automatically close all Observables generated from this shared
|
|
@@ -217,7 +212,7 @@ export function createSharedReference<T>(initialValue : T) : ISharedReference<T>
|
|
|
217
212
|
|
|
218
213
|
/**
|
|
219
214
|
* Update the value of this shared reference.
|
|
220
|
-
* @param {*}
|
|
215
|
+
* @param {*} newVal
|
|
221
216
|
*/
|
|
222
217
|
setValue(newVal : T) : void {
|
|
223
218
|
if (isFinished) {
|
|
@@ -244,6 +239,10 @@ export function createSharedReference<T>(initialValue : T) : ISharedReference<T>
|
|
|
244
239
|
}
|
|
245
240
|
},
|
|
246
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Update the value of this shared reference only if it changed.
|
|
244
|
+
* @param {*} newVal
|
|
245
|
+
*/
|
|
247
246
|
setValueIfChanged(newVal : T) : void {
|
|
248
247
|
if (newVal !== value) {
|
|
249
248
|
this.setValue(newVal);
|
|
@@ -353,6 +352,17 @@ export function createSharedReference<T>(initialValue : T) : ISharedReference<T>
|
|
|
353
352
|
};
|
|
354
353
|
}
|
|
355
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Create a new `ISharedReference` based on another one by mapping over its
|
|
357
|
+
* referenced value each time it is updated.
|
|
358
|
+
* @param {Object} originalRef - The Original `ISharedReference` you wish to map
|
|
359
|
+
* over.
|
|
360
|
+
* @param {Function} mappingFn - The mapping function which will receives
|
|
361
|
+
* `originalRef`'s value and outputs this new reference's value.
|
|
362
|
+
* @param {Object | undefined} [cancellationSignal] - Optionally, a
|
|
363
|
+
* `CancellationSignal` which will finish that reference when it emits.
|
|
364
|
+
* @returns {Object} - The new, mapped, reference.
|
|
365
|
+
*/
|
|
356
366
|
export function createMappedReference<T, U>(
|
|
357
367
|
originalRef : IReadOnlySharedReference<T>,
|
|
358
368
|
mappingFn : (x : T) => U,
|