214 lines
7.0 KiB
JavaScript
214 lines
7.0 KiB
JavaScript
import { Observer, Sender } from "/module/core/sender.js";
|
|
import { InputRemoting } from "/module/input/inputremoting.js";
|
|
|
|
export class VideoPlayer {
|
|
constructor() {
|
|
this.playerElement = null;
|
|
this.lockMouseCheck = null;
|
|
this.videoElement = null;
|
|
this.fullScreenButtonElement = null;
|
|
this.inputRemoting = null;
|
|
this.sender = null;
|
|
this.inputSenderChannel = null;
|
|
}
|
|
|
|
/**
|
|
* @param {Element} playerElement parent element for create video player
|
|
* @param {HTMLInputElement} lockMouseCheck use checked propety for lock mouse
|
|
*/
|
|
createPlayer(playerElement, lockMouseCheck) {
|
|
this.playerElement = playerElement;
|
|
this.lockMouseCheck = lockMouseCheck;
|
|
|
|
this.videoElement = document.createElement('video');
|
|
this.videoElement.id = 'Video';
|
|
this.videoElement.style.touchAction = 'none';
|
|
this.videoElement.playsInline = true;
|
|
this.videoElement.srcObject = new MediaStream();
|
|
this.videoElement.addEventListener('loadedmetadata', this._onLoadedVideo.bind(this), true);
|
|
this.playerElement.appendChild(this.videoElement);
|
|
|
|
// add fullscreen button
|
|
this.fullScreenButtonElement = document.createElement('img');
|
|
this.fullScreenButtonElement.id = 'fullscreenButton';
|
|
this.fullScreenButtonElement.src = '../images/FullScreen.png';
|
|
this.fullScreenButtonElement.addEventListener("click", this._onClickFullscreenButton.bind(this));
|
|
this.playerElement.appendChild(this.fullScreenButtonElement);
|
|
|
|
document.addEventListener('webkitfullscreenchange', this._onFullscreenChange.bind(this));
|
|
document.addEventListener('fullscreenchange', this._onFullscreenChange.bind(this));
|
|
this.videoElement.addEventListener("click", this._mouseClick.bind(this), false);
|
|
}
|
|
|
|
_onLoadedVideo() {
|
|
this.videoElement.play();
|
|
this.resizeVideo();
|
|
}
|
|
|
|
_onClickFullscreenButton() {
|
|
if (!document.fullscreenElement || !document.webkitFullscreenElement) {
|
|
if (document.documentElement.requestFullscreen) {
|
|
document.documentElement.requestFullscreen();
|
|
}
|
|
else if (document.documentElement.webkitRequestFullscreen) {
|
|
document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
|
} else {
|
|
if (this.playerElement.style.position == "absolute") {
|
|
this.playerElement.style.position = "relative";
|
|
} else {
|
|
this.playerElement.style.position = "absolute";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_onFullscreenChange() {
|
|
if (document.webkitFullscreenElement || document.fullscreenElement) {
|
|
this.playerElement.style.position = "absolute";
|
|
this.fullScreenButtonElement.style.display = 'none';
|
|
|
|
if (this.lockMouseCheck.checked) {
|
|
if (document.webkitFullscreenElement.requestPointerLock) {
|
|
document.webkitFullscreenElement.requestPointerLock();
|
|
} else if (document.fullscreenElement.requestPointerLock) {
|
|
document.fullscreenElement.requestPointerLock();
|
|
} else if (document.mozFullScreenElement.requestPointerLock) {
|
|
document.mozFullScreenElement.requestPointerLock();
|
|
}
|
|
|
|
// Subscribe to events
|
|
document.addEventListener('mousemove', this._mouseMove.bind(this), false);
|
|
document.addEventListener('click', this._mouseClickFullScreen.bind(this), false);
|
|
}
|
|
}
|
|
else {
|
|
this.playerElement.style.position = "relative";
|
|
this.fullScreenButtonElement.style.display = 'block';
|
|
|
|
document.removeEventListener('mousemove', this._mouseMove.bind(this), false);
|
|
document.removeEventListener('click', this._mouseClickFullScreen.bind(this), false);
|
|
}
|
|
}
|
|
|
|
_mouseMove(event) {
|
|
// Forward mouseMove event of fullscreen player directly to sender
|
|
// This is required, as the regular mousemove event doesn't fire when in fullscreen mode
|
|
this.sender._onMouseEvent(event);
|
|
}
|
|
|
|
_mouseClick() {
|
|
// Restores pointer lock when we unfocus the player and click on it again
|
|
if (this.lockMouseCheck.checked) {
|
|
if (this.videoElement.requestPointerLock) {
|
|
this.videoElement.requestPointerLock().catch(function () { });
|
|
}
|
|
}
|
|
}
|
|
|
|
_mouseClickFullScreen() {
|
|
// Restores pointer lock when we unfocus the fullscreen player and click on it again
|
|
if (this.lockMouseCheck.checked) {
|
|
if (document.webkitFullscreenElement.requestPointerLock) {
|
|
document.webkitFullscreenElement.requestPointerLock();
|
|
} else if (document.fullscreenElement.requestPointerLock) {
|
|
document.fullscreenElement.requestPointerLock();
|
|
} else if (document.mozFullScreenElement.requestPointerLock) {
|
|
document.mozFullScreenElement.requestPointerLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {MediaStreamTrack} track
|
|
*/
|
|
addTrack(track) {
|
|
if (!this.videoElement.srcObject) {
|
|
return;
|
|
}
|
|
|
|
this.videoElement.srcObject.addTrack(track);
|
|
}
|
|
|
|
resizeVideo() {
|
|
if (!this.videoElement) {
|
|
return;
|
|
}
|
|
|
|
const clientRect = this.videoElement.getBoundingClientRect();
|
|
const videoRatio = this.videoWidth / this.videoHeight;
|
|
const clientRatio = clientRect.width / clientRect.height;
|
|
|
|
this._videoScale = videoRatio > clientRatio ? clientRect.width / this.videoWidth : clientRect.height / this.videoHeight;
|
|
const videoOffsetX = videoRatio > clientRatio ? 0 : (clientRect.width - this.videoWidth * this._videoScale) * 0.5;
|
|
const videoOffsetY = videoRatio > clientRatio ? (clientRect.height - this.videoHeight * this._videoScale) * 0.5 : 0;
|
|
this._videoOriginX = clientRect.left + videoOffsetX;
|
|
this._videoOriginY = clientRect.top + videoOffsetY;
|
|
}
|
|
|
|
get videoWidth() {
|
|
return this.videoElement.videoWidth;
|
|
}
|
|
|
|
get videoHeight() {
|
|
return this.videoElement.videoHeight;
|
|
}
|
|
|
|
get videoOriginX() {
|
|
return this._videoOriginX;
|
|
}
|
|
|
|
get videoOriginY() {
|
|
return this._videoOriginY;
|
|
}
|
|
|
|
get videoScale() {
|
|
return this._videoScale;
|
|
}
|
|
|
|
deletePlayer() {
|
|
if (this.inputRemoting) {
|
|
this.inputRemoting.stopSending();
|
|
}
|
|
this.inputRemoting = null;
|
|
this.sender = null;
|
|
this.inputSenderChannel = null;
|
|
|
|
while (this.playerElement.firstChild) {
|
|
this.playerElement.removeChild(this.playerElement.firstChild);
|
|
}
|
|
|
|
this.playerElement = null;
|
|
this.lockMouseCheck = null;
|
|
}
|
|
|
|
_isTouchDevice() {
|
|
return (('ontouchstart' in window) ||
|
|
(navigator.maxTouchPoints > 0) ||
|
|
(navigator.msMaxTouchPoints > 0));
|
|
}
|
|
|
|
/**
|
|
* setup datachannel for player input (muouse/keyboard/touch/gamepad)
|
|
* @param {RTCDataChannel} channel
|
|
*/
|
|
setupInput(channel) {
|
|
this.sender = new Sender(this.videoElement);
|
|
this.sender.addMouse();
|
|
this.sender.addKeyboard();
|
|
if (this._isTouchDevice()) {
|
|
this.sender.addTouchscreen();
|
|
}
|
|
this.sender.addGamepad();
|
|
this.inputRemoting = new InputRemoting(this.sender);
|
|
|
|
this.inputSenderChannel = channel;
|
|
this.inputSenderChannel.onopen = this._onOpenInputSenderChannel.bind(this);
|
|
this.inputRemoting.subscribe(new Observer(this.inputSenderChannel));
|
|
}
|
|
|
|
async _onOpenInputSenderChannel() {
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
this.inputRemoting.startSending();
|
|
}
|
|
}
|