rx-player
Version:
Canal+ HTML5 Video Player
482 lines (447 loc) • 18 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 { IEMSG } from "../../../parsers/containers/isobmff";
import type {
ILocalIndexSegment,
ILocalManifestInitSegmentLoader,
ILocalManifestSegmentLoader,
} from "../../../parsers/manifest/local";
import type { IPlayerError } from "../../../public_types";
import type { ISegmentInformation } from "../../../transports";
/**
* Supplementary information specific to Smooth Initialization segments.
* Contains every information needed to generate an initialization segment.
*/
export interface ISmoothInitSegmentPrivateInfos {
/**
* Timescale the segments are in, in the Manifest.
* Needed because Smooth segment are created in JS based on timing information
* as found in the Manifest.
*/
timescale: number;
codecPrivateData?: string | undefined;
bitsPerSample?: number | undefined;
channels?: number | undefined;
packetSize?: number | undefined;
samplingRate?: number | undefined;
protection?: { keyId: Uint8Array } | undefined;
height?: number | undefined;
width?: number | undefined;
}
/**
* Supplementary information specific to Smooth media segments (that is, every
* segments but the initialization segment).
*/
export interface ISmoothMediaSegmentPrivateInfos {
/**
* Start time of the segment as announced in the Manifest, in the same
* timescale than the one indicated through `ISmoothInitSegmentPrivateInfos`.
*/
time: number;
/**
* Duration of the segment as announced in the Manifest, in the same timescale
* than the one indicated through `ISmoothInitSegmentPrivateInfos`.
*/
duration: number;
}
/** Supplementary information needed for segments in the "metaplaylist" transport. */
export interface IMetaPlaylistPrivateInfos {
/** The original transport protocol (e.g. "dash", "smooth" etc.) */
transportType: string;
contentStart: number;
contentEnd?: number | undefined;
/** The segment originally created by this transport's RepresentationIndex. */
originalSegment: ISegment;
isLive: boolean;
manifestPublishTime?: number | undefined;
periodEnd?: number | undefined;
periodStart: number;
}
/**
* Supplementary information needed for initialization segments of the "local"
* transport.
*/
export interface ILocalManifestInitSegmentPrivateInfos {
/** Callback used to load that segment. */
load: ILocalManifestInitSegmentLoader;
}
/** Supplementary information needed for media segments of the "local" transport. */
export interface ILocalManifestSegmentPrivateInfos {
/** Callback used to load that segment. */
load: ILocalManifestSegmentLoader;
/**
* Exact same segment than the one given in a local manifest.
* Stored (with at best the same reference than in it) to facilitate the job
* of retrieving the wanted segment (this task will generally be done by the
* content downloader tool) when the RxPlayer asks for it.
*/
segment: ILocalIndexSegment;
}
/**
* Supplementary information that can be added to any segment depending on the
* tranport logic used.
* Called "private" as it won't be read or exploited by any code in the core
* logic of the player. That information is only here to be retrieved and
* exploited by the corresponding transport logic when loading or parsing the
* corresponding segment.
*/
export interface IPrivateInfos {
/** Smooth-specific information allowing to generate an initialization segment. */
smoothInitSegment?: ISmoothInitSegmentPrivateInfos;
/** Smooth-specific information linked to all Smooth media segments. */
smoothMediaSegment?: ISmoothMediaSegmentPrivateInfos;
/** Information that should be present on all MetaPlaylist segments. */
metaplaylistInfos?: IMetaPlaylistPrivateInfos;
/**
* Local Manifest-specific information allowing to request the
* initialization segment.
*/
localManifestInitSegment?: ILocalManifestInitSegmentPrivateInfos;
/** Local Manifest-specific information allowing to request any media segment. */
localManifestSegment?: ILocalManifestSegmentPrivateInfos;
/**
* Function allowing to know if a given emsg's event name has been
* explicitely authorized.
*/
isEMSGWhitelisted?: (evt: IEMSG) => boolean;
}
/** Represent a single Segment from a Representation. */
export interface ISegment {
/** ID of the Segment. Should be unique for this Representation. */
id: string;
/**
* If true, this segment is an initialization segment with no decodable data.
*
* Those types of segment contain no decodable data and are only there for
* initialization purposes, such as giving initial infos to the decoder on
* subsequent media segments that will be pushed.
*
* Note that if `isInit` is false, it only means that the segment contains
* decodable media, it can also contain important initialization information.
*
* Also, a segment which would contain both all initialization data and the
* decodable data would have `isInit` set to `false` as it is not purely an
* initialization segment.
*
* Segments which are not purely an initialization segments are called "media
* segments" in the code.
*/
isInit: boolean;
/**
* Store supplementary information on a segment that can be later exploited by
* the transport logic.
*/
privateInfos: IPrivateInfos;
/**
* Estimated time, in seconds, at which the concerned segment should be
* offseted when decoded.
*/
timestampOffset?: number | undefined;
/**
* Estimated start time for the segment, in seconds.
* Note that some rounding errors and some differences between what the
* Manifest says and what the content really is might make that time not
* exact.
*
* `0` for initialization segments.
*/
time: number;
/**
* Estimated end time for the segment, in seconds.
* Note that some rounding errors and some differences between what the
* Manifest says and what the content really is might make that time not
* exact.
*
* `0` for initialization segments.
*/
end: number;
/**
* Estimated duration for the segment, in seconds.
*
* Note that this may not reflect the exact segment duration:
*
* 1. In some very specific cases, segments might be generated and served
* progressively. In this case, the full duration of a segment might not
* be yet known and thus this property only reflect the currently known
* `duration` of the segment, which may be inferior to its final duration.
*
* You can know if we're in that case when the `complete` property of
* this same segment is set to `false`.
*
* 2. some rounding errors and some differences between what the
* Manifest says and what the content really is might make that time not
* exact.
*
* `0` for initialization segments.
*/
duration: number;
/**
* Always set to 1 for API compatibility with v3.X.X.
* This was intended for conversion of the `time` and `duration` properties
* into seconds.
*
* As both are always in seconds now, this property became unneeded.
*/
timescale: 1;
/**
* If `false`, this segment's `duration` property may not be the duration of
* the full segment as it could still be in the process of being generated
* on the server-side (when this `ISegment` had been constructed).
*
* Note that if the `duration` is sure to be the final one, `complete`
* should be set to `true` even if the segment is still being
* generated.
*/
complete: boolean;
/**
* Optional relative or absolute URL to load the resource.
*
* If the URL is absolute (it contains the scheme at the beginning), it is the
* complete URL on which the resource should be requested.
*
* If the URL is relative (it does not contain a scheme at the beginning), it
* should be relative to the chosen CDN that should be recuperated through
* another mean
*
* If `null`, it means either:
*
* - that there is no way to reach the resource through a URL.
*
* - that there may be an URL, but is already communicated through another
* mean, like the currently chosen CDN.
*
* An empty string is equivalent to indicating that the chosen CDN's URL
* should be directly requested instead.
* In that way, it is equivalent to setting it to `null`.
*/
url: string | null;
/**
* Optional byte range to retrieve the Segment from its URL(s).
* TODO this should probably moved to `privateInfos` as this is
* transport-specific metadata only useful for performing requests, but it is
* sadly documented in the API, so moving it is actuall a v3.X.X breaking
* change.
*/
range?: [number, number] | undefined;
/**
* If set, the corresponding byte-range in the downloaded segment will
* contain an index describing other Segments
* TODO this should probably moved to `privateInfos` as this is
* transport-specific metadata only useful for performing requests, but it is
* sadly documented in the API, so moving it is actuall a v3.X.X breaking
* change.
*/
indexRange?: [number, number] | undefined;
/**
* Optional number of the Segment.
* TODO this should probably moved to `privateInfos` as this is
* transport-specific metadata only useful for performing requests, but it is
* sadly documented in the API, so moving it is actuall a v3.X.X breaking
* change.
*/
number?: number | undefined;
}
/** Interface that should be implemented by any Representation's `index` value. */
export interface IRepresentationIndex {
/**
* Returns Segment object for the initialization segment, allowing to do the
* Init Segment request.
*
* `null` if there's no initialization segment.
* @returns {Object}
*/
getInitSegment(): ISegment | null;
/**
* Returns an array of Segments needed for the amount of time given.
* @param {number} up - The first wanted position, in seconds.
* @param {number} duration - The amount of time in seconds you want from the
* starting position given in `up`.
* @returns {Array.<Object>} - The list of segments corresponding to your
* wanted range.
*/
getSegments(up: number, duration: number): ISegment[];
/**
* Returns `true` if, from the given situation, the manifest has to be
* refreshed.
* @param {number} up - Beginning time in seconds of the range that is
* currently wanted.
* @param {number} to - Ending time in seconds of the range that is
* currently wanted.
* @returns {Boolean}
*/
shouldRefresh(up: number, to: number): boolean;
/**
* Returns the starting time, in seconds, of the earliest segment currently
* available in this index.
* Returns `null` if nothing is in the index
* Returns `undefined` if we cannot know this value.
* @returns {Number|null}
*/
getFirstAvailablePosition(): number | null | undefined;
/**
* Returns the ending time, in seconds, of the last playable position
* currently available in this index.
* Returns `null` if nothing is in the index
* Returns `undefined` if we cannot know this value.
*
* The last playable position is generally equivalent to the end of the last
* segment associated to this index, excepted when it goes over the end limit
* of the corresponding `Period`, in which case it will be equal to this end
* instead.
* @returns {Number|null|undefined}
*/
getLastAvailablePosition(): number | null | undefined;
/**
* Returns the ending time, in seconds, of the Representation once it is
* "finished" (@see isStillAwaitingFutureSegments).
* Should thus be equivalent to `getLastAvailablePosition` once finished.
*
* Returns `null` if nothing is in the index
* Returns `undefined` if we cannot know this value.
*
* @returns {number|undefined}
*/
getEnd(): number | null | undefined;
/**
* Returns `true` if a Segment returned by this index is still considered
* available.
* Returns `false` if it is not available anymore.
* Returns `undefined` if we cannot know whether it is still available or not.
* @param {Object} segment
* @returns {Boolean|undefined}
*/
isSegmentStillAvailable(segment: ISegment): boolean | undefined;
/**
* Returns true if the `error` given following the request of `segment` can
* indicate that the index became "de-synchronized" with the server.
*
* Reasons for de-synchronizations includes for example Manifest parsing
* optimizations where a newer version will not be totally parsed. In those
* conditions, we could be left with doing a segment request for a segment
* that does not really exists.
*
* Note: This API assumes that the user first checked that the segment is
* still available through `isSegmentStillAvailable`.
* @param {Error} error
* @param {Object} segment
* @returns {Boolean}
*/
canBeOutOfSyncError(error: IPlayerError, segment: ISegment): boolean;
/**
* Checks if the given time - in seconds - is in a discontinuity.
* That is a "hole" in the stream with no segment defined.
* If that's the case, return the next available position where a segment
* should be available.
* If that's not the case, return `null`.
* @param {number} time - The time to check if it's in a discontinuity, in
* seconds.
* @returns {number | null} - If `null`, no discontinuity is encountered at
* `time`. If this is a number instead, there is one and that number is the
* position for which a segment is available in seconds.
*/
checkDiscontinuity(time: number): number | null;
/**
* Returns `false` if the last segments in this index have already been
* generated so that we can freely go to the next period.
* Returns `true` if the index is still waiting on future segments to be
* generated.
* @returns {boolean}
*/
isStillAwaitingFutureSegments(): boolean;
/**
* Returns `true` if this index has all the data it needs to give the list
* of available segments.
* Returns `false` if you first should load its initialization segment (or
* the initialization segment's associated index file) to get the list of
* available segments.
*
* Most index don't rely on the initialization segment to give an index and
* as such, this method should return `true` directly.
*
* However in some index, the segment list might only be known after the
* initialization has been loaded and parsed. In those case, it should return
* `false` until the corresponding segment list is known, at which point you
* can call the `initialize` method with that list so the `isInitialized` can
* return `true`.
* @returns {boolean}
*/
isInitialized(): boolean;
awaitSegmentBetween(start: number, end: number): boolean | undefined;
/**
* Some `RepresentationIndex` do not have the list of media segments known in
* advance.
* Instead, those are only known once the initialization segment is loaded and
* parsed.
*
* Such `RepresentationIndex` whose list of media segments is still unknown
* are called "uninitialized". You can know if a `RepresentationIndex` is
* uninitialized by checking if its `isInitialized` method returns `false`.
*
* To initialize those `RepresentationIndex` and thus be able to obtain the
* list of its linked media segments through its corresponding methods, you
* have to initialize it with the list of segments once it is known
* (presumably, after parsing the initialization segment) by giving them to
* this `initialize` method.
* @param {Array.<Object>} segmentList
*/
initialize(segmentList: ISegmentInformation[]): void;
/**
* Returns an approximate for the duration of that `RepresentationIndex`s
* segments, in seconds in the context of its Manifest (i.e. as the Manifest
* anounces them, actual segment duration may be different due to
* approximations), with the exception of the last one (that usually is
* shorter).
* @returns {number}
*/
getTargetSegmentDuration():
| {
/** Approximate duration of any segments but the last one in seconds. */
duration: number;
/**
* If `true`, the given duration should be relatively precize for all
* segments but the last one.
*
* If `false`, `duration` indicates only a general idea of what can be
* expected.
*/
isPrecize: boolean;
}
| undefined;
/**
* Add segments to a RepresentationIndex that were predicted after parsing the
* segment linked to `currentSegment`.
* @param {Array.<Object>} nextSegments - The segment information parsed.
* @param {Object} segment - Information on the segment which contained that
* new segment information.
*/
addPredictedSegments(
nextSegments: ISegmentInformation[],
currentSegment: ISegment,
): void;
/**
* Replace the index with another one, such as after a Manifest update.
* @param {Object} newIndex
*/
_replace(newIndex: IRepresentationIndex): void;
/**
* Update the current index with a new, partial, version.
* Unlike `replace`, this method do not completely overwrite the information
* about this index's segments, it should mainly add new information about new
* announced segments.
* @param {Object} newIndex
*/
_update(newIndex: IRepresentationIndex): void;
}