mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-06-24 21:25:23 +00:00
WebOS 22 and 6.0 collection of fixes
This commit is contained in:
parent
902ccff8bc
commit
d57e1368b1
13 changed files with 228 additions and 36 deletions
|
@ -61,7 +61,31 @@ export class FCastSession {
|
|||
|
||||
const size = 1 + data.length;
|
||||
const header = Buffer.alloc(4 + 1);
|
||||
header.writeUint32LE(size, 0);
|
||||
|
||||
// Web OS 22 and earlier node versions do not support `writeUint32LE`,
|
||||
// so manually checking endianness and writing as LE
|
||||
// @ts-ignore
|
||||
if (TARGET === 'webOS') {
|
||||
let uInt32 = new Uint32Array([0x11223344]);
|
||||
let uInt8 = new Uint8Array(uInt32.buffer);
|
||||
|
||||
if(uInt8[0] === 0x44) {
|
||||
// LE
|
||||
header[0] = size & 0xFF;
|
||||
header[1] = size & 0xFF00;
|
||||
header[2] = size & 0xFF0000;
|
||||
header[3] = size & 0xFF000000;
|
||||
} else if (uInt8[0] === 0x11) {
|
||||
// BE
|
||||
header[0] = size & 0xFF000000;
|
||||
header[1] = size & 0xFF0000;
|
||||
header[2] = size & 0xFF00;
|
||||
header[3] = size & 0xFF;
|
||||
}
|
||||
} else {
|
||||
header.writeUint32LE(size, 0);
|
||||
}
|
||||
|
||||
header[4] = opcode;
|
||||
|
||||
let packet: Buffer;
|
||||
|
|
|
@ -33,7 +33,19 @@ if (TARGET === 'electron') {
|
|||
require('lib/webOSTVjs-1.2.10/webOSTV.js');
|
||||
require('lib/webOSTVjs-1.2.10/webOSTV-dev.js');
|
||||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
let onDeviceInfoCb: any;
|
||||
let onDeviceInfoCb = () => { console.log('Main: Callback not set while fetching device info'); };
|
||||
|
||||
const keepAliveService = window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
method:"keepAlive",
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
console.log(`Main: keepAlive ${JSON.stringify(message)}`);
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Main: keepAlive ${JSON.stringify(message)}`);
|
||||
},
|
||||
// onComplete: (message) => {},
|
||||
});
|
||||
|
||||
const getDeviceInfoService = window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
method:"getDeviceInfo",
|
||||
|
@ -58,9 +70,16 @@ if (TARGET === 'electron') {
|
|||
console.log('Main: Registered play handler with service');
|
||||
}
|
||||
else {
|
||||
console.log(`Main: Playing ${JSON.stringify(message)}`);
|
||||
getDeviceInfoService.cancel();
|
||||
playService.cancel();
|
||||
if (message.value !== undefined && message.value.playData !== undefined) {
|
||||
console.log(`Main: Playing ${JSON.stringify(message)}`);
|
||||
getDeviceInfoService.cancel();
|
||||
playService.cancel();
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
// history.pushState({}, '', '../main_window/index.html');
|
||||
window.open('../player/index.html');
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
|
@ -71,14 +90,14 @@ if (TARGET === 'electron') {
|
|||
});
|
||||
|
||||
window.targetAPI = {
|
||||
onDeviceInfo: (callback: any) => onDeviceInfoCb = callback,
|
||||
onDeviceInfo: (callback: () => void) => onDeviceInfoCb = callback,
|
||||
getDeviceInfo: () => deviceInfo,
|
||||
};
|
||||
|
||||
document.addEventListener('webOSRelaunch', (args: any) => {
|
||||
console.log(`Relaunching FCast Receiver with args: ${JSON.stringify(args)}`);
|
||||
|
||||
if (args.playData !== null) {
|
||||
if (args.playData !== undefined) {
|
||||
if (getDeviceInfoService !== undefined) {
|
||||
getDeviceInfoService.cancel();
|
||||
}
|
||||
|
@ -86,7 +105,9 @@ if (TARGET === 'electron') {
|
|||
playService.cancel();
|
||||
}
|
||||
|
||||
history.pushState({}, '', '../main_window/index.html');
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
// history.pushState({}, '', '../main_window/index.html');
|
||||
window.open('../player/index.html');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -43,8 +43,13 @@ function renderIPsAndQRCode() {
|
|||
},
|
||||
errorCorrectionLevel : "M",
|
||||
},
|
||||
(e) => {
|
||||
console.log(`Error rendering QR Code: ${e}`)
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(`Error rendering QR Code: ${err}`);
|
||||
}
|
||||
else {
|
||||
console.log(`Rendered QR Code`);
|
||||
}
|
||||
});
|
||||
|
||||
onQRCodeRendered();
|
||||
|
|
|
@ -40,11 +40,23 @@ if (TARGET === 'electron') {
|
|||
let onSeekCb, onSetVolumeCb, onSetSpeedCb;
|
||||
let playerWindowOpen = false;
|
||||
|
||||
const keepAliveService = window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
method:"keepAlive",
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
console.log(`Player: keepAlive ${JSON.stringify(message)}`);
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: keepAlive ${JSON.stringify(message)}`);
|
||||
},
|
||||
// onComplete: (message) => {},
|
||||
});
|
||||
|
||||
const playService = window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
method:"play",
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
console.log(JSON.stringify(message));
|
||||
// console.log(JSON.stringify(message));
|
||||
if (message.value.subscribed === true) {
|
||||
console.log('Player: Registered play handler with service');
|
||||
}
|
||||
|
@ -122,8 +134,10 @@ if (TARGET === 'electron') {
|
|||
setVolumeService.cancel();
|
||||
setSpeedService.cancel();
|
||||
|
||||
// window.open('../main_window/index.html');
|
||||
history.back();
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
// history.back();
|
||||
window.open('../main_window/index.html');
|
||||
}
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
|
|
|
@ -258,6 +258,14 @@ function onPlay(_event, value: PlayMessage) {
|
|||
hlsPlayer.on(Hls.Events.LEVEL_LOADED, (eventName, level: LevelLoadedData) => {
|
||||
isLive = level.details.live;
|
||||
isLivePosition = isLive ? true : false;
|
||||
|
||||
// Event can fire after video load and play initialization
|
||||
if (isLive && playerCtrlLiveBadge.style.display === "none") {
|
||||
playerCtrlLiveBadge.style.display = "block";
|
||||
playerCtrlPosition.style.display = "none";
|
||||
playerCtrlDurationSeparator.style.display = "none";
|
||||
playerCtrlDuration.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
player = new Player(PlayerType.Hls, videoElement, hlsPlayer);
|
||||
|
@ -717,6 +725,10 @@ const volumeIncrement = 0.1;
|
|||
|
||||
function keyDownEventListener(event: any) {
|
||||
// console.log("KeyDown", event);
|
||||
const handledCase = targetKeyDownEventListener(event);
|
||||
if (handledCase) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.code) {
|
||||
case 'KeyF':
|
||||
|
@ -729,15 +741,11 @@ function keyDownEventListener(event: any) {
|
|||
event.preventDefault();
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
// Skip back
|
||||
player.setCurrentTime(Math.max(player.getCurrentTime() - skipInterval, 0));
|
||||
skipBack();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
// Skip forward
|
||||
if (!isLivePosition) {
|
||||
player.setCurrentTime(Math.min(player.getCurrentTime() + skipInterval, player.getDuration()));
|
||||
}
|
||||
skipForward();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case "Home":
|
||||
|
@ -756,7 +764,7 @@ function keyDownEventListener(event: any) {
|
|||
case 'KeyK':
|
||||
case 'Space':
|
||||
case 'Enter':
|
||||
// Pause/Continue
|
||||
// Play/pause toggle
|
||||
if (player.isPaused()) {
|
||||
player.play();
|
||||
} else {
|
||||
|
@ -777,11 +785,20 @@ function keyDownEventListener(event: any) {
|
|||
volumeChangeHandler(Math.max(player.getVolume() - volumeIncrement, 0));
|
||||
break;
|
||||
default:
|
||||
targetKeyDownEventListener(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function skipBack() {
|
||||
player.setCurrentTime(Math.max(player.getCurrentTime() - skipInterval, 0));
|
||||
}
|
||||
|
||||
function skipForward() {
|
||||
if (!isLivePosition) {
|
||||
player.setCurrentTime(Math.min(player.getCurrentTime() + skipInterval, player.getDuration()));
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', keyDownEventListener);
|
||||
|
||||
export {
|
||||
|
@ -806,4 +823,6 @@ export {
|
|||
onPlay,
|
||||
playerCtrlStateUpdate,
|
||||
formatDuration,
|
||||
skipBack,
|
||||
skipForward,
|
||||
};
|
||||
|
|
|
@ -42,20 +42,26 @@ export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean
|
|||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function targetKeyDownEventListener(event: any) {
|
||||
export function targetKeyDownEventListener(event: any): boolean {
|
||||
let handledCase = false;
|
||||
|
||||
switch (event.code) {
|
||||
case 'KeyF':
|
||||
case 'F11':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'Escape':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ExitFullscreen);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return handledCase
|
||||
};
|
||||
|
||||
export {
|
||||
|
|
|
@ -37,10 +37,16 @@ export class Main {
|
|||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
const service = new Service(serviceId);
|
||||
|
||||
// Not compatible with WebOS 22 and earlier simulator?
|
||||
// Service will timeout and casting will disconnect if not forced to be kept alive
|
||||
let keepAlive;
|
||||
service.activityManager.create("keepAlive", function(activity) {
|
||||
keepAlive = activity;
|
||||
// let keepAlive;
|
||||
// service.activityManager.create("keepAlive", function(activity) {
|
||||
// keepAlive = activity;
|
||||
// });
|
||||
|
||||
service.register("keepAlive", (_message: any) => {
|
||||
Main.logger.info("In keepAlive callback");
|
||||
// Do not respond to keep service alive
|
||||
});
|
||||
|
||||
service.register("getDeviceInfo", (message: any) => {
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
"icon": "assets/icons/icon.png",
|
||||
"largeIcon": "assets/icons/largeIcon.png",
|
||||
"iconColor": "#0a62f5",
|
||||
"splashBackground": "assets/images/splash.png"
|
||||
"splashBackground": "assets/images/splash.png",
|
||||
"disableBackHistoryAPI": "true"
|
||||
}
|
|
@ -1,6 +1,29 @@
|
|||
import 'common/main/Preload';
|
||||
|
||||
enum RemoteKeyCode {
|
||||
Stop = 413,
|
||||
Rewind = 412,
|
||||
Play = 415,
|
||||
Pause = 19,
|
||||
FastForward = 417,
|
||||
Back = 461,
|
||||
}
|
||||
|
||||
// Cannot go back to a state where user was previously casting a video, so exit.
|
||||
window.onpopstate = () => {
|
||||
window.webOS.platformBack();
|
||||
};
|
||||
// window.onpopstate = () => {
|
||||
// window.webOS.platformBack();
|
||||
// };
|
||||
|
||||
document.addEventListener('keydown', (event: any) => {
|
||||
// console.log("KeyDown", event);
|
||||
|
||||
switch (event.keyCode) {
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
case RemoteKeyCode.Back:
|
||||
window.webOS.platformBack();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,14 +2,19 @@ import 'common/main/Renderer';
|
|||
|
||||
const backgroundVideo = document.getElementById('video-player');
|
||||
const loadingScreen = document.getElementById('loading-screen');
|
||||
let backgroundVideoLoaded = false;
|
||||
let qrCodeRendered = false;
|
||||
|
||||
// WebOS 6.0 requires global scope for access during callback invocation
|
||||
// eslint-disable-next-line no-var
|
||||
var backgroundVideoLoaded: boolean;
|
||||
// eslint-disable-next-line no-var
|
||||
var qrCodeRendered: boolean;
|
||||
|
||||
backgroundVideo.onplaying = () => {
|
||||
backgroundVideoLoaded = true;
|
||||
|
||||
if (backgroundVideoLoaded && qrCodeRendered) {
|
||||
loadingScreen.style.display = 'none';
|
||||
backgroundVideo.onplaying = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,17 @@
|
|||
#overlay {
|
||||
font-family: InterRegular;
|
||||
font-size: 28px;
|
||||
|
||||
/* gap not supported in WebOS 6.0 */
|
||||
gap: unset;
|
||||
}
|
||||
|
||||
#main-view {
|
||||
padding: 25px;
|
||||
|
||||
/* gap not supported in WebOS 6.0 */
|
||||
gap: unset;
|
||||
margin-right: 15vw;
|
||||
}
|
||||
|
||||
#title-text {
|
||||
|
|
|
@ -17,12 +17,23 @@ import {
|
|||
playerCtrlVolumeBarProgress,
|
||||
videoCaptions,
|
||||
formatDuration,
|
||||
skipBack,
|
||||
skipForward,
|
||||
} from 'common/player/Renderer';
|
||||
|
||||
const captionsBaseHeightCollapsed = 150;
|
||||
const captionsBaseHeightExpanded = 320;
|
||||
const captionsLineHeight = 68;
|
||||
|
||||
enum RemoteKeyCode {
|
||||
Stop = 413,
|
||||
Rewind = 412,
|
||||
Play = 415,
|
||||
Pause = 19,
|
||||
FastForward = 417,
|
||||
Back = 461,
|
||||
}
|
||||
|
||||
export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean {
|
||||
let handledCase = false;
|
||||
|
||||
|
@ -74,11 +85,57 @@ export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean
|
|||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function targetKeyDownEventListener(event: any) {
|
||||
switch (event.code) {
|
||||
export function targetKeyDownEventListener(event: any): boolean {
|
||||
let handledCase = false;
|
||||
|
||||
switch (event.keyCode) {
|
||||
case RemoteKeyCode.Stop:
|
||||
// history.back();
|
||||
window.open('../main_window/index.html');
|
||||
handledCase = true;
|
||||
break;
|
||||
|
||||
case RemoteKeyCode.Rewind:
|
||||
skipBack();
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
|
||||
case RemoteKeyCode.Play:
|
||||
if (player.isPaused()) {
|
||||
player.play();
|
||||
}
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case RemoteKeyCode.Pause:
|
||||
if (!player.isPaused()) {
|
||||
player.pause();
|
||||
}
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
|
||||
case RemoteKeyCode.FastForward:
|
||||
skipForward();
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
case RemoteKeyCode.Back:
|
||||
// history.back();
|
||||
window.open('../main_window/index.html');
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return handledCase;
|
||||
};
|
||||
|
||||
if (window.webOSAPI.pendingPlay !== null) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "node",
|
||||
"target": "ES2015",
|
||||
"module": "ES2015",
|
||||
"moduleResolution": "node10",
|
||||
"sourceMap": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue