diff --git a/doc/api/Player_Events.md b/doc/api/Player_Events.md
index 4cc291d57d1..8e2fe1bb04d 100644
--- a/doc/api/Player_Events.md
+++ b/doc/api/Player_Events.md
@@ -657,6 +657,67 @@ The payload for this event is an object with the following properties:
application's logic.
+
This event is not sent in
DirectFile mode (see
transport option)
diff --git a/src/core/api/public_api.ts b/src/core/api/public_api.ts
index 7be15500b88..080d1e750ce 100644
--- a/src/core/api/public_api.ts
+++ b/src/core/api/public_api.ts
@@ -57,6 +57,7 @@ import {
ILockedAudioRepresentationsSettings,
ILockedVideoRepresentationsSettings,
ITrackUpdateEventPayload,
+ IRepresentationListUpdateContext,
IPeriod,
IPeriodChangeEvent,
IPlayerError,
@@ -70,7 +71,9 @@ import {
IVideoTrack,
IVideoTrackSetting,
IVideoTrackSwitchingMode,
+ ITrackType,
} from "../../public_types";
+import arrayFind from "../../utils/array_find";
import arrayIncludes from "../../utils/array_includes";
import assert from "../../utils/assert";
import assertUnreachable from "../../utils/assert_unreachable";
@@ -2162,6 +2165,60 @@ class Player extends EventEmitter
{
return;
}
}, contentInfos.currentContentCanceller.signal);
+
+ manifest.addEventListener("decipherabilityUpdate", (elts) => {
+ /**
+ * Array of tuples only including once the Period/Track combination, and
+ * only when it concerns the currently-selected track.
+ */
+ const periodsAndTrackTypes = elts.reduce(
+ (acc: Array<[Period, ITrackType]>, elt) => {
+ const isFound = arrayFind(
+ acc,
+ (x) => x[0].id === elt.period.id &&
+ x[1] === elt.adaptation.type
+ ) === undefined;
+
+ if (!isFound) {
+ // Only consider the currently-selected tracks.
+ // NOTE: Maybe there's room for optimizations? Unclear.
+ const { tracksStore } = contentInfos;
+ if (tracksStore === null) {
+ return acc;
+ }
+ let isCurrent = false;
+ const periodRef = tracksStore.getPeriodObjectFromPeriod(elt.period);
+ if (periodRef === undefined) {
+ return acc;
+ }
+ switch (elt.adaptation.type) {
+ case "audio":
+ isCurrent = tracksStore
+ .getChosenAudioTrack(periodRef)?.id === elt.adaptation.id;
+ break;
+ case "video":
+ isCurrent = tracksStore
+ .getChosenVideoTrack(periodRef)?.id === elt.adaptation.id;
+ break;
+ case "text":
+ isCurrent = tracksStore
+ .getChosenTextTrack(periodRef)?.id === elt.adaptation.id;
+ break;
+ }
+ if (isCurrent) {
+ acc.push([elt.period, elt.adaptation.type]);
+ }
+ }
+ return acc;
+ }, []);
+ for (const [period, trackType] of periodsAndTrackTypes) {
+ this._priv_triggerEventIfNotStopped(
+ "representationListUpdate",
+ { period, trackType, reason: "decipherability-update" },
+ contentInfos.currentContentCanceller.signal
+ );
+ }
+ }, contentInfos.currentContentCanceller.signal);
}
/**
@@ -2654,6 +2711,7 @@ interface IPublicAPIEvent {
newAvailablePeriods : IPeriod[];
brokenRepresentationsLock : IBrokenRepresentationsLockContext;
trackUpdate : ITrackUpdateEventPayload;
+ representationListUpdate : IRepresentationListUpdateContext;
seeking : null;
seeked : null;
streamEvent : IStreamEvent;
diff --git a/src/public_types.ts b/src/public_types.ts
index 2f4e2f0774b..379ffb25bf7 100644
--- a/src/public_types.ts
+++ b/src/public_types.ts
@@ -929,6 +929,13 @@ export interface ITrackUpdateEventPayload {
string;
}
+export interface IRepresentationListUpdateContext {
+ period : IPeriod;
+ trackType : ITrackType;
+ reason : "decipherability-update" |
+ string;
+}
+
export interface ILockedVideoRepresentationsSettings {
representations : string[];
periodId? : string | undefined;