ovenplayer
Version:
OvenPlayer is Open-Source HTML5 Player. OvenPlayer supports WebRTC Signaling from OvenMediaEngine for Sub-Second Latency Streaming.
420 lines (354 loc) • 13.9 kB
JavaScript
/**
* Created by hoho on 2018. 7. 20..
*/
import OvenTemplate from 'view/engine/OvenTemplate';
import Helpers from 'view/components/helpers/main';
import Controls from 'view/components/controls/main';
import PanelManager from "view/global/PanelManager";
import ContextPanel from 'view/components/helpers/contextPanel';
import LA$ from 'utils/likeA$';
import ResizeSensor from "utils/resize-sensor";
import getTouchSection from "utils/getTouchSection";
import {
READY,
DESTROY,
PLAYER_RESIZED,
PLAYER_PLAY,
STATE_IDLE,
STATE_AD_PLAYING,
STATE_PLAYING,
STATE_STALLED,
STATE_LOADING,
STATE_COMPLETE,
STATE_PAUSED,
STATE_ERROR,
CONTENT_META,
PLAYER_STATE,
PLAYER_CLICKED,
ERROR
} from "api/constants";
import '../../stylesheet/ovenplayer.less';
const View = function ($container) {
let viewTemplate = "", controls = "", helper = "", $playerRoot, contextPanel = "", api = null, autoHideTimer = "", playerState = STATE_IDLE;
let isShiftPressed = false;
let panelManager = PanelManager();
let screenSize = "";
let currentPlayerSize = "";
let resizeSensor = null;
let that = {};
//Member Functions
function setHide(hide, autoHide) {
if (autoHideTimer) {
clearTimeout(autoHideTimer);
autoHideTimer = null;
}
if (hide) {
if (panelManager.size() > 0) {
return false;
}
$playerRoot.addClass("op-autohide");
} else {
$playerRoot.removeClass("op-autohide");
if (autoHide) {
autoHideTimer = setTimeout(function () {
if (panelManager.size() > 0) {
return false;
}
$playerRoot.addClass("op-autohide");
}, 3000);
}
}
}
function togglePlayPause() {
const currentState = playerState;
if (currentState === STATE_IDLE || currentState === STATE_PAUSED || currentState === STATE_COMPLETE) {
if (currentState === STATE_COMPLETE) {
api.seek(0);
}
api.play();
} else if (currentState === STATE_PLAYING) {
api.pause();
}
}
function seek(seconds, isRewind) {
const duration = api.getDuration();
const currentPosition = api.getPosition();
let position = 0;
if (isRewind) {
position = Math.max(currentPosition - seconds, 0);
} else {
position = Math.min(currentPosition + seconds, duration);
}
api.seek(position);
}
function volume(isUp) {
const currentVolumn = api.getVolume();
let newVolume = 0;
if (isUp) {
newVolume = Math.min(currentVolumn + 5, 100);
} else {
newVolume = Math.max(currentVolumn - 5, 0);
}
api.setVolume(newVolume);
}
function createContextPanel(pageX, pageY) {
if (contextPanel) {
contextPanel.destroy();
contextPanel = null;
}
contextPanel = ContextPanel($playerRoot, api, { pageX: pageX, pageY: pageY });
}
function calcPlayerWidth() {
let playerWidth = $playerRoot.width();
if (playerWidth < 576) {
screenSize = "xsmall";
$playerRoot.addClass("xsmall");
if (playerWidth < 490) {
$playerRoot.addClass("xxsmall");
}
} else if (playerWidth < 768) {
screenSize = "small";
$playerRoot.addClass("small");
} else if (playerWidth < 992) {
screenSize = "medium";
$playerRoot.addClass("medium");
} else {
screenSize = "large";
$playerRoot.addClass("large");
}
}
const onRendered = function ($current, template) {
$playerRoot = $current;
viewTemplate = template;
calcPlayerWidth();
currentPlayerSize = screenSize;
resizeSensor = new ResizeSensor($playerRoot.get(), function () {
$playerRoot.removeClass("large");
$playerRoot.removeClass("medium");
$playerRoot.removeClass("small");
$playerRoot.removeClass("xsmall");
$playerRoot.removeClass("xxsmall");
calcPlayerWidth();
if (screenSize !== currentPlayerSize) {
currentPlayerSize = screenSize;
if (api) {
api.trigger(PLAYER_RESIZED, currentPlayerSize);
}
}
});
};
const onDestroyed = function () {
if (resizeSensor) {
resizeSensor.detach();
resizeSensor = null;
}
if (helper) {
helper.destroy();
helper = null;
}
if (controls) {
controls.destroy();
controls = null;
}
};
const events = {
"click .ovenplayer": function (event, $current, template) {
if (api) {
api.trigger(PLAYER_CLICKED, event);
}
if (contextPanel) {
event.preventDefault();
contextPanel.destroy();
contextPanel = null;
return false;
}
if (!(LA$(event.target).closest(".op-controls-container") || LA$(event.target).closest(".op-setting-panel"))) {
if (panelManager.size() > 0) {
event.preventDefault();
panelManager.clear();
return false;
}
if (api.getDuration() !== Infinity && !api.getBrowser().mobile) {
togglePlayPause();
}
}
},
"dblclick .ovenplayer": function (event, $current, template) {
if (api) {
const touchPosition = getTouchSection(event);
const currentPosition = api.getPosition();
const tapToSeekEnabled = api.getConfig().doubleTapToSeek;
// seek back 10s
if (tapToSeekEnabled && touchPosition == 'left') {
const newPosition = Math.max(currentPosition - 10, 0);
OvenPlayerConsole.log(`Seeking to ${newPosition}`);
api.seek(newPosition);
}
// seek forward 10s
if (tapToSeekEnabled && touchPosition === 'right') {
const newPosition = Math.min(currentPosition + 10, api.getDuration());
OvenPlayerConsole.log(`Seeking to ${newPosition}`);
api.seek(newPosition);
}
if (touchPosition === 'middle' || !tapToSeekEnabled) {
OvenPlayerConsole.log(`Toggling fullscreen`);
if (api.getConfig().expandFullScreenUI && api.toggleFullScreen) {
if (!(LA$(event.target).closest(".op-controls-container") || LA$(event.target).closest(".op-setting-panel"))) {
api.toggleFullScreen();
}
}
}
}
},
//For iOS safari
"touchstart .ovenplayer": function (event, $current, template) {
if (playerState === STATE_PLAYING || playerState === STATE_IDLE || playerState === STATE_LOADING || (playerState === STATE_AD_PLAYING && screenSize === "xsmall")) {
setHide(false, true);
} else {
setHide(false);
}
},
"mouseenter .ovenplayer": function (event, $current, template) {
event.preventDefault();
//small screen with STATE_AD_PLAYING setHide too. becuase mobile hide ad ui.
if (playerState === STATE_PLAYING || playerState === STATE_IDLE || playerState === STATE_LOADING || (playerState === STATE_AD_PLAYING && screenSize === "xsmall")) {
setHide(false, true);
} else {
setHide(false);
}
},
"mousemove .ovenplayer": function (event, $current, template) {
event.preventDefault();
if (playerState === STATE_PLAYING || playerState === STATE_IDLE || playerState === STATE_LOADING || (playerState === STATE_AD_PLAYING && screenSize === "xsmall")) {
setHide(false, true);
} else {
setHide(false);
}
},
"mouseleave .ovenplayer": function (event, $current, template) {
event.preventDefault();
if (playerState === STATE_PLAYING || playerState === STATE_IDLE || playerState === STATE_LOADING || (playerState === STATE_AD_PLAYING && screenSize === "xsmall")) {
setHide(true);
}
},
"keydown .ovenplayer": function (event, $current, template) {
let frameMode = api.getFramerate();
switch (event.keyCode) {
case 16: //shift
event.preventDefault();
isShiftPressed = true;
break;
case 32: //space
event.preventDefault();
togglePlayPause();
break;
case 37: //arrow left
event.preventDefault();
if (!api.getConfig().disableSeekUI) {
if (isShiftPressed && frameMode) {
api.seekFrame(-1);
} else {
seek(5, true);
}
}
break;
case 39: //arrow right
event.preventDefault();
if (!api.getConfig().disableSeekUI) {
if (isShiftPressed && frameMode) {
api.seekFrame(1);
} else {
seek(5, false);
}
}
break;
case 38: //arrow up
event.preventDefault();
volume(true);
break;
case 40: //arrow up
event.preventDefault();
volume(false);
break;
}
},
"keyup .ovenplayer": function (event, $current, template) {
switch (event.keyCode) {
case 16: //shift
event.preventDefault();
isShiftPressed = false;
break;
}
},
"contextmenu .ovenplayer": function (event, $current, template) {
event.stopPropagation();
if (!LA$(event.currentTarget).find("object")) {
event.preventDefault();
createContextPanel(event.pageX, event.pageY);
return false;
}
}
};
that = OvenTemplate($container, "View", null, $container.id, events, onRendered, onDestroyed, true);
that.getMediaElementContainer = () => {
return $playerRoot.find(".op-media-element-container").get();
};
that.setApi = (playerInstance) => {
api = playerInstance;
api.getContainerElement = () => {
return $playerRoot.get();
};
api.getContainerId = () => {
return $playerRoot.get().id;
};
api.on(READY, function (data) {
if (!controls) {
controls = Controls($playerRoot.find(".op-ui"), playerInstance);
}
if (!showControlBar) {
$playerRoot.addClass("op-no-controls");
}
setHide(false, true);
});
api.on(ERROR, function (error) {
if (api) {
let sources = api.getSources() || [];
if (controls && (sources.length <= 1)) {
// controls.destroy();
// controls = null;
}
}
});
api.on(DESTROY, function (data) {
viewTemplate.destroy();
});
api.on(PLAYER_PLAY, function (data) {
if (!controls && showControlBar) {
controls = Controls($playerRoot.find(".op-ui"), playerInstance);
}
});
let showControlBar = api.getConfig() && api.getConfig().controls;
helper = Helpers($playerRoot.find(".op-ui"), playerInstance);
controls = Controls($playerRoot.find(".op-ui"), playerInstance);
let aspectRatio = api.getConfig().aspectRatio;
if (aspectRatio) {
if (aspectRatio.split(':').length === 2) {
let width = aspectRatio.split(':')[0] * 1;
let height = aspectRatio.split(':')[1] * 1;
let ratio = height / width * 100;
$playerRoot.find('.op-ratio').css('padding-bottom', ratio + '%');
}
}
api.showControls = function (show, keepOpen) {
if (show) {
$playerRoot.removeClass("op-no-controls");
let autoHide = !keepOpen
setHide(false, autoHide);
} else {
$playerRoot.addClass("op-no-controls");
}
};
};
return that;
};
export default View;