diff --git a/src/README.md b/src/README.md index b5807f57074..5b87fa98ea4 100644 --- a/src/README.md +++ b/src/README.md @@ -182,9 +182,9 @@ For the subdirectories and files in this directory not represented in that schem - `manifest` (_./manifest_): Defines a `Manifest` structure and its properties, a central structure of the player describing a content. -- `PlaybackObserver` (./playback_observer): Defines `PlaybackObserver` instances, used by - many modules to obtain playback-related properties (such as the playing position, the - current playback speed etc.). +- `MediaElementMonitor` (./media_element_monitor): Defines the `MediaElementMonitor` , + used by many modules to poll the `HTMLMediaElement` for playback-related properties + (such as the playing position, the current playback speed etc.). - `parsers` (_./parsers_): Various parsers for several formats diff --git a/src/core/adaptive/adaptive_representation_selector.ts b/src/core/adaptive/adaptive_representation_selector.ts index 6f498b510be..9a6b81a0646 100644 --- a/src/core/adaptive/adaptive_representation_selector.ts +++ b/src/core/adaptive/adaptive_representation_selector.ts @@ -25,8 +25,8 @@ import type { } from "../../manifest/index.ts"; import type { ObservationPosition, - IReadOnlyPlaybackObserver, -} from "../../playback_observer/index.ts"; + IReadOnlyMediaElementMonitor, +} from "../../media_element_monitor/index.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; import noop from "../../utils/noop.ts"; import type { IRange } from "../../utils/ranges.ts"; @@ -88,7 +88,7 @@ export default function createAdaptiveRepresentationSelector( * @param {Object} context * @param {Object} currentRepresentation * @param {Object} representations - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {Object} stopAllEstimates * @returns {Array.} */ @@ -96,7 +96,7 @@ export default function createAdaptiveRepresentationSelector( context: { manifest: IManifest; period: IPeriod; adaptation: IAdaptation }, currentRepresentation: IReadOnlySharedReference, representations: IReadOnlySharedReference, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, stopAllEstimates: CancellationSignal, ): IRepresentationEstimatorResponse { const { type } = context.adaptation; @@ -113,7 +113,7 @@ export default function createAdaptiveRepresentationSelector( currentRepresentation, filters, initialBitrate, - playbackObserver, + mediaElementMonitor, representations, lowLatencyMode, }, @@ -165,7 +165,7 @@ function getEstimateReference( filters, initialBitrate, lowLatencyMode, - playbackObserver, + mediaElementMonitor, representations: representationsRef, }: IRepresentationEstimatorArguments, stopAllEstimates: CancellationSignal, @@ -263,25 +263,25 @@ function getEstimateReference( const guessBasedChooser = new GuessBasedChooser(scoreCalculator, prevEstimate); // get initial observation for initial estimate - let lastPlaybackObservation = playbackObserver.getReference().getValue(); + let lastMediaObservation = mediaElementMonitor.getReference().getValue(); /** Reference through which estimates are emitted. */ const innerEstimateRef = new SharedReference(getCurrentEstimate()); - // Listen to playback observations - playbackObserver.listen( + // Listen to media observations + mediaElementMonitor.listen( (obs) => { - lastPlaybackObservation = obs; + lastMediaObservation = obs; updateEstimate(); }, { includeLastObservation: false, clearSignal: innerCancellationSignal }, ); onAddedSegment = function (val: IAddedSegmentCallbackPayload) { - if (lastPlaybackObservation === null) { + if (lastMediaObservation === null) { return; } - const { position, speed } = lastPlaybackObservation; + const { position, speed } = lastMediaObservation; const timeRanges = val.buffered; const bufferGap = getLeftSizeOfRange(timeRanges, position.getWanted()); const { representation } = val.content; @@ -310,7 +310,7 @@ function getEstimateReference( /** Returns the actual estimate based on all methods and algorithm available. */ function getCurrentEstimate(): IABREstimate { - const { bufferGap, position, maximumPosition } = lastPlaybackObservation; + const { bufferGap, position, maximumPosition } = lastMediaObservation; const resolutionLimit = filters.limitResolution.getValue(); const bitrateThrottle = filters.throttleBitrate.getValue(); const currentRepresentationVal = currentRepresentation.getValue(); @@ -322,7 +322,7 @@ function getEstimateReference( ); const requests = requestsStore.getRequests(); const { bandwidthEstimate, bitrateChosen } = networkAnalyzer.getBandwidthEstimate( - lastPlaybackObservation, + lastMediaObservation, bandwidthEstimator, currentRepresentationVal, requests, @@ -334,7 +334,7 @@ function getEstimateReference( stableRepresentation === null ? undefined : stableRepresentation.bitrate / - (lastPlaybackObservation.speed > 0 ? lastPlaybackObservation.speed : 1); + (lastMediaObservation.speed > 0 ? lastMediaObservation.speed : 1); const { ABR_ENTER_BUFFER_BASED_ALGO, ABR_EXIT_BUFFER_BASED_ALGO } = config.getCurrent(); @@ -415,7 +415,7 @@ function getEstimateReference( ) { chosenRepFromGuessMode = guessBasedChooser.getGuess( sortedRepresentations, - lastPlaybackObservation, + lastMediaObservation, currentRepresentationVal, currentBestBitrate, requests, @@ -460,7 +460,7 @@ function getEstimateReference( chosenRepFromBufferSize.bitrate, currentRepresentationVal, requests, - lastPlaybackObservation, + lastMediaObservation, ), knownStableBitrate, }; @@ -481,7 +481,7 @@ function getEstimateReference( chosenRepFromBandwidth.bitrate, currentRepresentationVal, requests, - lastPlaybackObservation, + lastMediaObservation, ), knownStableBitrate, }; @@ -634,7 +634,7 @@ export interface IABREstimate { } /** Media properties `getEstimateReference` will need to keep track of. */ -export interface IRepresentationEstimatorPlaybackObservation { +export interface IRepresentationEstimatorMediaObservation { /** * For the concerned media buffer, difference in seconds between the next * position where no segment data is available and the current position. @@ -642,7 +642,7 @@ export interface IRepresentationEstimatorPlaybackObservation { bufferGap: number; /** * Information on the current media position in seconds at the time of a - * Playback Observation. + * media observation. */ position: ObservationPosition; /** @@ -744,7 +744,7 @@ export interface IRepresentationEstimatorArguments { /** Class allowing to estimate the current network bandwidth. */ bandwidthEstimator: BandwidthEstimator; /** Emit regular playback information. */ - playbackObserver: IReadOnlyPlaybackObserver; + mediaElementMonitor: IReadOnlyMediaElementMonitor; /** * The Representation currently loaded. * `null` if no Representation is currently loaded. @@ -794,7 +794,7 @@ export type IRepresentationEstimator = ( /** Reference emitting the list of available Representations to choose from. */ representations: IReadOnlySharedReference, /** Regularly emits playback conditions */ - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, /** * After this `CancellationSignal` emits, resources will be disposed and * estimates will stop to be emitted. diff --git a/src/core/adaptive/buffer_based_chooser.ts b/src/core/adaptive/buffer_based_chooser.ts index 2bf7c085240..324ce32e417 100644 --- a/src/core/adaptive/buffer_based_chooser.ts +++ b/src/core/adaptive/buffer_based_chooser.ts @@ -130,15 +130,13 @@ export default class BufferBasedChooser { } /** - * @param {Object} playbackObservation + * @param {Object} mediaObservation * @returns {number|undefined} */ - public onAddedSegment( - playbackObservation: IBufferBasedChooserPlaybackObservation, - ): void { + public onAddedSegment(mediaObservation: IBufferBasedChooserMediaObservation): void { const bufferLevels = this._levelsMap; const bitrates = this._bitrates; - const { bufferGap, currentBitrate, currentScore, speed } = playbackObservation; + const { bufferGap, currentBitrate, currentScore, speed } = mediaObservation; if (isNullOrUndefined(currentBitrate)) { this._currentEstimate = bitrates[0]; return; @@ -256,8 +254,8 @@ export default class BufferBasedChooser { } } -/** Playback observation needed by the `BufferBasedChooser`. */ -export interface IBufferBasedChooserPlaybackObservation { +/** media observation needed by the `BufferBasedChooser`. */ +export interface IBufferBasedChooserMediaObservation { /** * Difference in seconds between the current position and the next * non-buffered position in the buffer for the currently-considered diff --git a/src/core/adaptive/guess_based_chooser.ts b/src/core/adaptive/guess_based_chooser.ts index f3ce56dd434..1ca9c4f1071 100644 --- a/src/core/adaptive/guess_based_chooser.ts +++ b/src/core/adaptive/guess_based_chooser.ts @@ -70,7 +70,7 @@ export default class GuessBasedChooser { * GuessBasedChooser can choose from, sorted by bitrate ascending. * /!\ It is very important that Representation in that Array are sorted by * bitrate ascending for this method to work as intented. - * @param {Object} observation - Last playback observation performed. + * @param {Object} observation - Last media observation performed. * @param {Object} currentRepresentation - The Representation currently * loading. * @param {number} incomingBestBitrate - The bitrate of the Representation diff --git a/src/core/adaptive/index.ts b/src/core/adaptive/index.ts index c315d5e1848..c2195fa5909 100644 --- a/src/core/adaptive/index.ts +++ b/src/core/adaptive/index.ts @@ -21,7 +21,7 @@ import type { IMetricsCallbackPayload, IRepresentationEstimator, IRepresentationEstimatorCallbacks, - IRepresentationEstimatorPlaybackObservation, + IRepresentationEstimatorMediaObservation, IRepresentationEstimatorThrottlers as IABRThrottlers, IRequestBeginCallbackPayload, IRequestEndCallbackPayload, @@ -39,7 +39,7 @@ export type { IABREstimate, IMetricsCallbackPayload, IRepresentationEstimatorCallbacks, - IRepresentationEstimatorPlaybackObservation, + IRepresentationEstimatorMediaObservation, IRequestBeginCallbackPayload, IRequestProgressCallbackPayload, IRequestEndCallbackPayload, diff --git a/src/core/adaptive/network_analyzer.ts b/src/core/adaptive/network_analyzer.ts index 40ffcf75f70..41ae50fc7b2 100644 --- a/src/core/adaptive/network_analyzer.ts +++ b/src/core/adaptive/network_analyzer.ts @@ -20,7 +20,7 @@ import type { IRepresentation } from "../../manifest/index.ts"; import arrayFind from "../../utils/array_find.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; import getMonotonicTimeStamp from "../../utils/monotonic_timestamp.ts"; -import type { IRepresentationEstimatorPlaybackObservation } from "./adaptive_representation_selector.ts"; +import type { IRepresentationEstimatorMediaObservation } from "./adaptive_representation_selector.ts"; import type BandwidthEstimator from "./utils/bandwidth_estimator.ts"; import EWMA from "./utils/ewma.ts"; import type { @@ -30,7 +30,7 @@ import type { /** Object describing the current playback conditions. */ export type IPlaybackConditionsInfo = Pick< - IRepresentationEstimatorPlaybackObservation, + IRepresentationEstimatorMediaObservation, "bufferGap" | "position" | "speed" | "duration" >; diff --git a/src/core/cmcd/cmcd_data_builder.ts b/src/core/cmcd/cmcd_data_builder.ts index 35fb2a6070f..8d2593087b7 100644 --- a/src/core/cmcd/cmcd_data_builder.ts +++ b/src/core/cmcd/cmcd_data_builder.ts @@ -7,10 +7,10 @@ import type { ISegment, } from "../../manifest/index.ts"; import type { - IReadOnlyPlaybackObserver, + IReadOnlyMediaElementMonitor, IRebufferingStatus, ObservationPosition, -} from "../../playback_observer/index.ts"; +} from "../../media_element_monitor/index.ts"; import type { ICmcdOptions, ICmcdPayload, ITrackType } from "../../public_types.ts"; import createUuid from "../../utils/create_uuid.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; @@ -60,10 +60,10 @@ export interface ICmcdSegmentInfo { } /** - * Media playback observation's properties the `CmcdDataBuilder` wants to have + * Media media observation's properties the `CmcdDataBuilder` wants to have * access to. */ -export interface ICmcdDataBuilderPlaybackObservation { +export interface ICmcdDataBuilderMediaObservation { /** * Ranges of buffered data per type of media. * `null` if no buffer exists for that type of media. @@ -81,7 +81,7 @@ export interface ICmcdDataBuilderPlaybackObservation { * status. * "Rebuffering" is a status where the player has not enough buffer ahead to * play reliably. - * The RxPlayer should pause playback when a playback observation indicates the + * The RxPlayer should pause playback when a media observation indicates the * rebuffering status. */ rebuffering: IRebufferingStatus | null; @@ -98,7 +98,7 @@ export default class CmcdDataBuilder { private _contentId: string; private _typePreference: TypePreference; private _lastThroughput: Partial>; - private _playbackObserver: IReadOnlyPlaybackObserver | null; + private _mediaElementMonitor: IReadOnlyMediaElementMonitor | null; private _bufferStarvationToggle: boolean; private _canceller: TaskCanceller | null; @@ -115,28 +115,28 @@ export default class CmcdDataBuilder { ? TypePreference.Headers : TypePreference.QueryString; this._bufferStarvationToggle = false; - this._playbackObserver = null; + this._mediaElementMonitor = null; this._lastThroughput = {}; this._canceller = null; } /** - * Start listening to the given `playbackObserver` so the `CmcdDataBuilder` + * Start listening to the given `mediaElementMonitor` so the `CmcdDataBuilder` * can extract some playback-linked metadata that it needs. * * It will keep listening for media data until `stopMonitoringPlayback` is called. * * If `startMonitoringPlayback` is called again, the previous monitoring is * also cancelled. - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor */ public startMonitoringPlayback( - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, ): void { this._canceller?.cancel("CmcdDataBuilder start"); this._canceller = new TaskCanceller("CMCD monitoring"); - this._playbackObserver = playbackObserver; - playbackObserver.listen( + this._mediaElementMonitor = mediaElementMonitor; + mediaElementMonitor.listen( (obs) => { if (obs.rebuffering !== null) { this._bufferStarvationToggle = true; @@ -153,7 +153,7 @@ export default class CmcdDataBuilder { public stopMonitoringPlayback(): void { this._canceller?.cancel("CmcdDataBuilder stop"); this._canceller = null; - this._playbackObserver = null; + this._mediaElementMonitor = null; } /** @@ -184,7 +184,7 @@ export default class CmcdDataBuilder { : undefined; props.sid = this._sessionId; - const lastObservation = this._playbackObserver?.getReference().getValue(); + const lastObservation = this._mediaElementMonitor?.getReference().getValue(); props.pr = lastObservation === undefined || !isFinite(lastObservation.speed) || @@ -232,7 +232,7 @@ export default class CmcdDataBuilder { * @returns {Object} */ public getCmcdDataForSegmentRequest(content: ICmcdSegmentInfo): ICmcdPayload { - const lastObservation = this._playbackObserver?.getReference().getValue(); + const lastObservation = this._mediaElementMonitor?.getReference().getValue(); const props = this._getCommonCmcdData(this._lastThroughput[content.adaptation.type]); props.br = Math.round(content.representation.bitrate / 1000); @@ -289,7 +289,7 @@ export default class CmcdDataBuilder { if (!isNullOrUndefined(bufferedForType)) { // TODO more precize position estimate? const position = - this._playbackObserver?.getCurrentTime() ?? + this._mediaElementMonitor?.getCurrentTime() ?? lastObservation.position.getWanted() ?? lastObservation.position.getPolled(); for (const range of bufferedForType) { diff --git a/src/core/cmcd/index.ts b/src/core/cmcd/index.ts index 3ebd7cf5816..7ef06e36214 100644 --- a/src/core/cmcd/index.ts +++ b/src/core/cmcd/index.ts @@ -2,6 +2,6 @@ import CmcdDataBuilder from "./cmcd_data_builder.ts"; export type { ICmcdSegmentInfo, - ICmcdDataBuilderPlaybackObservation, + ICmcdDataBuilderMediaObservation, } from "./cmcd_data_builder.ts"; export default CmcdDataBuilder; diff --git a/src/core/entry/FreezeResolver.ts b/src/core/entry/FreezeResolver.ts index edaeb9bfef7..9421cc7ffd7 100644 --- a/src/core/entry/FreezeResolver.ts +++ b/src/core/entry/FreezeResolver.ts @@ -5,7 +5,7 @@ import type { IFreezingStatus, IRebufferingStatus, ObservationPosition, -} from "../../playback_observer/index.ts"; +} from "../../media_element_monitor/index.ts"; import getMonotonicTimeStamp from "../../utils/monotonic_timestamp.ts"; import type SegmentSinksStore from "../segment_sinks/index.ts"; import type { IBufferedChunk } from "../segment_sinks/index.ts"; @@ -192,7 +192,7 @@ export default class FreezeResolver { * * Refer to the returned type's definition for more information. * - * @param {Object} observation - The last playback observation produced, it + * @param {Object} observation - The last media observation produced, it * has to be recent (just triggered for example). * @returns {Object|null} */ @@ -291,7 +291,7 @@ export default class FreezeResolver { * an object describing this wanted unfreezing strategy. * * If this method decides to take no action for now, it returns `null`. - * @param {Object} observation - playback observation that has just been + * @param {Object} observation - media observation that has just been * performed. * @param {number} now - Monotonically-raising timestamp for the current * time. @@ -568,7 +568,7 @@ function haveBuffersUndecipherableData(segmentSinksStore: SegmentSinksStore): { /** * Constructs a `bufferGap` value that is more usable than what the - * `PlaybackObserver` returns: + * `MediaElementMonitor` returns: * - it cannot be `undefined` * - its weird `Infinity` value is translated to the more explicit `0`. * @param {number|undefined} bufferGap @@ -596,7 +596,7 @@ interface IPlayedHistoryEntry { timestamp: number; } -/** Playback observation needed by the `FreezeResolver`. */ +/** Media observation needed by the `FreezeResolver`. */ export interface IFreezeResolverObservation { /** Current `readyState` value on the media element. */ readyState: number; diff --git a/src/core/entry/content_time_boundaries_observer.ts b/src/core/entry/content_time_boundaries_observer.ts index 8b70941ba75..63fff146b04 100644 --- a/src/core/entry/content_time_boundaries_observer.ts +++ b/src/core/entry/content_time_boundaries_observer.ts @@ -15,7 +15,7 @@ */ import type { - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, IBufferType, } from "../../core/types.ts"; import { MediaError } from "../../errors/index.ts"; @@ -25,7 +25,7 @@ import type { IRepresentationIndex, IPeriod, } from "../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../media_element_monitor/index.ts"; import type { IPlayerError } from "../../public_types.ts"; import arrayIncludes from "../../utils/array_includes.ts"; import EventEmitter from "../../utils/event_emitter.ts"; @@ -79,11 +79,11 @@ export default class ContentTimeBoundariesObserver extends EventEmitter, + mediaElementMonitor: IReadOnlyMediaElementMonitor, bufferTypes: IBufferType[], ) { super(); @@ -116,7 +116,7 @@ export default class ContentTimeBoundariesObserver extends EventEmitter { - playbackObserver.listen( + mediaElementMonitor.listen( ({ position }) => { const wantedPosition = position.getWanted(); const minimumPosition = manifest.getMinimumSafePosition(); @@ -694,7 +694,7 @@ interface IActiveStreamsInfo { hasFinishedLoadingLastPeriod: boolean; } -export type IContentTimeObserverPlaybackObservation = Pick< - IStreamOrchestratorPlaybackObservation, +export type IContentTimeObserverMediaObservation = Pick< + IStreamOrchestratorMediaObservation, "position" >; diff --git a/src/core/entry/core_entry.ts b/src/core/entry/core_entry.ts index f8a18012fbe..b5eebcf5784 100644 --- a/src/core/entry/core_entry.ts +++ b/src/core/entry/core_entry.ts @@ -14,9 +14,9 @@ import Manifest, { Period, Representation, } from "../../manifest/classes/index.ts"; -import type { ICorePlaybackObservation } from "../../playback_observer/core_playback_observer.ts"; -import CorePlaybackObserver from "../../playback_observer/core_playback_observer.ts"; -import { ObservationPosition } from "../../playback_observer/index.ts"; +import type { ICoreMediaObservation } from "../../media_element_monitor/core_media_element_monitor.ts"; +import CoreMediaElementMonitor from "../../media_element_monitor/core_media_element_monitor.ts"; +import { ObservationPosition } from "../../media_element_monitor/index.ts"; import type { IPlayerError, ITrackType } from "../../public_types.ts"; import arrayFind from "../../utils/array_find.ts"; import assert, { assertUnreachable } from "../../utils/assert.ts"; @@ -104,9 +104,9 @@ export default function initializeCoreEntry( let currentContentHandle: IContentHandle | null = null; /** - * When set, emit playback observation made on the main thread. + * When set, emit media observation made on the main thread. */ - let playbackObservationRef: SharedReference | null = null; + let mediaObservationRef: SharedReference | null = null; setMessageReceiver((e) => { log.debug("Core", "received message", { name: e.data.type }); @@ -166,15 +166,14 @@ export default function initializeCoreEntry( } currentContentHandle?.stop(); - playbackObservationRef?.finish(); + mediaObservationRef?.finish(); - const currentContentObservationRef = - new SharedReference( - objectAssign(msg.value.initialObservation, { - position: new ObservationPosition(...msg.value.initialObservation.position), - }), - ); - playbackObservationRef = currentContentObservationRef; + const currentContentObservationRef = new SharedReference( + objectAssign(msg.value.initialObservation, { + position: new ObservationPosition(...msg.value.initialObservation.position), + }), + ); + mediaObservationRef = currentContentObservationRef; currentContentHandle = loadPreparedContent( sendMessage, msg.value, @@ -185,7 +184,7 @@ export default function initializeCoreEntry( break; } - case MainThreadMessageType.PlaybackObservation: { + case MainThreadMessageType.MediaObservation: { const currentContent = contentPreparer.getCurrentContent(); if (msg.contentId !== currentContent?.contentId) { return; @@ -202,7 +201,7 @@ export default function initializeCoreEntry( if (newBuffered.video !== null) { buffered.video = newBuffered.video; } - playbackObservationRef?.setValue( + mediaObservationRef?.setValue( objectAssign(observation, { position: new ObservationPosition(...msg.value.position), }), @@ -223,8 +222,8 @@ export default function initializeCoreEntry( currentContentHandle?.stop(); currentContentHandle = null; - playbackObservationRef?.finish(); - playbackObservationRef = null; + mediaObservationRef?.finish(); + mediaObservationRef = null; break; case MainThreadMessageType.MediaSourceReload: @@ -582,7 +581,7 @@ function loadPreparedContent( sendMessage: (msg: ICoreMessage, transferables?: Transferable[]) => void, val: ILoadingContentParameters, contentPreparer: ContentPreparer, - playbackObservationRef: IReadOnlySharedReference, + mediaObservationRef: IReadOnlySharedReference, refs: ICoreReferences, ): IContentHandle { log.debug("Core", "Loading pepared content."); @@ -640,7 +639,7 @@ function loadPreparedContent( } = preparedContent; const { drmSystemId, enableFastSwitching, onCodecSwitch } = val; - playbackObservationRef.onUpdate( + mediaObservationRef.onUpdate( (observation) => { synchronizeSegmentSinksOnObservation(observation, segmentSinksStore); const freezeResolution = @@ -672,13 +671,13 @@ function loadPreparedContent( throw error; } - const playbackObserver = new CorePlaybackObserver( - playbackObservationRef, + const mediaElementMonitor = new CoreMediaElementMonitor( + mediaObservationRef, contentId, sendMessage, currentLoadCanceller.signal, ); - cmcdDataBuilder?.startMonitoringPlayback(playbackObserver); + cmcdDataBuilder?.startMonitoringPlayback(mediaElementMonitor); currentLoadCanceller.signal.register(() => { cmcdDataBuilder?.stopMonitoringPlayback(); }); @@ -686,7 +685,7 @@ function loadPreparedContent( const contentTimeBoundariesObserver = createContentTimeBoundariesObserver( manifest, mediaSource, - playbackObserver, + mediaElementMonitor, segmentSinksStore, { onWarning: (err: IPlayerError) => @@ -708,7 +707,7 @@ function loadPreparedContent( StreamOrchestrator( { initialPeriod, manifest }, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -1024,7 +1023,7 @@ function loadPreparedContent( function onMediaSourceReload(): void { // TODO more precize one day? - const lastObservation = playbackObservationRef.getValue(); + const lastObservation = mediaObservationRef.getValue(); const newInitialTime = lastObservation.position.getWanted(); if (currentLoadCanceller !== null) { currentLoadCanceller.cancel("MediaSource reload"); diff --git a/src/core/entry/create_content_time_boundaries_observer.ts b/src/core/entry/create_content_time_boundaries_observer.ts index 140abc14237..aab729cde22 100644 --- a/src/core/entry/create_content_time_boundaries_observer.ts +++ b/src/core/entry/create_content_time_boundaries_observer.ts @@ -1,11 +1,11 @@ import type { ISegmentSinksStore, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, } from "../../core/types.ts"; import log from "../../log.ts"; import type { IManifest, IPeriod } from "../../manifest/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../media_element_monitor/index.ts"; import type { IMediaSourceInterface } from "../../mse/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../playback_observer/index.ts"; import type { IPlayerError } from "../../public_types.ts"; import type { CancellationSignal } from "../../utils/task_canceller.ts"; import ContentTimeBoundariesObserver from "./content_time_boundaries_observer.ts"; @@ -25,7 +25,7 @@ export interface IContentTimeBoundariesObserverCallbacks { * (see `ContentTimeBoundariesObserver`). * @param {Object} manifest * @param {Object} mediaSource - * @param {Object} streamObserver + * @param {Object} mediaElementMonitor * @param {Object} segmentSinksStore * @param {Object} cancelSignal * @returns {Object} @@ -33,7 +33,7 @@ export interface IContentTimeBoundariesObserverCallbacks { export default function createContentTimeBoundariesObserver( manifest: IManifest, mediaSource: IMediaSourceInterface, - streamObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, segmentSinksStore: ISegmentSinksStore, callbacks: IContentTimeBoundariesObserverCallbacks, cancelSignal: CancellationSignal, @@ -43,7 +43,7 @@ export default function createContentTimeBoundariesObserver( }); const contentTimeBoundariesObserver = new ContentTimeBoundariesObserver( manifest, - streamObserver, + mediaElementMonitor, segmentSinksStore.getBufferTypes(), ); cancelSignal.register((err) => { diff --git a/src/core/entry/utils.ts b/src/core/entry/utils.ts index 47b76f04be1..48db196e7fc 100644 --- a/src/core/entry/utils.ts +++ b/src/core/entry/utils.ts @@ -1,6 +1,6 @@ import BROWSER_GLOBALS from "../../compat/browser_compatibility_types.ts"; import { formatError } from "../../errors/index.ts"; -import type { ICorePlaybackObservation } from "../../main_thread/init/utils/create_core_playback_observer.ts"; +import type { ICoreMediaObservation } from "../../main_thread/init/utils/create_core_media_element_monitor.ts"; import type Manifest from "../../manifest/classes/index.ts"; import { createRepresentationFilterFromFnString } from "../../manifest/index.ts"; import type { @@ -42,13 +42,13 @@ export function formatErrorForSender(error: unknown): ISentError { /** * Synchronize SegmentSinks with what has been buffered. - * @param {Object} observation - The just-received playback observation, + * @param {Object} observation - The just-received media observation, * including what has been buffered on lower-level buffers * @param {Object} segmentSinksStore - Interface allowing to interact * with `SegmentSink`s, so their inventory can be updated accordingly. */ export function synchronizeSegmentSinksOnObservation( - observation: ICorePlaybackObservation, + observation: ICoreMediaObservation, segmentSinksStore: SegmentSinksStore, ): void { // Synchronize SegmentSinks with what has been buffered. diff --git a/src/core/segment_sinks/README.md b/src/core/segment_sinks/README.md index dd525dca06f..b7168d75db8 100644 --- a/src/core/segment_sinks/README.md +++ b/src/core/segment_sinks/README.md @@ -132,8 +132,8 @@ The `BufferGarbageCollector` is a function used by the RxPlayer to periodically It is based on the following building bricks: -- A playback observer emitting the current time (in seconds) when the garbage collection - task should be performed +- A `MediaElementMonitor` emitting the current time (in seconds) when the garbage + collection task should be performed - The `SegmentSink` on which the garbage collection task should run @@ -141,9 +141,9 @@ It is based on the following building bricks: - The maximum time margin authorized for the buffer ahead of the current position -Basically, each times the given playback observer emits, the BufferGarbageCollector will -ensure that the volume of data before and ahead of the current position does not grow into -a larger value than what is configured. +Basically, each times the given `MediaElementMonitor` emits, the BufferGarbageCollector +will ensure that the volume of data before and ahead of the current position does not grow +into a larger value than what is configured. For now, its code is completely decoupled for the rest of the code in that directory. This is why it is not included in the schema included on the top of this page. diff --git a/src/core/segment_sinks/garbage_collector.ts b/src/core/segment_sinks/garbage_collector.ts index e0e0a2fdf6a..da4fca12880 100644 --- a/src/core/segment_sinks/garbage_collector.ts +++ b/src/core/segment_sinks/garbage_collector.ts @@ -15,22 +15,22 @@ */ import log from "../../log.ts"; -import type { IReadOnlyPlaybackObserver } from "../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../media_element_monitor/index.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; import type { IRange } from "../../utils/ranges.ts"; import { getInnerAndOuterRanges } from "../../utils/ranges.ts"; import type { IReadOnlySharedReference } from "../../utils/reference.ts"; import type { CancellationSignal } from "../../utils/task_canceller.ts"; import TaskCanceller from "../../utils/task_canceller.ts"; -import type { IStreamOrchestratorPlaybackObservation } from "../stream/index.ts"; +import type { IStreamOrchestratorMediaObservation } from "../stream/index.ts"; import type { SegmentSink } from "./implementations/index.ts"; export interface IGarbageCollectorArgument { /** SegmentSink implementation */ segmentSink: SegmentSink; /** Emit current position in seconds regularly */ - playbackObserver: IReadOnlyPlaybackObserver< - Pick + mediaElementMonitor: IReadOnlyMediaElementMonitor< + Pick >; /** Maximum time to keep behind current time position, in seconds */ maxBufferBehind: IReadOnlySharedReference; @@ -40,7 +40,7 @@ export interface IGarbageCollectorArgument { /** * Perform cleaning of the buffer according to the values set by the user - * each time `playbackObserver` emits and each times the + * each time `mediaElementMonitor` emits and each times the * maxBufferBehind/maxBufferAhead values change. * * Abort this operation when the `cancellationSignal` emits. @@ -51,7 +51,7 @@ export interface IGarbageCollectorArgument { export default function BufferGarbageCollector( { segmentSink, - playbackObserver, + mediaElementMonitor, maxBufferBehind, maxBufferAhead, }: IGarbageCollectorArgument, @@ -59,7 +59,7 @@ export default function BufferGarbageCollector( ): void { let lastPosition: number; let lastBuffered: IRange[] | null = []; - playbackObserver.listen( + mediaElementMonitor.listen( (o) => { lastPosition = o.position.getWanted(); lastBuffered = o.buffered[segmentSink.bufferType]; diff --git a/src/core/stream/adaptation/adaptation_stream.ts b/src/core/stream/adaptation/adaptation_stream.ts index d4a208d57ef..345d61fc404 100644 --- a/src/core/stream/adaptation/adaptation_stream.ts +++ b/src/core/stream/adaptation/adaptation_stream.ts @@ -53,7 +53,7 @@ import type { IAdaptationStreamArguments, IAdaptationStreamCallbacks } from "./t */ export default function AdaptationStream( { - playbackObserver, + mediaElementMonitor, content, options, representationEstimator, @@ -110,13 +110,13 @@ export default function AdaptationStream( { manifest, period, adaptation }, currentRepresentation, representationsList, - playbackObserver, + mediaElementMonitor, adapStreamCanceller.signal, ); const isMediaSegmentQueueInterrupted = new SharedReference(false); /** Update the `canLoad` ref on observation update */ - playbackObserver.listen( + mediaElementMonitor.listen( (observation) => { const observationCanStream = observation.canStream ?? true; if (isMediaSegmentQueueInterrupted.getValue() === observationCanStream) { @@ -227,7 +227,7 @@ export default function AdaptationStream( adaptation, choice, segmentSink, - playbackObserver, + mediaElementMonitor, ); switch (switchStrat.type) { @@ -239,7 +239,7 @@ export default function AdaptationStream( // the next observation (which may reflect very different playback conditions) // is actually received. return queueMicrotask(() => { - playbackObserver.listen( + mediaElementMonitor.listen( () => { if (repsChoiceCancelSignal.isCancelled()) { return; @@ -510,7 +510,7 @@ export default function AdaptationStream( }); RepresentationStream( { - playbackObserver, + mediaElementMonitor, content: { representation, adaptation, period, manifest }, segmentSink, segmentQueue, diff --git a/src/core/stream/adaptation/get_representations_switch_strategy.ts b/src/core/stream/adaptation/get_representations_switch_strategy.ts index 2a81e2007ae..e1bee00cd0d 100644 --- a/src/core/stream/adaptation/get_representations_switch_strategy.ts +++ b/src/core/stream/adaptation/get_representations_switch_strategy.ts @@ -16,7 +16,7 @@ import config from "../../../config.ts"; import type { IAdaptation, IPeriod } from "../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../media_element_monitor/index.ts"; import arrayIncludes from "../../../utils/array_includes.ts"; import type { IRange } from "../../../utils/ranges.ts"; import { excludeFromRanges, insertInto } from "../../../utils/ranges.ts"; @@ -28,7 +28,7 @@ import { } from "../../segment_sinks/index.ts"; import type { IRepresentationsChoice, - IRepresentationStreamPlaybackObservation, + IRepresentationStreamMediaObservation, } from "../representation/index.ts"; export default function getRepresentationsSwitchingStrategy( @@ -36,7 +36,7 @@ export default function getRepresentationsSwitchingStrategy( adaptation: IAdaptation, settings: IRepresentationsChoice, segmentSink: SegmentSink, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, ): IRepresentationSwitchStrategy { if (settings.switchingMode === "lazy") { return { type: "continue", value: undefined }; @@ -79,7 +79,7 @@ export default function getRepresentationsSwitchingStrategy( } if (settings.switchingMode === "reload") { - const readyState = playbackObserver.getReadyState(); + const readyState = mediaElementMonitor.getReadyState(); if (readyState === undefined || readyState > 1) { return { type: "needs-reload", value: undefined }; } @@ -115,10 +115,10 @@ export default function getRepresentationsSwitchingStrategy( const paddingBefore = ADAP_REP_SWITCH_BUFFER_PADDINGS[bufferType].before ?? 0; const paddingAfter = ADAP_REP_SWITCH_BUFFER_PADDINGS[bufferType].after ?? 0; - let currentTime = playbackObserver.getCurrentTime(); + let currentTime = mediaElementMonitor.getCurrentTime(); if (currentTime === undefined) { // TODO current position might be old. A better solution should be found. - const lastObservation = playbackObserver.getReference().getValue(); + const lastObservation = mediaElementMonitor.getReference().getValue(); currentTime = lastObservation.position.getPolled(); } diff --git a/src/core/stream/adaptation/types.ts b/src/core/stream/adaptation/types.ts index 96932f9d4cf..927d3d11727 100644 --- a/src/core/stream/adaptation/types.ts +++ b/src/core/stream/adaptation/types.ts @@ -4,7 +4,7 @@ import type { IPeriod, IRepresentation, } from "../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../media_element_monitor/index.ts"; import type { IAudioTrackSwitchingMode, IVideoTrackSwitchingMode, @@ -16,7 +16,7 @@ import type { IBufferType, SegmentSink } from "../../segment_sinks/index.ts"; import type { IRepresentationsChoice, IRepresentationStreamCallbacks, - IRepresentationStreamPlaybackObservation, + IRepresentationStreamMediaObservation, } from "../representation/index.ts"; /** Callbacks called by the `AdaptationStream` on various events. */ @@ -118,7 +118,7 @@ export interface INeedsBufferFlushPayload { } /** Regular playback information needed by the AdaptationStream. */ -export interface IAdaptationStreamPlaybackObservation extends IRepresentationStreamPlaybackObservation { +export interface IAdaptationStreamMediaObservation extends IRepresentationStreamMediaObservation { /** * For the current SegmentSink, difference in seconds between the next position * where no segment data is available and the current position. @@ -143,7 +143,7 @@ export interface IAdaptationStreamPlaybackObservation extends IRepresentationStr /** Arguments given when creating a new `AdaptationStream`. */ export interface IAdaptationStreamArguments { /** Regularly emit playback conditions. */ - playbackObserver: IReadOnlyPlaybackObserver; + mediaElementMonitor: IReadOnlyMediaElementMonitor; /** Content you want to create this Stream for. */ content: { manifest: IManifest; diff --git a/src/core/stream/index.ts b/src/core/stream/index.ts index 887ef613cb3..28525343cd1 100644 --- a/src/core/stream/index.ts +++ b/src/core/stream/index.ts @@ -17,11 +17,11 @@ import type { INeedsMediaSourceReloadPayload, IStreamOrchestratorOptions, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, IStreamOrchestratorCallbacks, } from "./orchestrator/index.ts"; import StreamOrchestrator from "./orchestrator/index.ts"; -import type { IPausedPlaybackObservation } from "./period/index.ts"; +import type { IPausedMediaObservation } from "./period/index.ts"; export type { IRepresentationsChoice, IInbandEvent, @@ -36,9 +36,9 @@ export type { export default StreamOrchestrator; export type { - IPausedPlaybackObservation, + IPausedMediaObservation, INeedsMediaSourceReloadPayload, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, IStreamOrchestratorOptions, IStreamOrchestratorCallbacks, }; diff --git a/src/core/stream/orchestrator/index.ts b/src/core/stream/orchestrator/index.ts index 9337edb86ca..0b3c08120be 100644 --- a/src/core/stream/orchestrator/index.ts +++ b/src/core/stream/orchestrator/index.ts @@ -18,7 +18,7 @@ import type { INeedsMediaSourceReloadPayload, IStreamOrchestratorCallbacks, IStreamOrchestratorOptions, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, } from "./stream_orchestrator.ts"; import StreamOrchestrator from "./stream_orchestrator.ts"; @@ -27,5 +27,5 @@ export type { INeedsMediaSourceReloadPayload, IStreamOrchestratorCallbacks, IStreamOrchestratorOptions, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, }; diff --git a/src/core/stream/orchestrator/stream_orchestrator.ts b/src/core/stream/orchestrator/stream_orchestrator.ts index 744115bab22..0e7e5785247 100644 --- a/src/core/stream/orchestrator/stream_orchestrator.ts +++ b/src/core/stream/orchestrator/stream_orchestrator.ts @@ -22,7 +22,7 @@ import type { IUpdatedRepresentationInfo, IPeriod, } from "../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../media_element_monitor/index.ts"; import isNullOrUndefined from "../../../utils/is_null_or_undefined.ts"; import queueMicrotask from "../../../utils/queue_microtask.ts"; import type { IReadOnlySharedReference } from "../../../utils/reference.ts"; @@ -40,7 +40,7 @@ import type { IWaitingMediaSourceReloadPayload } from "../adaptation/index.ts"; import type { IPeriodStreamCallbacks, IPeriodStreamOptions, - IPeriodStreamPlaybackObservation, + IPeriodStreamMediaObservation, IPeriodStreamReadyPayload, } from "../period/index.ts"; import PeriodStream from "../period/index.ts"; @@ -63,7 +63,7 @@ import getTimeRangesForContent from "./get_time_ranges_for_content.ts"; * - Call various callbacks to notify of its health and issues * * @param {Object} content - * @param {Object} playbackObserver - Emit position information + * @param {Object} mediaElementMonitor - Emit position information * @param {Object} representationEstimator - Emit bitrate estimates and best * Representation to play. * @param {Object} segmentSinksStore - Will be used to lazily create @@ -91,7 +91,7 @@ import getTimeRangesForContent from "./get_time_ranges_for_content.ts"; */ export default function StreamOrchestrator( content: { manifest: IManifest; initialPeriod: IPeriod }, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, representationEstimator: IRepresentationEstimator, segmentSinksStore: SegmentSinksStore, segmentQueueCreator: SegmentQueueCreator, @@ -119,7 +119,7 @@ export default function StreamOrchestrator( BufferGarbageCollector( { segmentSink, - playbackObserver, + mediaElementMonitor, maxBufferBehind: createMappedReference( maxBufferBehind, (val) => Math.min(val, defaultMaxBehind), @@ -174,7 +174,7 @@ export default function StreamOrchestrator( // Restart the current Stream when the wanted time is in another period // than the ones already considered - playbackObserver.listen( + mediaElementMonitor.listen( ({ position }) => { const time = position.getWanted(); if (!enableOutOfBoundsCheck || !isOutOfPeriodList(time)) { @@ -391,14 +391,14 @@ export default function StreamOrchestrator( } } - // Schedule micro task before checking the last playback observation + // Schedule micro task before checking the last media observation // to reduce the risk of race conditions where the next observation // was going to be emitted synchronously. queueMicrotask(() => { if (restartCanceller.signal.isCancelled()) { return; } - const observation = playbackObserver.getReference().getValue(); + const observation = mediaElementMonitor.getReference().getValue(); if (needsFlushingAfterClean(observation, undecipherableRanges)) { // Bind to Period start and end callbacks.needsDecipherabilityFlush(); @@ -516,7 +516,7 @@ export default function StreamOrchestrator( // Stop current PeriodStream when the current position goes over the end of // that Period. - playbackObserver.listen( + mediaElementMonitor.listen( ({ position }, stopListeningObservations) => { if (basePeriod.end !== undefined && position.getWanted() >= basePeriod.end) { const nextPeriod = manifest.getPeriodAfter(basePeriod); @@ -555,7 +555,7 @@ export default function StreamOrchestrator( segmentQueueCreator, segmentSinksStore, options, - playbackObserver, + mediaElementMonitor, representationEstimator, wantedBufferAhead, }; @@ -703,7 +703,7 @@ export default function StreamOrchestrator( } } -export type IStreamOrchestratorPlaybackObservation = IPeriodStreamPlaybackObservation; +export type IStreamOrchestratorMediaObservation = IPeriodStreamMediaObservation; /** Options tweaking the behavior of the StreamOrchestrator. */ export type IStreamOrchestratorOptions = IPeriodStreamOptions & { @@ -826,7 +826,7 @@ export interface ILockedStreamPayload { * @returns {boolean} */ function needsFlushingAfterClean( - observation: IStreamOrchestratorPlaybackObservation, + observation: IStreamOrchestratorMediaObservation, cleanedRanges: Array<{ start: number; end: number }>, ): boolean { if (cleanedRanges.length === 0) { diff --git a/src/core/stream/period/period_stream.ts b/src/core/stream/period/period_stream.ts index c714bac9ab8..341c5b0642d 100644 --- a/src/core/stream/period/period_stream.ts +++ b/src/core/stream/period/period_stream.ts @@ -19,7 +19,7 @@ import { formatError, MediaError } from "../../../errors/index.ts"; import log from "../../../log.ts"; import type { IAdaptation, IPeriod } from "../../../manifest/index.ts"; import { toTaggedTrack } from "../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../media_element_monitor/index.ts"; import type { ITrackType } from "../../../public_types.ts"; import arrayFind from "../../../utils/array_find.ts"; import objectAssign from "../../../utils/object_assign.ts"; @@ -34,14 +34,14 @@ import SegmentSinksStore from "../../segment_sinks/index.ts"; import type { IAdaptationChoice, IAdaptationStreamCallbacks, - IAdaptationStreamPlaybackObservation, + IAdaptationStreamMediaObservation, } from "../adaptation/index.ts"; import AdaptationStream from "../adaptation/index.ts"; import type { IRepresentationsChoice } from "../representation/index.ts"; import type { IPeriodStreamArguments, IPeriodStreamCallbacks, - IPeriodStreamPlaybackObservation, + IPeriodStreamMediaObservation, } from "./types.ts"; import getAdaptationSwitchStrategy from "./utils/get_adaptation_switch_strategy.ts"; @@ -81,7 +81,7 @@ export default function PeriodStream( bufferType, content, garbageCollectors, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentQueueCreator, segmentSinksStore, @@ -179,7 +179,7 @@ export default function PeriodStream( } return createEmptyAdaptationStream( - playbackObserver, + mediaElementMonitor, wantedBufferAhead, bufferType, { period }, @@ -288,7 +288,7 @@ export default function PeriodStream( period, adaptation, choice.switchingMode, - playbackObserver, + mediaElementMonitor, options, ); if (strategy.type === "needs-reload") { @@ -353,8 +353,8 @@ export default function PeriodStream( segmentSink: SegmentSink, cancelSignal: CancellationSignal, ): void { - const adaptationPlaybackObserver = createAdaptationStreamPlaybackObserver( - playbackObserver, + const adaptationMediaElementMonitor = createAdaptationStreamMediaElementMonitor( + mediaElementMonitor, adaptation.type, ); @@ -362,7 +362,7 @@ export default function PeriodStream( { content: { manifest, period, adaptation, representations }, options, - playbackObserver: adaptationPlaybackObserver, + mediaElementMonitor: adaptationMediaElementMonitor, representationEstimator, segmentSink, segmentQueueCreator, @@ -395,7 +395,7 @@ export default function PeriodStream( } return createEmptyAdaptationStream( - playbackObserver, + mediaElementMonitor, wantedBufferAhead, bufferType, { period }, @@ -413,8 +413,8 @@ export default function PeriodStream( } /** - * Regularly ask to reload the MediaSource on each playback observation - * performed by the playback observer. + * Regularly ask to reload the MediaSource on each media observation + * performed by the `MediaElementMonitor`. * * @param {number} timeOffset - Relative position, compared to the current * playhead, at which we should restart playback after reloading. @@ -440,9 +440,9 @@ export default function PeriodStream( // the next observation (which may reflect very different playback conditions) // is actually received. // It can happen when `askForMediaSourceReload` is called as a side-effect of - // the same event that triggers the playback observation to be emitted. + // the same event that triggers the media observation to be emitted. queueMicrotask(() => { - playbackObserver.listen( + mediaElementMonitor.listen( () => { if (cancelSignal.isCancelled()) { return; @@ -504,31 +504,31 @@ function getFirstDeclaredMimeType(adaptation: IAdaptation): string { } /** - * Create AdaptationStream's version of a playback observer. - * @param {Object} initialPlaybackObserver + * Create AdaptationStream's version of a `MediaElementMonitor`. + * @param {Object} initialMediaElementMonitor * @param {string} trackType * @returns {Object} */ -function createAdaptationStreamPlaybackObserver( - initialPlaybackObserver: IReadOnlyPlaybackObserver, +function createAdaptationStreamMediaElementMonitor( + initialMediaElementMonitor: IReadOnlyMediaElementMonitor, trackType: ITrackType, -): IReadOnlyPlaybackObserver { - return initialPlaybackObserver.deriveReadOnlyObserver(function transform( - observationRef: IReadOnlySharedReference, +): IReadOnlyMediaElementMonitor { + return initialMediaElementMonitor.deriveReadOnlyMonitor(function transform( + observationRef: IReadOnlySharedReference, cancellationSignal: CancellationSignal, - ): IReadOnlySharedReference { + ): IReadOnlySharedReference { const newRef = new SharedReference( - constructAdaptationStreamPlaybackObservation(), + constructAdaptationStreamMediaObservation(), cancellationSignal, ); - observationRef.onUpdate(emitAdaptationStreamPlaybackObservation, { + observationRef.onUpdate(emitAdaptationStreamMediaObservation, { clearSignal: cancellationSignal, emitCurrentValue: false, }); return newRef; - function constructAdaptationStreamPlaybackObservation(): IAdaptationStreamPlaybackObservation { + function constructAdaptationStreamMediaObservation(): IAdaptationStreamMediaObservation { const baseObservation = observationRef.getValue(); const buffered = baseObservation.buffered[trackType]; const bufferGap = @@ -538,8 +538,8 @@ function createAdaptationStreamPlaybackObserver( return objectAssign({}, baseObservation, { bufferGap, buffered }); } - function emitAdaptationStreamPlaybackObservation() { - newRef.setValue(constructAdaptationStreamPlaybackObservation()); + function emitAdaptationStreamMediaObservation() { + newRef.setValue(constructAdaptationStreamMediaObservation()); } }); } @@ -548,7 +548,7 @@ function createAdaptationStreamPlaybackObserver( * Create empty AdaptationStream, linked to a Period. * This AdaptationStream will never download any segment and just emit a "full" * event when reaching the end. - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {Object} wantedBufferAhead * @param {string} bufferType * @param {Object} content @@ -556,7 +556,7 @@ function createAdaptationStreamPlaybackObserver( * @param {Object} cancelSignal */ function createEmptyAdaptationStream( - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, wantedBufferAhead: IReadOnlySharedReference, bufferType: IBufferType, content: { period: IPeriod }, @@ -569,14 +569,14 @@ function createEmptyAdaptationStream( emitCurrentValue: false, clearSignal: cancelSignal, }); - playbackObserver.listen(sendStatus, { + mediaElementMonitor.listen(sendStatus, { includeLastObservation: false, clearSignal: cancelSignal, }); sendStatus(); function sendStatus(): void { - const observation = playbackObserver.getReference().getValue(); + const observation = mediaElementMonitor.getReference().getValue(); const wba = wantedBufferAhead.getValue(); const position = observation.position.getWanted(); if (period.end !== undefined && position + wba >= period.end) { diff --git a/src/core/stream/period/types.ts b/src/core/stream/period/types.ts index 7cabb7534ba..02f272cf235 100644 --- a/src/core/stream/period/types.ts +++ b/src/core/stream/period/types.ts @@ -1,8 +1,8 @@ import type { IManifest, IAdaptation, IPeriod } from "../../../manifest/index.ts"; import type { ObservationPosition, - IReadOnlyPlaybackObserver, -} from "../../../playback_observer/index.ts"; + IReadOnlyMediaElementMonitor, +} from "../../../media_element_monitor/index.ts"; import type { ITrackType } from "../../../public_types.ts"; import type { IRange } from "../../../utils/ranges.ts"; import type { IReadOnlySharedReference } from "../../../utils/reference.ts"; @@ -18,9 +18,9 @@ import type { IAdaptationStreamCallbacks, IAdaptationStreamOptions, } from "../adaptation/index.ts"; -import type { IPausedPlaybackObservation } from "../representation/index.ts"; +import type { IPausedMediaObservation } from "../representation/index.ts"; -export type { IPausedPlaybackObservation }; +export type { IPausedMediaObservation }; /** Callbacks called by the `AdaptationStream` on various events. */ export interface IPeriodStreamCallbacks extends IAdaptationStreamCallbacks { @@ -71,13 +71,13 @@ export interface IPeriodStreamReadyPayload { adaptationRef: SharedReference; } -/** Playback observation required by the `PeriodStream`. */ -export interface IPeriodStreamPlaybackObservation { +/** Media observation required by the `PeriodStream`. */ +export interface IPeriodStreamMediaObservation { /** * Information on whether the media element was paused at the time of the * Observation. */ - paused: IPausedPlaybackObservation; + paused: IPausedMediaObservation; /** * Information on the current media position in seconds at the time of the * Observation. @@ -118,7 +118,7 @@ export interface IPeriodStreamArguments { >; segmentQueueCreator: SegmentQueueCreator; segmentSinksStore: SegmentSinksStore; - playbackObserver: IReadOnlyPlaybackObserver; + mediaElementMonitor: IReadOnlyMediaElementMonitor; options: IPeriodStreamOptions; representationEstimator: IRepresentationEstimator; wantedBufferAhead: IReadOnlySharedReference; 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 8e203347d99..a3a7a557e74 100644 --- a/src/core/stream/period/utils/get_adaptation_switch_strategy.ts +++ b/src/core/stream/period/utils/get_adaptation_switch_strategy.ts @@ -16,7 +16,7 @@ import config from "../../../../config.ts"; import type { IAdaptation, IPeriod } from "../../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../../media_element_monitor/index.ts"; import areCodecsCompatible from "../../../../utils/are_codecs_compatible.ts"; import type { IRange } from "../../../../utils/ranges.ts"; import { excludeFromRanges, insertInto } from "../../../../utils/ranges.ts"; @@ -27,7 +27,7 @@ import { SegmentSinkOperation, } from "../../../segment_sinks/index.ts"; import type { ITrackSwitchingMode } from "../../adaptation/index.ts"; -import type { IPeriodStreamPlaybackObservation } from "../types.ts"; +import type { IPeriodStreamMediaObservation } from "../types.ts"; export type IAdaptationSwitchStrategy = /** Do nothing special. */ @@ -56,7 +56,7 @@ export interface IAdaptationSwitchOptions { * @param {Object} segmentSink * @param {Object} period * @param {Object} adaptation - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @returns {Object} */ export default function getAdaptationSwitchStrategy( @@ -64,7 +64,7 @@ export default function getAdaptationSwitchStrategy( period: IPeriod, adaptation: IAdaptation, switchingMode: ITrackSwitchingMode, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, options: IAdaptationSwitchOptions, ): IAdaptationSwitchStrategy { if ( @@ -105,7 +105,7 @@ export default function getAdaptationSwitchStrategy( } if (switchingMode === "reload") { - const readyState = playbackObserver.getReadyState(); + const readyState = mediaElementMonitor.getReadyState(); if (readyState === undefined || readyState > 1) { return { type: "needs-reload", value: undefined }; } @@ -141,10 +141,10 @@ export default function getAdaptationSwitchStrategy( const paddingBefore = ADAP_REP_SWITCH_BUFFER_PADDINGS[bufferType].before ?? 0; const paddingAfter = ADAP_REP_SWITCH_BUFFER_PADDINGS[bufferType].after ?? 0; - let currentTime = playbackObserver.getCurrentTime(); + let currentTime = mediaElementMonitor.getCurrentTime(); if (currentTime === undefined) { // TODO current position might be old. A better solution should be found. - const lastObservation = playbackObserver.getReference().getValue(); + const lastObservation = mediaElementMonitor.getReference().getValue(); currentTime = lastObservation.position.getPolled(); } diff --git a/src/core/stream/representation/representation_stream.ts b/src/core/stream/representation/representation_stream.ts index 67105e75206..85e4dd827ae 100644 --- a/src/core/stream/representation/representation_stream.ts +++ b/src/core/stream/representation/representation_stream.ts @@ -83,7 +83,7 @@ export default function RepresentationStream( { content, options, - playbackObserver, + mediaElementMonitor, segmentSink, segmentQueue, terminate, @@ -190,7 +190,7 @@ export default function RepresentationStream( segmentQueue.stop(err.reason); }); - playbackObserver.listen(checkStatus, { + mediaElementMonitor.listen(checkStatus, { includeLastObservation: false, clearSignal: canceller.signal, }); @@ -219,12 +219,12 @@ export default function RepresentationStream( if (canceller.isUsed()) { return; // Stop all buffer status checking if load operations are stopped } - const observation = playbackObserver.getReference().getValue(); + const observation = mediaElementMonitor.getReference().getValue(); const initialWantedTime = observation.position.getWanted(); const status = getBufferStatus( content, initialWantedTime, - playbackObserver, + mediaElementMonitor, fastSwitchThreshold.getValue(), bufferGoal.getValue(), maxBufferSize.getValue(), @@ -367,7 +367,7 @@ export default function RepresentationStream( segmentSink.declareInitSegment(initSegmentUniqueId, evt.initializationData); pushInitSegment( { - playbackObserver, + mediaElementMonitor, bufferGoal, content, initSegmentUniqueId, @@ -411,7 +411,7 @@ export default function RepresentationStream( const initSegmentUniqueId = initSegmentState.uniqueId; pushMediaSegment( { - playbackObserver, + mediaElementMonitor, bufferGoal, content, initSegmentUniqueId, diff --git a/src/core/stream/representation/types.ts b/src/core/stream/representation/types.ts index 15c9f1322f9..d8f9435ca9f 100644 --- a/src/core/stream/representation/types.ts +++ b/src/core/stream/representation/types.ts @@ -6,11 +6,11 @@ import type { IPeriod, IRepresentation, } from "../../../manifest/index.ts"; -import type { IEMSG } from "../../../parsers/containers/isobmff/index.ts"; import type { ObservationPosition, - IReadOnlyPlaybackObserver, -} from "../../../playback_observer/index.ts"; + IReadOnlyMediaElementMonitor, +} from "../../../media_element_monitor/index.ts"; +import type { IEMSG } from "../../../parsers/containers/isobmff/index.ts"; import type { IAudioRepresentationsSwitchingMode, IPlayerError, @@ -178,18 +178,18 @@ export interface IBufferDiscontinuity { end: number | null; } -/** Object that should be emitted by the given `IReadOnlyPlaybackObserver`. */ -export interface IRepresentationStreamPlaybackObservation { +/** Object that should be emitted by the given `IReadOnlyMediaElementMonitor`. */ +export interface IRepresentationStreamMediaObservation { /** * Information on the current media position in seconds at the time of a - * Playback Observation. + * media Observation. */ position: ObservationPosition; /** * Information on whether the media element was paused at the time of the * Observation. */ - paused: IPausedPlaybackObservation; + paused: IPausedMediaObservation; /** Last "playback rate" asked by the user. */ speed: number; /** @@ -204,8 +204,8 @@ export interface IRepresentationStreamPlaybackObservation { canStream: boolean; } -/** Pause-related information linked to an emitted Playback observation. */ -export interface IPausedPlaybackObservation { +/** Pause-related information linked to an emitted media observation. */ +export interface IPausedMediaObservation { /** * Known paused state at the time the Observation was emitted. * @@ -224,8 +224,8 @@ export interface IPausedPlaybackObservation { pending: boolean | undefined; } -/** Position-related information linked to an emitted Playback observation. */ -export interface IPositionPlaybackObservation { +/** Position-related information linked to an emitted media observation. */ +export interface IPositionMediaObservation { /** * Known position at the time the Observation was emitted, in seconds. * @@ -283,8 +283,8 @@ export interface IRepresentationStreamArguments { * and stopping all `RepresentationStream` current tasks). */ terminate: IReadOnlySharedReference; - /** Periodically emits the current playback conditions. */ - playbackObserver: IReadOnlyPlaybackObserver; + /** Regularly polls and emits current playback conditions. */ + mediaElementMonitor: IReadOnlyMediaElementMonitor; /** Supplementary arguments which configure the RepresentationStream's behavior. */ options: IRepresentationStreamOptions; } diff --git a/src/core/stream/representation/utils/append_segment_to_buffer.ts b/src/core/stream/representation/utils/append_segment_to_buffer.ts index 35654002fdd..c0127f9c3d9 100644 --- a/src/core/stream/representation/utils/append_segment_to_buffer.ts +++ b/src/core/stream/representation/utils/append_segment_to_buffer.ts @@ -21,7 +21,7 @@ import { MediaError, SourceBufferError } from "../../../../errors/index.ts"; import log from "../../../../log.ts"; import { toTaggedTrack } from "../../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../../media_element_monitor/index.ts"; import type { IRange } from "../../../../utils/ranges.ts"; import type { IReadOnlySharedReference } from "../../../../utils/reference.ts"; import sleep from "../../../../utils/sleep.ts"; @@ -32,13 +32,13 @@ import type { IPushChunkInfos, SegmentSink, } from "../../../segment_sinks/index.ts"; -import type { IRepresentationStreamPlaybackObservation } from "../types.ts"; +import type { IRepresentationStreamMediaObservation } from "../types.ts"; /** * Append a segment to the given segmentSink. * If it leads to an Error due to a full buffer, try to run our custom range * _garbage collector_ then retry. - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {Object} segmentSink * @param {Object} dataInfos * @param {number} bufferGoal @@ -46,7 +46,7 @@ import type { IRepresentationStreamPlaybackObservation } from "../types.ts"; * @returns {Promise} */ export default async function appendSegmentToBuffer( - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, segmentSink: SegmentSink, dataInfos: IPushChunkInfos & { inventoryInfos: IInsertedChunkInfos }, bufferGoal: IReadOnlySharedReference, @@ -66,7 +66,7 @@ export default async function appendSegmentToBuffer( tracks: [toTaggedTrack(dataInfos.inventoryInfos.adaptation)], }); } - const { position } = playbackObserver.getReference().getValue(); + const { position } = mediaElementMonitor.getReference().getValue(); const currentPos = position.getWanted(); try { log.warn("Stream", "Running garbage collector"); diff --git a/src/core/stream/representation/utils/get_buffer_status.ts b/src/core/stream/representation/utils/get_buffer_status.ts index 9144c6281e3..f8164aea333 100644 --- a/src/core/stream/representation/utils/get_buffer_status.ts +++ b/src/core/stream/representation/utils/get_buffer_status.ts @@ -20,7 +20,7 @@ import type { IPeriod, IRepresentation, } from "../../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../../media_element_monitor/index.ts"; import isNullOrUndefined from "../../../../utils/is_null_or_undefined.ts"; import type { ISignalCompleteSegmentOperation, @@ -29,7 +29,7 @@ import type { import SegmentSinksStore, { SegmentSinkOperation } from "../../../segment_sinks/index.ts"; import type { IBufferDiscontinuity, - IRepresentationStreamPlaybackObservation, + IRepresentationStreamMediaObservation, IQueuedSegment, } from "../types.ts"; import checkForDiscontinuity from "./check_for_discontinuity.ts"; @@ -77,7 +77,7 @@ export interface IBufferStatus { * * @param {Object} content * @param {number} initialWantedTime - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {number|undefined} fastSwitchThreshold * @param {number} bufferGoal * @param {number} maxBufferSize @@ -92,7 +92,7 @@ export default function getBufferStatus( representation: IRepresentation; }, initialWantedTime: number, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, fastSwitchThreshold: number | undefined, bufferGoal: number, maxBufferSize: number, @@ -100,12 +100,12 @@ export default function getBufferStatus( ): IBufferStatus { const { representation } = content; const isPaused = - playbackObserver.getIsPaused() ?? - playbackObserver.getReference().getValue().paused.pending ?? - playbackObserver.getReference().getValue().paused.last; + mediaElementMonitor.getIsPaused() ?? + mediaElementMonitor.getReference().getValue().paused.pending ?? + mediaElementMonitor.getReference().getValue().paused.last; const playbackRate = - playbackObserver.getPlaybackRate() ?? - playbackObserver.getReference().getValue().speed; + mediaElementMonitor.getPlaybackRate() ?? + mediaElementMonitor.getReference().getValue().speed; let askedStart = initialWantedTime; if ( isPaused === undefined || @@ -136,10 +136,13 @@ export default function getBufferStatus( /** Data on every segments buffered around `neededRange`. */ const bufferedSegments = segmentSink.getLastKnownInventory(); - let currentPlaybackTime = playbackObserver.getCurrentTime(); + let currentPlaybackTime = mediaElementMonitor.getCurrentTime(); if (currentPlaybackTime === undefined) { // We're in a WebWorker, just consider the last known position - currentPlaybackTime = playbackObserver.getReference().getValue().position.getWanted(); + currentPlaybackTime = mediaElementMonitor + .getReference() + .getValue() + .position.getWanted(); } /** Callback allowing to retrieve a segment's history in the buffer. */ diff --git a/src/core/stream/representation/utils/push_init_segment.ts b/src/core/stream/representation/utils/push_init_segment.ts index c78115336e3..ebaef404e38 100644 --- a/src/core/stream/representation/utils/push_init_segment.ts +++ b/src/core/stream/representation/utils/push_init_segment.ts @@ -21,13 +21,13 @@ import type { IPeriod, IRepresentation, } from "../../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../../media_element_monitor/index.ts"; import objectAssign from "../../../../utils/object_assign.ts"; import type { IReadOnlySharedReference } from "../../../../utils/reference.ts"; import type { CancellationSignal } from "../../../../utils/task_canceller.ts"; import type { IPushedChunkData, SegmentSink } from "../../../segment_sinks/index.ts"; import type { - IRepresentationStreamPlaybackObservation, + IRepresentationStreamMediaObservation, IStreamEventAddedSegmentPayload, } from "../types.ts"; import appendSegmentToBuffer from "./append_segment_to_buffer.ts"; @@ -40,14 +40,14 @@ import appendSegmentToBuffer from "./append_segment_to_buffer.ts"; */ export default async function pushInitSegment( { - playbackObserver, + mediaElementMonitor, content, initSegmentUniqueId, segment, segmentSink, bufferGoal, }: { - playbackObserver: IReadOnlyPlaybackObserver; + mediaElementMonitor: IReadOnlyMediaElementMonitor; content: { adaptation: IAdaptation; manifest: IManifest; @@ -75,7 +75,7 @@ export default async function pushInitSegment( content, ); const buffered = await appendSegmentToBuffer( - playbackObserver, + mediaElementMonitor, segmentSink, { data, inventoryInfos }, bufferGoal, diff --git a/src/core/stream/representation/utils/push_media_segment.ts b/src/core/stream/representation/utils/push_media_segment.ts index e3194e8b001..ead200fdd50 100644 --- a/src/core/stream/representation/utils/push_media_segment.ts +++ b/src/core/stream/representation/utils/push_media_segment.ts @@ -22,14 +22,14 @@ import type { IPeriod, IRepresentation, } from "../../../../manifest/index.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../../playback_observer/index.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../../media_element_monitor/index.ts"; import type { ISegmentParserParsedMediaChunk } from "../../../../transports/index.ts"; import objectAssign from "../../../../utils/object_assign.ts"; import type { IReadOnlySharedReference } from "../../../../utils/reference.ts"; import type { CancellationSignal } from "../../../../utils/task_canceller.ts"; import type { SegmentSink } from "../../../segment_sinks/index.ts"; import type { - IRepresentationStreamPlaybackObservation, + IRepresentationStreamMediaObservation, IStreamEventAddedSegmentPayload, } from "../types.ts"; import appendSegmentToBuffer from "./append_segment_to_buffer.ts"; @@ -42,7 +42,7 @@ import appendSegmentToBuffer from "./append_segment_to_buffer.ts"; */ export default async function pushMediaSegment( { - playbackObserver, + mediaElementMonitor, bufferGoal, content, initSegmentUniqueId, @@ -50,7 +50,7 @@ export default async function pushMediaSegment( segment, segmentSink, }: { - playbackObserver: IReadOnlyPlaybackObserver; + mediaElementMonitor: IReadOnlyMediaElementMonitor; content: { adaptation: IAdaptation; manifest: IManifest; @@ -106,7 +106,7 @@ export default async function pushMediaSegment( content, ); const buffered = await appendSegmentToBuffer( - playbackObserver, + mediaElementMonitor, segmentSink, { data, inventoryInfos }, bufferGoal, diff --git a/src/core/types.ts b/src/core/types.ts index 88e80ba2eeb..c100a601244 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -34,10 +34,10 @@ import type SegmentSinksStore from "./segment_sinks/index.ts"; import type { ISegmentSinkMetrics } from "./segment_sinks/segment_sinks_store.ts"; import type { IAdaptationChoice, - IPausedPlaybackObservation, + IPausedMediaObservation, IInbandEvent, IRepresentationsChoice, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, ITrackSwitchingMode, } from "./stream/index.ts"; @@ -62,8 +62,8 @@ export type { // Stream Metadata IAdaptationChoice, IInbandEvent, - IPausedPlaybackObservation, - IStreamOrchestratorPlaybackObservation, + IPausedMediaObservation, + IStreamOrchestratorMediaObservation, IRepresentationsChoice, ITrackSwitchingMode, diff --git a/src/main_thread/api/public_api.ts b/src/main_thread/api/public_api.ts index 23fd021a9c8..6fa0c7a40c1 100644 --- a/src/main_thread/api/public_api.ts +++ b/src/main_thread/api/public_api.ts @@ -68,8 +68,8 @@ import { toVideoRepresentation, toAudioRepresentation, } from "../../manifest/index.ts"; -import type { IPlaybackObservation } from "../../playback_observer/index.ts"; -import MediaElementPlaybackObserver from "../../playback_observer/media_element_playback_observer.ts"; +import type { IMediaObservation } from "../../media_element_monitor/index.ts"; +import MediaElementMonitor from "../../media_element_monitor/media_element_monitor.ts"; import type { IAudioRepresentation, IAudioRepresentationsSwitchingMode, @@ -1349,8 +1349,8 @@ class Player extends EventEmitter { }); } - /** Global "playback observer" which will emit playback conditions */ - const playbackObserver = new MediaElementPlaybackObserver({ + /** Global `MediaElementMonitor` which will poll media properties */ + const mediaElementMonitor = new MediaElementMonitor({ withMediaSource: !isDirectFile, lowLatencyMode, }); @@ -1359,17 +1359,17 @@ class Player extends EventEmitter { * We want to block seeking operations until we know the media element is * ready for it. */ - playbackObserver.blockSeeking(); + mediaElementMonitor.blockSeeking(); currentContentCanceller.signal.register((err) => { - playbackObserver.stop(err.reason); + mediaElementMonitor.destroy(err.reason); }); /** Future `this._priv_contentInfos` related to this content. */ const contentInfos: IPublicApiContentInfos = { contentId: generateContentId(), originalUrl: url, - playbackObserver, + mediaElementMonitor, currentContentCanceller, defaultAudioTrackSwitchingMode, initializer, @@ -1478,13 +1478,13 @@ class Player extends EventEmitter { // content. this.stop(); - playbackObserver.attachMediaElement(videoElement); + mediaElementMonitor.attachMediaElement(videoElement); // Update the RxPlayer's state at the right events const playerStateRef = constructPlayerStateReference( initializer, videoElement, - playbackObserver, + mediaElementMonitor, isDirectFile, currentContentCanceller.signal, ); @@ -1506,13 +1506,13 @@ class Player extends EventEmitter { break; // keep previous metadata case "ENDED": this._priv_reloadingMetadata.reloadInPause = true; - this._priv_reloadingMetadata.reloadPosition = playbackObserver + this._priv_reloadingMetadata.reloadPosition = mediaElementMonitor .getReference() .getValue() .position.getPolled(); break; default: { - const o = playbackObserver.getReference().getValue(); + const o = mediaElementMonitor.getReference().getValue(); this._priv_reloadingMetadata.reloadInPause = o.paused; this._priv_reloadingMetadata.reloadPosition = o.position.getWanted(); break; @@ -1604,7 +1604,7 @@ class Player extends EventEmitter { seekEventsCanceller = new TaskCanceller("API seek events"); seekEventsCanceller.linkToSignal(currentContentCanceller.signal); emitSeekEvents( - playbackObserver, + mediaElementMonitor, () => this.trigger("seeking", null), () => this.trigger("seeked", null), seekEventsCanceller.signal, @@ -1615,7 +1615,7 @@ class Player extends EventEmitter { ); // React to playback conditions change - playbackObserver.listen( + mediaElementMonitor.listen( (observation) => { updateReloadingMetadata(this.state); this._priv_triggerPositionUpdate(contentInfos, observation); @@ -1634,7 +1634,7 @@ class Player extends EventEmitter { stopListeningToLock(); // start playback! - initializer.start(videoElement, playbackObserver); + initializer.start(videoElement, mediaElementMonitor); } }, { emitCurrentValue: true, clearSignal: currentContentCanceller.signal }, @@ -2126,7 +2126,7 @@ class Player extends EventEmitter { throw new Error("invalid time given"); } log.info("API", "API seekTo", { positionWanted }); - this._priv_contentInfos.playbackObserver.setCurrentTime(positionWanted, false); + this._priv_contentInfos.mediaElementMonitor.setCurrentTime(positionWanted, false); return positionWanted; } @@ -3522,7 +3522,7 @@ class Player extends EventEmitter { } /** - * Triggered each time a playback observation. + * Triggered each time a media observation. * * Trigger the right Player Event * @@ -3531,7 +3531,7 @@ class Player extends EventEmitter { */ private _priv_triggerPositionUpdate( contentInfos: IPublicApiContentInfos, - observation: IPlaybackObservation, + observation: IMediaObservation, ): void { if (contentInfos.contentId !== this._priv_contentInfos?.contentId) { return; // Event for another content @@ -3911,8 +3911,8 @@ export interface IPublicApiContentInfos { originalUrl: string | undefined; /** `ContentInitializer` used to load the content. */ initializer: ContentInitializer; - /** interface emitting regularly playback observations. */ - playbackObserver: MediaElementPlaybackObserver; + /** interface emitting regularly media observations. */ + mediaElementMonitor: MediaElementMonitor; /** TaskCanceller triggered when it's time to stop the current content. */ currentContentCanceller: TaskCanceller; /** The default behavior to adopt when switching the audio track. */ diff --git a/src/main_thread/api/utils.ts b/src/main_thread/api/utils.ts index 080f0a494bf..eda7fc10654 100644 --- a/src/main_thread/api/utils.ts +++ b/src/main_thread/api/utils.ts @@ -18,10 +18,10 @@ import type { IMediaElement } from "../../compat/browser_compatibility_types.ts" import canPreloadBeforePlay from "../../compat/can_preload_before_play.ts"; import config from "../../config.ts"; import type { - IPlaybackObservation, - IReadOnlyPlaybackObserver, -} from "../../playback_observer/index.ts"; -import { SeekingState } from "../../playback_observer/index.ts"; + IMediaObservation, + IReadOnlyMediaElementMonitor, +} from "../../media_element_monitor/index.ts"; +import { SeekingState } from "../../media_element_monitor/index.ts"; import type { IPlayerState } from "../../public_types.ts"; import arrayIncludes from "../../utils/array_includes.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; @@ -31,7 +31,7 @@ import type { CancellationSignal } from "../../utils/task_canceller.ts"; import type { ContentInitializer, IStallingSituation } from "../init/index.ts"; /** - * @param {Object} playbackObserver - Observes playback conditions on + * @param {Object} mediaElementMonitor - Observes playback conditions on * `mediaElement`. * @param {function} onSeeking - Callback called when a seeking operation starts * on `mediaElement`. @@ -41,7 +41,7 @@ import type { ContentInitializer, IStallingSituation } from "../init/index.ts"; * remove all listeners this function has registered. */ export function emitSeekEvents( - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, onSeeking: () => void, onSeeked: () => void, cancelSignal: CancellationSignal, @@ -51,14 +51,14 @@ export function emitSeekEvents( } let wasSeeking = - playbackObserver.getReference().getValue().seeking === SeekingState.External; + mediaElementMonitor.getReference().getValue().seeking === SeekingState.External; if (wasSeeking) { onSeeking(); if (cancelSignal.isCancelled()) { return; } } - playbackObserver.listen( + mediaElementMonitor.listen( (obs) => { if (obs.event === "seeking") { wasSeeking = true; @@ -115,7 +115,7 @@ export const enum PLAYER_STATES { export function constructPlayerStateReference( initializer: ContentInitializer, mediaElement: IMediaElement, - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, isDirectFile: boolean, cancelSignal: CancellationSignal, ): IReadOnlySharedReference { @@ -191,7 +191,7 @@ export function constructPlayerStateReference( cancelSignal, ); - playbackObserver.listen( + mediaElementMonitor.listen( (observation) => { if (arrayIncludes(["seeking", "ended", "play", "pause"], observation.event)) { updateStateIfLoaded(prevStallReason); diff --git a/src/main_thread/init/directfile_content_initializer.ts b/src/main_thread/init/directfile_content_initializer.ts index da2e7ecafe3..5a3f4a7e047 100644 --- a/src/main_thread/init/directfile_content_initializer.ts +++ b/src/main_thread/init/directfile_content_initializer.ts @@ -20,11 +20,9 @@ */ import type { IMediaElement } from "../../compat/browser_compatibility_types.ts"; -import clearElementSrc from "../../compat/clear_element_src.ts"; import getStartDate from "../../compat/get_start_date.ts"; -import type { MediaError } from "../../errors/index.ts"; import log from "../../log.ts"; -import type { IMediaElementPlaybackObserver } from "../../playback_observer/index.ts"; +import type { IMediaElementMonitor } from "../../media_element_monitor/index.ts"; import type { IKeySystemOption, IPlayerError } from "../../public_types.ts"; import assert from "../../utils/assert.ts"; import isNullOrUndefined from "../../utils/is_null_or_undefined.ts"; @@ -33,12 +31,12 @@ import type { IReadOnlySharedReference } from "../../utils/reference.ts"; import type { CancellationSignal } from "../../utils/task_canceller.ts"; import TaskCanceller from "../../utils/task_canceller.ts"; import { ContentInitializer } from "./types.ts"; +import formatMediaError from "./utils/format_media_error.ts"; import type { IInitialTimeOptions } from "./utils/get_initial_time.ts"; import getLoadedReference from "./utils/get_loaded_reference.ts"; import performInitialSeekAndPlay from "./utils/initial_seek_and_play.ts"; import initializeContentDecryption from "./utils/initialize_content_decryption.ts"; import RebufferingController from "./utils/rebuffering_controller.ts"; -import listenToMediaError from "./utils/throw_on_media_error.ts"; /** * `ContentIntializer` which will load contents by putting their URL in the @@ -80,21 +78,19 @@ export default class DirectFileContentInitializer extends ContentInitializer { /** * Start playback of the content linked to this `DirectFileContentInitializer` - * on the given `HTMLMediaElement` and its associated `PlaybackObserver`. + * on the given `HTMLMediaElement` and its associated `MediaElementMonitor`. * @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the * content will be played. - * @param {Object} playbackObserver - Object regularly emitting playback + * @param {Object} mediaElementMonitor - Object regularly emitting playback * information. */ public start( mediaElement: IMediaElement, - playbackObserver: IMediaElementPlaybackObserver, + mediaElementMonitor: IMediaElementMonitor, ): void { const cancelSignal = this._initCanceller.signal; const { keySystems, speed, url } = this._settings; - clearElementSrc(mediaElement); - // Set the autoplay attribute on the mediaElement. // On Apple devices, the native HLS player needs autoplay to be set // in order to start buffering,which is required for our API's autoplay to work. @@ -113,18 +109,16 @@ export default class DirectFileContentInitializer extends ContentInitializer { ); /** Translate errors coming from the media element into RxPlayer errors. */ - listenToMediaError( - mediaElement, - (error: MediaError) => this._onFatalError(error), - cancelSignal, - ); + mediaElementMonitor.addMediaErrorListener((mediaError) => { + this._onFatalError(formatMediaError(mediaError)); + }, cancelSignal); /** * Class trying to avoid various stalling situations, emitting "stalled" * events when it cannot, as well as "unstalled" events when it get out of one. */ const rebufferingController = new RebufferingController( - playbackObserver, + mediaElementMonitor, null, speed, ); @@ -151,13 +145,7 @@ export default class DirectFileContentInitializer extends ContentInitializer { // Start everything! (Just put the URL in the element's src). log.info("Init", "Setting URL to HTMLMediaElement", { url }); - mediaElement.src = url; - cancelSignal.register(() => { - log.info("Init", "Removing directfile src from media element", { - src: mediaElement.src, - }); - clearElementSrc(mediaElement); - }); + mediaElementMonitor.linkUrl(url, false, cancelSignal); if (evt.initializationState.type === "awaiting-media-link") { evt.initializationState.value.isMediaLinked.setValue(true); @@ -165,14 +153,14 @@ export default class DirectFileContentInitializer extends ContentInitializer { (newDrmStatus, stopListeningToDrmUpdatesAgain) => { if (newDrmStatus.initializationState.type === "initialized") { stopListeningToDrmUpdatesAgain(); - this._seekAndPlay(mediaElement, playbackObserver); + this._seekAndPlay(mediaElement, mediaElementMonitor); } }, { emitCurrentValue: true, clearSignal: cancelSignal }, ); } else { assert(evt.initializationState.type === "initialized"); - this._seekAndPlay(mediaElement, playbackObserver); + this._seekAndPlay(mediaElement, mediaElementMonitor); } }, { emitCurrentValue: true, clearSignal: cancelSignal }, @@ -211,11 +199,11 @@ export default class DirectFileContentInitializer extends ContentInitializer { * Perform the initial seek (to begin playback at an initially-calculated * position based on settings) and auto-play if needed when loaded. * @param {HTMLMediaElement} mediaElement - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor */ private _seekAndPlay( mediaElement: IMediaElement, - playbackObserver: IMediaElementPlaybackObserver, + mediaElementMonitor: IMediaElementMonitor, ): void { const cancelSignal = this._initCanceller.signal; const { autoPlay, startAt } = this._settings; @@ -227,8 +215,7 @@ export default class DirectFileContentInitializer extends ContentInitializer { }; performInitialSeekAndPlay( { - mediaElement, - playbackObserver, + mediaElementMonitor, startTime: initialTime, mustAutoPlay: autoPlay, onWarning: (err) => this.trigger("warning", err), @@ -237,7 +224,7 @@ export default class DirectFileContentInitializer extends ContentInitializer { cancelSignal, ) .autoPlayResult.then(() => - getLoadedReference(playbackObserver, true, cancelSignal).onUpdate( + getLoadedReference(mediaElementMonitor, true, cancelSignal).onUpdate( (isLoaded, stopListening) => { if (isLoaded) { stopListening(); diff --git a/src/main_thread/init/media_source_content_initializer.ts b/src/main_thread/init/media_source_content_initializer.ts index 44d1f42aa22..a475b651923 100644 --- a/src/main_thread/init/media_source_content_initializer.ts +++ b/src/main_thread/init/media_source_content_initializer.ts @@ -18,7 +18,6 @@ import type { ISentLogValue, } from "../../core/types.ts"; import { CoreMessageType } from "../../core/types.ts"; -import type { MediaError } from "../../errors/index.ts"; import { deserializeMediaError, EncryptedMediaError, @@ -35,11 +34,11 @@ import { updateDecipherabilityFromKeyIds, updateDecipherabilityFromProtectionData, } from "../../manifest/index.ts"; -import MainMediaSourceInterface from "../../mse/main_media_source_interface.ts"; import type { - IReadOnlyPlaybackObserver, - IMediaElementPlaybackObserver, -} from "../../playback_observer/index.ts"; + IReadOnlyMediaElementMonitor, + IMediaElementMonitor, +} from "../../media_element_monitor/index.ts"; +import MainMediaSourceInterface from "../../mse/main_media_source_interface.ts"; import type { ICmcdOptions, IInitialManifest, @@ -70,15 +69,15 @@ import { MainThreadMessageType } from "../types.ts"; import { canHandleTextTracks } from "../utils/media_capabilities.ts"; import type { ITextDisplayerOptions } from "./types.ts"; import { ContentInitializer } from "./types.ts"; -import type { ICorePlaybackObservation } from "./utils/create_core_playback_observer.ts"; -import createCorePlaybackObserver from "./utils/create_core_playback_observer.ts"; +import type { ICoreMediaObservation } from "./utils/create_core_media_element_monitor.ts"; +import createCoreMediaElementMonitor from "./utils/create_core_media_element_monitor.ts"; +import formatMediaError from "./utils/format_media_error.ts"; import type { IInitialTimeOptions } from "./utils/get_initial_time.ts"; import getInitialTime from "./utils/get_initial_time.ts"; import getLoadedReference from "./utils/get_loaded_reference.ts"; import performInitialSeekAndPlay from "./utils/initial_seek_and_play.ts"; import RebufferingController from "./utils/rebuffering_controller.ts"; import StreamEventsEmitter from "./utils/stream_events_emitter/stream_events_emitter.ts"; -import listenToMediaError from "./utils/throw_on_media_error.ts"; import { updateManifestCodecSupport } from "./utils/update_manifest_codec_support.ts"; const generateContentId = idGenerator(); @@ -344,11 +343,11 @@ export default class MediaSourceContentInitializer extends ContentInitializer { /** * @param {HTMLMediaElement} mediaElement - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor */ public start( mediaElement: IMediaElement, - playbackObserver: IMediaElementPlaybackObserver, + mediaElementMonitor: IMediaElementMonitor, ): void { this.prepare(); // Load Manifest if not already done if (this._initCanceller.isUsed()) { @@ -385,11 +384,9 @@ export default class MediaSourceContentInitializer extends ContentInitializer { }); /** Translate errors coming from the media element into RxPlayer errors. */ - listenToMediaError( - mediaElement, - (error: MediaError) => this._onFatalError(error), - this._initCanceller.signal, - ); + mediaElementMonitor.addMediaErrorListener((mediaError) => { + this._onFatalError(formatMediaError(mediaError)); + }, this._initCanceller.signal); /** * Send content protection initialization data. @@ -414,7 +411,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { contentInfo.contentDecryptor = contentDecryptor; } - const streamEventsEmitter = new StreamEventsEmitter(playbackObserver); + const streamEventsEmitter = new StreamEventsEmitter(mediaElementMonitor); streamEventsEmitter.addEventListener( "event", (payload) => { @@ -436,7 +433,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { const playbackStartParams = { mediaElement, textDisplayer, - playbackObserver, + mediaElementMonitor, drmInitializationStatus, mediaSourceStatus, streamEventsEmitter, @@ -522,7 +519,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { log.warn("Init", "Asked to reload when no content is loaded."); return; } - const lastObservation = playbackObserver.getReference().getValue(); + const lastObservation = mediaElementMonitor.getReference().getValue(); const currentPosition = lastObservation.position.getWanted(); const isPaused = reloadingContentInfo.initialPlayPerformed?.getValue() === true || @@ -540,7 +537,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { this._reload( mediaElement, textDisplayer, - playbackObserver, + mediaElementMonitor, mediaSourceStatus, streamEventsEmitter, position, @@ -823,7 +820,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { if (this._currentContentInfo?.contentId !== msgData.contentId) { return; } - const lastObservation = playbackObserver.getReference().getValue(); + const lastObservation = mediaElementMonitor.getReference().getValue(); const currentTime = lastObservation.position.isAwaitingFuturePosition() ? lastObservation.position.getWanted() : mediaElement.currentTime; @@ -840,7 +837,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { } else { wantedSeekingTime = currentTime + relativeResumingPosition; } - playbackObserver.setCurrentTime(wantedSeekingTime); + mediaElementMonitor.setCurrentTime(wantedSeekingTime); break; } @@ -992,7 +989,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { if (this._currentContentInfo?.contentId !== msgData.contentId) { return; } - playbackObserver.setPlaybackRate(msgData.value); + mediaElementMonitor.setPlaybackRate(msgData.value); break; case CoreMessageType.BitrateEstimateChange: @@ -1266,16 +1263,16 @@ export default class MediaSourceContentInitializer extends ContentInitializer { if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem?.[0])) { notifyAndStartMediaSourceReload(0, undefined, undefined); } else { - const lastObservation = playbackObserver.getReference().getValue(); + const lastObservation = mediaElementMonitor.getReference().getValue(); const currentPosition = lastObservation.position.getWanted(); // simple seek close to the current position // to flush the buffers if (currentPosition + 0.001 < lastObservation.duration) { - playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001); + mediaElementMonitor.setCurrentTime(mediaElement.currentTime + 0.001); } else { - playbackObserver.setCurrentTime(currentPosition); + mediaElementMonitor.setCurrentTime(currentPosition); } } } @@ -1581,7 +1578,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { private _reload( mediaElement: IMediaElement, textDisplayer: ITextDisplayer | null, - playbackObserver: IMediaElementPlaybackObserver, + mediaElementMonitor: IMediaElementMonitor, mediaSourceStatus: SharedReference, streamEventsEmitter: StreamEventsEmitter, position: number, @@ -1600,13 +1597,13 @@ export default class MediaSourceContentInitializer extends ContentInitializer { return; } stopListeningMSStatusUpdates(); - const corePlaybackObserver = this._setUpModulesOnNewMediaSource( + const coreMediaElementMonitor = this._setUpModulesOnNewMediaSource( { initialTime: position, autoPlay, mediaElement, textDisplayer, - playbackObserver, + mediaElementMonitor, streamEventsEmitter, }, this._currentMediaSourceCanceller.signal, @@ -1614,14 +1611,14 @@ export default class MediaSourceContentInitializer extends ContentInitializer { if ( !this._currentMediaSourceCanceller.isUsed() && - corePlaybackObserver !== null && + coreMediaElementMonitor !== null && this._currentContentInfo !== null ) { const contentId = this._currentContentInfo.contentId; - corePlaybackObserver.listen( + coreMediaElementMonitor.listen( (obs) => { this._settings.coreInterface.sendMessage({ - type: MainThreadMessageType.PlaybackObservation, + type: MainThreadMessageType.MediaObservation, contentId, value: objectAssign(obs, { position: obs.position.serialize(), @@ -1662,11 +1659,11 @@ export default class MediaSourceContentInitializer extends ContentInitializer { autoPlay: boolean; mediaElement: IMediaElement; textDisplayer: ITextDisplayer | null; - playbackObserver: IMediaElementPlaybackObserver; + mediaElementMonitor: IMediaElementMonitor; streamEventsEmitter: StreamEventsEmitter; }, cancelSignal: CancellationSignal, - ): IReadOnlyPlaybackObserver | null { + ): IReadOnlyMediaElementMonitor | null { if (cancelSignal.isCancelled()) { return null; } @@ -1684,9 +1681,8 @@ export default class MediaSourceContentInitializer extends ContentInitializer { const { initialTime, autoPlay, - mediaElement, textDisplayer, - playbackObserver, + mediaElementMonitor, streamEventsEmitter, } = parameters; this._currentContentInfo.initialTime = initialTime; @@ -1695,8 +1691,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { const { autoPlayResult, initialPlayPerformed } = performInitialSeekAndPlay( { - mediaElement, - playbackObserver, + mediaElementMonitor, startTime: initialTime, mustAutoPlay: autoPlay, onWarning: (err) => this.trigger("warning", err), @@ -1714,8 +1709,8 @@ export default class MediaSourceContentInitializer extends ContentInitializer { }, { clearSignal: cancelSignal, emitCurrentValue: true }, ); - const corePlaybackObserver = createCorePlaybackObserver( - playbackObserver, + const coreMediaElementMonitor = createCoreMediaElementMonitor( + mediaElementMonitor, { autoPlay, initialPlayPerformed, @@ -1737,7 +1732,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { * events when it cannot, as well as "unstalled" events when it get out of one. */ const rebufferingController = new RebufferingController( - playbackObserver, + mediaElementMonitor, manifest, speed, ); @@ -1825,7 +1820,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { */ autoPlayResult .then(() => { - getLoadedReference(playbackObserver, false, cancelSignal).onUpdate( + getLoadedReference(mediaElementMonitor, false, cancelSignal).onUpdate( (isLoaded, stopListening) => { if (isLoaded) { stopListening(); @@ -1845,7 +1840,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { this._onFatalError(err); }); - return corePlaybackObserver; + return coreMediaElementMonitor; } /** @@ -1867,7 +1862,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer { private _startPlaybackIfReady(parameters: { mediaElement: IMediaElement; textDisplayer: ITextDisplayer | null; - playbackObserver: IMediaElementPlaybackObserver; + mediaElementMonitor: IMediaElementMonitor; drmInitializationStatus: IReadOnlySharedReference; mediaSourceStatus: IReadOnlySharedReference; streamEventsEmitter: StreamEventsEmitter; @@ -1893,22 +1888,22 @@ export default class MediaSourceContentInitializer extends ContentInitializer { ); log.debug("Init", "Initial time calculated", { initialTime }); const { enableFastSwitching, onCodecSwitch } = this._settings.bufferOptions; - const corePlaybackObserver = this._setUpModulesOnNewMediaSource( + const coreMediaElementMonitor = this._setUpModulesOnNewMediaSource( { initialTime, autoPlay: this._settings.autoPlay, mediaElement: parameters.mediaElement, textDisplayer: parameters.textDisplayer, - playbackObserver: parameters.playbackObserver, + mediaElementMonitor: parameters.mediaElementMonitor, streamEventsEmitter: parameters.streamEventsEmitter, }, this._currentMediaSourceCanceller.signal, ); - if (this._currentMediaSourceCanceller.isUsed() || corePlaybackObserver === null) { + if (this._currentMediaSourceCanceller.isUsed() || coreMediaElementMonitor === null) { return true; } - const initialObservation = corePlaybackObserver.getReference().getValue(); + const initialObservation = coreMediaElementMonitor.getReference().getValue(); const sentInitialObservation = objectAssign(initialObservation, { position: initialObservation.position.serialize(), }); @@ -1924,10 +1919,10 @@ export default class MediaSourceContentInitializer extends ContentInitializer { }, }); - corePlaybackObserver.listen( + coreMediaElementMonitor.listen( (obs) => { this._settings.coreInterface.sendMessage({ - type: MainThreadMessageType.PlaybackObservation, + type: MainThreadMessageType.MediaObservation, contentId, value: objectAssign(obs, { position: obs.position.serialize() }), }); diff --git a/src/main_thread/init/types.ts b/src/main_thread/init/types.ts index 0b98d215cba..14a97942c8b 100644 --- a/src/main_thread/init/types.ts +++ b/src/main_thread/init/types.ts @@ -25,7 +25,7 @@ import type { IRepresentationMetadata, IDecipherabilityStatusChangedElement, } from "../../manifest/index.ts"; -import type { IMediaElementPlaybackObserver } from "../../playback_observer/index.ts"; +import type { IMediaElementMonitor } from "../../media_element_monitor/index.ts"; import type { IPlayerError } from "../../public_types.ts"; import type { IThumbnailResponse } from "../../transports/index.ts"; import EventEmitter from "../../utils/event_emitter.ts"; @@ -73,16 +73,16 @@ export abstract class ContentInitializer extends EventEmitter { - return srcPlaybackObserver.deriveReadOnlyObserver(function transform( - observationRef: IReadOnlySharedReference, +): IReadOnlyMediaElementMonitor { + return srcMediaElementMonitor.deriveReadOnlyMonitor(function transform( + observationRef: IReadOnlySharedReference, parentObserverCancelSignal: CancellationSignal, - ): IReadOnlySharedReference { - const canceller = new TaskCanceller("Core PlaybackObserver"); + ): IReadOnlySharedReference { + const canceller = new TaskCanceller("Core MediaElementMonitor"); canceller.linkToSignal(parentObserverCancelSignal); canceller.linkToSignal(fnCancelSignal); - const newRef = new SharedReference( - constructCorePlaybackObservation(), - canceller.signal, - ); + const newRef = new SharedReference(constructCoreMediaObservation(), canceller.signal); // TODO there might be subtle unexpected behavior here as updating the // speed will send observation which may be outdated at the time it is sent - speed.onUpdate(emitCorePlaybackObservation, { + speed.onUpdate(emitCoreMediaObservation, { clearSignal: canceller.signal, emitCurrentValue: false, }); - observationRef.onUpdate(emitCorePlaybackObservation, { + observationRef.onUpdate(emitCoreMediaObservation, { clearSignal: canceller.signal, emitCurrentValue: false, }); @@ -147,13 +144,13 @@ export default function createCorePlaybackObserver( mediaSource?.addEventListener( "streamingChanged", () => { - emitCorePlaybackObservation(); + emitCoreMediaObservation(); }, canceller.signal, ); return newRef; - function constructCorePlaybackObservation() { + function constructCoreMediaObservation() { const observation = observationRef.getValue(); const lastSpeed = speed.getValue(); updateWantedPositionIfAfterManifest(observation, manifest); @@ -177,14 +174,14 @@ export default function createCorePlaybackObserver( }; } - function emitCorePlaybackObservation() { - newRef.setValue(constructCorePlaybackObservation()); + function emitCoreMediaObservation() { + newRef.setValue(constructCoreMediaObservation()); } }); } export function updateWantedPositionIfAfterManifest( - observation: IPlaybackObservation, + observation: IMediaObservation, manifest: IManifestMetadata, ): void { if (!manifest.isDynamic || manifest.isLastPeriodKnown) { diff --git a/src/main_thread/init/utils/format_media_error.ts b/src/main_thread/init/utils/format_media_error.ts new file mode 100644 index 00000000000..2364b0d9a4c --- /dev/null +++ b/src/main_thread/init/utils/format_media_error.ts @@ -0,0 +1,47 @@ +import { MediaError as RxPlayerMediaError } from "../../../errors/index.ts"; +import isNullOrUndefined from "../../../utils/is_null_or_undefined.ts"; + +/** + * Format a `MediaError` as linked to an `HMTLMediaElement` into the + * corresponding RxPlayer's `MediaError`. + * @param {MediaError|null} mediaError - The media error currently linked to + * the media element. + * @returns {Object} - RxPlayer's `MediaError` instance corresponding to this + * error. + */ +export default function formatMediaError( + mediaError: MediaError | null, +): RxPlayerMediaError { + let errorCode: number | undefined; + let errorMessage: string | undefined; + if (!isNullOrUndefined(mediaError)) { + errorCode = mediaError.code; + errorMessage = mediaError.message; + } + + switch (errorCode) { + case 1: + errorMessage = + errorMessage ?? + "The fetching of the associated resource was aborted by the user's request."; + return new RxPlayerMediaError("MEDIA_ERR_ABORTED", errorMessage); + case 2: + errorMessage = + errorMessage ?? + "A network error occurred which prevented the media from being " + + "successfully fetched"; + return new RxPlayerMediaError("MEDIA_ERR_NETWORK", errorMessage); + case 3: + errorMessage = + errorMessage ?? "An error occurred while trying to decode the media resource"; + return new RxPlayerMediaError("MEDIA_ERR_DECODE", errorMessage); + case 4: + errorMessage = + errorMessage ?? "The media resource has been found to be unsuitable."; + return new RxPlayerMediaError("MEDIA_ERR_SRC_NOT_SUPPORTED", errorMessage); + default: + errorMessage = + errorMessage ?? "The HTMLMediaElement errored due to an unknown reason."; + return new RxPlayerMediaError("MEDIA_ERR_UNKNOWN", errorMessage); + } +} diff --git a/src/main_thread/init/utils/get_loaded_reference.ts b/src/main_thread/init/utils/get_loaded_reference.ts index 342fff92ec7..27faa71ced4 100644 --- a/src/main_thread/init/utils/get_loaded_reference.ts +++ b/src/main_thread/init/utils/get_loaded_reference.ts @@ -18,9 +18,9 @@ import shouldValidateMetadata from "../../../compat/should_validate_metadata.ts" import shouldWaitForDataBeforeLoaded from "../../../compat/should_wait_for_data_before_loaded.ts"; import shouldWaitForHaveEnoughData from "../../../compat/should_wait_for_have_enough_data.ts"; import type { - IPlaybackObservation, - IReadOnlyPlaybackObserver, -} from "../../../playback_observer/index.ts"; + IMediaObservation, + IReadOnlyMediaElementMonitor, +} from "../../../media_element_monitor/index.ts"; import type { IReadOnlySharedReference } from "../../../utils/reference.ts"; import SharedReference from "../../../utils/reference.ts"; import type { CancellationSignal } from "../../../utils/task_canceller.ts"; @@ -29,20 +29,20 @@ import TaskCanceller from "../../../utils/task_canceller.ts"; /** * Returns an `IReadOnlySharedReference` that switches to `true` once the * content is considered loaded (i.e. once it can begin to be played). - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {boolean} isDirectfile - `true` if this is a directfile content * @param {Object} cancelSignal * @returns {Object} */ export default function getLoadedReference( - playbackObserver: IReadOnlyPlaybackObserver, + mediaElementMonitor: IReadOnlyMediaElementMonitor, isDirectfile: boolean, cancelSignal: CancellationSignal, ): IReadOnlySharedReference { const listenCanceller = new TaskCanceller("Loaded Reference update"); listenCanceller.linkToSignal(cancelSignal); const isLoaded = new SharedReference(false, listenCanceller.signal); - playbackObserver.listen( + mediaElementMonitor.listen( (observation) => { if ( observation.rebuffering !== null || diff --git a/src/main_thread/init/utils/initial_seek_and_play.ts b/src/main_thread/init/utils/initial_seek_and_play.ts index d00fe5b88f3..3511eee5f80 100644 --- a/src/main_thread/init/utils/initial_seek_and_play.ts +++ b/src/main_thread/init/utils/initial_seek_and_play.ts @@ -19,8 +19,8 @@ import shouldPerformInitialSeekToZero from "../../../compat/should_seek_at_zero. import shouldValidateMetadata from "../../../compat/should_validate_metadata.ts"; import { MediaError } from "../../../errors/index.ts"; import log from "../../../log.ts"; -import type { IMediaElementPlaybackObserver } from "../../../playback_observer/index.ts"; -import { SeekingState } from "../../../playback_observer/index.ts"; +import type { IMediaElementMonitor } from "../../../media_element_monitor/index.ts"; +import { SeekingState } from "../../../media_element_monitor/index.ts"; import type { IPlayerError } from "../../../public_types.ts"; import type { IReadOnlySharedReference } from "../../../utils/reference.ts"; import SharedReference from "../../../utils/reference.ts"; @@ -62,15 +62,13 @@ export interface IInitialSeekAndPlayObject { */ export default function performInitialSeekAndPlay( { - mediaElement, - playbackObserver, + mediaElementMonitor, startTime, mustAutoPlay, isDirectfile, onWarning, }: { - mediaElement: IMediaElement; - playbackObserver: IMediaElementPlaybackObserver; + mediaElementMonitor: IMediaElementMonitor; startTime: number | (() => number | undefined); mustAutoPlay: boolean; isDirectfile: boolean; @@ -89,11 +87,11 @@ export default function performInitialSeekAndPlay( return; } - /** `true` if we asked the `PlaybackObserver` to perform an initial seek. */ + /** `true` if we asked the `MediaElementMonitor` to perform an initial seek. */ let hasAskedForInitialSeek = false; const performInitialSeek = (initialSeekTime: number) => { - const pendingSeek = playbackObserver.getPendingSeekInformation(); + const pendingSeek = mediaElementMonitor.getPendingSeekInformation(); /* * NOTE: The user might have asked for a seek before the media element @@ -103,10 +101,10 @@ export default function performInitialSeekAndPlay( * last one. */ if (pendingSeek === null || pendingSeek.isInternal) { - playbackObserver.setCurrentTime(initialSeekTime); + mediaElementMonitor.setCurrentTime(initialSeekTime); } hasAskedForInitialSeek = true; - playbackObserver.unblockSeeking(); + mediaElementMonitor.unblockSeeking(); }; // `startTime` defined as a function might depend on metadata to make its @@ -122,11 +120,11 @@ export default function performInitialSeekAndPlay( if (initiallySeekedTime !== 0 && initiallySeekedTime !== undefined) { performInitialSeek(initiallySeekedTime); } else { - playbackObserver.unblockSeeking(); + mediaElementMonitor.unblockSeeking(); } waitForSeekable(); } else { - playbackObserver.listen( + mediaElementMonitor.listen( (obs, stopListening) => { const initiallySeekedTime = typeof startTime === "number" ? startTime : startTime(); @@ -152,7 +150,7 @@ export default function performInitialSeekAndPlay( ) { performInitialSeek(initiallySeekedTime); } else { - playbackObserver.unblockSeeking(); + mediaElementMonitor.unblockSeeking(); } waitForSeekable(); } @@ -163,7 +161,7 @@ export default function performInitialSeekAndPlay( /** * Logic that should be run once the initial seek has been asked to the - * PlaybackObserver. + * MediaElementMonitor. * * Actually wait until the seek has been performed, wait for the right moment * to perform autoplay, resolve the promise once everything has been done and @@ -176,8 +174,13 @@ export default function performInitialSeekAndPlay( * seek arised. */ let hasStartedSeeking = false; - playbackObserver.listen( + mediaElementMonitor.listen( (obs, stopListening) => { + const mediaElement = mediaElementMonitor.getMediaElement(); + if (mediaElement === null) { + // media element not yet attached + return; + } if ( !hasStartedSeeking && (obs.seeking !== SeekingState.None || @@ -201,7 +204,7 @@ export default function performInitialSeekAndPlay( if (cancelSignal.isCancelled()) { return; } - waitForPlayable(); + waitForPlayable(mediaElement); }, { includeLastObservation: false, clearSignal: cancelSignal }, ); @@ -214,8 +217,8 @@ export default function performInitialSeekAndPlay( * if asked. Potentially send warning if a minor issue has been detected while * doing so. */ - function waitForPlayable() { - playbackObserver.listen( + function waitForPlayable(mediaElement: IMediaElement) { + mediaElementMonitor.listen( (observation, stopListening) => { if ( observation.seeking === SeekingState.None && @@ -223,7 +226,7 @@ export default function performInitialSeekAndPlay( observation.readyState >= 1 ) { stopListening(); - onPlayable(); + onPlayable(mediaElement); } }, { includeLastObservation: true, clearSignal: cancelSignal }, @@ -237,7 +240,7 @@ export default function performInitialSeekAndPlay( * Promise when done. * Might also send warnings if minor issues arise. */ - function onPlayable() { + function onPlayable(mediaElement: IMediaElement) { log.info("Init", "Can begin to play content"); if (!mustAutoPlay) { if (mediaElement.autoplay) { diff --git a/src/main_thread/init/utils/rebuffering_controller.ts b/src/main_thread/init/utils/rebuffering_controller.ts index 4c08f279370..9580c1c7517 100644 --- a/src/main_thread/init/utils/rebuffering_controller.ts +++ b/src/main_thread/init/utils/rebuffering_controller.ts @@ -21,11 +21,11 @@ import { MediaError } from "../../../errors/index.ts"; import log from "../../../log.ts"; import type { IManifestMetadata, IPeriodMetadata } from "../../../manifest/index.ts"; import { getPeriodAfter } from "../../../manifest/index.ts"; -import { SeekingState } from "../../../playback_observer/index.ts"; +import { SeekingState } from "../../../media_element_monitor/index.ts"; import type { - IMediaElementPlaybackObserver, - IPlaybackObservation, -} from "../../../playback_observer/index.ts"; + IMediaElementMonitor, + IMediaObservation, +} from "../../../media_element_monitor/index.ts"; import type { IPlayerError } from "../../../public_types.ts"; import EventEmitter from "../../../utils/event_emitter.ts"; import getMonotonicTimeStamp from "../../../utils/monotonic_timestamp.ts"; @@ -50,7 +50,7 @@ const EPSILON = 1 / 60; */ export default class RebufferingController extends EventEmitter { /** Emit the current playback conditions */ - private _playbackObserver: IMediaElementPlaybackObserver; + private _mediaElementMonitor: IMediaElementMonitor; private _manifest: IManifestMetadata | null; private _speed: IReadOnlySharedReference; private _isStarted: boolean; @@ -64,17 +64,17 @@ export default class RebufferingController extends EventEmitter, ) { super(); - this._playbackObserver = playbackObserver; + this._mediaElementMonitor = mediaElementMonitor; this._manifest = manifest; this._speed = speed; this._discontinuitiesStore = []; @@ -89,14 +89,14 @@ export default class RebufferingController extends EventEmitter { playbackRateUpdater.dispose(err.reason); }); - this._playbackObserver.listen( + this._mediaElementMonitor.listen( (observation) => { const discontinuitiesStore = this._discontinuitiesStore; const { buffered, position, readyState, rebuffering, freezing } = observation; @@ -183,7 +183,7 @@ export default class RebufferingController extends EventEmitter targetTime ) { const nextPeriod = this._manifest.periods[i + 1]; - this._playbackObserver.setCurrentTime(nextPeriod.start); + this._mediaElementMonitor.setCurrentTime(nextPeriod.start); this.trigger( "warning", generateDiscontinuityError(positionBlockedAt, nextPeriod.start), @@ -289,7 +289,7 @@ export default class RebufferingController extends EventEmitter; private _speedUpdateCanceller: TaskCanceller; private _isRebuffering: boolean; @@ -503,16 +503,16 @@ class PlaybackRateUpdater { /** * Create a new `PlaybackRateUpdater`. - * @param {Object} playbackObserver + * @param {Object} mediaElementMonitor * @param {Object} speed */ constructor( - playbackObserver: IMediaElementPlaybackObserver, + mediaElementMonitor: IMediaElementMonitor, speed: IReadOnlySharedReference, ) { this._speedUpdateCanceller = new TaskCanceller("PlaybackRateUpdater speed updates"); this._isRebuffering = false; - this._playbackObserver = playbackObserver; + this._mediaElementMonitor = mediaElementMonitor; this._isDisposed = false; this._speed = speed; this._updateSpeed(); @@ -530,7 +530,7 @@ class PlaybackRateUpdater { this._isRebuffering = true; this._speedUpdateCanceller.cancel("start rebuffering"); log.info("Init", "Pause playback to build buffer"); - this._playbackObserver.setPlaybackRate(0); + this._mediaElementMonitor.setPlaybackRate(0); } /** @@ -567,7 +567,7 @@ class PlaybackRateUpdater { this._speed.onUpdate( (lastSpeed) => { log.info("Init", "Resume playback speed", { newSpeed: lastSpeed }); - this._playbackObserver.setPlaybackRate(lastSpeed); + this._mediaElementMonitor.setPlaybackRate(lastSpeed); }, { clearSignal: this._speedUpdateCanceller.signal, diff --git a/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts b/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts index 18398a72f6c..df379095786 100644 --- a/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts +++ b/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts @@ -17,10 +17,10 @@ import config from "../../../../config.ts"; import type { IManifestMetadata } from "../../../../manifest/index.ts"; import type { - IPlaybackObservation, - IReadOnlyPlaybackObserver, -} from "../../../../playback_observer/index.ts"; -import { SeekingState } from "../../../../playback_observer/index.ts"; + IMediaObservation, + IReadOnlyMediaElementMonitor, +} from "../../../../media_element_monitor/index.ts"; +import { SeekingState } from "../../../../media_element_monitor/index.ts"; import EventEmitter from "../../../../utils/event_emitter.ts"; import SharedReference from "../../../../utils/reference.ts"; import type { CancellationSignal } from "../../../../utils/task_canceller.ts"; @@ -43,7 +43,7 @@ interface IStreamEventsEmitterEvent { */ export default class StreamEventsEmitter extends EventEmitter { /** Regularly emit playback metrics such as the position. */ - private _playbackObserver: IReadOnlyPlaybackObserver; + private _mediaElementMonitor: IReadOnlyMediaElementMonitor; /** Current stream events tracked for the whole content. */ private _scheduledEventsRef: SharedReference< Array @@ -66,11 +66,11 @@ export default class StreamEventsEmitter extends EventEmitter) { + constructor(mediaElementMonitor: IReadOnlyMediaElementMonitor) { super(); - this._playbackObserver = playbackObserver; + this._mediaElementMonitor = mediaElementMonitor; this._canceller = null; this._scheduledEventsRef = new SharedReference< Array @@ -147,7 +147,7 @@ export default class StreamEventsEmitter extends EventEmitter} scheduledEvents * @param {Object} oldObservation diff --git a/src/main_thread/init/utils/throw_on_media_error.ts b/src/main_thread/init/utils/throw_on_media_error.ts deleted file mode 100644 index 9eac8d074f5..00000000000 --- a/src/main_thread/init/utils/throw_on_media_error.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IMediaElement } from "../../../compat/browser_compatibility_types.ts"; -import { MediaError } from "../../../errors/index.ts"; -import isNullOrUndefined from "../../../utils/is_null_or_undefined.ts"; -import type { CancellationSignal } from "../../../utils/task_canceller.ts"; - -/** - * @param {HTMLMediaElement} mediaElement - * @param {Function} onError - * @param {Object} cancelSignal - */ -export default function listenToMediaError( - mediaElement: IMediaElement, - onError: (error: MediaError) => void, - cancelSignal: CancellationSignal, -): void { - if (cancelSignal.isCancelled()) { - return; - } - - mediaElement.addEventListener("error", onMediaError); - cancelSignal.register(() => { - mediaElement.removeEventListener("error", onMediaError); - }); - - function onMediaError(): void { - const mediaError = mediaElement.error; - let errorCode: number | undefined; - let errorMessage: string | undefined; - if (!isNullOrUndefined(mediaError)) { - errorCode = mediaError.code; - errorMessage = mediaError.message; - } - - switch (errorCode) { - case 1: - errorMessage = - errorMessage ?? - "The fetching of the associated resource was aborted by the user's request."; - return onError(new MediaError("MEDIA_ERR_ABORTED", errorMessage)); - case 2: - errorMessage = - errorMessage ?? - "A network error occurred which prevented the media from being " + - "successfully fetched"; - return onError(new MediaError("MEDIA_ERR_NETWORK", errorMessage)); - case 3: - errorMessage = - errorMessage ?? "An error occurred while trying to decode the media resource"; - return onError(new MediaError("MEDIA_ERR_DECODE", errorMessage)); - case 4: - errorMessage = - errorMessage ?? "The media resource has been found to be unsuitable."; - return onError(new MediaError("MEDIA_ERR_SRC_NOT_SUPPORTED", errorMessage)); - default: - errorMessage = - errorMessage ?? "The HTMLMediaElement errored due to an unknown reason."; - return onError(new MediaError("MEDIA_ERR_UNKNOWN", errorMessage)); - } - } -} diff --git a/src/main_thread/types.ts b/src/main_thread/types.ts index d64d920779e..dbcc4ac75a7 100644 --- a/src/main_thread/types.ts +++ b/src/main_thread/types.ts @@ -2,14 +2,17 @@ import type { IResolutionInfo, IManifestFetcherSettings, ISegmentQueueCreatorBackoffOptions, - IPausedPlaybackObservation, + IPausedMediaObservation, IRepresentationsChoice, ITrackSwitchingMode, } from "../core/types.ts"; import type { IDefaultConfig } from "../default_config.ts"; import type { ISerializedSourceBufferError } from "../errors/source_buffer_error.ts"; +import type { + IFreezingStatus, + IRebufferingStatus, +} from "../media_element_monitor/index.ts"; import type { SourceBufferType } from "../mse/index.ts"; -import type { IFreezingStatus, IRebufferingStatus } from "../playback_observer/index.ts"; import type { ICmcdOptions, IManifestLoader, @@ -241,8 +244,8 @@ export interface IStartPreparedContentMessage { export interface IStartPreparedContentMessageValue { /** The start time at which we should play, in seconds. */ initialTime: number; - /** The current playback observation. */ - initialObservation: ISerializedPlaybackObservation; + /** The current media observation. */ + initialObservation: ISerializedMediaObservation; /** * Hex-encoded string identifying the key system used. * May be cross-referenced with the content's metadata when performing @@ -287,15 +290,15 @@ export interface ICodecSupportInfo { * Those messages are sent until the `IStopContentMessage` for that same * `contentId`. */ -export interface IPlaybackObservationMessage { - type: MainThreadMessageType.PlaybackObservation; +export interface IMediaObservationMessage { + type: MainThreadMessageType.MediaObservation; /** * Same `contentId` than for the corresponding `IPrepareContentMessage` message. * Allows to prevent race conditions. */ contentId: string; /** The media-related metadata that has just been observed now. */ - value: ISerializedPlaybackObservation; + value: ISerializedMediaObservation; } /** @@ -398,12 +401,12 @@ export interface IRepresentationUpdateMessage { } /** Media-related metadata. */ -export interface ISerializedPlaybackObservation { +export interface ISerializedMediaObservation { /** * Information on whether the media element was paused at the time of the * Observation. */ - paused: IPausedPlaybackObservation; + paused: IPausedMediaObservation; position: [number, number | null]; /** `readyState` property of the HTMLMediaElement. */ readyState: number; @@ -624,7 +627,7 @@ export const enum MainThreadMessageType { DecipherabilityStatusUpdate = "decipherability-update", LogLevelUpdate = "log-level-update", MediaSourceReadyStateChange = "media-source-ready-state-change", - PlaybackObservation = "observation", + MediaObservation = "observation", PrepareContent = "prepare", ReferenceUpdate = "ref-update", RepresentationUpdate = "rep-update", @@ -648,7 +651,7 @@ export type IMainThreadMessage = | IStartPreparedContentMessage | IReferenceUpdateMessage | ICodecSupportUpdateMessage - | IPlaybackObservationMessage + | IMediaObservationMessage | IDecipherabilityStatusChangedMessage | IUpdateContentUrlsMessage | ITriggerMediaSourceReloadMainMessage diff --git a/src/playback_observer/core_playback_observer.ts b/src/media_element_monitor/core_media_element_monitor.ts similarity index 85% rename from src/playback_observer/core_playback_observer.ts rename to src/media_element_monitor/core_media_element_monitor.ts index bf022a5638c..e7fd26eae75 100644 --- a/src/playback_observer/core_playback_observer.ts +++ b/src/media_element_monitor/core_media_element_monitor.ts @@ -6,18 +6,18 @@ import type { IReadOnlySharedReference } from "../utils/reference.ts"; import type { CancellationSignal } from "../utils/task_canceller.ts"; import type { IFreezingStatus, - IReadOnlyPlaybackObserver, + IReadOnlyMediaElementMonitor, IRebufferingStatus, } from "./types.ts"; -import generateReadOnlyObserver from "./utils/generate_read_only_observer.ts"; +import generateReadOnlyObserver from "./utils/generate_read_only_monitor.ts"; import type ObservationPosition from "./utils/observation_position.ts"; -export interface ICorePlaybackObservation { +export interface ICoreMediaObservation { /** * Information on whether the media element was paused at the time of the * Observation. */ - paused: IPausedPlaybackObservation; + paused: IPausedMediaObservation; /** * Information on the current media position in seconds at the time of the * Observation. @@ -54,7 +54,7 @@ export interface ICorePlaybackObservation { } /** Pause-related information linked to an emitted Playback observation. */ -export interface IPausedPlaybackObservation { +export interface IPausedMediaObservation { /** * Known paused state at the time the Observation was emitted. * @@ -73,14 +73,14 @@ export interface IPausedPlaybackObservation { pending: boolean | undefined; } -export default class CorePlaybackObserver implements IReadOnlyPlaybackObserver { - private _src: IReadOnlySharedReference; +export default class CoreMediaElementMonitor implements IReadOnlyMediaElementMonitor { + private _src: IReadOnlySharedReference; private _cancelSignal: CancellationSignal; private _messageSender: (msg: IUpdatePlaybackRateCoreMessage) => void; private _contentId: string; constructor( - src: IReadOnlySharedReference, + src: IReadOnlySharedReference, contentId: string, sendMessage: (msg: IUpdatePlaybackRateCoreMessage) => void, cancellationSignal: CancellationSignal, @@ -103,7 +103,7 @@ export default class CorePlaybackObserver implements IReadOnlyPlaybackObserver { + public getReference(): IReadOnlySharedReference { return this._src; } @@ -120,7 +120,7 @@ export default class CorePlaybackObserver implements IReadOnlyPlaybackObserver void) => void, + cb: (observation: ICoreMediaObservation, stopListening: () => void) => void, params: { includeLastObservation?: boolean | undefined; clearSignal: CancellationSignal; @@ -136,12 +136,12 @@ export default class CorePlaybackObserver implements IReadOnlyPlaybackObserver( + public deriveReadOnlyMonitor( transform: ( - observationRef: IReadOnlySharedReference, + observationRef: IReadOnlySharedReference, cancellationSignal: CancellationSignal, ) => IReadOnlySharedReference, - ): IReadOnlyPlaybackObserver { + ): IReadOnlyMediaElementMonitor { return generateReadOnlyObserver(this, transform, this._cancelSignal); } } diff --git a/src/playback_observer/index.ts b/src/media_element_monitor/index.ts similarity index 50% rename from src/playback_observer/index.ts rename to src/media_element_monitor/index.ts index 634ba9854f6..f3e8403bcf4 100644 --- a/src/playback_observer/index.ts +++ b/src/media_element_monitor/index.ts @@ -1,12 +1,12 @@ -import type MediaElementPlaybackObserver from "./media_element_playback_observer.ts"; +import type MediaElementMonitor from "./media_element_monitor.ts"; import ObservationPosition from "./utils/observation_position.ts"; export { SeekingState } from "./types.ts"; export type { IFreezingStatus, IRebufferingStatus, - IPlaybackObservation, - IReadOnlyPlaybackObserver, + IMediaObservation, + IReadOnlyMediaElementMonitor, } from "./types.ts"; -export type IMediaElementPlaybackObserver = MediaElementPlaybackObserver; +export type IMediaElementMonitor = MediaElementMonitor; export { ObservationPosition }; diff --git a/src/playback_observer/media_element_playback_observer.ts b/src/media_element_monitor/media_element_monitor.ts similarity index 85% rename from src/playback_observer/media_element_playback_observer.ts rename to src/media_element_monitor/media_element_monitor.ts index 9ab5251b9c3..9a2273b0b58 100644 --- a/src/playback_observer/media_element_playback_observer.ts +++ b/src/media_element_monitor/media_element_monitor.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import type { IMediaElement } from "../compat/browser_compatibility_types.ts"; +import { type IMediaElement } from "../compat/browser_compatibility_types.ts"; +import clearElementSrc from "../compat/clear_element_src.ts"; +import disableRemotePlaybackOnManagedMediaSource from "../compat/disable_remote_playback_on_managed_media_source.ts"; import isSeekingApproximate from "../compat/is_seeking_approximate.ts"; +import resetMediaElement from "../compat/reset_media_element.ts"; import config from "../config.ts"; import ManualTimeRanges from "../core/segment_sinks/implementations/utils/manual_time_ranges.ts"; import log from "../log.ts"; @@ -25,22 +28,22 @@ import objectAssign from "../utils/object_assign.ts"; import { getBufferedTimeRange } from "../utils/ranges.ts"; import type { IReadOnlySharedReference } from "../utils/reference.ts"; import SharedReference from "../utils/reference.ts"; -import type { CancellationSignal } from "../utils/task_canceller.ts"; import TaskCanceller from "../utils/task_canceller.ts"; +import type { CancellationSignal } from "../utils/task_canceller.ts"; import type { IMediaInfos, - IPlaybackObservation, - IPlaybackObserverEventType, - IReadOnlyPlaybackObserver, + IMediaObservation, + IMediaElementMonitorEventType, + IReadOnlyMediaElementMonitor, IRebufferingStatus, IFreezingStatus, } from "./types.ts"; import { SeekingState } from "./types.ts"; -import generateReadOnlyObserver from "./utils/generate_read_only_observer.ts"; +import generateReadOnlyMonitor from "./utils/generate_read_only_monitor.ts"; import ObservationPosition from "./utils/observation_position.ts"; /** - * HTMLMediaElement Events for which playback observations are calculated and + * HTMLMediaElement Events for which media observations are calculated and * emitted. */ const SCANNED_MEDIA_ELEMENTS_EVENTS = [ @@ -59,15 +62,15 @@ const SCANNED_MEDIA_ELEMENTS_EVENTS = [ * then able to react upon them. * * This is a central class of the RxPlayer as many modules rely on the - * `PlaybackObserver` to know the current state of the media being played. + * `MediaElementMonitor` to know the current state of the media being played. * - * You can use the PlaybackObserver to either get the last observation + * You can use the MediaElementMonitor to either get the last observation * performed, get the current media state or listen to media observation sent * at a regular interval. * - * @class {PlaybackObserver} + * @class {MediaElementMonitor} */ -export default class PlaybackObserver { +export default class MediaElementMonitor { /** HTMLMediaElement which we want to observe. */ private _mediaElementRef: SharedReference; @@ -94,7 +97,7 @@ export default class PlaybackObserver { * the RxPlayer's internal logic vs when it was sourced from an outside * application code. * - * To implement this in the PlaybackObserver, we maintain this counter + * To implement this in the MediaElementMonitor, we maintain this counter * allowing to know when a "seeking" event received from a `HTMLMediaElement` * was due to an "internal seek" or an external seek: * - This counter is incremented each time an "internal seek" (seek from the @@ -107,9 +110,9 @@ export default class PlaybackObserver { private _internalSeeksIncoming: number[]; /** - * Stores the last playback observation produced by the `PlaybackObserver`.: + * Stores the last media observation produced by the `MediaElementMonitor`.: */ - private _observationRef: SharedReference; + private _observationRef: SharedReference; /** * `TaskCanceller` allowing to free all resources and stop producing playback @@ -137,30 +140,30 @@ export default class PlaybackObserver { /** * If `true` seek operations asked through the - * `MediaElementPlaybackObserver` will not be performed now but after the + * `MediaElementMonitor` will not be performed now but after the * `unblockSeeking` method is called. */ private _isSeekBlocked: boolean; /** - * Create a new `PlaybackObserver`, which allows to produce new "playback + * Create a new `MediaElementMonitor`, which allows to produce new "playback * observations" on various media events and intervals. * - * Once a `PlaybackObserver` is created, you will want to "attach" the + * Once a `MediaElementMonitor` is created, you will want to "attach" the * media element to it through the `attachMediaElement` method once that * element is ready to play your content. * - * Note that creating a `PlaybackObserver` lead to the usage of resources, - * such as event listeners which will only be freed once the `stop` method is - * called. + * Note that creating a `MediaElementMonitor` lead to the usage of resources, + * such as event listeners which will only be freed once the `destroy` method + * is called. * @param {Object} options */ - constructor(options: IPlaybackObserverOptions) { + constructor(options: IMediaElementMonitorOptions) { this._internalSeeksIncoming = []; this._mediaElementRef = new SharedReference(null); this._withMediaSource = options.withMediaSource; this._lowLatencyMode = options.lowLatencyMode; - this._canceller = new TaskCanceller("MediaElementPlaybackObserver"); + this._canceller = new TaskCanceller("MediaElementMonitor"); this._expectedSeekingPosition = null; this._pendingSeek = null; this._isSeekBlocked = false; @@ -172,7 +175,7 @@ export default class PlaybackObserver { } /** - * "Link" the actual `HTMLMediaElement` to this `PlaybackObserver`. + * "Link" the actual `HTMLMediaElement` to this `MediaElementMonitor`. * * This is done in a step separate from the constructor to allow complex * situations where you want to inialize the polling logic before the media @@ -185,8 +188,9 @@ export default class PlaybackObserver { public attachMediaElement(mediaElement: IMediaElement): void { const prevMediaElement = this._mediaElementRef.getValue(); if (prevMediaElement !== null) { - throw new Error("A media element was already attached to this PlaybackObserver"); + throw new Error("A media element was already attached to this MediaElementMonitor"); } + clearElementSrc(mediaElement); this._mediaElementRef.setValue(mediaElement); if (this._canceller.isUsed()) { return; @@ -205,19 +209,81 @@ export default class PlaybackObserver { } /** - * Stop the `PlaybackObserver` from emitting playback observations and free all + * Get direct access to the `HTMLMediaElement`. + * + * `null` if not already attached. + * @returns {HTMLMediaElement|null} + */ + public getMediaElement(): IMediaElement | null { + return this._mediaElementRef.getValue(); + } + + public addMediaErrorListener( + cb: (error: MediaError | null) => void, + cancelSignal: CancellationSignal, + ): void { + this._mediaElementRef.onUpdate( + (mediaElement: IMediaElement | null, stopListening) => { + if (mediaElement === null) { + return; + } + stopListening(); + const onError = () => { + cb(mediaElement.error); + }; + mediaElement.addEventListener("error", onError); + cancelSignal.register(() => { + mediaElement.removeEventListener("error", onError); + }); + }, + { emitCurrentValue: true, clearSignal: cancelSignal }, + ); + } + + public linkUrl( + value: string | MediaProvider, + isMediaSource: boolean, + cancelSignal: CancellationSignal, + ): void { + this._mediaElementRef.onUpdate( + (mediaElement: IMediaElement | null, stopListening) => { + if (mediaElement === null) { + return; + } + stopListening(); + if (typeof value === "string") { + mediaElement.src = value; + cancelSignal.register(() => { + resetMediaElement(mediaElement, value); + }); + } else { + mediaElement.srcObject = value; + cancelSignal.register(() => { + mediaElement.srcObject = null; + }); + } + if (isMediaSource) { + disableRemotePlaybackOnManagedMediaSource(mediaElement, cancelSignal); + } + }, + { emitCurrentValue: true, clearSignal: cancelSignal }, + ); + } + + /** + * Stop the `MediaElementMonitor` from emitting media observations and free all * resources reserved to emitting them such as event listeners and intervals. * - * Once `stop` is called, no new playback observation will ever be emitted. + * Once `destroy` is called, no new media observation will ever be emitted. * - * Note that it is important to call stop once the `PlaybackObserver` is no - * more needed to avoid unnecessarily leaking resources. + * Note that it is important to call `destroy` once the `MediaElementMonitor` is + * no more needed to avoid unnecessarily leaking resources. * @param {string | undefined} reason - Human-inspectable reason behind the * stop. Used for debugging matters, especially for debug log * inspection. */ - public stop(reason: string | undefined) { - this._canceller.cancel(reason ?? "MediaElementPlaybackObserver stop"); + public destroy(reason: string | undefined) { + this._canceller.cancel(reason ?? "MediaElementMonitor destroy"); } /** @@ -258,7 +324,7 @@ export default class PlaybackObserver { /** * Prevent seeking operations from being performed from inside the - * `MediaElementPlaybackObserver` until the `unblockSeeking` method is called. + * `MediaElementMonitor` until the `unblockSeeking` method is called. * * You might want to call this method when you want to ensure that the next * seek operation on the media element happens at a specific, controlled, @@ -272,7 +338,7 @@ export default class PlaybackObserver { * Remove seeking block created by the `blockSeeking` method if it was called. * * If a seek operation was requested while the block was active, the - * `MediaElementPlaybackObserver` will seek at the last seeked position as + * `MediaElementMonitor` will seek at the last seeked position as * soon as possible (either right now, or when the `readyState` of the * `HTMLMediaElement` will have at least reached the `"HAVE_METADATA"` state). */ @@ -371,21 +437,21 @@ export default class PlaybackObserver { } /** - * Returns an `IReadOnlySharedReference` storing the last playback observation - * produced by the `PlaybackObserver` and updated each time a new one is + * Returns an `IReadOnlySharedReference` storing the last media observation + * produced by the `MediaElementMonitor` and updated each time a new one is * produced. * * This value can then be for example listened to to be notified of future - * playback observations. + * media observations. * * @returns {Object} */ - public getReference(): IReadOnlySharedReference { + public getReference(): IReadOnlySharedReference { return this._observationRef; } /** - * Register a callback so it regularly receives playback observations. + * Register a callback so it regularly receives media observations. * @param {Function} cb * @param {Object} params - Configuration parameters: * - `includeLastObservation`: If set to `true` the last observation will @@ -394,7 +460,7 @@ export default class PlaybackObserver { * CancellationSignal emits. */ public listen( - cb: (observation: IPlaybackObservation, stopListening: () => void) => void, + cb: (observation: IMediaObservation, stopListening: () => void) => void, params: { includeLastObservation?: boolean | undefined; clearSignal: CancellationSignal; @@ -410,12 +476,12 @@ export default class PlaybackObserver { } /** - * Generate a new playback observer which can listen to other + * Generate a new `MediaElementMonitor` which can listen to other * properties and which can only be accessed to read observations (e.g. * it cannot ask to perform a seek). * - * The object returned will respect the `IReadOnlyPlaybackObserver` interface - * and will inherit this `PlaybackObserver`'s lifecycle: it will emit when + * The object returned will respect the `IReadOnlyMediaElementMonitor` interface + * and will inherit this `MediaElementMonitor`'s lifecycle: it will emit when * the latter emits. * * As argument, this method takes a function which will allow to produce @@ -423,13 +489,13 @@ export default class PlaybackObserver { * @param {Function} transform * @returns {Object} */ - public deriveReadOnlyObserver( + public deriveReadOnlyMonitor( transform: ( - observationRef: IReadOnlySharedReference, + observationRef: IReadOnlySharedReference, cancellationSignal: CancellationSignal, ) => IReadOnlySharedReference, - ): IReadOnlyPlaybackObserver { - return generateReadOnlyObserver(this, transform, this._canceller.signal); + ): IReadOnlyMediaElementMonitor { + return generateReadOnlyMonitor(this, transform, this._canceller.signal); } private _actuallySetCurrentTime( @@ -449,7 +515,7 @@ export default class PlaybackObserver { * observations. * @returns {Object} */ - private _createSharedReference(): SharedReference { + private _createSharedReference(): SharedReference { if (this._observationRef !== undefined) { return this._observationRef; } @@ -475,10 +541,10 @@ export default class PlaybackObserver { } private _getCurrentObservation( - event: IPlaybackObserverEventType, - ): IPlaybackObservation { + event: IMediaElementMonitorEventType, + ): IMediaObservation { /** Actual event emitted through an observation. */ - let tmpEvt: IPlaybackObserverEventType = event; + let tmpEvt: IMediaElementMonitorEventType = event; const mediaElement = this._mediaElementRef.getValue(); // NOTE: `this._observationRef` may be `undefined` because we might here be @@ -490,14 +556,14 @@ export default class PlaybackObserver { /** * If `true`, there is a seek operation ongoing but it was done from the - * `PlaybackObserver`'s `setCurrentTime` method, not from external code. + * `MediaElementMonitor`'s `setCurrentTime` method, not from external code. */ let isInternalSeeking = false; /** If set, the position for which we plan to seek to as soon as possible. */ let pendingPosition: number | null = this._pendingSeek?.position ?? null; - /** Initially-polled playback observation, before adjustments. */ + /** Initially-polled media observation, before adjustments. */ const mediaTimings = mediaElement === null ? getEmptyMediaInfo() : getMediaInfos(mediaElement); const { buffered, readyState, position, seeking } = mediaTimings; @@ -612,7 +678,7 @@ export default class PlaybackObserver { seekingState = SeekingState.None; } - const timings: IPlaybackObservation = objectAssign({}, mediaTimings, { + const timings: IMediaObservation = objectAssign({}, mediaTimings, { position: new ObservationPosition(mediaTimings.position, pendingPosition), event: tmpEvt, seeking: seekingState, @@ -640,7 +706,7 @@ export default class PlaybackObserver { return timings; } - private _generateObservationForEvent(event: IPlaybackObserverEventType): void { + private _generateObservationForEvent(event: IMediaElementMonitorEventType): void { const newObservation = this._getCurrentObservation(event); if (log.hasLevel("DEBUG")) { log.debug( @@ -768,7 +834,7 @@ function hasLoadedUntilTheEnd( /** * Get polled media metrics for when the `HTMLMediaElement` is not yet "attached" - * to the `PlaybackObserver`. + * to the `MediaElementMonitor`. * * Those metrics actually corresponds to an idle media element. * @returns {Object} @@ -829,8 +895,8 @@ function getRebufferingStatus({ bufferGap, fullyLoaded, }: { - /** Previous Playback Observation produced. */ - previousObservation: IPlaybackObservation; + /** Previous media observation produced. */ + previousObservation: IMediaObservation; /** New media information collected. */ currentObservation: IMediaInfos; /** @@ -841,7 +907,7 @@ function getRebufferingStatus({ */ basePosition: number; /** Name of the event that triggers this new observation. */ - observationEvent: IPlaybackObserverEventType; + observationEvent: IMediaElementMonitorEventType; /** * If `true`, we're relying on MSE API for the current content, if `false`, * we're relying on regular HTML5 video playback handled by the browser. @@ -989,9 +1055,9 @@ function getRebufferingStatus({ * @returns {Object|null} */ function getFreezingStatus( - prevObservation: IPlaybackObservation, + prevObservation: IMediaObservation, currentInfo: IMediaInfos, - currentEvt: IPlaybackObserverEventType, + currentEvt: IMediaElementMonitorEventType, bufferGap: number | undefined, ): IFreezingStatus | null { const { MINIMUM_BUFFER_AMOUNT_BEFORE_FREEZING } = config.getCurrent(); @@ -1020,7 +1086,7 @@ function getFreezingStatus( : null; } -export interface IPlaybackObserverOptions { +export interface IMediaElementMonitorOptions { withMediaSource: boolean; lowLatencyMode: boolean; } @@ -1086,12 +1152,12 @@ function prettyPrintBuffered(buffered: TimeRanges, currentTime: number): string } /** - * Generate the initial playback observation for when no event has yet been + * Generate the initial media observation for when no event has yet been * emitted to lead to one. * @param {HTMLMediaElement} mediaElement * @returns {Object} */ -function getInitialObservation(mediaElement: IMediaElement | null): IPlaybackObservation { +function getInitialObservation(mediaElement: IMediaElement | null): IMediaObservation { const mediaTimings = mediaElement === null ? getEmptyMediaInfo() : getMediaInfos(mediaElement); return objectAssign(mediaTimings, { diff --git a/src/playback_observer/types.ts b/src/media_element_monitor/types.ts similarity index 83% rename from src/playback_observer/types.ts rename to src/media_element_monitor/types.ts index 7be20eb8752..5d83670781f 100644 --- a/src/playback_observer/types.ts +++ b/src/media_element_monitor/types.ts @@ -2,13 +2,13 @@ import type { IReadOnlySharedReference } from "../utils/reference.ts"; import type { CancellationSignal } from "../utils/task_canceller.ts"; import type ObservationPosition from "./utils/observation_position.ts"; -/** "Event" that triggered the playback observation. */ -export type IPlaybackObserverEventType = - /** First playback observation automatically emitted. */ +/** "Event" that triggered the media observation. */ +export type IMediaElementMonitorEventType = + /** First media observation automatically emitted. */ | "init" - /** Observation manually forced by the PlaybackObserver. */ + /** Observation manually forced by the MediaElementMonitor. */ | "manual" - /** Regularly emitted playback observation when no event happened in a long time. */ + /** Regularly emitted media observation when no event happened in a long time. */ | "timeupdate" /** On the HTML5 event with the same name */ | "canplay" @@ -33,13 +33,13 @@ export type IPlaybackObserverEventType = /** An internal seek happens */ | "internal-seeking"; -/** Information recuperated on the media element on each playback observation. */ +/** Information recuperated on the media element on each media observation. */ export interface IMediaInfos { /** Value of `buffered` (buffered ranges) for the media element. */ buffered: TimeRanges; /** * `currentTime` (position) set on the media element at the time of the - * PlaybackObserver's measure. + * MediaElementMonitor's measure. */ position: number; /** Current `duration` set on the media element. */ @@ -74,7 +74,7 @@ export const enum SeekingState { * status. * "Rebuffering" is a status where the player has not enough buffer ahead to * play reliably. - * The RxPlayer should pause playback when a playback observation indicates the + * The RxPlayer should pause playback when a media observation indicates the * rebuffering status. */ export interface IRebufferingStatus { @@ -109,10 +109,10 @@ export interface IFreezingStatus { timestamp: number; } -/** Information emitted on each playback observation. */ -export interface IPlaybackObservation extends Omit { - /** Event that triggered this playback observation. */ - event: IPlaybackObserverEventType; +/** Information emitted on each media observation. */ +export interface IMediaObservation extends Omit { + /** Event that triggered this media observation. */ + event: IMediaElementMonitorEventType; /** Current seeking state. */ seeking: SeekingState; /** @@ -151,7 +151,7 @@ export interface IPlaybackObservation extends Omit { +export interface IReadOnlyMediaElementMonitor { /** * Get the current playing position, in seconds. * Returns `undefined` when this cannot be known, such as when the playback @@ -196,18 +196,18 @@ export interface IReadOnlyPlaybackObserver { */ getIsPaused(): boolean | undefined; /** - * Returns an `IReadOnlySharedReference` storing the last playback observation - * produced by the `IReadOnlyPlaybackObserver` and updated each time a new one + * Returns an `IReadOnlySharedReference` storing the last media observation + * produced by the `IReadOnlyMediaElementMonitor` and updated each time a new one * is produced. * * This value can then be for example listened to to be notified of future - * playback observations. + * media observations. * * @returns {Object} */ getReference(): IReadOnlySharedReference; /** - * Register a callback so it regularly receives playback observations. + * Register a callback so it regularly receives media observations. * @param {Function} cb * @param {Object} options - Configuration options: * - `includeLastObservation`: If set to `true` the last observation will @@ -224,17 +224,17 @@ export interface IReadOnlyPlaybackObserver { }, ): void; /** - * Generate a new `IReadOnlyPlaybackObserver` from this one. + * Generate a new `IReadOnlyMediaElementMonitor` from this one. * * As argument, this method takes a function which will allow to produce * the new set of properties to be present on each observation. * @param {Function} transform * @returns {Object} */ - deriveReadOnlyObserver( + deriveReadOnlyMonitor( transform: ( observationRef: IReadOnlySharedReference, cancellationSignal: CancellationSignal, ) => IReadOnlySharedReference, - ): IReadOnlyPlaybackObserver; + ): IReadOnlyMediaElementMonitor; } diff --git a/src/playback_observer/utils/generate_read_only_observer.ts b/src/media_element_monitor/utils/generate_read_only_monitor.ts similarity index 83% rename from src/playback_observer/utils/generate_read_only_observer.ts rename to src/media_element_monitor/utils/generate_read_only_monitor.ts index 5285a489f7e..072e6047c3d 100644 --- a/src/playback_observer/utils/generate_read_only_observer.ts +++ b/src/media_element_monitor/utils/generate_read_only_monitor.ts @@ -1,22 +1,22 @@ import type { IReadOnlySharedReference } from "../../utils/reference.ts"; import type { CancellationSignal } from "../../utils/task_canceller.ts"; -import type { IReadOnlyPlaybackObserver } from "../types.ts"; +import type { IReadOnlyMediaElementMonitor } from "../types.ts"; /** - * Create `IReadOnlyPlaybackObserver` from a source `IReadOnlyPlaybackObserver` + * Create `IReadOnlyMediaElementMonitor` from a source `IReadOnlyMediaElementMonitor` * and a mapping function. * @param {Object} src * @param {Function} transform * @returns {Object} */ export default function generateReadOnlyObserver( - src: IReadOnlyPlaybackObserver, + src: IReadOnlyMediaElementMonitor, transform: ( observationRef: IReadOnlySharedReference, cancellationSignal: CancellationSignal, ) => IReadOnlySharedReference, cancellationSignal: CancellationSignal, -): IReadOnlyPlaybackObserver { +): IReadOnlyMediaElementMonitor { const mappedRef = transform(src.getReference(), cancellationSignal); return { getCurrentTime() { @@ -49,12 +49,12 @@ export default function generateReadOnlyObserver( emitCurrentValue: params.includeLastObservation, }); }, - deriveReadOnlyObserver( + deriveReadOnlyMonitor( newTransformFn: ( observationRef: IReadOnlySharedReference, signal: CancellationSignal, ) => IReadOnlySharedReference, - ): IReadOnlyPlaybackObserver { + ): IReadOnlyMediaElementMonitor { return generateReadOnlyObserver(this, newTransformFn, cancellationSignal); }, }; diff --git a/src/playback_observer/utils/observation_position.ts b/src/media_element_monitor/utils/observation_position.ts similarity index 98% rename from src/playback_observer/utils/observation_position.ts rename to src/media_element_monitor/utils/observation_position.ts index 14779cb8bf8..69674092313 100644 --- a/src/playback_observer/utils/observation_position.ts +++ b/src/media_element_monitor/utils/observation_position.ts @@ -45,7 +45,7 @@ export default class ObservationPosition { /** * Returns the playback position actually observed on the media element at - * the time the playback observation was made. + * the time the media observation was made. * * Note that it may be different than the position for which media data is * wanted in rare scenarios where the goal position is not yet set on the diff --git a/tests/unit/mocks/playback_observer.ts b/tests/unit/mocks/media_element_monitor.ts similarity index 65% rename from tests/unit/mocks/playback_observer.ts rename to tests/unit/mocks/media_element_monitor.ts index 66a9fb4f6f9..037205bedd9 100644 --- a/tests/unit/mocks/playback_observer.ts +++ b/tests/unit/mocks/media_element_monitor.ts @@ -1,17 +1,17 @@ -import type CorePlaybackObserver from "../../../src/playback_observer/core_playback_observer.ts"; -import type MediaElementPlaybackObserver from "../../../src/playback_observer/media_element_playback_observer.ts"; -import type { IReadOnlyPlaybackObserver } from "../../../src/playback_observer/types.ts"; -import type ObservationPosition from "../../../src/playback_observer/utils/observation_position.ts"; +import type CoreMediaElementMonitor from "../../../src/media_element_monitor/core_media_element_monitor.ts"; +import type MediaElementMonitor from "../../../src/media_element_monitor/media_element_monitor.ts"; +import type { IReadOnlyMediaElementMonitor } from "../../../src/media_element_monitor/types.ts"; +import type ObservationPosition from "../../../src/media_element_monitor/utils/observation_position.ts"; import SharedReference from "../../../src/utils/reference.ts"; import type { CancellationSignal } from "../../../src/utils/task_canceller.ts"; import { makeMockedClass } from "./utils.ts"; /** - * Construct a class implementing the `MediaElementPlaybackObserver` interface. - * @class DummyMediaElementPlaybackObserver + * Construct a class implementing the `MediaElementMonitor` interface. + * @class DummyMediaElementMonitor */ -export const DummyMediaElementPlaybackObserver = - makeMockedClass( +export const DummyMediaElementMonitor = + makeMockedClass( { attachMediaElement: notImplemented("attachMediaElement"), getCurrentTime: notImplemented("getCurrentTime"), @@ -20,23 +20,26 @@ export const DummyMediaElementPlaybackObserver = getPlaybackRate: notImplemented("getPlaybackRate"), getReadyState: notImplemented("getReadyState"), getReference: notImplemented("getReference"), - stop: notImplemented("stop"), + getMediaElement: notImplemented("getMediaElement"), + addMediaErrorListener: notImplemented("addMediaErrorListener"), + linkUrl: notImplemented("linkUrl"), + destroy: notImplemented("destroy"), blockSeeking: notImplemented("blockSeeking"), unblockSeeking: notImplemented("unblockSeeking"), isSeekingBlocked: notImplemented("isSeekingBlocked"), setCurrentTime: notImplemented("setCurrentTime"), setPlaybackRate: notImplemented("setPlaybackRate"), listen: notImplemented("listen"), - deriveReadOnlyObserver: notImplemented("deriveReadOnlyObserver"), + deriveReadOnlyMonitor: notImplemented("deriveReadOnlyMonitor"), }, {}, ); /** - * Construct a class implementing the `CorePlaybackObserver` interface. - * @class DummyCorePlaybackObserver + * Construct a class implementing the `CoreMediaElementMonitor` interface. + * @class DummyCoreMediaElementMonitor */ -export const DummyCorePlaybackObserver = makeMockedClass( +export const DummyCoreMediaElementMonitor = makeMockedClass( { getCurrentTime: notImplemented("getCurrentTime"), getIsPaused: notImplemented("getIsPaused"), @@ -45,20 +48,20 @@ export const DummyCorePlaybackObserver = makeMockedClass( getReference: notImplemented("getReference"), setPlaybackRate: notImplemented("setPlaybackRate"), listen: notImplemented("listen"), - deriveReadOnlyObserver: notImplemented("deriveReadOnlyObserver"), + deriveReadOnlyMonitor: notImplemented("deriveReadOnlyMonitor"), }, {}, ); /** - * Object facilitation the usage of a IReadOnlyPlaybackObserver`. + * Object facilitation the usage of a IReadOnlyMediaElementMonitor`. * /!\ Do not forget to call `reset` when done to ensure no memory leak. */ -export interface IMockedReadOnlyPlaybackObserver { +export interface IMockedReadOnlyMediaElementMonitor { /** - * The `IReadOnlyPlaybackObserver` itself. + * The `IReadOnlyMediaElementMonitor` itself. */ - observer: IReadOnlyPlaybackObserver; + observer: IReadOnlyMediaElementMonitor; /** * Allows to trigger new observations through `observer`. */ @@ -73,19 +76,19 @@ export interface IMockedReadOnlyPlaybackObserver { } /** - * Allows to create any `IReadOnlyPlaybackObserver` with TypeScript typechecking + * Allows to create any `IReadOnlyMediaElementMonitor` with TypeScript typechecking * and to obtain a function to emit new observations. * @param {Object} initialData - The initial observation emitted. * @returns {Object} res - * @returns {IReadOnlyPlaybackObserver} res.observer - The - * `IReadOnlyPlaybackObserver` instance. + * @returns {IReadOnlyMediaElementMonitor} res.observer - The + * `IReadOnlyMediaElementMonitor` instance. * @returns {Function} res.emit - A function allowing to emit new observations. - * @returns {Function} res.reset - Reset the playback observer to its initial + * @returns {Function} res.reset - Reset the media element monitor to its initial * state, also removing all its listeners. Call this between tests. */ -export function makeReadyOnlyPlaybackObserver( +export function makeReadyOnlyMediaElementMonitor( initialData: TObservationData, -): IMockedReadOnlyPlaybackObserver { +): IMockedReadOnlyMediaElementMonitor { let ref = new SharedReference(initialData); const ret = { observer: makeObserver(), @@ -99,8 +102,8 @@ export function makeReadyOnlyPlaybackObserver( }; return ret; - function makeObserver(): IReadOnlyPlaybackObserver { - const klass = makeMockedClass>( + function makeObserver(): IReadOnlyMediaElementMonitor { + const klass = makeMockedClass>( { getCurrentTime: notImplemented("getCurrentTime"), getIsPaused: notImplemented("getIsPaused"), @@ -122,7 +125,7 @@ export function makeReadyOnlyPlaybackObserver( emitCurrentValue: params.includeLastObservation, }); }, - deriveReadOnlyObserver: notImplemented("deriveReadOnlyObserver"), + deriveReadOnlyMonitor: notImplemented("deriveReadOnlyMonitor"), }, {}, ); diff --git a/tests/unit/src/core/adaptive/adaptive_representation_selector.test.ts b/tests/unit/src/core/adaptive/adaptive_representation_selector.test.ts index 16a767236e2..bca8f163021 100644 --- a/tests/unit/src/core/adaptive/adaptive_representation_selector.test.ts +++ b/tests/unit/src/core/adaptive/adaptive_representation_selector.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, vi, afterEach } from "vitest"; import type { IAdaptiveRepresentationSelectorArguments, - IRepresentationEstimatorPlaybackObservation, + IRepresentationEstimatorMediaObservation, } from "../../../../../src/core/adaptive/adaptive_representation_selector.ts"; import createAdaptiveRepresentationSelector from "../../../../../src/core/adaptive/adaptive_representation_selector.ts"; import BufferBasedChooser from "../../../../../src/core/adaptive/buffer_based_chooser.ts"; @@ -28,17 +28,17 @@ import { createSegment, } from "../../../mocks/manifest.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../mocks/playback_observer.ts"; +} from "../../../mocks/media_element_monitor.ts"; vi.mock("../../../../../src/log", () => ({ default: { debug: vi.fn(), warn: vi.fn(), info: vi.fn(), error: vi.fn() }, })); -/** Dummy object that will be used as the `PlaybackObserver` instance */ -const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ +/** Dummy object that will be used as the `MediaElementMonitor` instance */ +const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ bufferGap: 10, position: makeObservationPosition(0), speed: 1, @@ -88,11 +88,11 @@ function makeAbrOptions(): IAdaptiveRepresentationSelectorArguments { }; } -/** Emit a new playback observation through `mockedPlaybackObserver`. */ +/** Emit a new media observation through `mockedMediaElementMonitor`. */ function emitObservation( - overrides: Partial = {}, + overrides: Partial = {}, ) { - mockedPlaybackObserver.emit({ + mockedMediaElementMonitor.emit({ bufferGap: 0, position: makeObservationPosition(10), speed: 1, @@ -102,7 +102,7 @@ function emitObservation( }); } -/** Create the `position` attribute for a playback observation. */ +/** Create the `position` attribute for a media observation. */ function makeObservationPosition(wanted: number) { return new DummyObservationPosition({ getWanted: () => wanted, @@ -111,7 +111,7 @@ function makeObservationPosition(wanted: number) { describe("createAdaptiveRepresentationSelector", () => { afterEach(() => { - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetAllMocks(); }); @@ -131,7 +131,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); expect(result).not.toBeNull(); @@ -149,14 +149,14 @@ describe("createAdaptiveRepresentationSelector", () => { ctx, new SharedReference(null), new SharedReference([rep]), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); const result2 = selector( ctx, new SharedReference(null), new SharedReference([rep]), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -205,14 +205,14 @@ describe("createAdaptiveRepresentationSelector", () => { videoCtx, new SharedReference(null), new SharedReference([rep]), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); const audioResult = selector( audioCtx, new SharedReference(null), new SharedReference([rep]), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -259,7 +259,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); const estimate = estimates.getValue(); @@ -275,7 +275,7 @@ describe("createAdaptiveRepresentationSelector", () => { describe("getEstimates (multiple representations)", () => { function setupMultiRep( overrides: { - obs?: Partial; + obs?: Partial; lowLatencyMode?: boolean; isDynamic?: boolean; bitrateChosen?: number; @@ -331,7 +331,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(isDynamic), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -487,7 +487,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(true), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -511,7 +511,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -695,7 +695,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), new SharedReference(null), new SharedReference(reps), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -727,7 +727,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), new SharedReference(null), new SharedReference(reps), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -760,7 +760,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), new SharedReference(null), new SharedReference(reps), - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -791,7 +791,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); @@ -834,7 +834,7 @@ describe("createAdaptiveRepresentationSelector", () => { makeContext(), currentRepRef, repsRef, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, canceller.signal, ); const valueBefore = estimates.getValue(); diff --git a/tests/unit/src/core/adaptive/network_analyzer.test.ts b/tests/unit/src/core/adaptive/network_analyzer.test.ts index 986a45e7f9e..470a46dce34 100644 --- a/tests/unit/src/core/adaptive/network_analyzer.test.ts +++ b/tests/unit/src/core/adaptive/network_analyzer.test.ts @@ -16,7 +16,7 @@ import { DummyManifest, createSegment, } from "../../../mocks/manifest.ts"; -import { DummyObservationPosition } from "../../../mocks/playback_observer.ts"; +import { DummyObservationPosition } from "../../../mocks/media_element_monitor.ts"; import { makeMockedClass } from "../../../mocks/utils.ts"; vi.mock("../../../../../src/log", () => ({ diff --git a/tests/unit/src/core/cmcd/cmcd_data_builder.test.ts b/tests/unit/src/core/cmcd/cmcd_data_builder.test.ts index 4911563db61..e1dd36b88fd 100644 --- a/tests/unit/src/core/cmcd/cmcd_data_builder.test.ts +++ b/tests/unit/src/core/cmcd/cmcd_data_builder.test.ts @@ -29,7 +29,7 @@ vi.mock("../../../../../src/utils/url-utils", () => ({ })); /** Helpers */ -function makePlaybackObserver( +function makeMediaElementMonitor( overrides: Partial<{ rebuffering: object | null; speed: number; @@ -333,7 +333,7 @@ describe("CmcdDataBuilder", () => { describe("startMonitoringPlayback / buffer starvation", () => { it("sets bs=true when rebuffering was observed, then clears it on next request", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ rebuffering: { timestamp: 0 } }); + const observer = makeMediaElementMonitor({ rebuffering: { timestamp: 0 } }); builder.startMonitoringPlayback(observer); const payload1: any = builder.getCmcdDataForManifest("dash"); @@ -347,9 +347,9 @@ describe("CmcdDataBuilder", () => { expect(status2).not.toContain("bs"); }); - it("includes bl (buffer length) for video when playback observer is set", () => { + it("includes bl (buffer length) for video when MediaElementMonitor is set", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ + const observer = makeMediaElementMonitor({ buffered: { video: [{ start: 5, end: 20 }], audio: null, @@ -368,7 +368,7 @@ describe("CmcdDataBuilder", () => { it("includes pr when playback speed is not 1", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ speed: 2, rebuffering: null }); + const observer = makeMediaElementMonitor({ speed: 2, rebuffering: null }); builder.startMonitoringPlayback(observer); const payload: any = builder.getCmcdDataForManifest("dash"); @@ -378,7 +378,7 @@ describe("CmcdDataBuilder", () => { it("does not include pr when speed is 1", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ speed: 1, rebuffering: null }); + const observer = makeMediaElementMonitor({ speed: 1, rebuffering: null }); builder.startMonitoringPlayback(observer); const payload: any = builder.getCmcdDataForManifest("dash"); @@ -388,7 +388,7 @@ describe("CmcdDataBuilder", () => { it("does not include pr when playback speed is negative", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ speed: -1, rebuffering: null }); + const observer = makeMediaElementMonitor({ speed: -1, rebuffering: null }); builder.startMonitoringPlayback(observer); const payload: any = builder.getCmcdDataForManifest("dash"); @@ -398,7 +398,10 @@ describe("CmcdDataBuilder", () => { it("includes su when rebuffering is active", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ rebuffering: { timestamp: 0 }, speed: 1 }); + const observer = makeMediaElementMonitor({ + rebuffering: { timestamp: 0 }, + speed: 1, + }); builder.startMonitoringPlayback(observer); const payload: any = builder.getCmcdDataForManifest("dash"); @@ -408,7 +411,7 @@ describe("CmcdDataBuilder", () => { it("does not include dl or rtp when playback speed is 0", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ + const observer = makeMediaElementMonitor({ buffered: { video: [{ start: 5, end: 20 }], audio: null, @@ -429,9 +432,9 @@ describe("CmcdDataBuilder", () => { }); describe("stopMonitoringPlayback", () => { - it("clears the playback observer so subsequent calls work without observation data", () => { + it("clears the MediaElementMonitor so subsequent calls work without observation data", () => { const builder = new CmcdDataBuilder({ communicationType: "headers" }); - const observer = makePlaybackObserver({ speed: 2, rebuffering: null }); + const observer = makeMediaElementMonitor({ speed: 2, rebuffering: null }); builder.startMonitoringPlayback(observer); builder.stopMonitoringPlayback(); diff --git a/tests/unit/src/core/entry/content_time_boundaries_observer.test.ts b/tests/unit/src/core/entry/content_time_boundaries_observer.test.ts index 379cab21a49..b8c81a5359a 100644 --- a/tests/unit/src/core/entry/content_time_boundaries_observer.test.ts +++ b/tests/unit/src/core/entry/content_time_boundaries_observer.test.ts @@ -12,7 +12,7 @@ const { mockTrigger, mockCancellerSignal, mockCanceller, - mockPlaybackObserverListen, + mockMediaElementMonitorListen, mockManifestEventListener, mockGetMinimumSafePosition, mockGetMaximumSafePosition, @@ -26,7 +26,7 @@ const { isUsed: vi.fn(() => false), cancel: vi.fn(), }, - mockPlaybackObserverListen: vi.fn(), + mockMediaElementMonitorListen: vi.fn(), mockManifestEventListener: vi.fn(), mockGetMinimumSafePosition: vi.fn(() => 0), mockGetMaximumSafePosition: vi.fn((): number | undefined => 100), @@ -65,8 +65,8 @@ describe("ContentTimeBoundariesObserver", () => { ...overrides, }); - const createMockPlaybackObserver = (): any => ({ - listen: mockPlaybackObserverListen, + const createMockMediaElementMonitor = (): any => ({ + listen: mockMediaElementMonitorListen, }); const createMockPeriod = (id: string, start: number = 0): any => ({ @@ -99,14 +99,14 @@ describe("ContentTimeBoundariesObserver", () => { }); describe("constructor", () => { - it("should initialize and set up playback observer", async () => { + it("should initialize and set up MediaElementMonitor", async () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const bufferTypes: IBufferType[] = ["audio", "video"]; - new ContentTimeBoundariesObserver(manifest, playbackObserver, bufferTypes); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, bufferTypes); await sleep(0); - expect(mockPlaybackObserverListen).toHaveBeenCalledWith( + expect(mockMediaElementMonitorListen).toHaveBeenCalledWith( expect.any(Function), expect.objectContaining({ includeLastObservation: false, @@ -117,9 +117,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should set up manifest event listener", async () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); await sleep(0); expect(mockManifestEventListener).toHaveBeenCalledWith( @@ -132,12 +132,12 @@ describe("ContentTimeBoundariesObserver", () => { it("should trigger warning when position is before manifest minimum", async () => { mockGetMinimumSafePosition.mockReturnValue(10); const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); await sleep(0); - const positionCallback = mockPlaybackObserverListen.mock.calls[0][0]; + const positionCallback = mockMediaElementMonitorListen.mock.calls[0][0]; positionCallback({ position: { getWanted: () => 5 } }); expect(mockTrigger).toHaveBeenCalledWith("warning", expect.any(Object)); @@ -153,12 +153,12 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger warning when position is within epsilon of manifest minimum", async () => { mockGetMinimumSafePosition.mockReturnValue(10); const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); await sleep(0); - const positionCallback = mockPlaybackObserverListen.mock.calls[0][0]; + const positionCallback = mockMediaElementMonitorListen.mock.calls[0][0]; positionCallback({ position: { getWanted: () => 9.9995 } }); expect(mockTrigger).not.toHaveBeenCalled(); @@ -167,12 +167,12 @@ describe("ContentTimeBoundariesObserver", () => { it("should trigger warning when position is after manifest maximum", async () => { mockGetMaximumSafePosition.mockReturnValue(100); const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); await sleep(0); - const positionCallback = mockPlaybackObserverListen.mock.calls[0][0]; + const positionCallback = mockMediaElementMonitorListen.mock.calls[0][0]; positionCallback({ position: { getWanted: () => 150 } }); expect(mockTrigger).toHaveBeenCalledWith("warning", expect.any(Object)); @@ -185,9 +185,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should return ending position when manifest is not dynamic", async () => { mockGetMaximumSafePosition.mockReturnValue(100); const manifest = createMockManifest({ isDynamic: false }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); await sleep(0); @@ -210,9 +210,9 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -229,9 +229,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should return isEnd: false when ending position is undetermined for non-dynamic content", () => { mockGetMaximumSafePosition.mockReturnValue(undefined); const manifest = createMockManifest({ isDynamic: false }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -253,9 +253,9 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: false, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -280,9 +280,9 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -305,9 +305,9 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "video", ]); @@ -324,10 +324,10 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger events after canceller is used", () => { mockCanceller.isUsed.mockReturnValue(true); const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period = createMockPeriod("period-1"); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -357,9 +357,9 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", "video", ]); @@ -377,10 +377,10 @@ describe("ContentTimeBoundariesObserver", () => { describe("onRepresentationChange", () => { it("should add period to active periods", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period1 = createMockPeriod("period-1", 0); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -394,11 +394,11 @@ describe("ContentTimeBoundariesObserver", () => { describe("onPeriodCleared", () => { it("should remove period from active periods", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period1 = createMockPeriod("period-1", 0); const period2 = createMockPeriod("period-2", 10); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -415,10 +415,10 @@ describe("ContentTimeBoundariesObserver", () => { it("should handle clearing non-existent period gracefully", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period1 = createMockPeriod("period-1", 0); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -432,10 +432,10 @@ describe("ContentTimeBoundariesObserver", () => { describe("periodChange event", () => { it("should trigger periodChange only when period is active in all buffer types", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period = createMockPeriod("period-1", 0); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", "video", ]); @@ -458,10 +458,10 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger periodChange multiple times for same period", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period = createMockPeriod("period-1", 0); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -479,13 +479,13 @@ describe("ContentTimeBoundariesObserver", () => { it("should trigger periodChange when switching to different period", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); const period1 = createMockPeriod("period-1", 0); const period2 = createMockPeriod("period-2", 10); const adap1 = createMockAdaptation([]); const adap2 = createMockAdaptation([]); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -503,9 +503,9 @@ describe("ContentTimeBoundariesObserver", () => { describe("onLastSegmentFinishedLoading", () => { it("should trigger endOfStream when all buffer types finished loading", () => { const manifest = createMockManifest({ isLastPeriodKnown: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", "video", ]); @@ -520,9 +520,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger endOfStream if not all buffer types finished", () => { const manifest = createMockManifest({ isLastPeriodKnown: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", "video", ]); @@ -539,9 +539,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger endOfStream if last period is not known", () => { const manifest = createMockManifest({ isLastPeriodKnown: false }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -557,9 +557,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger multiple times for same buffer type", () => { const manifest = createMockManifest({ isLastPeriodKnown: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -579,9 +579,9 @@ describe("ContentTimeBoundariesObserver", () => { describe("onLastSegmentLoadingResume", () => { it("should trigger resumeStream after endOfStream", () => { const manifest = createMockManifest({ isLastPeriodKnown: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", "video", ]); @@ -598,9 +598,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger if already in loading state", () => { const manifest = createMockManifest({ isLastPeriodKnown: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -620,9 +620,9 @@ describe("ContentTimeBoundariesObserver", () => { describe("manifestUpdate event", () => { it("should trigger endingPositionChange on manifest update", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); const manifestUpdateCallback = mockManifestEventListener.mock.calls[0][1]; @@ -641,9 +641,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should not trigger events if canceller is cancelled", () => { mockCancellerSignal.isCancelled.mockReturnValue(true); const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]); + new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, ["audio"]); const manifestUpdateCallback = mockManifestEventListener.mock.calls[0][1]; @@ -661,9 +661,9 @@ describe("ContentTimeBoundariesObserver", () => { describe("dispose", () => { it("should cancel operations with provided reason", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -674,9 +674,9 @@ describe("ContentTimeBoundariesObserver", () => { it("should cancel operations with default reason when none provided", () => { const manifest = createMockManifest(); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ + const observer = new ContentTimeBoundariesObserver(manifest, mediaElementMonitor, [ "audio", ]); @@ -693,11 +693,13 @@ describe("ContentTimeBoundariesObserver", () => { it("should return manifest safe position for dynamic content", () => { mockGetMaximumSafePosition.mockReturnValue(120); const manifest = createMockManifest({ isDynamic: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio"], + ); const result = observer.getCurrentEndingTime(); @@ -707,12 +709,13 @@ describe("ContentTimeBoundariesObserver", () => { it("should return manifest safe position when adaptations not set", () => { mockGetMaximumSafePosition.mockReturnValue(100); const manifest = createMockManifest({ isDynamic: false }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); const result = observer.getCurrentEndingTime(); @@ -729,12 +732,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); observer.onAdaptationChange("audio", period, null); observer.onAdaptationChange("video", period, videoAdaptation); @@ -754,12 +758,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); observer.onAdaptationChange("audio", period, audioAdaptation); observer.onAdaptationChange("video", period, null); @@ -777,12 +782,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); observer.onAdaptationChange("audio", period, null); observer.onAdaptationChange("video", period, null); @@ -803,11 +809,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio"], + ); observer.onAdaptationChange("audio", period, audioAdaptation); @@ -820,12 +828,13 @@ describe("ContentTimeBoundariesObserver", () => { describe("getEndingPosition for dynamic content", () => { it("should return undefined when adaptations not set", () => { const manifest = createMockManifest({ isDynamic: true }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); const result = observer.getCurrentEndingTime(); @@ -842,12 +851,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); observer.onAdaptationChange("audio", period, audioAdaptation); observer.onAdaptationChange("video", period, null); @@ -867,12 +877,13 @@ describe("ContentTimeBoundariesObserver", () => { isLastPeriodKnown: true, periods: [period], }); - const playbackObserver = createMockPlaybackObserver(); + const mediaElementMonitor = createMockMediaElementMonitor(); - const observer = new ContentTimeBoundariesObserver(manifest, playbackObserver, [ - "audio", - "video", - ]); + const observer = new ContentTimeBoundariesObserver( + manifest, + mediaElementMonitor, + ["audio", "video"], + ); observer.onAdaptationChange("audio", period, null); observer.onAdaptationChange("video", period, null); diff --git a/tests/unit/src/core/segment_sinks/garbage_collector.test.ts b/tests/unit/src/core/segment_sinks/garbage_collector.test.ts index 3405f3e1a67..6a5093eacd8 100644 --- a/tests/unit/src/core/segment_sinks/garbage_collector.test.ts +++ b/tests/unit/src/core/segment_sinks/garbage_collector.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import BufferGarbageCollector from "../../../../../src/core/segment_sinks/garbage_collector.ts"; -import type { IStreamOrchestratorPlaybackObservation } from "../../../../../src/core/stream/index.ts"; +import type { IStreamOrchestratorMediaObservation } from "../../../../../src/core/stream/index.ts"; import type { IRange } from "../../../../../src/utils/ranges.ts"; import SharedReference from "../../../../../src/utils/reference.ts"; import TaskCanceller from "../../../../../src/utils/task_canceller.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../mocks/playback_observer.ts"; +} from "../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../mocks/segment_sinks.ts"; const mockLog = vi.hoisted(() => ({ @@ -19,8 +19,8 @@ const mockLog = vi.hoisted(() => ({ vi.mock("../../../../../src/log", () => ({ default: mockLog })); describe("BufferGarbageCollector", () => { - const mockedPlaybackObserver = makeReadyOnlyPlaybackObserver< - Pick + const mockedMediaElementMonitor = makeReadyOnlyMediaElementMonitor< + Pick >({ position: new DummyObservationPosition({ getWanted: vi.fn(() => 0), @@ -30,7 +30,7 @@ describe("BufferGarbageCollector", () => { const mockRemoveBuffer = vi.spyOn(DummySegmentSink.prototype, "removeBuffer"); function emitObservation(position: number, videoBuffered: IRange[] | null) { - mockedPlaybackObserver.emit({ + mockedMediaElementMonitor.emit({ position: new DummyObservationPosition({ getWanted: () => position, }), @@ -42,7 +42,7 @@ describe("BufferGarbageCollector", () => { }); afterEach(() => { - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetAllMocks(); }); @@ -55,7 +55,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -79,7 +79,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -102,7 +102,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -125,7 +125,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -148,7 +148,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -171,7 +171,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -194,7 +194,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -216,7 +216,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -240,7 +240,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -260,7 +260,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -288,7 +288,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -307,7 +307,7 @@ describe("BufferGarbageCollector", () => { expect(mockRemoveBuffer).toHaveBeenCalledTimes(1); }); - it("re-runs clean on new playback observation", async () => { + it("re-runs clean on new media observation", async () => { // Initially empty buffer, then buffered grows behind position emitObservation(100, []); const segmentSink = new DummySegmentSink({ bufferType: "video" }); @@ -317,7 +317,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -356,7 +356,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -389,7 +389,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, @@ -418,7 +418,7 @@ describe("BufferGarbageCollector", () => { BufferGarbageCollector( { segmentSink, - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, maxBufferBehind, maxBufferAhead, }, diff --git a/tests/unit/src/core/stream/adaptation/adaptation_stream.test.ts b/tests/unit/src/core/stream/adaptation/adaptation_stream.test.ts index e89236b37a8..356f16155fa 100644 --- a/tests/unit/src/core/stream/adaptation/adaptation_stream.test.ts +++ b/tests/unit/src/core/stream/adaptation/adaptation_stream.test.ts @@ -19,7 +19,7 @@ import type { IPeriod, IRepresentation, } from "../../../../../../src/manifest/index.ts"; -import type { ObservationPosition } from "../../../../../../src/playback_observer/index.ts"; +import type { ObservationPosition } from "../../../../../../src/media_element_monitor/index.ts"; import SharedReference from "../../../../../../src/utils/reference.ts"; import TaskCanceller, { CancellationError, @@ -33,8 +33,8 @@ import { } from "../../../../mocks/manifest.ts"; import { DummyObservationPosition, - makeReadyOnlyPlaybackObserver, -} from "../../../../mocks/playback_observer.ts"; + makeReadyOnlyMediaElementMonitor, +} from "../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../mocks/segment_sinks.ts"; import { makeMockedClass } from "../../../../mocks/utils.ts"; @@ -90,7 +90,7 @@ const DummySegmentQueueCreator = makeMockedClass( describe("AdaptationStream", () => { let manifest: IManifest; - interface IPlaybackObservation { + interface IMediaObservation { position: ObservationPosition; paused: { last: boolean; pending: undefined }; speed: number; @@ -109,8 +109,8 @@ describe("AdaptationStream", () => { let adaptation: IAdaptation; let representation: IRepresentation; let parentCanceller: TaskCanceller; - let playbackObserver: ReturnType< - typeof makeReadyOnlyPlaybackObserver + let mediaElementMonitor: ReturnType< + typeof makeReadyOnlyMediaElementMonitor >; let manifestUpdateListener: ((updates: IPeriodsUpdateResult) => void) | undefined; @@ -121,7 +121,7 @@ describe("AdaptationStream", () => { representation = new DummyRepresentation({ id: "rep-1", bitrate: 1000 }); parentCanceller = new TaskCanceller("test"); manifestUpdateListener = undefined; - const initialObservation: IPlaybackObservation = { + const initialObservation: IMediaObservation = { position: new DummyObservationPosition({ getPolled: () => 10, getWanted: () => 10, @@ -133,9 +133,9 @@ describe("AdaptationStream", () => { duration: 100, maximumPosition: 100, }; - playbackObserver = makeReadyOnlyPlaybackObserver(initialObservation); - vi.spyOn(playbackObserver.observer, "getCurrentTime").mockReturnValue(10); - vi.spyOn(playbackObserver.observer, "getReadyState").mockReturnValue(4); + mediaElementMonitor = makeReadyOnlyMediaElementMonitor(initialObservation); + vi.spyOn(mediaElementMonitor.observer, "getCurrentTime").mockReturnValue(10); + vi.spyOn(mediaElementMonitor.observer, "getReadyState").mockReturnValue(4); vi.spyOn(manifest, "addEventListener").mockImplementation((eventName, listener) => { if (eventName === "manifestUpdate") { manifestUpdateListener = (updates) => { @@ -153,7 +153,7 @@ describe("AdaptationStream", () => { afterEach(() => { parentCanceller.cancel("cleanup"); - playbackObserver.reset(); + mediaElementMonitor.reset(); vi.resetAllMocks(); }); @@ -272,7 +272,7 @@ describe("AdaptationStream", () => { await Promise.resolve(); expect(waitingMediaSourceReload).toHaveBeenCalledTimes(1); - playbackObserver.emit({ + mediaElementMonitor.emit({ position: new DummyObservationPosition({ getPolled: () => 11, getWanted: () => 11, @@ -496,7 +496,7 @@ describe("AdaptationStream", () => { expect(fastSwitchThresholdRef?.getValue()).toBe(240); }); - it("should update segment queue interruption state from playback observations", () => { + it("should update segment queue interruption state from media observations", () => { const { callbacks } = createCallbacks(); const segmentQueueCreator = new DummySegmentQueueCreator(); let interruptionRef: SharedReference | undefined; @@ -524,7 +524,7 @@ describe("AdaptationStream", () => { } expect(interruptionRef.getValue()).toBe(false); - playbackObserver.emit({ + mediaElementMonitor.emit({ position: new DummyObservationPosition({ getPolled: () => 12, getWanted: () => 12, @@ -538,7 +538,7 @@ describe("AdaptationStream", () => { }); expect(interruptionRef.getValue()).toBe(true); - playbackObserver.emit({ + mediaElementMonitor.emit({ position: new DummyObservationPosition({ getPolled: () => 13, getWanted: () => 13, @@ -891,7 +891,7 @@ describe("AdaptationStream", () => { }; }) { return { - playbackObserver: playbackObserver.observer, + mediaElementMonitor: mediaElementMonitor.observer, content: { manifest, period, @@ -915,7 +915,7 @@ describe("AdaptationStream", () => { _context, _currentRepresentation, _representations, - _playbackObserver, + _mediaElementMonitor, _stopAllEstimates, ) => ({ estimates, diff --git a/tests/unit/src/core/stream/adaptation/get_representations_switch_strategy.test.ts b/tests/unit/src/core/stream/adaptation/get_representations_switch_strategy.test.ts index 1352c99e715..3f6a34ecaa8 100644 --- a/tests/unit/src/core/stream/adaptation/get_representations_switch_strategy.test.ts +++ b/tests/unit/src/core/stream/adaptation/get_representations_switch_strategy.test.ts @@ -7,7 +7,7 @@ import { type SegmentSink, } from "../../../../../../src/core/segment_sinks/index.ts"; import getRepresentationsSwitchingStrategy from "../../../../../../src/core/stream/adaptation/get_representations_switch_strategy.ts"; -import type { IRepresentationStreamPlaybackObservation } from "../../../../../../src/core/stream/representation/index.ts"; +import type { IRepresentationStreamMediaObservation } from "../../../../../../src/core/stream/representation/index.ts"; import type { IAdaptation, IPeriod } from "../../../../../../src/manifest/index.ts"; import SharedReference from "../../../../../../src/utils/reference.ts"; import { @@ -17,17 +17,17 @@ import { createSegment, } from "../../../../mocks/manifest.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../../mocks/playback_observer.ts"; +} from "../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../mocks/segment_sinks.ts"; describe("getRepresentationsSwitchingStrategy", () => { let mockPeriod: IPeriod; let mockAdaptation: IAdaptation; let mockSegmentSink: SegmentSink; - const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ + const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getPolled: () => 10, }), @@ -103,15 +103,15 @@ describe("getRepresentationsSwitchingStrategy", () => { getLastKnownInventory: () => [], getPendingOperations: () => [], }); - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockImplementation( () => 4, ); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockImplementation( () => 10, ); }); afterEach(() => { - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetAllMocks(); }); @@ -122,7 +122,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "lazy", representationIds: ["rep-1"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); }); @@ -135,7 +135,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-1"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); }); @@ -151,7 +151,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-1"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); }); @@ -175,7 +175,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); }); @@ -197,7 +197,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-1"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); }); @@ -220,7 +220,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); @@ -263,7 +263,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); }); @@ -285,7 +285,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); }); @@ -293,7 +293,7 @@ describe("getRepresentationsSwitchingStrategy", () => { describe("reload switching mode", () => { it("should return needs-reload when readyState > 1 and mode is reload", () => { - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockImplementation( () => 4, ); vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockImplementation(() => { @@ -307,14 +307,14 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "reload", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "needs-reload", value: undefined }); }); it("should reload when readyState is undefined", () => { - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockImplementation( () => undefined, ); vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockImplementation(() => { @@ -328,14 +328,14 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "reload", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("needs-reload"); }); it("should not reload when readyState <= 1", () => { - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockImplementation( () => 1, ); vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockImplementation(() => { @@ -349,7 +349,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "reload", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).not.toBe("needs-reload"); @@ -369,7 +369,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); @@ -387,7 +387,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "seamless", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("clean-buffer"); @@ -397,10 +397,10 @@ describe("getRepresentationsSwitchingStrategy", () => { describe("getCurrentTime fallback", () => { it("should use getPolled when getCurrentTime returns undefined", () => { const getPolledMock = vi.fn(() => 15); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockImplementation( () => undefined, ); - vi.spyOn(mockedPlaybackObserver.observer, "getReference").mockImplementation(() => { + vi.spyOn(mockedMediaElementMonitor.observer, "getReference").mockImplementation(() => { return new SharedReference({ position: new DummyObservationPosition({ getPolled: getPolledMock, @@ -424,7 +424,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "seamless", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(getPolledMock).toHaveBeenCalled(); @@ -444,7 +444,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); @@ -467,7 +467,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-2"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result.type).toBe("flush-buffer"); @@ -493,7 +493,7 @@ describe("getRepresentationsSwitchingStrategy", () => { mockAdaptation, { switchingMode: "direct", representationIds: ["rep-1", "rep-2", "rep-3"] }, mockSegmentSink, - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, ); expect(result).toEqual({ type: "continue", value: undefined }); diff --git a/tests/unit/src/core/stream/orchestrator/stream_orchestrator.test.ts b/tests/unit/src/core/stream/orchestrator/stream_orchestrator.test.ts index 1d5354b4fb9..074d6258b61 100644 --- a/tests/unit/src/core/stream/orchestrator/stream_orchestrator.test.ts +++ b/tests/unit/src/core/stream/orchestrator/stream_orchestrator.test.ts @@ -15,7 +15,7 @@ import StreamOrchestrator from "../../../../../../src/core/stream/orchestrator/s import type { IPeriodStreamClearedPayload, IStreamOrchestratorCallbacks, - IStreamOrchestratorPlaybackObservation, + IStreamOrchestratorMediaObservation, } from "../../../../../../src/core/stream/orchestrator/stream_orchestrator.ts"; import type { IPeriodStreamArguments, @@ -43,8 +43,8 @@ import { } from "../../../../mocks/manifest.ts"; import { DummyObservationPosition, - makeReadyOnlyPlaybackObserver, -} from "../../../../mocks/playback_observer.ts"; + makeReadyOnlyMediaElementMonitor, +} from "../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../mocks/segment_sinks.ts"; import { makeMockedClass } from "../../../../mocks/utils.ts"; @@ -99,8 +99,8 @@ describe("StreamOrchestrator", () => { let period: IPeriod; let nextPeriod: IPeriod; let manifestEventEmitter: TestManifestEventEmitter; - let playbackObserver: ReturnType< - typeof makeReadyOnlyPlaybackObserver + let mediaElementMonitor: ReturnType< + typeof makeReadyOnlyMediaElementMonitor >; let segmentSink: SegmentSink; let removeBufferSpy: ReturnType>; @@ -152,8 +152,8 @@ describe("StreamOrchestrator", () => { }); vi.spyOn(manifest, "getNextPeriod").mockReturnValue(undefined); - playbackObserver = - makeReadyOnlyPlaybackObserver({ + mediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getWanted: () => 5, getPolled: () => 5, @@ -204,7 +204,7 @@ describe("StreamOrchestrator", () => { afterEach(() => { orchestratorCanceller.cancel("cleanup"); - playbackObserver.reset(); + mediaElementMonitor.reset(); vi.resetAllMocks(); }); @@ -212,7 +212,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -247,7 +247,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -282,7 +282,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -301,7 +301,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -324,7 +324,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -353,7 +353,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -364,7 +364,7 @@ describe("StreamOrchestrator", () => { makePeriodStreamReadyPayload(period), ); - playbackObserver.emit(makeObservationAt(15)); + mediaElementMonitor.emit(makeObservationAt(15)); expect(periodStreamClearedSpy).toHaveBeenCalledWith({ type: "video", @@ -382,7 +382,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -408,7 +408,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -452,7 +452,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, boundedPeriod, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -460,7 +460,7 @@ describe("StreamOrchestrator", () => { orchestratorCanceller, ); - playbackObserver.emit(makeObservationAt(12)); + mediaElementMonitor.emit(makeObservationAt(12)); expect(periodStreamClearedSpy).toHaveBeenCalledWith({ type: "video", @@ -474,7 +474,7 @@ describe("StreamOrchestrator", () => { startOrchestrator( manifest, period, - playbackObserver, + mediaElementMonitor, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -521,8 +521,8 @@ class TestManifestEventEmitter extends EventEmitter { function startOrchestrator( manifest: IManifest, initialPeriod: IPeriod, - playbackObserver: ReturnType< - typeof makeReadyOnlyPlaybackObserver + mediaElementMonitor: ReturnType< + typeof makeReadyOnlyMediaElementMonitor >, representationEstimator: IRepresentationEstimator, segmentSinksStore: SegmentSinksStore, @@ -532,7 +532,7 @@ function startOrchestrator( ): void { StreamOrchestrator( { manifest, initialPeriod }, - playbackObserver.observer, + mediaElementMonitor.observer, representationEstimator, segmentSinksStore, segmentQueueCreator, @@ -642,7 +642,7 @@ function makeManifestUpdateRemovingNextPeriod(nextPeriod: IPeriod): IPeriodsUpda }; } -function makeObservationAt(position: number): IStreamOrchestratorPlaybackObservation { +function makeObservationAt(position: number): IStreamOrchestratorMediaObservation { return { position: new DummyObservationPosition({ getWanted: () => position, diff --git a/tests/unit/src/core/stream/period/utils/get_adaptation_switch_strategy.test.ts b/tests/unit/src/core/stream/period/utils/get_adaptation_switch_strategy.test.ts index 94837e593d0..20320194a6d 100644 --- a/tests/unit/src/core/stream/period/utils/get_adaptation_switch_strategy.test.ts +++ b/tests/unit/src/core/stream/period/utils/get_adaptation_switch_strategy.test.ts @@ -8,7 +8,7 @@ import { ChunkStatus, SegmentSinkOperation, } from "../../../../../../../src/core/segment_sinks/index.ts"; -import type { IPeriodStreamPlaybackObservation } from "../../../../../../../src/core/stream/period/types.ts"; +import type { IPeriodStreamMediaObservation } from "../../../../../../../src/core/stream/period/types.ts"; import getAdaptationSwitchStrategy from "../../../../../../../src/core/stream/period/utils/get_adaptation_switch_strategy.ts"; import { type Adaptation, @@ -21,17 +21,17 @@ import { DummyRepresentation, } from "../../../../../mocks/manifest.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../../../mocks/playback_observer.ts"; +} from "../../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../../mocks/segment_sinks.ts"; describe("getAdaptationSwitchStrategy", () => { let mockSegmentSink: SegmentSink; let mockPeriod: Period; let mockAdaptation: Adaptation; - const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ + const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getPolled: () => 15, }), @@ -69,15 +69,15 @@ describe("getAdaptationSwitchStrategy", () => { id: "adaptation-1", type: "video", }); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockImplementation( () => 15, ); - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation( + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockImplementation( () => 3, ); }); afterEach(() => { - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetModules(); }); function makeBufferedChunk({ @@ -146,7 +146,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, currMockAdap, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "reload" }, ); @@ -171,7 +171,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, currMockAdap, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "reload" }, ); @@ -196,7 +196,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, currMockAdap, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -222,7 +222,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -246,7 +246,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -272,7 +272,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -296,7 +296,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -339,7 +339,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -368,7 +368,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -391,13 +391,13 @@ describe("getAdaptationSwitchStrategy", () => { }); it("should return needs-reload when switchingMode is reload and readyState > 1", () => { - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockReturnValue(3); + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockReturnValue(3); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "reload", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -405,14 +405,14 @@ describe("getAdaptationSwitchStrategy", () => { }); it("should not reload when readyState is 1 or less", () => { - vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockReturnValue(1); + vi.spyOn(mockedMediaElementMonitor.observer, "getReadyState").mockReturnValue(1); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "reload", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -425,7 +425,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "direct", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -445,7 +445,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, currMockAdap, "direct", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -460,7 +460,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -494,13 +494,13 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-2", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(15); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -520,14 +520,14 @@ describe("getAdaptationSwitchStrategy", () => { }), ]); // Away from segment - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(18); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -555,14 +555,14 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-2", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(18); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -593,14 +593,14 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-1", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(12); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(12); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -621,14 +621,14 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-2", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(18); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -648,14 +648,14 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-2", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(15); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -675,14 +675,14 @@ describe("getAdaptationSwitchStrategy", () => { adaptationId: "adaptation-2", }), ]); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue(15); const result = getAdaptationSwitchStrategy( mockSegmentSink, mockPeriod, mockAdaptation, "direct", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); @@ -692,8 +692,8 @@ describe("getAdaptationSwitchStrategy", () => { }); it("should use polled position when getCurrentTime returns undefined", () => { - const mockGetRef = vi.spyOn(mockedPlaybackObserver.observer, "getReference"); - vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue( + const mockGetRef = vi.spyOn(mockedMediaElementMonitor.observer, "getReference"); + vi.spyOn(mockedMediaElementMonitor.observer, "getCurrentTime").mockReturnValue( undefined, ); vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([ @@ -713,7 +713,7 @@ describe("getAdaptationSwitchStrategy", () => { mockPeriod, mockAdaptation, "seamless", - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, { onCodecSwitch: "continue" }, ); diff --git a/tests/unit/src/core/stream/representation/utils/append_segment_to_buffer.test.ts b/tests/unit/src/core/stream/representation/utils/append_segment_to_buffer.test.ts index 49ffa85b670..840e932ec80 100644 --- a/tests/unit/src/core/stream/representation/utils/append_segment_to_buffer.test.ts +++ b/tests/unit/src/core/stream/representation/utils/append_segment_to_buffer.test.ts @@ -4,7 +4,7 @@ import type { IPushChunkInfos, SegmentSink, } from "../../../../../../../src/core/segment_sinks/index.ts"; -import type { IRepresentationStreamPlaybackObservation } from "../../../../../../../src/core/stream/representation/types.ts"; +import type { IRepresentationStreamMediaObservation } from "../../../../../../../src/core/stream/representation/types.ts"; import appendSegmentToBuffer from "../../../../../../../src/core/stream/representation/utils/append_segment_to_buffer.ts"; import { MediaError, SourceBufferError } from "../../../../../../../src/errors/index.ts"; import SharedReference from "../../../../../../../src/utils/reference.ts"; @@ -18,9 +18,9 @@ import { createSegment, } from "../../../../../mocks/manifest.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../../../mocks/playback_observer.ts"; +} from "../../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../../mocks/segment_sinks.ts"; vi.mock("../../../../../../../src/log", () => ({ @@ -34,8 +34,8 @@ vi.mock("../../../../../../../src/utils/sleep", () => ({ })); describe("appendSegmentToBuffer", () => { - const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ + const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getWanted: vi.fn(() => 10), }), @@ -91,14 +91,14 @@ describe("appendSegmentToBuffer", () => { afterEach(() => { mockBufferGoal.finish(); mockTaskCanceller.cancel("test end"); - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetAllMocks(); }); describe("successful append", () => { it("should push chunk successfully on first try", async () => { const result = await appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -124,7 +124,7 @@ describe("appendSegmentToBuffer", () => { .mockResolvedValueOnce([{ start: 0, end: 10 }]); const result = await appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -148,7 +148,7 @@ describe("appendSegmentToBuffer", () => { .mockResolvedValueOnce([{ start: 0, end: 10 }]); await appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -173,7 +173,7 @@ describe("appendSegmentToBuffer", () => { mockBufferGoal.setValue(30); await appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -195,7 +195,7 @@ describe("appendSegmentToBuffer", () => { .mockRejectedValueOnce(bufferFullError) .mockResolvedValueOnce([{ start: 0, end: 10 }]); - mockedPlaybackObserver.emit({ + mockedMediaElementMonitor.emit({ position: new DummyObservationPosition({ getWanted: vi.fn(() => 3), }), @@ -207,7 +207,7 @@ describe("appendSegmentToBuffer", () => { canStream: true, }); await appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -234,7 +234,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -250,7 +250,7 @@ describe("appendSegmentToBuffer", () => { mockPushChunk.mockRejectedValueOnce(error); await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -277,7 +277,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -291,7 +291,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -309,7 +309,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -330,7 +330,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, @@ -354,7 +354,7 @@ describe("appendSegmentToBuffer", () => { await expect( appendSegmentToBuffer( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, mockDataInfos, mockBufferGoal, diff --git a/tests/unit/src/core/stream/representation/utils/push_init_segment.test.ts b/tests/unit/src/core/stream/representation/utils/push_init_segment.test.ts index b804725b055..95fd706699f 100644 --- a/tests/unit/src/core/stream/representation/utils/push_init_segment.test.ts +++ b/tests/unit/src/core/stream/representation/utils/push_init_segment.test.ts @@ -1,7 +1,7 @@ import type { Mock } from "vitest"; import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { type SegmentSink } from "../../../../../../../src/core/segment_sinks/index.ts"; -import type { IRepresentationStreamPlaybackObservation } from "../../../../../../../src/core/stream/representation/types.ts"; +import type { IRepresentationStreamMediaObservation } from "../../../../../../../src/core/stream/representation/types.ts"; import type appendSegmentToBuffer from "../../../../../../../src/core/stream/representation/utils/append_segment_to_buffer.ts"; import pushInitSegment from "../../../../../../../src/core/stream/representation/utils/push_init_segment.ts"; import { @@ -22,9 +22,9 @@ import { createSegment, } from "../../../../../mocks/manifest.ts"; import { - makeReadyOnlyPlaybackObserver, + makeReadyOnlyMediaElementMonitor, DummyObservationPosition, -} from "../../../../../mocks/playback_observer.ts"; +} from "../../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../../mocks/segment_sinks.ts"; const mockAppendSegmentToBuffer = vi.hoisted((): Mock => @@ -38,8 +38,8 @@ vi.mock( ); describe("pushInitSegment", () => { - const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ + const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getWanted: vi.fn(() => 10), }), @@ -89,7 +89,7 @@ describe("pushInitSegment", () => { afterEach(() => { mockBufferGoal.finish(); mockCanceller.cancel("test end"); - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); vi.resetModules(); }); @@ -105,7 +105,7 @@ describe("pushInitSegment", () => { await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId, segmentData: null, @@ -119,7 +119,7 @@ describe("pushInitSegment", () => { expect(mockAppendSegmentToBuffer).toHaveBeenCalledTimes(1); const callArgs = mockAppendSegmentToBuffer.mock.calls[0]; - expect(callArgs[0]).toBe(mockedPlaybackObserver.observer); + expect(callArgs[0]).toBe(mockedMediaElementMonitor.observer); expect(callArgs[1]).toBe(mockSegmentSink); expect(callArgs[3]).toBe(mockBufferGoal); expect(callArgs[4]).toBe(mockCanceller.signal); @@ -151,7 +151,7 @@ describe("pushInitSegment", () => { const result = await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId: "init-456", segmentData: null, @@ -178,7 +178,7 @@ describe("pushInitSegment", () => { await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId: "init-789", segmentData: null, @@ -197,7 +197,7 @@ describe("pushInitSegment", () => { await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId: "init-abc", segmentData: { someData: "value" }, @@ -217,7 +217,7 @@ describe("pushInitSegment", () => { await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId: "init-def", segmentData: null, @@ -237,7 +237,7 @@ describe("pushInitSegment", () => { await pushInitSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, content: mockContent, initSegmentUniqueId: "init-ghi", segmentData: null, diff --git a/tests/unit/src/core/stream/representation/utils/push_media_segment.test.ts b/tests/unit/src/core/stream/representation/utils/push_media_segment.test.ts index c8c84038434..e3ad005a6e3 100644 --- a/tests/unit/src/core/stream/representation/utils/push_media_segment.test.ts +++ b/tests/unit/src/core/stream/representation/utils/push_media_segment.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import configHandler from "../../../../../../../src/config.ts"; -import type { IRepresentationStreamPlaybackObservation } from "../../../../../../../src/core/stream/representation/types.ts"; +import type { IRepresentationStreamMediaObservation } from "../../../../../../../src/core/stream/representation/types.ts"; import pushMediaSegment from "../../../../../../../src/core/stream/representation/utils/push_media_segment.ts"; import type { IRange } from "../../../../../../../src/utils/ranges.ts"; import SharedReference from "../../../../../../../src/utils/reference.ts"; @@ -14,8 +14,8 @@ import { } from "../../../../../mocks/manifest.ts"; import { DummyObservationPosition, - makeReadyOnlyPlaybackObserver, -} from "../../../../../mocks/playback_observer.ts"; + makeReadyOnlyMediaElementMonitor, +} from "../../../../../mocks/media_element_monitor.ts"; import { DummySegmentSink } from "../../../../../mocks/segment_sinks.ts"; const mockAppendSegmentToBuffer = vi.hoisted(() => @@ -29,8 +29,8 @@ vi.mock( ); describe("pushMediaSegment", () => { - const mockedPlaybackObserver = - makeReadyOnlyPlaybackObserver({ + const mockedMediaElementMonitor = + makeReadyOnlyMediaElementMonitor({ position: new DummyObservationPosition({ getWanted: vi.fn(() => 10), }), @@ -76,7 +76,7 @@ describe("pushMediaSegment", () => { }); afterEach(() => { - mockedPlaybackObserver.reset(); + mockedMediaElementMonitor.reset(); mockBufferGoal.finish(); mockCanceller.cancel("test end"); vi.resetModules(); @@ -85,7 +85,7 @@ describe("pushMediaSegment", () => { it("should return null when chunkData is null", async () => { const result = await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -116,7 +116,7 @@ describe("pushMediaSegment", () => { const result = await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -136,7 +136,7 @@ describe("pushMediaSegment", () => { ); expect(mockAppendSegmentToBuffer).toHaveBeenCalledWith( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, { data: { @@ -171,7 +171,7 @@ describe("pushMediaSegment", () => { await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: null, @@ -191,7 +191,7 @@ describe("pushMediaSegment", () => { ); expect(mockAppendSegmentToBuffer).toHaveBeenCalledWith( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, { data: { @@ -219,7 +219,7 @@ describe("pushMediaSegment", () => { mockAppendSegmentToBuffer.mockResolvedValue([]); await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -268,7 +268,7 @@ describe("pushMediaSegment", () => { await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -288,7 +288,7 @@ describe("pushMediaSegment", () => { ); expect(mockAppendSegmentToBuffer).toHaveBeenCalledWith( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, { data: { @@ -317,7 +317,7 @@ describe("pushMediaSegment", () => { await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -337,7 +337,7 @@ describe("pushMediaSegment", () => { ); expect(mockAppendSegmentToBuffer).toHaveBeenCalledWith( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, { data: { @@ -366,7 +366,7 @@ describe("pushMediaSegment", () => { await pushMediaSegment( { - playbackObserver: mockedPlaybackObserver.observer, + mediaElementMonitor: mockedMediaElementMonitor.observer, bufferGoal: mockBufferGoal, content: mockContent, initSegmentUniqueId: "init-123", @@ -386,7 +386,7 @@ describe("pushMediaSegment", () => { ); expect(mockAppendSegmentToBuffer).toHaveBeenCalledWith( - mockedPlaybackObserver.observer, + mockedMediaElementMonitor.observer, mockSegmentSink, { data: { diff --git a/tests/unit/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.test.ts b/tests/unit/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.test.ts index bf48ed28229..059e2456919 100644 --- a/tests/unit/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.test.ts +++ b/tests/unit/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.test.ts @@ -2,10 +2,10 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import StreamEventsEmitter from "../../../../../../../src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts"; import type { IManifestMetadata } from "../../../../../../../src/manifest/index.ts"; import type { - IPlaybackObservation, - IReadOnlyPlaybackObserver, -} from "../../../../../../../src/playback_observer/index.ts"; -import { SeekingState } from "../../../../../../../src/playback_observer/index.ts"; + IMediaObservation, + IReadOnlyMediaElementMonitor, +} from "../../../../../../../src/media_element_monitor/index.ts"; +import { SeekingState } from "../../../../../../../src/media_element_monitor/index.ts"; import SharedReference from "../../../../../../../src/utils/reference.ts"; import type { CancellationSignal } from "../../../../../../../src/utils/task_canceller.ts"; import TaskCanceller from "../../../../../../../src/utils/task_canceller.ts"; @@ -19,8 +19,8 @@ describe("init - StreamEventsEmitter", () => { vi.useFakeTimers(); const observationRef = new SharedReference(generateObservation(4)); - const playbackObserver = createPlaybackObserver(observationRef); - const streamEventsEmitter = new StreamEventsEmitter(playbackObserver); + const mediaElementMonitor = createMediaElementMonitor(observationRef); + const streamEventsEmitter = new StreamEventsEmitter(mediaElementMonitor); const skippedEvents: unknown[] = []; const regularEvents: unknown[] = []; const stopCanceller = new TaskCanceller("test"); @@ -61,8 +61,8 @@ describe("init - StreamEventsEmitter", () => { vi.useFakeTimers(); const observationRef = new SharedReference(generateObservation(4)); - const playbackObserver = createPlaybackObserver(observationRef); - const streamEventsEmitter = new StreamEventsEmitter(playbackObserver); + const mediaElementMonitor = createMediaElementMonitor(observationRef); + const streamEventsEmitter = new StreamEventsEmitter(mediaElementMonitor); const regularEvents: unknown[] = []; const stopCanceller = new TaskCanceller("test"); @@ -89,9 +89,9 @@ describe("init - StreamEventsEmitter", () => { }); }); -function createPlaybackObserver( - observationRef: SharedReference, -): IReadOnlyPlaybackObserver { +function createMediaElementMonitor( + observationRef: SharedReference, +): IReadOnlyMediaElementMonitor { return { getCurrentTime() { return observationRef.getValue().position.getPolled(); @@ -109,7 +109,7 @@ function createPlaybackObserver( return observationRef; }, listen( - cb: (observation: IPlaybackObservation, stopListening: () => void) => void, + cb: (observation: IMediaObservation, stopListening: () => void) => void, options: { includeLastObservation?: boolean | undefined; clearSignal: CancellationSignal; @@ -120,7 +120,7 @@ function createPlaybackObserver( emitCurrentValue: options.includeLastObservation, }); }, - deriveReadOnlyObserver() { + deriveReadOnlyMonitor() { throw new Error("unused in this test"); }, }; @@ -151,7 +151,7 @@ function generateManifest(): IManifestMetadata { } as unknown as IManifestMetadata; } -function generateObservation(currentTime: number): IPlaybackObservation { +function generateObservation(currentTime: number): IMediaObservation { return { event: "timeupdate", seeking: SeekingState.None, @@ -170,6 +170,6 @@ function generateObservation(currentTime: number): IPlaybackObservation { getPolled() { return currentTime; }, - } as IPlaybackObservation["position"], + } as IMediaObservation["position"], }; } diff --git a/tests/unit/src/main_thread/render_thumbnail.test.ts b/tests/unit/src/main_thread/render_thumbnail.test.ts index bcd2c46f117..14f05744c1a 100644 --- a/tests/unit/src/main_thread/render_thumbnail.test.ts +++ b/tests/unit/src/main_thread/render_thumbnail.test.ts @@ -150,7 +150,7 @@ function createContentInfos( mediaElementTracksStore: null, onAudioTracksNotPlayable: "continue", onVideoTracksNotPlayable: "continue", - playbackObserver: {} as IPublicApiContentInfos["playbackObserver"], + mediaElementMonitor: {} as IPublicApiContentInfos["mediaElementMonitor"], segmentSinkMetricsCallback: null, thumbnailRequestsInfo: { pendingRequests: new WeakMap(),