rx-player
Version:
Canal+ HTML5 Video Player
269 lines (259 loc) • 10.3 kB
text/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 type { ISegmentSinkMetrics } from "../../core/segment_sinks/segment_sinks_store";
import type { IBufferType, IAdaptationChoice, IInbandEvent } from "../../core/types";
import type {
IPeriodsUpdateResult,
IAdaptationMetadata,
IManifestMetadata,
IPeriodMetadata,
IRepresentationMetadata,
IDecipherabilityStatusChangedElement,
} from "../../manifest";
import type { IMediaElementPlaybackObserver } from "../../playback_observer";
import type { IPlayerError } from "../../public_types";
import type { IThumbnailResponse } from "../../transports";
import EventEmitter from "../../utils/event_emitter";
import type SharedReference from "../../utils/reference";
import type {
IPublicNonFiniteStreamEvent,
IPublicStreamEvent,
} from "./utils/stream_events_emitter";
/**
* Class allowing to start playing a content on an `HTMLMediaElement`.
*
* The actual constructor arguments depend on the `ContentInitializer` defined,
* but should reflect all potential configuration wanted relative to this
* content's playback.
*
* Various events may be emitted by a `ContentInitializer`. However, no event
* should be emitted before `prepare` or `start` is called and no event should
* be emitted after `dispose` is called.
*/
export abstract class ContentInitializer extends EventEmitter<IContentInitializerEvents> {
/**
* Prepare the content linked to this `ContentInitializer` in the background,
* without actually trying to play it.
*
* This method may be used for optimization reasons, for example to prepare a
* future content without interrupting the previous one playing on a given
* `HTMLMediaElement`.
*/
public abstract prepare(): void;
/**
* Actually starts playing the content linked to this `ContentInitializer` on
* the given `mediaElement`.
*
* Only a single call to `start` is expected to be performed on each
* `ContentInitializer`.
*
* A call to `prepare` may or may not have been performed before calling
* `start`. If it was, it may or may not have yet finished the preparation
* phase before `start` is called (the `ContentInitializer` should stay
* resilient in both scenarios).
*
* @param {HTMLMediaElement} mediaElement - `HTMLMediaElement` on which the
* content will play. This is given to `start` (and not sooner) to ensure
* that no prior step influence the `HTMLMediaElement`, on which a previous
* content could have been playing until then.
*
* If a content was already playing on that `HTMLMediaElement`, it will be
* stopped.
* @param {Object} playbackObserver - Interface allowing to poll playback
* information on what's playing on the `HTMLMediaElement` at regular
* intervals.
*/
public abstract start(
mediaElement: IMediaElement,
playbackObserver: IMediaElementPlaybackObserver,
): void;
/**
* Update URL of the content currently being played (e.g. DASH's MPD).
* @param {Array.<string>|undefined} urls - URLs to reach that content /
* Manifest from the most prioritized URL to the least prioritized URL.
* @param {boolean} refreshNow - If `true` the resource in question (e.g.
* DASH's MPD) will be refreshed immediately.
*/
public abstract updateContentUrls(
urls: string[] | undefined,
refreshNow: boolean,
): void;
/**
* Stop playing the content linked to this `ContentInitializer` on the
* `HTMLMediaElement` linked to it and dispose of every resources taken while
* trying to do so.
*/
public abstract dispose(): void;
}
/** Every events emitted by a `ContentInitializer`. */
export interface IContentInitializerEvents {
/** Event sent when a minor happened. */
warning: IPlayerError;
/** A fatal error occured, leading to the current content being stopped. */
error: unknown;
/** Event sent after the Manifest has been loaded and parsed for the first time. */
manifestReady: IManifestMetadata;
/** Event sent after the Manifest has been updated. */
manifestUpdate: IPeriodsUpdateResult;
/**
* The codecs support for some tracks may have changed.
*/
codecSupportUpdate: null;
/**
* Event sent after the decipherability status of at least one Representation
* in the Manifest has been updated.
*/
decipherabilityUpdate: IDecipherabilityStatusChangedElement[];
/**
* Event sent when we're starting attach a new MediaSource to the media element
* (after removing the previous one).
*/
reloadingMediaSource: {
/** The position we're reloading at, in seconds. */
position: number;
/**
* If `true`, we'll play directly after finishing the reloading operation.
* If `false`, we'll be paused after it.
*/
autoPlay: boolean;
};
/** Event sent after the player stalled. */
stalled: IStallingSituation;
/** Event sent when the player goes out of a stalling situation. */
unstalled: null;
/**
* Event sent just as the content is considered as "loaded".
* From this point on, the user can reliably play/pause/resume the stream.
*/
loaded: {
getSegmentSinkMetrics: null | (() => Promise<ISegmentSinkMetrics | undefined>);
/**
* Fetch the thumbnail data of the given Period for the corresponding time.
* If there's no thumbnail for that Period or if the request fails, reject
* the Promise with a given reason.
* @param {number} time
*/
getThumbnailData: (
periodId: string,
thumbnailTrackId: string,
time: number,
) => Promise<IThumbnailResponse>;
};
/** Event emitted when a stream event is encountered. */
streamEvent: IPublicStreamEvent | IPublicNonFiniteStreamEvent;
streamEventSkip: IPublicStreamEvent | IPublicNonFiniteStreamEvent;
/** Emitted when a new `Period` is currently playing. */
activePeriodChanged: {
/** The Period we're now playing. */
period: IPeriodMetadata;
};
/**
* A new `PeriodStream` is ready to start but needs an Adaptation (i.e. track)
* to be chosen first.
*/
periodStreamReady: {
/** The type of buffer linked to the `PeriodStream` we want to create. */
type: IBufferType;
/** The `Period` linked to the `PeriodStream` we have created. */
period: IPeriodMetadata;
/**
* The Reference through which any Adaptation (i.e. track) choice should be
* emitted for that `PeriodStream`.
*
* The `PeriodStream` will not do anything until this Reference has emitted
* at least one to give its initial choice.
* You can send `null` through it to tell this `PeriodStream` that you don't
* want any `Adaptation`.
* It is set to `undefined` by default, you SHOULD NOT set it to `undefined`
* yourself.
*/
adaptationRef: SharedReference<IAdaptationChoice | null | undefined>;
};
/**
* A `PeriodStream` has been removed.
* This event can be used for clean-up purposes. For example, you are free to
* remove from scope the shared reference that you used to choose a track for
* that `PeriodStream`.
*/
periodStreamCleared: {
/**
* The type of buffer linked to the `PeriodStream` we just removed.
*
* The combination of this and `Period` should give you enough information
* about which `PeriodStream` has been removed.
*/
type: IBufferType;
/**
* The `id` property of the `Period` linked to the `PeriodStream` we just
* removed.
*
* The combination of this and `Period` should give you enough information
* about which `PeriodStream` has been removed.
*/
periodId: string;
};
/** Emitted when a new `Adaptation` is being considered. */
adaptationChange: IAdaptationChangeEventPayload;
/** Emitted as new bitrate estimates are done. */
bitrateEstimateChange: {
/** The type of buffer for which the estimation is done. */
type: IBufferType;
/**
* The bitrate estimate, in bits per seconds. `undefined` when no bitrate
* estimate is currently available.
*/
bitrate: number | undefined;
};
/** Emitted when a new `Representation` is being considered. */
representationChange: {
/** The type of buffer linked to that `RepresentationStream`. */
type: IBufferType;
/** The `Period` linked to the `RepresentationStream` we're creating. */
period: IPeriodMetadata;
/**
* The `Representation` linked to the `RepresentationStream` we're creating.
* `null` when we're choosing no Representation at all.
*/
representation: IRepresentationMetadata | null;
};
/**
* Event emitted when one or multiple inband events (i.e. events inside a
* given segment) have been encountered.
*/
inbandEvents: IInbandEvent[];
}
export interface IAdaptationChangeEventPayload {
/** The type of buffer for which the Representation is changing. */
type: IBufferType;
/** The `Period` linked to the `RepresentationStream` we're creating. */
period: IPeriodMetadata;
/**
* The `Adaptation` linked to the `AdaptationStream` we're creating.
* `null` when we're choosing no Adaptation at all.
*/
adaptation: IAdaptationMetadata | null;
}
export type IStallingSituation =
| "seeking" // Rebuffering after seeking
| "not-ready" // Rebuffering after low ready state
| "internal-seek" // Rebuffering after a seek happened inside the player
| "buffering" // Other rebuffering cases
| "freezing"; // stalled for an unknown reason (might be waiting for
// a decryption key)
export type ITextDisplayerOptions =
| { textTrackMode?: "native" }
| { textTrackMode: "html"; textTrackElement: HTMLElement };