rx-player
Version:
Canal+ HTML5 Video Player
287 lines • 12.3 kB
TypeScript
/**
* 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";
import noop from "../utils/noop";
import type { IReadOnlySharedReference } from "../utils/reference";
import type { CancellationSignal } from "../utils/task_canceller";
import type { IPlaybackObservation, IReadOnlyPlaybackObserver } from "./types";
/**
* Class allowing to "observe" current playback conditions so the RxPlayer is
* 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.
*
* You can use the PlaybackObserver to either get the last observation
* performed, get the current media state or listen to media observation sent
* at a regular interval.
*
* @class {PlaybackObserver}
*/
export default class PlaybackObserver {
/** HTMLMediaElement which we want to observe. */
private _mediaElementRef;
/** If `true`, a `MediaSource` object is linked to the `HTMLMediaElement`. */
private _withMediaSource;
/**
* If `true`, we're playing in a low-latency mode, which might have an
* influence on some chosen interval values here.
*/
private _lowLatencyMode;
/**
* If set, position which could not yet be seeked to due to either seeking
* operations being blocked or due to the HTMLMediaElement having a
* `readyState` of `0`.
* This position should be seeked to as soon as none of those conditions are
* met.
*/
private _pendingSeek;
/**
* The RxPlayer usually wants to differientate when a seek was sourced from
* 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
* 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
* inside of the RxPlayer has been performed.
* - This counter is decremented each time we received a "seeking" event.
*
* This allows us to correctly characterize seeking events: if the counter is
* superior to `0`, it is probably due to an internal "seek".
*/
private _internalSeeksIncoming;
/**
* Stores the last playback observation produced by the `PlaybackObserver`.:
*/
private _observationRef;
/**
* `TaskCanceller` allowing to free all resources and stop producing playback
* observations.
*/
private _canceller;
/**
* On some devices (right now only seen on Tizen), seeking through the
* `currentTime` property can lead to the browser re-seeking once the
* segments have been loaded to improve seeking performances (for
* example, by seeking right to an intra video frame).
* In that case, we risk being in a conflict with that behavior: if for
* example we encounter a small discontinuity at the position the browser
* seeks to, we will seek over it, the browser would seek back and so on.
*
* This variable allows to store the maximum known position we were seeking to
* so we can detect when the browser seeked back (to avoid performing another
* seek after that). When browsers seek back to a position behind a
* discontinuity, they are usually able to skip them without our help.
*/
private _expectedSeekingPosition;
private _observationIntervalId;
/**
* If `true` seek operations asked through the
* `MediaElementPlaybackObserver` will not be performed now but after the
* `unblockSeeking` method is called.
*/
private _isSeekBlocked;
/**
* Create a new `PlaybackObserver`, which allows to produce new "playback
* observations" on various media events and intervals.
*
* Once a `PlaybackObserver` 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.
* @param {Object} options
*/
constructor(options: IPlaybackObserverOptions);
/**
* "Link" the actual `HTMLMediaElement` to this `PlaybackObserver`.
*
* 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
* element is ready to play your content (e.g. when pre-loading the next
* content).
*
* @param {HTMLMediaElement} mediaElement - The `HTMLMediaElement` on which
* the content plays.
*/
attachMediaElement(mediaElement: IMediaElement): void;
/**
* Stop the `PlaybackObserver` from emitting playback 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.
*
* Note that it is important to call stop once the `PlaybackObserver` 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.
*/
stop(reason: string | undefined): void;
/**
* Returns the current position advertised by the `HTMLMediaElement`, in
* seconds.
* @returns {number}
*/
getCurrentTime(): number;
/**
* Returns the current playback rate advertised by the `HTMLMediaElement`.
* @returns {number|undefined}
*/
getPlaybackRate(): number;
/**
* Returns the current `paused` status advertised by the `HTMLMediaElement`.
*
* Use this instead of the same status emitted on an observation when you want
* to be sure you're using the current value.
* @returns {boolean|undefined}
*/
getIsPaused(): boolean;
/**
* Prevent seeking operations from being performed from inside the
* `MediaElementPlaybackObserver` 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,
* point in time.
*/
blockSeeking(): void;
/**
* 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
* soon as possible (either right now, or when the `readyState` of the
* `HTMLMediaElement` will have at least reached the `"HAVE_METADATA"` state).
*/
unblockSeeking(): void;
/**
* Returns `true` if seeking operations are currently blocked due to a call to
* `blockSeeking` that was not yet undone by a call to `unblockSeeking`.
* @returns {boolean} - `true` if seeking operations are blocked currently.
*/
isSeekingBlocked(): boolean;
/**
* Seek operations, as performed by the `setCurrentTime` method, might be not
* yet performed due to either of those reasons:
*
* - Seek operations are blocked due to a call to the `blockSeeking` method.
*
* - The `HTMLMediaElement`'s `readyState` property has not yet reached the
* `"HAVE_METADATA"` state.
*
* Under any of those two conditions, this method will return the position
* that is planned to be seeked to as soon as both conditions are not met
* anymore.
*
* If seeks are possible right now, no seek should be "pending" and as such
* this method will return `null`.
*
* @returns {Object|null} - If a seek is planned, the position to seek to.
* `null` otherwise.
*/
getPendingSeekInformation(): IPendingSeekInformation | null;
/**
* Update the current position (seek) on the `HTMLMediaElement`, by giving a
* new position in seconds.
*
* Note that seeks performed through this method are caracherized as
* "internal" seeks. They don't result into the exact same playback
* observation than regular seeks (which most likely comes from the outside,
* e.g. the user).
* @param {number} time
* @param {boolean} [isInternal=true] - If `false`, the seek was performed by
* the user.
*/
setCurrentTime(time: number, isInternal?: boolean): void;
/**
* Update the playback rate of the `HTMLmediaElement`.
* @param {number} playbackRate
*/
setPlaybackRate(playbackRate: number): void;
/**
* Returns the current `readyState` advertised by the `HTMLmediaElement`.
* @returns {number}
*/
getReadyState(): number;
/**
* Returns an `IReadOnlySharedReference` storing the last playback observation
* produced by the `PlaybackObserver` 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.
*
* @returns {Object}
*/
getReference(): IReadOnlySharedReference<IPlaybackObservation>;
/**
* Register a callback so it regularly receives playback observations.
* @param {Function} cb
* @param {Object} params - Configuration parameters:
* - `includeLastObservation`: If set to `true` the last observation will
* be first emitted synchronously.
* - `clearSignal`: If set, the callback will be unregistered when this
* CancellationSignal emits.
*/
listen(cb: (observation: IPlaybackObservation, stopListening: () => void) => void, params: {
includeLastObservation?: boolean | undefined;
clearSignal: CancellationSignal;
}): typeof noop | undefined;
/**
* Generate a new playback observer 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 latter emits.
*
* 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<TDest>(transform: (observationRef: IReadOnlySharedReference<IPlaybackObservation>, cancellationSignal: CancellationSignal) => IReadOnlySharedReference<TDest>): IReadOnlyPlaybackObserver<TDest>;
private _actuallySetCurrentTime;
/**
* Creates the `IReadOnlySharedReference` that will generate playback
* observations.
* @returns {Object}
*/
private _createSharedReference;
private _getCurrentObservation;
private _generateObservationForEvent;
private _restartInterval;
private _registerMediaElementEvents;
private _registerLoadedMetadataEvent;
private _onLoadedMetadataEvent;
}
export interface IPlaybackObserverOptions {
withMediaSource: boolean;
lowLatencyMode: boolean;
}
export interface IPendingSeekInformation {
/** Position to seek to. */
position: number;
/** If `true`, the seek was performed by the RxPlayer's internal logic. */
isInternal: boolean;
}
//# sourceMappingURL=media_element_playback_observer.d.ts.map