rx-player
Version:
Canal+ HTML5 Video Player
483 lines (440 loc) • 14.9 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 { IListener } from "../utils/event_emitter";
import globalScope from "../utils/global_scope";
import type { IEmeApiImplementation } from "./eme";
/**
* Browser implementation of a VTTCue constructor.
* TODO open TypeScript issue about it?
*/
type ICompatVTTCueConstructor = new (
start: number,
end: number,
cueText: string,
) => ICompatVTTCue;
/** Browser implementation for a single VTTCue. */
interface ICompatVTTCue {
align: string;
endTime: number;
id: string;
line: number | "auto";
lineAlign: string;
position: number | "auto";
positionAlign: string;
size: number | string;
snapToLines: boolean;
startTime: number;
vertical: string;
}
/**
* Overriden TextTrack browser implementation, to also include our own
* definition of a VTTCue.
*/
interface ICompatTextTrack extends TextTrack {
addCue(cue: TextTrackCue | ICompatVTTCue): void;
removeCue(cue: TextTrackCue | ICompatVTTCue): void;
HIDDEN?: "hidden";
SHOWING?: "showing";
}
/**
* Browser implementation of the `document` object with added optional vendored
* functions for some "old" browsers.
*/
interface ICompatDocument extends Document {
mozHidden?: boolean;
msHidden?: boolean;
webkitHidden?: boolean;
}
/**
* Simpler re-definition of an `EventTarget`, allowing more straightforward
* TypeScript exploitation in the RxPlayer.
*/
export interface IEventTarget<TEventMap> {
addEventListener<TEventName extends keyof TEventMap>(
evt: TEventName,
fn: IListener<TEventMap, TEventName>,
): void;
removeEventListener<TEventName extends keyof TEventMap>(
evt?: TEventName,
fn?: IListener<TEventMap, TEventName>,
): void;
}
/** Events potentially dispatched by an `ISourceBufferList` */
export interface ISourceBufferListEventMap {
addsourcebuffer: Event;
removesourcebuffer: Event;
}
/**
* Type-compatible with the `SourceBufferList` type (i.e. a `SourceBufferList`
* is a valid `ISourceBufferList`), the `ISourceBufferList` type allows to:
*
* - re-define some attributes or methods in cases where we detected that some
* platforms have a different implementation.
*
* - list all `SourceBufferList` attributes, methods and events that are
* relied on by the RxPlayer.
*
* - Allow an easier re-definition of that API for tests or for platforms
* which do not implement it.
*/
export interface ISourceBufferList extends IEventTarget<ISourceBufferListEventMap> {
readonly length: number;
onaddsourcebuffer: ((evt: Event) => void) | null;
onremovesourcebuffer: ((evt: Event) => void) | null;
[index: number]: ISourceBuffer;
}
/** Events potentially dispatched by an `IMediaSource` */
export interface IMediaSourceEventMap {
sourceopen: Event;
sourceended: Event;
sourceclose: Event;
startstreaming: Event;
endstreaming: Event;
}
/**
* Type-compatible with the `MediaSource` type (i.e. a `MediaSource` is a valid
* `IMediaSource`), the `IMediaSource` type allows to:
*
* - re-define some attributes or methods in cases where we detected that some
* platforms have a different implementation.
*
* - list all `MediaSource` attributes, methods and events that are relied on
* by the RxPlayer.
*
* - Allow an easier re-definition of that API for tests or for platforms
* which do not implement it.
*/
export interface IMediaSource extends IEventTarget<IMediaSourceEventMap> {
duration: number;
handle?: MediaProvider | IMediaSource | undefined;
readyState: "closed" | "open" | "ended";
sourceBuffers: ISourceBufferList;
streaming?: boolean | undefined;
addSourceBuffer(type: string): ISourceBuffer;
clearLiveSeekableRange(): void;
endOfStream(): void;
removeSourceBuffer(sb: ISourceBuffer): void;
setLiveSeekableRange(start: number, end: number): void;
onsourceopen: ((evt: Event) => void) | null;
onsourceended: ((evt: Event) => void) | null;
onsourceclose: ((evt: Event) => void) | null;
}
/** Events potentially dispatched by an `ISourceBuffer` */
export interface ISourceBufferEventMap {
abort: Event;
error: Event;
update: Event;
updateend: Event;
updatestart: Event;
}
/**
* Type-compatible with the `SourceBuffer` type (i.e. a `SourceBuffer` is a valid
* `ISourceBuffer`), the `ISourceBuffer` type allows to:
*
* - re-define some attributes or methods in cases where we detected that some
* platforms have a different implementation.
*
* - list all `SourceBuffer` attributes, methods and events that are relied on
* by the RxPlayer.
*
* - Allow an easier re-definition of that API for tests or for platforms
* which do not implement it.
*/
export interface ISourceBuffer extends IEventTarget<ISourceBufferEventMap> {
appendWindowEnd: number;
appendWindowStart: number;
buffered: TimeRanges;
timestampOffset: number;
updating: boolean;
abort(): void;
appendBuffer(data: BufferSource): void;
changeType(type: string): void;
remove(start: number, end: number): void;
onabort: ((evt: Event) => void) | null;
onerror: ((evt: Event) => void) | null;
onupdate: ((evt: Event) => void) | null;
onupdateend: ((evt: Event) => void) | null;
onupdatestart: ((evt: Event) => void) | null;
}
export interface IMediaEncryptedEvent extends MediaEncryptedEvent {
forceSessionRecreation?: boolean;
}
/** Events potentially dispatched by an `IMediaElement` */
export interface IMediaElementEventMap {
canplay: Event;
canplaythrough: Event;
encrypted: IMediaEncryptedEvent;
ended: Event;
enterpictureinpicture: Event;
error: Event;
leavepictureinpicture: Event;
loadeddata: Event;
loadedmetadata: Event;
needkey: IMediaEncryptedEvent;
pause: Event;
play: Event;
playing: Event;
ratechange: Event;
seeked: Event;
seeking: Event;
stalled: Event;
timeupdate: Event;
visibilitychange: Event;
volumechange: Event;
waiting: Event;
webkitneedkey: IMediaEncryptedEvent;
}
/**
* Type-compatible with the `HTMLMediaElement` type (i.e. a `HTMLMediaElement` is
* a valid `IMediaElement`), the `IMediaElement` type allows to:
*
* - re-define some attributes or methods in cases where we detected that some
* platforms have a different implementation.
*
* - list all `HTMLMediaElement` attributes, methods and events that are
* relied on by the RxPlayer.
*
* - Allow a re-definition of that API for tests or for platforms which do not
* implement it.
*/
export interface IMediaElement extends IEventTarget<IMediaElementEventMap> {
/**
* Optional property allowing to force a specific MSE Implementation when
* relying on a given `IMediaElement`.
*/
FORCED_MEDIA_SOURCE?: new () => IMediaSource;
FORCED_EME_API?: IEmeApiImplementation;
/* From `HTMLMediaElement`: */
autoplay: boolean;
buffered: TimeRanges;
childNodes: NodeList | never[];
clientHeight: number | undefined;
clientWidth: number | undefined;
currentTime: number;
duration: number;
ended: boolean;
error: MediaError | null;
mediaKeys: null | IMediaKeys;
muted: boolean;
nodeName: string;
paused: boolean;
playbackRate: number;
preload: "none" | "metadata" | "auto" | "";
readyState: number;
seekable: TimeRanges;
seeking: boolean;
src: string;
srcObject?: undefined | null | MediaProvider;
textTracks: TextTrackList | never[];
volume: number;
disableRemotePlayback?: boolean;
addTextTrack: (kind: TextTrackKind) => TextTrack;
appendChild<T extends Node>(x: T): void;
hasChildNodes(): boolean;
pause(): void;
play(): Promise<void>;
removeAttribute(attr: "src"): void;
removeChild(x: unknown): void;
setMediaKeys(x: IMediaKeys | null): Promise<void>;
onencrypted: ((evt: IMediaEncryptedEvent) => void) | null;
oncanplay: ((evt: Event) => void) | null;
oncanplaythrough: ((evt: Event) => void) | null;
onended: ((evt: Event) => void) | null;
onenterpictureinpicture?:
| ((
evt: Event & {
pictureInPictureWindow: ICompatPictureInPictureWindow;
},
) => void)
| null;
onleavepictureinpicture?:
| ((
evt: Event & {
pictureInPictureWindow: ICompatPictureInPictureWindow;
},
) => void)
| null;
onerror: ((evt: Event) => void) | null;
onloadeddata: ((evt: Event) => void) | null;
onloadedmetadata: ((evt: Event) => void) | null;
onpause: ((evt: Event) => void) | null;
onplay: ((evt: Event) => void) | null;
onplaying: ((evt: Event) => void) | null;
onratechange: ((evt: Event) => void) | null;
onseeked: ((evt: Event) => void) | null;
onseeking: ((evt: Event) => void) | null;
onstalled: ((evt: Event) => void) | null;
ontimeupdate: ((evt: Event) => void) | null;
onvolumechange: ((evt: Event) => void) | null;
onwaiting: ((evt: Event) => void) | null;
mozRequestFullScreen?: () => void;
msRequestFullscreen?: () => void;
webkitRequestFullscreen?: () => void;
webkitSupportsPresentationMode?: boolean;
webkitSetPresentationMode?: () => void;
webkitPresentationMode?: string;
mozSetMediaKeys?: (mediaKeys: unknown) => void;
msSetMediaKeys?: (mediaKeys: unknown) => void;
webkitSetMediaKeys?: (mediaKeys: unknown) => void;
webkitKeys?: {
createSession?: (mimeType: string, initData: BufferSource) => IMediaKeySession;
};
audioTracks?: ICompatAudioTrackList;
videoTracks?: ICompatVideoTrackList;
}
export interface IMediaKeySystemAccess {
readonly keySystem: string;
getConfiguration(): MediaKeySystemConfiguration;
createMediaKeys(): Promise<IMediaKeys>;
}
export interface IMediaKeys {
isTypeSupported?: (type: string) => boolean; // IE11 only
createSession(sessionType?: MediaKeySessionType): IMediaKeySession;
setServerCertificate(serverCertificate: BufferSource): Promise<boolean>;
}
export interface IMediaKeySession extends IEventTarget<MediaKeySessionEventMap> {
readonly closed: Promise<MediaKeySessionClosedReason>;
readonly expiration: number;
readonly keyStatuses: MediaKeyStatusMap;
readonly sessionId: string;
close(): Promise<void>;
generateRequest(_initDataType: string, _initData: BufferSource): Promise<void>;
load(sessionId: string): Promise<boolean>;
remove(): Promise<void>;
update(response: BufferSource): Promise<void>;
}
// Trick to ensure our own types are compatible to TypeScript's
function assertTypeCompatibility<T, _U extends T>(): void {
// noop
}
/* eslint-disable @typescript-eslint/no-restricted-types */
assertTypeCompatibility<IMediaElement, HTMLMediaElement>();
assertTypeCompatibility<IMediaSource, MediaSource>();
assertTypeCompatibility<ISourceBuffer, SourceBuffer>();
assertTypeCompatibility<ISourceBufferList, SourceBufferList>();
assertTypeCompatibility<IMediaKeySystemAccess, MediaKeySystemAccess>();
assertTypeCompatibility<IMediaKeys, MediaKeys>();
assertTypeCompatibility<IMediaKeySession, MediaKeySession>();
/* eslint-enable @typescript-eslint/no-restricted-types */
/**
* AudioTrackList implementation (that TS forgot).
* Directly taken from the WHATG spec:
* https://html.spec.whatwg.org/multipage/media.html#audiotracklist
*/
interface ICompatAudioTrackList extends EventTarget {
readonly length: number;
getTrackById(id: string): ICompatAudioTrack;
onchange?: ((n: Event) => void) | null;
onaddtrack?: ((n: Event) => void) | null;
onremovetrack?: ((n: Event) => void) | null;
// It can be indexed
[x: number]: ICompatAudioTrack;
}
/**
* AudioTrack implementation (that TS forgot).
* Directly taken from the WHATG spec:
* https://html.spec.whatwg.org/multipage/media.html#audiotracklist
*/
interface ICompatAudioTrack {
id: string;
kind: string;
label: string;
language: string;
enabled: boolean;
}
/**
* VideoTrackList implementation (that TS forgot).
* Directly taken from the WHATG spec:
* https://html.spec.whatwg.org/multipage/media.html#audiotracklist
*/
interface ICompatVideoTrackList extends EventTarget {
readonly length: number;
selectedIndex: number;
getTrackById(id: string): ICompatVideoTrack;
onchange?: ((n: Event) => void) | null;
onaddtrack?: ((n: Event) => void) | null;
onremovetrack?: ((n: Event) => void) | null;
// It can be indexed
[x: number]: ICompatVideoTrack;
}
/**
* VideoTrack implementation (that TS forgot).
* Directly taken from the WHATG spec:
* https://html.spec.whatwg.org/multipage/media.html#audiotracklist
*/
interface ICompatVideoTrack {
id: string;
kind: string;
label: string;
language: string;
selected: boolean;
}
/**
* Browser implementation of a Picture in picture window, as defined in the the
* draft from the W3C:
* https://wicg.github.io/picture-in-picture/#pictureinpicturewindow
*/
export interface ICompatPictureInPictureWindow extends EventTarget {
width: number;
height: number;
onresize: ((evt: Event) => void) | null;
}
/** MediaSource implementation, including vendored implementations. */
const gs = globalScope as typeof window & {
MozMediaSource?: typeof MediaSource | undefined | null;
WebKitMediaSource?: typeof MediaSource | undefined | null;
MSMediaSource?: typeof MediaSource | undefined | null;
ManagedMediaSource?: typeof MediaSource | undefined | null;
};
const MediaSource_:
| { new (): IMediaSource; isTypeSupported(type: string): boolean }
| undefined =
gs?.MediaSource ??
gs?.MozMediaSource ??
gs?.WebKitMediaSource ??
gs?.MSMediaSource ??
gs?.ManagedMediaSource ??
undefined;
const isManagedMediaSource =
MediaSource_ !== undefined && MediaSource_ === gs?.ManagedMediaSource;
/** List an HTMLMediaElement's possible values for its readyState property. */
const READY_STATES = {
HAVE_NOTHING: 0,
HAVE_METADATA: 1,
HAVE_CURRENT_DATA: 2,
HAVE_FUTURE_DATA: 3,
HAVE_ENOUGH_DATA: 4,
};
/**
* TextTrackList browser implementation.
* TODO W3C defines onremovetrack and onchange attributes which are not present on
* ts type definition, open a TS issue?
*/
export interface ICompatTextTrackList extends TextTrackList {
onremovetrack: ((ev: TrackEvent) => void) | null;
onchange: (() => void) | null;
}
export type {
ICompatDocument,
ICompatAudioTrackList,
ICompatVideoTrackList,
ICompatAudioTrack,
ICompatVideoTrack,
ICompatTextTrack,
ICompatVTTCue,
ICompatVTTCueConstructor,
};
export { MediaSource_, isManagedMediaSource, READY_STATES };