hasplayer.js
hasplayer.js is a javascript implementation of a video player based on the W3C premium extensions, i.e. MSE and EME.
hasplayer.js is an extension of the dash.js project with the aim of supporting additional http adaptive streaming protocols such as Microsoft Smooth Streaming protocol and Apple Http Live Streaming.
If your intent is to use the player code without contributing back to this project, then use the MASTER branch which holds the approved and stable public releases.
If your goal is to improve or extend the code and contribute back to this project, then you should make your changes in, and submit a pull request against, the DEVELOPMENT branch.
Getting Started
Create a video element somewhere in your html. For our purposes, make sure to set the controls property to true.
<video id="videoPlayer" controls="true"></video>
Add hasplayer.js to the end of the body.
<body>
...
<script src="yourPathToHasplayer/hasplayer.js"></script>
</body>
Now comes the good stuff. We need to create an MediaPlayer. Then we need to initialize it, attach it to our "videoPlayer" and then tell it where to get the video from. We will do this in an anonymous self executing function, that way it will run as soon as the page loads. So, here is how we do it:
(function(){
var stream = {
url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest"
};
var mediaPlayer = new MediaPlayer();
MediaPlayer.init(document.querySelector("#videoPlayer"));
MediaPlayer.load(stream);
})();
When it is all done, it should look similar to this:
<!doctype html>
<html>
<head>
<title>hasplayer.js Rocks</title>
</head>
<body>
<div>
<video id="videoPlayer" controls="true"></video>
</div>
<script src="yourPathToHasplayer/hasplayer.js"></script>
<script>
(function(){
var stream = {
url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest"
};
var mediaPlayer = new MediaPlayer();
mediaPlayer.init(document.querySelector("#videoPlayer"));
mediaPlayer.load(stream);
})();
</script>
</body>
</html>
DRM Video Stream
In the case of protected content, here is an example illustrating setting of the protection data:
<!doctype html>
<html>
<head>
<title>Hasplayer.js Rocks</title>
</head>
<body>
<div>
<video id="videoPlayer" controls="true"></video>
</div>
<script src="yourPathToHasplayer/hasplayer.js"></script>
<script>
(function(){
var stream = {
url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest",
protData: {
com.microsoft.playready: {
laURL: "http://roap.purplecast.us/test/services/StandardPlayReadyAquireLicenseByContent.cfm?distrib=olps",
customData: "B2C99B73-CA41-4003-84A3AA16CE92B304"
}
}
};
var mediaPlayer = new MediaPlayer();
mediaPlayer.init(document.querySelector("#videoPlayer"));
mediaPlayer.load(stream);
})();
</script>
</body>
</html>
Events
MediaPlayer offers events to be notified of differents events on video streaming. Those events are, for a part, sent by the HTML5 video element, and for an other part, sent by hasPlayer.js.
function registerMediaPlayerEvents() {
// MediaPlayer events
mediaPlayer.addEventListener("error", onError);
mediaPlayer.addEventListener("warning", onWarning);
mediaPlayer.addEventListener("cueEnter", onCueEnter);
mediaPlayer.addEventListener("cueExit", onCueExit);
mediaPlayer.addEventListener("play_bitrate", onPlayBitrateChanged);
mediaPlayer.addEventListener("download_bitrate", onDownloadBitrateChanged);
mediaPlayer.addEventListener("manifestUrlUpdate", onManifestUrlUpdate);
mediaPlayer.addEventListener("metricAdded", onMetricAdded);
mediaPlayer.addEventListener("metricChanged", onMetricChanged);
mediaPlayer.addEventListener("bufferLevel_updated", onBufferLevelUpdated);
mediaPlayer.addEventListener("state_changed", onStateChanged);
// <video> element events
mediaPlayer.addEventListener("loadeddata", onload);
mediaPlayer.addEventListener("play", onPlay);
mediaPlayer.addEventListener("pause", onPause);
mediaPlayer.addEventListener("timeupdate", onTimeUpdate);
mediaPlayer.addEventListener("volumechange", onVolumeChange);
};
For instance, callback function looks like this :
function onPlayBitrateChanged(e) {
handlePlayBitrate(e.detail.bitrate, e.detail.time);
};
Errors
The following table provides the list of the errors and warnings that can be notified by the MediaPlayer (see MediaPlayer's addEventListener() function).
Category | Event type | Code | Message | Description | Callback 'event' parameter format | Comment |
HTML5_VIDEO | ERROR | MEDIA_ERR_ABORTED | <video> error: fetching process aborted | The fetching process for the media resource was aborted by the user agent at the user's request | { code: <code>, message: <message> } |
|
HTML5_VIDEO | ERROR | MEDIA_ERR_NETWORK | <video> error: network error | A network error caused the user agent to stop fetching the media resource | { code: <code>, message: <message> } |
|
HTML5_VIDEO | ERROR | MEDIA_ERR_DECODE | <video> error: media decoding error | An error of some description occurred while decoding the media | { code: <code>, message: <message> } |
|
HTML5_VIDEO | ERROR | MEDIA_ERR_SRC_NOT_SUPPORTED | <video> error: media format not supported | The media resource indicated by the src attribute was not suitable | { code: <code>, message: <message> } |
|
HTML5_VIDEO | ERROR | MEDIA_ERR_ENCRYPTED | <video> error: media is encrypted or Media is encrypted and no key is available |
The media is encrypted and no valid key is available to decrypt the media | { code: <code>, message: <message> } |
|
MSE | ERROR | CAPABILITY_ERR_MEDIASOURCE | MediaSource extension not supported by the browser | The MediaSource API is not available in the browser | { code: <code>, message: <message> } |
|
MSE | ERROR | MEDIA_ERR_CODEC_CREATE_MEDIASOURCE | Failed to create MediaSource | An error occurred while creatingthe MediaSource object, due to system error | { code: <code>, message: <message>, data: { name: <error name>, message: <error message> } |
|
MSE | ERROR WARNING |
MEDIA_ERR_CODEC_UNSUPPORTED | (Video/Audio/Text) Codec is not supported | The codec is unsupported neither by the HTMLMediaElement nor the MSE MediaSource, or the codec is unsupported by the MediaPlayer. ERROR for audio/video tracks. WARNING for text tracks. |
{ code: <code>, message: <message>, data: { codec: <codec> } } |
# Event type: - ERROR for video and audio tracks - WARNING for text tracks |
MSE | ERROR WARNING |
MEDIA_ERR_CREATE_SOURCEBUFFER | Failed to create audio/video/text source buffer | Failed to add a source buffer the media source, the provided MIME type is not supported. ERROR for audio/video tracks. WARNING for text tracks. |
{ code: <code>, message: <message>, data: { code: <DOMException code>, name: <DOMException name>, message: <DOMException message> } } |
# Event type: - ERROR for video and audio tracks - WARNING for text tracks # Possible DOMException: - InvalidAccessError: MediaSource not available or not ready, or invalid input MIME type - QuotaExceededError: no more SourceBuffer can be created or unsupported configuration of SourceBuffers |
MSE | ERROR | MEDIA_ERR_APPEND_SOURCEBUFFER | Failed to append data into audio/video/text source buffer | Failed to append data into source buffer | { code: <code>, message: <message>, data: { code: <DOMException code>, name: <DOMException name>, message: <DOMException message> } } |
# Possible DOMException: - InvalidStateError: appending is performed while source buffer is still processing some operation - QuotaExceededError: no more data can be appended (browser memory limitation) |
MSE | WARNING | MEDIA_ERR_REMOVE_SOURCEBUFFER | Failed to remove data from audio/video source buffer | Failed to remove data from source buffer | { code: <code>, message: <message>, data: { code: <DOMException code>, name: <DOMException name>, message: <DOMException message> } } |
# Possible DOMException: - InvalidStateError: removing is performed while source buffer is still processing some operation |
MEDIA_PLAYER | ERROR WARNING |
DOWNLOAD_ERR_MANIFEST | Failed to download manifest | Failed to download manifest file | { code: <code>, message: <message>, data: { url: <URL of the manifest>, status: <HTTP status code> } } |
# Event type: - ERROR when failed to download main manifest file - WARNING when failed to refresh manifest (MSS language switch, HLS manifest update, …) |
MEDIA_PLAYER | ERROR | MANIFEST_ERR_PARSE | Failed to parse manifest | An XML parsing error occurred while parsing the manifest. | { code: <code>, message: <message>, data: { url: <URL of the manifest> } } |
|
MEDIA_PLAYER | ERROR | MANIFEST_ERR_NO_STREAM | No stream/period is provided in the manifest | The manifest contains no stream/period description | { code: <code>, message: <message> }{ code: <code>, message: <message> } |
# Applies only for MPEG DASH streams |
MEDIA_PLAYER | ERROR | MANIFEST_ERR_NO_VIDEO | No video data in manifest | No video track is provided in the manifest | { code: <code>, message: <message> }{ code: <code>, message: <message> } |
|
MEDIA_PLAYER | WARNING | MANIFEST_ERR_NO_AUDIO | No audio data in manifest | No audio track is provided in the manifest | { code: <code>, message: <message> }{ code: <code>, message: <message> } |
|
MEDIA_PLAYER | ERROR WARNING |
DOWNLOAD_ERR_CONTENT | Failed to download media segment | Failed to download a media segment file | { code: <code>, message: <message>, data: { url: <URL of the segment>, status: <HTTP status code> } } |
# When a segment download fails, a warning is raised # Afterwards, when the buffer becomes underflow, the session si reloaded # Then, when a third segment download fails, an error is raised # For text tracks only warnings are raised |
EME | ERROR | CAPABILITY_ERR_MEDIAKEYS | EME not supported/enabled | Content is signalized protected but EME is not supported/enabled | { code: <code> message: <message> } |
|
EME | ERROR | MEDIA_KEYSYSERR_ACCESS_DENIED | No KeySystem/CDM available | { code: <code>, message: <message>, data: { keySystems: [{ schemeIdUri: <KS scheme id uri>, systemString: <KS name> }] } } |
# 'data.ks' contains array of signalized Key Systems # Applies on Chrome if EME is disabled (see chrome://flags) |
|
EME | ERROR | MEDIA_KEYMESSERR_NO_SESSION | Failed to create MediaKeys session | Failed to create a MediaKey session or to load an existing MediaKey session | { code: <code>, message: <message>, data: { reason: <reason>, error: { code: <error code>, name: <error name>, message: <error message> } } } |
|
EME | ERROR | MEDIA_KEYMESSERR_LICENSER_UNKNOWN | No licenser URL specified | No licenser URL is specified: - neither in input stream's protection data information - nor in content's DRM initialization Data |
||
EME | ERROR | MEDIA_KEYMESSERR_NO_CHALLENGE | No licenser challenge from CDM key message | The challenge returned by the CDM is not valid according to the Key System | { code: <code>, message: <message> } |
|
EME | ERROR | MEDIA_KEYMESSERR_LICENSER_ERROR | License request failed | License request failed. The http request failed or the licenser server returned an error. | { code: <code>, message: <message>, data: { url: <URL of the licenser>, status: <HTTP status code>, error: { code: <licenser error code>, name: <licenser error name>, message: <licenser error message> } } |
|
EME | ERROR | MEDIA_KEYERR | Error while providing license to the CDM | { code: <code>, message: <message>, code: <DOMException code>, name: <DOMException name>, message: <DOMException message> } |
# Applies only for Chrome | |
EME | ERROR | MEDIA_KEYERR_UNKNOWN | An unspecified error occurred. This value is used for errors that don't match any of the following codes | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge | |
EME | ERROR | MEDIA_KEYERR_CLIENT | The Key System could not be installed or updated | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge | |
EME | ERROR | MEDIA_KEYERR_SERVICE | The message passed into addKey indicated an error from the license service | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge | |
EME | ERROR | MEDIA_KEYERR_OUTPUT | There is no available output device with the required characteristics for the content protection system | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge | |
EME | ERROR | MEDIA_KEYERR_HARDWARECHANGE | A hardware configuration change caused a content protection error | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge | |
EME | ERROR | MEDIA_KEYERR_DOMAIN | An error occurred in a multi-device domain licensing configuration. The most common error is a failure to join the domain | { code: <code>, message: <message> } |
# Applies only for IE11 and Edge |