From c233f4297095adda07549ff1e865710b8edb16fa Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Fri, 6 Sep 2024 10:28:45 +0200 Subject: [PATCH] Add isRepresentationPlayable util --- src/core/cmcd/cmcd_data_builder.ts | 7 ++-- .../stream/adaptation/adaptation_stream.ts | 7 ++-- src/core/stream/period/period_stream.ts | 12 +++---- .../utils/get_adaptation_switch_strategy.ts | 5 ++- .../tracks_store/track_dispatcher.ts | 14 ++------ src/main_thread/tracks_store/tracks_store.ts | 6 ++-- src/manifest/utils.ts | 32 +++++++++---------- 7 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/core/cmcd/cmcd_data_builder.ts b/src/core/cmcd/cmcd_data_builder.ts index 4f9687a853..6be0ae32f3 100644 --- a/src/core/cmcd/cmcd_data_builder.ts +++ b/src/core/cmcd/cmcd_data_builder.ts @@ -6,6 +6,7 @@ import type { IRepresentation, ISegment, } from "../../manifest"; +import { isRepresentationPlayable } from "../../manifest"; import type { IReadOnlyPlaybackObserver, IRebufferingStatus, @@ -294,11 +295,7 @@ export default class CmcdDataBuilder { props.st = content.manifest.isDynamic ? "l" : "v"; props.tb = content.adaptation.representations.reduce( (acc: number | undefined, representation: IRepresentation) => { - if ( - representation.isCodecSupported !== true || - representation.isResolutionSupported === false || - representation.decipherable === false - ) { + if (isRepresentationPlayable(representation) !== true) { return acc; } if (acc === undefined) { diff --git a/src/core/stream/adaptation/adaptation_stream.ts b/src/core/stream/adaptation/adaptation_stream.ts index 7c054816b4..4265168942 100644 --- a/src/core/stream/adaptation/adaptation_stream.ts +++ b/src/core/stream/adaptation/adaptation_stream.ts @@ -2,6 +2,7 @@ import config from "../../../config"; import { formatError } from "../../../errors"; import log from "../../../log"; import type { IRepresentation } from "../../../manifest"; +import { isRepresentationPlayable } from "../../../manifest"; import arrayIncludes from "../../../utils/array_includes"; import { assertUnreachable } from "../../../utils/assert"; import cancellableSleep from "../../../utils/cancellable_sleep"; @@ -95,11 +96,7 @@ export default function AdaptationStream( const initialRepIds = content.representations.getValue().representationIds; const initialRepresentations = content.adaptation.representations.filter( - (r) => - arrayIncludes(initialRepIds, r.id) && - r.decipherable !== false && - r.isCodecSupported !== false && - r.isResolutionSupported !== false, + (r) => arrayIncludes(initialRepIds, r.id) && isRepresentationPlayable(r) !== false, ); /** Emit the list of Representation for the adaptive logic. */ diff --git a/src/core/stream/period/period_stream.ts b/src/core/stream/period/period_stream.ts index 4c054c79aa..eec0143746 100644 --- a/src/core/stream/period/period_stream.ts +++ b/src/core/stream/period/period_stream.ts @@ -18,7 +18,7 @@ import config from "../../../config"; import { formatError, MediaError } from "../../../errors"; import log from "../../../log"; import type { IAdaptation, IPeriod } from "../../../manifest"; -import { toTaggedTrack } from "../../../manifest"; +import { isRepresentationPlayable, toTaggedTrack } from "../../../manifest"; import type { IReadOnlyPlaybackObserver } from "../../../playback_observer"; import type { ITrackType } from "../../../public_types"; import arrayFind from "../../../utils/array_find"; @@ -472,13 +472,9 @@ function createOrReuseSegmentSink( * @returns {string} */ function getFirstDeclaredMimeType(adaptation: IAdaptation): string { - const representations = adaptation.representations.filter((r) => { - return ( - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false - ); - }); + const representations = adaptation.representations.filter( + (r) => isRepresentationPlayable(r) !== false, + ); if (representations.length === 0) { const noRepErr = new MediaError( "NO_PLAYABLE_REPRESENTATION", diff --git a/src/core/stream/period/utils/get_adaptation_switch_strategy.ts b/src/core/stream/period/utils/get_adaptation_switch_strategy.ts index d141797ddb..9cc00a6f98 100644 --- a/src/core/stream/period/utils/get_adaptation_switch_strategy.ts +++ b/src/core/stream/period/utils/get_adaptation_switch_strategy.ts @@ -16,6 +16,7 @@ import config from "../../../../config"; import type { IAdaptation, IPeriod } from "../../../../manifest"; +import { isRepresentationPlayable } from "../../../../manifest"; import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer"; import areCodecsCompatible from "../../../../utils/are_codecs_compatible"; import type { IRange } from "../../../../utils/ranges"; @@ -189,9 +190,7 @@ export default function getAdaptationSwitchStrategy( function hasCompatibleCodec(adaptation: IAdaptation, segmentSinkCodec: string): boolean { return adaptation.representations.some( (rep) => - rep.isCodecSupported === true && - rep.decipherable !== false && - rep.isResolutionSupported !== false && + isRepresentationPlayable(rep) === true && areCodecsCompatible(rep.getMimeTypeString(), segmentSinkCodec), ); } diff --git a/src/main_thread/tracks_store/track_dispatcher.ts b/src/main_thread/tracks_store/track_dispatcher.ts index 4a550d7b87..a08da01211 100644 --- a/src/main_thread/tracks_store/track_dispatcher.ts +++ b/src/main_thread/tracks_store/track_dispatcher.ts @@ -4,6 +4,7 @@ import type { ITrackSwitchingMode, } from "../../core/types"; import type { IAdaptationMetadata, IRepresentationMetadata } from "../../manifest"; +import { isRepresentationPlayable } from "../../manifest"; import type { IAudioRepresentationsSwitchingMode, IVideoRepresentationsSwitchingMode, @@ -186,13 +187,7 @@ export default class TrackDispatcher extends EventEmitter if (repSettings === null) { // unlocking playableRepresentations = trackInfo.adaptation.representations.filter( - (representation) => { - return ( - representation.isCodecSupported === true && - representation.decipherable !== false && - representation.isResolutionSupported !== false - ); - }, + (representation) => isRepresentationPlayable(representation) === true, ); // No need to remove the previous content when unlocking @@ -204,10 +199,7 @@ export default class TrackDispatcher extends EventEmitter arrayIncludes(representationIds, r.id), ); playableRepresentations = representations.filter( - (r) => - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false, + (representation) => isRepresentationPlayable(representation) === true, ); if (playableRepresentations.length === 0) { self.trigger("noPlayableLockedRepresentation", null); diff --git a/src/main_thread/tracks_store/tracks_store.ts b/src/main_thread/tracks_store/tracks_store.ts index aba0addf70..c74a027c73 100644 --- a/src/main_thread/tracks_store/tracks_store.ts +++ b/src/main_thread/tracks_store/tracks_store.ts @@ -30,6 +30,7 @@ import type { } from "../../manifest"; import { getSupportedAdaptations, + isRepresentationPlayable, toAudioTrack, toTextTrack, toVideoTrack, @@ -399,10 +400,7 @@ export default class TracksStore extends EventEmitter { return false; } const playableRepresentations = adaptation.representations.filter( - (r) => - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false, + (r) => isRepresentationPlayable(r) === true, ); return playableRepresentations.length > 0; }, diff --git a/src/manifest/utils.ts b/src/manifest/utils.ts index 2a7234c4e7..02fc4091d0 100644 --- a/src/manifest/utils.ts +++ b/src/manifest/utils.ts @@ -237,12 +237,7 @@ export function toAudioTrack( audioDescription: adaptation.isAudioDescription === true, id: adaptation.id, representations: (filterPlayable - ? adaptation.representations.filter( - (r) => - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false, - ) + ? adaptation.representations.filter((r) => isRepresentationPlayable(r)) : adaptation.representations ).map(toAudioRepresentation), label: adaptation.label, @@ -286,10 +281,7 @@ export function toVideoTrack( const representations = ( filterPlayable ? trickModeAdaptation.representations.filter( - (r) => - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false, + (r) => isRepresentationPlayable(r) === true, ) : trickModeAdaptation.representations ).map(toVideoRepresentation); @@ -308,12 +300,7 @@ export function toVideoTrack( const videoTrack: IVideoTrack = { id: adaptation.id, representations: (filterPlayable - ? adaptation.representations.filter( - (r) => - r.isCodecSupported === true && - r.decipherable !== false && - r.isResolutionSupported !== false, - ) + ? adaptation.representations.filter((r) => isRepresentationPlayable(r) === true) : adaptation.representations ).map(toVideoRepresentation), label: adaptation.label, @@ -400,6 +387,19 @@ export function toTaggedTrack(adaptation: IAdaptation): ITaggedTrack { } } +export function isRepresentationPlayable( + representation: IRepresentationMetadata, +): boolean | undefined { + if (representation.isCodecSupported === undefined) { + return undefined; + } + return ( + representation.isCodecSupported && + representation.isResolutionSupported !== false && + representation.decipherable !== false + ); +} + /** * Information on a Representation affected by a `decipherabilityUpdates` event. */