@byomakase/omakase-tams-player
v1.0.2
Published
Omakase TAMS adapter
Readme
Omakase TAMS Player
Omakase TAMS Player is a TypeScript component that allows native playback of media stored in TAMS. Omakase TAMS Player has the same interface as the vanilla Omakase Player so it can be easily integrated in an existing Omakase Player project.
Omakase TAMS Player can load a source or a flow by URL or can receive flow(s) and flow segments directly.
Omakase TAMS Player implements OmakasePlayerApi but it extends certain functionalities and APIs. No core Omakase Player capabilities have been changed by the Omakase TAMS Player.
| Addition | Explanation |
| ----------------------------------------------------------------------------------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| loadVideo(videoSource: string, options?: TamsVideoLoadOptions): Observable<TamsVideo | Video> | Accepts a URL of TAMS source or flow resource, if protocol is set in options, media other than TAMS can be loaded (all of the formats supported by Omakase Player). |
| loadVideo(videoSource: string[], options?: TamsVideoLoadOptions): Observable<TamsVideo | Video> | Accepts an array of flows. Flows should be time aligned, either part of the same source or different time synchronized sources. Only one video flow is allowed. Multi flows are not allowed in this case. |
| loadVideo(videoSource: TamsMediaData, options?: TamsVideoLoadOptions): Observable<TamsVideo | Video> | Allows user to fetch and manage resources and resource segments manually. Omakase Player doesn’t interact with TAMS API in this case, it just fetches provided segments from TAMS storage. |
| setTamsEndpoint(endpoint: string) | Sets TAMS endpoint. If not invoked before video load, the endpoint is resolved from the url |
| video.getVideo(): TamsVideo | Video | getVideo returns TamsVideo if TAMS flow is loaded |
| video.onVideoLoading$(): TamsVideoLoadingEvent | |
| video.onVideoLoaded$(): TamsVideoLoadedEvent | |
| isTamsLoaded(): boolean; | Returns true if the currently loaded media is sourced from TAMS |
TamsMediaData is an object containing all of the data needed for manually loading a TAMS resource
export type TamsMediaData = {
flow: Flow;
subflows?: Flow[];
flowsSegments: Map<string, FlowSegment[]>;
};As seen in the TamsMediaData, playback of multiflows is supported as well as the playback of a single (audio or video) flow. Text tracks are also supported with automatic slewing.
TamsVideo is an extended Video interface:
export interface TamsVideo extends Video {
mediaStartTime: number;
thumbnailVttTrackUrl?: string;
tamsMediaData?: TamsMediaData;
videoUrls?: Map<string, string>;
audioUrls?: Map<string, string>;
textUrls?: Map<string, string>;
}mediaStartTimerepresents the start time of the first main media segment in regards to TAMS timeline. Useful to align segments with Omakase timeline.thumbnailVttTrackUrlrepresents the URL of the generated thumbnail VTT file if an image flow is found.tamsMediaDatarepresents the flows and segments used to bootstrap the playback. Present ifreturnTamsMediaDatais set totrueduring video loadvideoUrlsrepresents a map of created video manifest urlsaudioUrlsrepresents a map of created audio manifest urlstextUrlsrepresents a map of created text manifest urls
TamsVideoLoadOptions is an extended VideoLoadOptions interface:
export interface TamsVideoLoadOptions extends VideoLoadOptions {
timerange?: string | undefined;
duration?: number | undefined;
returnTamsMediaData?: boolean;
ffomTimeZoneOffset?: number;
}timerangecan be used to specify the timerange of flows to be loaded into the player. Overridesdurationif both are present.durationcan be used to load the requested duration from the flow's end.returnTamsMediaDatacan be used to return the fetched flows and segments in theTamsVideoobjectffomTimeZoneOffsetcan be used to shift the ffom from UTC to other timezones. The provided value has to be an integer from[-23, 23]range.
If protocol is not provided, the player assumes the provided URL represents a TAMS resource. If neither timerange nor duration is specified, the player will load last 600 seconds of media.
TamsVideoLoadingEvent is an extended VideoLoadingEvent interface:
export interface TamsVideoLoadingEvent extends VideoLoadingEvent {
isTamsLoading?: boolean;
}TamsVideoLoadedEvent is an extended VideoLoadedEvent interface:
export interface TamsVideoLoadedEvent extends VideoLoadedEvent {
isTamsLoaded?: boolean;
video: Video | TamsVideo;
}Usage
Loading TAMS media by providing resource URL:
let omakasePlayer = new OmakaseTamsPlayer(config);
omakasePlayer
.loadVideo("https://tams.example/sources/uuid1", videoLoadOptions)
.subscribe({
next: (tamsVideo) => {
console.log(tamsVideo);
},
});Loading TAMS media by providing manually fetched resource:
let omakasePlayer = new OmakaseTamsPlayer(config);
omakasePlayer
.loadVideo(
{ flow: flow, subflows: subflows, flowsSegments: flowsSegments },
videoLoadOptions,
)
.subscribe({
next: (tamsVideo) => {
console.log(tamsVideo);
},
});Loading multiple TAMS flows:
omakasePlayer
.loadVideo([
"https://tams.example/flows/uuid1",
"https://tams.example/flows/uuid2",
"https://tams.example/flows/uuid3",
"https://tams.example/flows/uuid4",
])
.subscribe((tamsVideo) => {
console.log(tamsVideo);
});When providing a list of urls, player will assume that the urls represent TAMS flows. If TAMS sources or multiflows are provided the player will return an error. If more than one video flow is provided the player will return an error.
Omakase timeline can be instantiated as follows:
omakasePlayer
.loadVideo("https://tams.example/flows/uuid")
.subscribe((tamsVideo) => {
omakasePlayer
.createTimeline({
timelineHTMLElementId: "omakase-timeline",
})
.subscribe({
next: (timelineApi) => {
if (tamsVideo.thumbnailVttTrackUrl) {
let thumbnailLane = new omakase.ThumbnailLane({
description: "Thumbnails",
vttUrl: tamsVideo.thumbnailVttTrackUrl,
});
timelineApi.addTimelineLane(thumbnailLane);
}
tamsVideo?.textUrls?.forEach((textUrl, label) => {
// external function for now - not provided
fetchAndMergeSubtitlesManifest(textUrl).subscribe((vtt) => {
const subtitlesLane = new SubtitlesLane({
vttUrl: vtt,
description: label,
style: {
paddingTop: 5,
paddingBottom: 5,
marginBottom: 5,
},
});
timelineApi.addTimelineLane(subtitlesLane);
});
});
},
});
});Setting authentication should usually be done before the video loads or through the OmakaseTamsPlayer's constructor:
omakasePlayer.setAuthentication({
type: "custom",
headers: (url) => {
// Returns empty headers for S3 presigned resources to exclude them from custom authentication
if (url.includes('X-Amz-Signature') || url.includes('x-amz-signature')) {
return { headers: {} };
}
// Default behavior adds a Bearer access token for TAMS API requests
return {
headers: {
Authorization: `Bearer ${getAccessToken()}`,
}
};
// Any additional resource provider authentication should be handled if Omakase Player
// is accessing such resources
},
});