Overview
AAMP is a native video engine build on top of gstreamer, optimized for performance, memory use, and code size. AAMP Reference Player demonstrates use of Unified Video Engine (UVE) JavaScript binding APIs to interact with AAMP player.
The bindings are made available in JavaScript with the help of injected bundle once DOM elements are loaded by webkit.
Target Audience:
This README is targeted to OTT app vendors and HTML5 developers who are interested in evaluating/adopting AAMP for their media player applications on set-tops.
Features
- HLS (Clear, Access, Vanilla AES-128)
- DASH ( Clear, Playready/Widevine)
- Inband Closed Captions
- Audio Language Selection
- Trick-play and Audio/Video Bitrate Selection
Minimal Sample Player
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>UVE Reference Player</title></head> <script> var url = "https://tungsten.aaplimg.com/VOD/bipbop_adv_example_v2/master.m3u8"; window.onload = function() { var player = new AAMPMediaPlayer(); player.load(url); player.play(); } </script> <body> <div id="videoContainer"> <video style="height:100%; width:100%; position:absolute; bottom:0; left:0"> <source src="placeholder.mp4" type="video/ave"> <!-- hole punching --> </video> </div> </body> </html>
General Setup:
- Setup in RDK devices(Comcast).
- Host ReferencePlayer folder in a web server or in /opt/www/ folder in device
- Folders in /opt/www/ can be accessed using http://localhost:50050/<folder name>
- To launch reference player, use Comcast's Chariot App (https://send2chariot.xreapps.net:8443/send2chariot/#/send/html)
- Fill in X1 Device ID (from XRAY)
- Select "Chariot XRE" for Launch Type
- fill in URL to launch (i.e. http://localhost:50050/ReferencePlayer/index.html)
- Specify "Default" for Browser Type
- Select "Mute Player"
- Select "Use Background"
- Select "Enable Debug Mode -1"
- Click "Send" button
- If hosted in /opt/www folder, need the following override config files in /opt folder since XRE rejects Fling requests with URLs with domain localhost/127.0.0.1. Contents for the override files are provided in Appendix section.
- /opt/webfilterpatterns.conf
- /opt/xrehtmlappswhitelist.conf
- Host ReferencePlayer folder in a web server or in /opt/www/ folder in device
Folder Structure
- icons // UI elements of reference players and homepage
- UVE
- index.html // Homepage of UVE reference player
- UVEMediaPlayer.js // Includes "AAMPPlayer" JS class which wraps UVE binding object AAMPMediaPlayer
- UVEPlayerUI.js // JS code for the UI elements and their functionality
- UVERefPlayer.js // Main JS file
- UVERefPlayerStyle.js // CSS for reference player and its UI
- index.html // Homepage of reference player
- ReferencePlayer.js // JS code for Homepage and redirection to respective reference players
- URLs.js // list of selectable streams
- ReferencePlayerStyle.css // CSS for Homepage and its UI
Universal Video engine(UVE) APIs
export interface IVideoEngine { /** * URI of the Media being played by the Video Engine */ load(uri: string); /** * IConfig Object with key value pair of launch configuration */ initConfig(IConfig: Object[]); /** * Starts playback when enough data is buffered at playhead */ play(): void; /** * Pauses playback */ pause(): void; /** * Stop playback and free resources */ stop(): void; /** * Performs a seek * @param timeSec the time in seconds to seek */ seek(timeSec: number): void; /** * Gets the current state * This defaults to PlayState.PAUSED */ getCurrentState(): PlayState; /** * Gets the duration of the content in seconds. */ getDurationSec(): number; /** * Gets the current user time in seconds. */ getCurrentPosition(): number; /** * Gets available video bitrates */ getVideoBitrates(): number; /** * Gets the current video bitrate. */ getCurrentVideoBitrate(): number; /** * Sets the current video bitrate. */ setVideoBitrate(bitrate: number): void; /** * Gets the current audio bitrate */ getCurrentAudioBitrate(): number; /** * Gets the current volume (value between 0 and 1) */ getVolume(): number; /** * Sets the current volume (value between 0 and 1) */ setVolume(volume: number): void; /** * Gets the current playback rate */ getPlaybackRate(): number; /** * Sets the current playback rate and overshoot if necessary */ setPlaybackRate(rate: number, overshoot:number ?= 0): void; /** * Black out the video for parental controls */ setVideoMute(enabled: boolean): void; // DAI /** * Subscribe to specific tags / DOM Element */ setSubscribedTags(tagNames: string []); // Used to identify Content Break period addEventListener(name: string, handler: Function); removeEventListener(name: string, handler: Function); /** * Set the DRM config params */ setDRMConfig(config: DRMConfig); /** * Add custom headers to HTTP requests */ addCustomHTTPHeader(headerName: string, headerValue: string []); /** * Remove a custom headers set previously, with empty args will delete all */ removeCustomHTTPHeader(headerName: string); /** * Set display video rectangle co-ordinates */ setVideoRect(x: number, y: number, w: number, h: number); /** * Set video zoom */ setVideoZoom(videoZoom: string); } export interface IConfig { /** * max initial bitrate (kbps) */ initialBitrate: number; /** * start position offset (ms) */ offset?: number; /** * network request timeout (ms) */ networkTimeout: number; /** * max amount of time to download ahead of playhead (seconds) * e.x: * with a downloadBuffer of 10s there will be 10 seconds of * video or audio stored in javascript memory and not in a * playback buffer */ downloadBuffer: number; preferredAudioLanguage: string; drm: DRMConfig; /** * network proxy to use (Format <SCHEME>://<PROXY IP:PROXY PORT>) */ networkProxy: string; /** * network proxy to use for license requests (Format same as network proxy) */ licenseProxy: string; }
DRM Configuration
drmConfig = { 'com.microsoft.playready': 'http://test.playready.microsoft.com/service/rightsmanager.asmx'; 'com.widevine.alpha': 'https://widevine-proxy.appspot.com/proxy'; 'preferredKeysystem': 'com.widevine.alpha'; }; // set the DRM options videoEngine.setDRMConfig(drmConfig);
Player Events
Event | Payload | Description |
playbackStateChanged | state: number | fired as state changes across play/pause seek/not-seek quadruplet |
playbackProgressUpdate | durationMiliseconds: number, positionMiliseconds: number, playbackSpeed: number, startMiliseconds: number, endMiliseconds: number | fired based on the interval set |
playbackCompleted | fired when there is nothing left to play | |
playbackSpeedChanged | speed: number, reason: string | |
playbackFailed | shouldRetry: boolean, code: number, description: string | fired when an error occurs |
decoderAvailable | decoderHandle: number | fired when video decoder handle becomes available, required for closedcaption parsing + rendering by RDK ClosedCaptions module |
mediaMetadata | durationMiliseconds: number, languages: string[], bitrates: number[], playbackSpeeds: number[], width: number, height: number, hasDrm: boolean | fired with metadata of the asset currently played, includes duration(in ms), audio language list, available bitrate list, hasDrm, supported playback speeds |
speedsChanged | playbackSpeeds: number[] | fired when supported playback speeds changes (based on iframe availability) |
Player States
- Idle
- Playing
- Paused
- Seeking
Player Errors
Error Code | Media Error | Error String | Remarks |
AAMP_TUNE_INIT_FAILED | 10 | AAMP: init failed | Fragmentcollector initialization failed |
AAMP_TUNE_MANIFEST_REQ_FAILED | 10 | AAMP: Manifest Download failed | Playlist refresh failed |
AAMP_TUNE_AUTHORISATION_FAILURE | 40 | AAMP: Authorization failure | |
AAMP_TUNE_FRAGMENT_DOWNLOAD_FAILURE | 10 | AAMP: fragment download failures | |
AAMP_TUNE_INIT_FRAGMENT_DOWNLOAD_FAILURE | 10 | AAMP: init fragment download failed | |
AAMP_TUNE_UNTRACKED_DRM_ERROR | 50 | AAMP: DRM error untracked error | |
AAMP_TUNE_DRM_INIT_FAILED | 50 | AAMP: DRM Initialization Failed | |
AAMP_TUNE_DRM_DATA_BIND_FAILED | 50 | AAMP: InitData-DRM Binding Failed | |
AAMP_TUNE_DRM_CHALLENGE_FAILED | 50 | AAMP: DRM License Challenge Generation Failed | |
AAMP_TUNE_LICENCE_TIMEOUT | 50 | AAMP: DRM License Request Timed out | |
AAMP_TUNE_LICENCE_REQUEST_FAILED | 50 | AAMP: DRM License Request Failed | |
AAMP_TUNE_INVALID_DRM_KEY | 50 | AAMP: Invalid Key Error, from DRM | |
AAMP_TUNE_UNSUPPORTED_STREAM_TYPE | 50 | AAMP: Unsupported Stream Type | Unable to determine stream type for DRM Init |
AAMP_TUNE_FAILED_TO_GET_KEYID | 50 | AAMP: Failed to parse key id from PSSH | |
AAMP_TUNE_FAILED_TO_GET_ACCESS_TOKEN | 50 | AAMP: Failed to get access token from Auth Service | |
AAMP_TUNE_CORRUPT_DRM_DATA | 51 | AAMP: DRM failure due to Corrupt DRM files | |
AAMP_TUNE_CORRUPT_DRM_METADATA | 50 | AAMP: DRM failure due to Bad DRMMetadata in stream | |
AAMP_TUNE_DRM_DECRYPT_FAILED | 50 | AAMP: DRM Decryption Failed for Fragments | |
AAMP_TUNE_GST_PIPELINE_ERROR | 80 | AAMP: Error from gstreamer pipeline | |
AAMP_TUNE_PLAYBACK_STALLED | 7600 | AAMP: Playback was stalled due to lack of new fragments | |
AAMP_TUNE_CONTENT_NOT_FOUND | 20 | AAMP: Resource was not found at the URL(HTTP 404) | |
AAMP_TUNE_DRM_KEY_UPDATE_FAILED | 50 | AAMP: Failed to process DRM key | |
AAMP_TUNE_DEVICE_NOT_PROVISIONED | 52 | AAMP: Device not provisioned | |
AAMP_TUNE_INVALID_MANIFEST_FAILURE | 10 | AAMP: Invalid Manifest, parse failed | |
AAMP_TUNE_FAILED_PTS_ERROR | 80 | AAMP: Playback failed due to PTS error | |
AAMP_TUNE_FAILURE_UNKNOWN | 100 | AAMP: Unknown Failure |
Appendix
/opt/webfilterpatterns.conf
{"webfilter":[ {"host":"localhost", "block":"0"}, {"host":"127.0.0.1", "block":"1"}, {"host":"169.254.*", "block":"1"}, {"host":"192.168.*", "block":"1"}, {"host":"[::1]", "block":"1"}, {"scheme":"file", "block":"1"}, {"scheme":"ftp", "block":"1"}, {"scheme":"*", "block":"0"}, {"block":"1"} ]}
/opt/xrehtmlappswhitelist.conf
{"htmlappswhitelist": [ { "name" : "About Blank Page", "url" : "about:blank" }, { "name" : "Viper Player", "url" : "ccr.player-platform-stage.xcr.comcast.net/index.html" }, { "name" : "Google", "url" : "www.google.com" }, { "name" : "AAMP Reference Player", "url" : "localhost:50050/ReferencePlayer/index.html" } ] }