rx-player
Version:
Canal+ HTML5 Video Player
177 lines (176 loc) • 7.4 kB
JavaScript
;
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.emitSeekEvents = emitSeekEvents;
exports.emitPlayPauseEvents = emitPlayPauseEvents;
exports.constructPlayerStateReference = constructPlayerStateReference;
exports.getLoadedContentState = getLoadedContentState;
exports.isLoadedState = isLoadedState;
var config_1 = require("../../config");
var array_includes_1 = require("../../utils/array_includes");
var is_null_or_undefined_1 = require("../../utils/is_null_or_undefined");
var reference_1 = require("../../utils/reference");
/**
* @param {Object} playbackObserver - Observes playback conditions on
* `mediaElement`.
* @param {function} onSeeking - Callback called when a seeking operation starts
* on `mediaElement`.
* @param {function} onSeeked - Callback called when a seeking operation ends
* on `mediaElement`.
* @param {Object} cancelSignal - When triggered, stop calling callbacks and
* remove all listeners this function has registered.
*/
function emitSeekEvents(playbackObserver, onSeeking, onSeeked, cancelSignal) {
if (cancelSignal.isCancelled()) {
return;
}
var wasSeeking = playbackObserver.getReference().getValue().seeking === 2 /* SeekingState.External */;
if (wasSeeking) {
onSeeking();
if (cancelSignal.isCancelled()) {
return;
}
}
playbackObserver.listen(function (obs) {
if (obs.event === "seeking") {
wasSeeking = true;
onSeeking();
}
else if (wasSeeking && obs.event === "seeked") {
wasSeeking = false;
onSeeked();
}
}, { includeLastObservation: true, clearSignal: cancelSignal });
}
/**
* @param {HTMLMediaElement} mediaElement
* @param {function} onPlay - Callback called when a play operation has started
* on `mediaElement`.
* @param {function} onPause - Callback called when a pause operation has
* started on `mediaElement`.
* @param {Object} cancelSignal - When triggered, stop calling callbacks and
* remove all listeners this function has registered.
*/
function emitPlayPauseEvents(mediaElement, onPlay, onPause, cancelSignal) {
if (cancelSignal.isCancelled() || mediaElement === null) {
return;
}
mediaElement.addEventListener("play", onPlay);
mediaElement.addEventListener("pause", onPause);
cancelSignal.register(function () {
mediaElement.removeEventListener("play", onPlay);
mediaElement.removeEventListener("pause", onPause);
});
}
function constructPlayerStateReference(initializer, mediaElement, playbackObserver, cancelSignal) {
var playerStateRef = new reference_1.default("LOADING" /* PLAYER_STATES.LOADING */, cancelSignal);
initializer.addEventListener("loaded", function () {
if (playerStateRef.getValue() === "LOADING" /* PLAYER_STATES.LOADING */) {
playerStateRef.setValue("LOADED" /* PLAYER_STATES.LOADED */);
if (!cancelSignal.isCancelled()) {
var newState = getLoadedContentState(mediaElement, null);
if (newState !== "PAUSED" /* PLAYER_STATES.PAUSED */) {
playerStateRef.setValue(newState);
}
}
}
else if (playerStateRef.getValue() === "RELOADING" /* PLAYER_STATES.RELOADING */) {
playerStateRef.setValue(getLoadedContentState(mediaElement, null));
}
else {
updateStateIfLoaded(null);
}
}, cancelSignal);
initializer.addEventListener("reloadingMediaSource", function () {
if (isLoadedState(playerStateRef.getValue())) {
playerStateRef.setValueIfChanged("RELOADING" /* PLAYER_STATES.RELOADING */);
}
}, cancelSignal);
/**
* Keep track of the last known stalling situation.
* `null` if playback is not stalled.
*/
var prevStallReason = null;
initializer.addEventListener("stalled", function (s) {
if (s !== prevStallReason) {
updateStateIfLoaded(s);
prevStallReason = s;
}
}, cancelSignal);
initializer.addEventListener("unstalled", function () {
if (prevStallReason !== null) {
updateStateIfLoaded(null);
prevStallReason = null;
}
}, cancelSignal);
playbackObserver.listen(function (observation) {
if ((0, array_includes_1.default)(["seeking", "ended", "play", "pause"], observation.event)) {
updateStateIfLoaded(prevStallReason);
}
}, { clearSignal: cancelSignal });
return playerStateRef;
function updateStateIfLoaded(stallRes) {
if (!isLoadedState(playerStateRef.getValue())) {
return;
}
var newState = getLoadedContentState(mediaElement, stallRes);
var prevState = playerStateRef.getValue();
// Some safety checks to avoid having nonsense state switches
if (prevState === "LOADED" /* PLAYER_STATES.LOADED */ && newState === "PAUSED" /* PLAYER_STATES.PAUSED */) {
return;
}
playerStateRef.setValueIfChanged(newState);
}
}
/**
* Get state string for a _loaded_ content.
* @param {HTMLMediaElement} mediaElement
* @param {Object} stalledStatus - Current stalled state:
* - null when not stalled
* - a description of the situation if stalled.
* @returns {string}
*/
function getLoadedContentState(mediaElement, stalledStatus) {
var FORCED_ENDED_THRESHOLD = config_1.default.getCurrent().FORCED_ENDED_THRESHOLD;
if (mediaElement.ended) {
return "ENDED" /* PLAYER_STATES.ENDED */;
}
if (stalledStatus !== null) {
// On some old browsers (e.g. Chrome 54), the browser does not
// emit an 'ended' event in some conditions. Detect if we
// reached the end by comparing the current position and the
// duration instead.
var gapBetweenDurationAndCurrentTime = Math.abs(mediaElement.duration - mediaElement.currentTime);
if (!(0, is_null_or_undefined_1.default)(FORCED_ENDED_THRESHOLD) &&
gapBetweenDurationAndCurrentTime < FORCED_ENDED_THRESHOLD) {
return "ENDED" /* PLAYER_STATES.ENDED */;
}
if (stalledStatus === "seeking") {
return "SEEKING" /* PLAYER_STATES.SEEKING */;
}
if (stalledStatus === "freezing") {
return "FREEZING" /* PLAYER_STATES.FREEZING */;
}
return "BUFFERING" /* PLAYER_STATES.BUFFERING */;
}
return mediaElement.paused ? "PAUSED" /* PLAYER_STATES.PAUSED */ : "PLAYING" /* PLAYER_STATES.PLAYING */;
}
function isLoadedState(state) {
return (state !== "LOADING" /* PLAYER_STATES.LOADING */ &&
state !== "RELOADING" /* PLAYER_STATES.RELOADING */ &&
state !== "STOPPED" /* PLAYER_STATES.STOPPED */);
}