bitmovin-player-ui
Version:
Bitmovin Player UI Framework
194 lines (193 loc) • 9.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlayerUtils = void 0;
var EventDispatcher_1 = require("../EventDispatcher");
var BrowserUtils_1 = require("./BrowserUtils");
/**
* @category Utils
*/
var PlayerUtils;
(function (PlayerUtils) {
var PlayerState;
(function (PlayerState) {
PlayerState[PlayerState["Idle"] = 0] = "Idle";
PlayerState[PlayerState["Prepared"] = 1] = "Prepared";
PlayerState[PlayerState["Playing"] = 2] = "Playing";
PlayerState[PlayerState["Paused"] = 3] = "Paused";
PlayerState[PlayerState["Finished"] = 4] = "Finished";
})(PlayerState = PlayerUtils.PlayerState || (PlayerUtils.PlayerState = {}));
function isTimeShiftAvailable(player) {
return player.isLive() && player.getMaxTimeShift() !== 0;
}
PlayerUtils.isTimeShiftAvailable = isTimeShiftAvailable;
function getState(player) {
if (player.hasEnded()) {
return PlayerState.Finished;
}
else if (player.isPlaying()) {
return PlayerState.Playing;
}
else if (player.isPaused()) {
return PlayerState.Paused;
}
else if (player.getSource() != null) {
return PlayerState.Prepared;
}
else {
return PlayerState.Idle;
}
}
PlayerUtils.getState = getState;
/**
* Returns the currentTime - seekableRange.start. This ensures a user-friendly currentTime after a live stream
* transitioned to VoD.
* @param player
*/
function getCurrentTimeRelativeToSeekableRange(player) {
var currentTime = player.getCurrentTime();
if (player.isLive()) {
return currentTime;
}
var seekableRangeStart = PlayerUtils.getSeekableRangeStart(player, 0);
return currentTime - seekableRangeStart;
}
PlayerUtils.getCurrentTimeRelativeToSeekableRange = getCurrentTimeRelativeToSeekableRange;
/**
* Returns the start value of the seekable range or the defaultValue if no seekableRange is present.
* For now this happens only in combination with Mobile SDKs.
*
* TODO: remove this function in next major release
*
* @param player
* @param defaultValue
*/
function getSeekableRangeStart(player, defaultValue) {
if (defaultValue === void 0) { defaultValue = 0; }
return (player.getSeekableRange() && player.getSeekableRange().start) || defaultValue;
}
PlayerUtils.getSeekableRangeStart = getSeekableRangeStart;
/**
* Calculates player seekable time range for live.
* As the player returns `{ start: -1, end: -1 }` for live streams we need to calculate the `seekableRange` based on `maxTimeshift`.
*
* @param player
*/
function getSeekableRangeRespectingLive(player) {
if (!player.isLive()) {
return player.getSeekableRange();
}
var currentTimeshift = -player.getTimeShift();
var maxTimeshift = -player.getMaxTimeShift();
var currentTime = player.getCurrentTime();
var end = currentTime + currentTimeshift;
var start = currentTime - (maxTimeshift - currentTimeshift);
return { start: start, end: end };
}
PlayerUtils.getSeekableRangeRespectingLive = getSeekableRangeRespectingLive;
var TimeShiftAvailabilityDetector = /** @class */ (function () {
function TimeShiftAvailabilityDetector(player) {
var _this = this;
this.timeShiftAvailabilityChangedEvent = new EventDispatcher_1.EventDispatcher();
this.player = player;
this.timeShiftAvailable = undefined;
var timeShiftDetector = function () {
_this.detect();
};
// Try to detect timeshift availability when source is loaded, which works for DASH streams
player.on(player.exports.PlayerEvent.SourceLoaded, timeShiftDetector);
// With HLS/NativePlayer streams, getMaxTimeShift can be 0 before the buffer fills, so we need to additionally
// check timeshift availability in TimeChanged
player.on(player.exports.PlayerEvent.TimeChanged, timeShiftDetector);
}
TimeShiftAvailabilityDetector.prototype.detect = function () {
if (this.player.isLive()) {
var timeShiftAvailableNow = PlayerUtils.isTimeShiftAvailable(this.player);
// When the availability changes, we fire the event
if (timeShiftAvailableNow !== this.timeShiftAvailable) {
this.timeShiftAvailabilityChangedEvent.dispatch(this.player, { timeShiftAvailable: timeShiftAvailableNow });
this.timeShiftAvailable = timeShiftAvailableNow;
}
}
};
Object.defineProperty(TimeShiftAvailabilityDetector.prototype, "onTimeShiftAvailabilityChanged", {
get: function () {
return this.timeShiftAvailabilityChangedEvent.getEvent();
},
enumerable: false,
configurable: true
});
return TimeShiftAvailabilityDetector;
}());
PlayerUtils.TimeShiftAvailabilityDetector = TimeShiftAvailabilityDetector;
/**
* Detects changes of the stream type, i.e. changes of the return value of the player#isLive method.
* Normally, a stream cannot change its type during playback, it's either VOD or live. Due to bugs on some
* platforms or browsers, it can still change. It is therefore unreliable to just check #isLive and this detector
* should be used as a workaround instead.
*
* Additionally starting with player v8.19.0 we have the use-case that a live stream changes into a vod.
* The DurationChanged event indicates this switch.
*
* Known cases:
*
* - HLS VOD on Android 4.3
* Video duration is initially 'Infinity' and only gets available after playback starts, so streams are wrongly
* reported as 'live' before playback (the live-check in the player checks for infinite duration).
*
* @deprecated since UI v3.9.0 in combination with player v8.19.0 use PlayerEvent.DurationChanged instead
*
* TODO: remove this class in next major release
*/
var LiveStreamDetector = /** @class */ (function () {
function LiveStreamDetector(player, uimanager) {
var _this = this;
this.liveChangedEvent = new EventDispatcher_1.EventDispatcher();
this.player = player;
this.uimanager = uimanager;
this.live = undefined;
var liveDetector = function () {
_this.detect();
};
this.uimanager.getConfig().events.onUpdated.subscribe(liveDetector);
// Re-evaluate when playback starts
player.on(player.exports.PlayerEvent.Play, liveDetector);
// HLS live detection workaround for Android:
// Also re-evaluate during playback, because that is when the live flag might change.
// (Doing it only in Android Chrome saves unnecessary overhead on other platforms)
if (BrowserUtils_1.BrowserUtils.isAndroid && BrowserUtils_1.BrowserUtils.isChrome) {
player.on(player.exports.PlayerEvent.TimeChanged, liveDetector);
}
// DurationChanged event was introduced with player v8.19.0
if (player.exports.PlayerEvent.DurationChanged) {
player.on(player.exports.PlayerEvent.DurationChanged, liveDetector);
}
// Ad video's isLive() might be different than the actual video's isLive().
player.on(player.exports.PlayerEvent.AdBreakStarted, liveDetector);
player.on(player.exports.PlayerEvent.AdBreakFinished, liveDetector);
}
LiveStreamDetector.prototype.detect = function () {
var liveNow = this.player.isLive();
// Compare current to previous live state flag and fire event when it changes. Since we initialize the flag
// with undefined, there is always at least an initial event fired that tells listeners the live state.
if (liveNow !== this.live) {
this.liveChangedEvent.dispatch(this.player, { live: liveNow });
this.live = liveNow;
}
};
Object.defineProperty(LiveStreamDetector.prototype, "onLiveChanged", {
get: function () {
return this.liveChangedEvent.getEvent();
},
enumerable: false,
configurable: true
});
return LiveStreamDetector;
}());
PlayerUtils.LiveStreamDetector = LiveStreamDetector;
function clampValueToRange(value, boundary1, boundary2) {
var lowerBoundary = Math.min(boundary1, boundary2);
var upperBoundary = Math.max(boundary1, boundary2);
return Math.min(Math.max(value, lowerBoundary), upperBoundary);
}
PlayerUtils.clampValueToRange = clampValueToRange;
})(PlayerUtils || (exports.PlayerUtils = PlayerUtils = {}));