diff --git a/apps/server/src/services/__tests__/timerUtils.test.ts b/apps/server/src/services/__tests__/timerUtils.test.ts index 07d7f9ed9..bb6d05628 100644 --- a/apps/server/src/services/__tests__/timerUtils.test.ts +++ b/apps/server/src/services/__tests__/timerUtils.test.ts @@ -4,7 +4,6 @@ import { EndAction, Playback, TimeStrategy, TimerPhase, TimerType } from 'ontime import { getCurrent, getExpectedFinish, - getRelativeOffset, getRuntimeOffset, getTimerPhase, normaliseEndTime, @@ -741,8 +740,8 @@ describe('getRuntimeOffset()', () => { }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(-50); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-50); }); it('added time subtracts time offset (positive offset)', () => { @@ -764,8 +763,8 @@ describe('getRuntimeOffset()', () => { }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(-60); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-60); }); it('considers running overtime (negative offset)', () => { @@ -788,8 +787,8 @@ describe('getRuntimeOffset()', () => { }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(-10); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-10); }); it('paused time is delayed time (negative offset)', () => { @@ -813,8 +812,8 @@ describe('getRuntimeOffset()', () => { }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(-25); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-25); }); it('offset doesnt exist if we havent started', () => { @@ -851,8 +850,8 @@ describe('getRuntimeOffset()', () => { _timer: { pausedAt: null }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(0); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(0); }); it('handles loaded event', () => { @@ -892,8 +891,8 @@ describe('getRuntimeOffset()', () => { _timer: { pausedAt: null }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(81000000 - 79521653); // clock - timestart + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(81000000 - 79521653); // clock - timestart }); it('with time-to-end, offsets dont exist if we are not in overtime', () => { @@ -945,8 +944,8 @@ describe('getRuntimeOffset()', () => { _timer: { pausedAt: null }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(0); + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(0); }); it('with time-to-end, offset is the overtime', () => { @@ -998,8 +997,8 @@ describe('getRuntimeOffset()', () => { _timer: { pausedAt: null }, } as RuntimeState; - const offset = getRuntimeOffset(state); - expect(offset).toBe(-400000); // <--- offset is always the overtime + const { absoluteOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-400000); // <--- offset is always the overtime }); it('handles time-to-end started after the end time', () => { @@ -1041,9 +1040,9 @@ describe('getRuntimeOffset()', () => { const updateCurrent = getCurrent(state); state.timer.current = updateCurrent; - const offset = getRuntimeOffset(state); - expect(millisToString(offset)).toBe('-00:16:40'); - expect(offset).toBe(81000000 - 82000000); // <-- planned end - now + const { absoluteOffset } = getRuntimeOffset(state); + expect(millisToString(absoluteOffset)).toBe('-00:16:40'); + expect(absoluteOffset).toBe(81000000 - 82000000); // <-- planned end - now }); }); @@ -1068,10 +1067,9 @@ describe('getRelativeOffset()', () => { }, } as RuntimeState; - state.runtime.offset = getRuntimeOffset(state); - expect(state.runtime.offset).toBe(0); - const relativeOffsetoffset = getRelativeOffset(state); - expect(relativeOffsetoffset).toBe(0); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(0); + expect(relativeOffset).toBe(0); }); it('relative offset is 0 when starting after the planed time', () => { const state = { @@ -1093,10 +1091,9 @@ describe('getRelativeOffset()', () => { }, } as RuntimeState; - state.runtime.offset = getRuntimeOffset(state); - expect(state.runtime.offset).toBe(-50); - const relativeOffsetoffset = getRelativeOffset(state); - expect(relativeOffsetoffset).toBe(0); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(-50); + expect(relativeOffset).toBe(0); }); it('relative offset is 0 when starting before the planed time', () => { const state = { @@ -1118,10 +1115,9 @@ describe('getRelativeOffset()', () => { }, } as RuntimeState; - state.runtime.offset = getRuntimeOffset(state); - expect(state.runtime.offset).toBe(50); - const relativeOffsetoffset = getRelativeOffset(state); - expect(relativeOffsetoffset).toBe(0); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(state); + expect(absoluteOffset).toBe(50); + expect(relativeOffset).toBe(0); }); }); diff --git a/apps/server/src/services/timerUtils.ts b/apps/server/src/services/timerUtils.ts index 003f76314..16d189efa 100644 --- a/apps/server/src/services/timerUtils.ts +++ b/apps/server/src/services/timerUtils.ts @@ -116,10 +116,10 @@ export function skippedOutOfEvent(state: RuntimeState, previousTime: number, ski * Positive offset is time ahead * Negative offset is time delayed */ -export function getRuntimeOffset(state: RuntimeState): number { +export function getRuntimeOffset(state: RuntimeState): { absoluteOffset: number; relativeOffset: number } { // nothing to calculate if there are no loaded events or if we havent started if (state.eventNow === null || state.runtime.actualStart === null) { - return 0; + return { absoluteOffset: 0, relativeOffset: 0 }; } // eslint-disable-next-line no-unused-labels -- dev code path @@ -133,18 +133,16 @@ export function getRuntimeOffset(state: RuntimeState): number { const { clock } = state; const { countToEnd, timeStart } = state.eventNow; const { addedTime, current, startedAt } = state.timer; + const { actualStart, plannedStart } = state.runtime; // if we havent started, but the timer is armed // the offset is the difference to the schedule if (startedAt === null) { - return timeStart - clock; + return { absoluteOffset: timeStart - clock, relativeOffset: 0 }; } const overtime = Math.min(current, 0); // in time-to-end, offset is overtime - if (countToEnd) { - return overtime; - } const startOffset = timeStart - startedAt; const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt; @@ -153,24 +151,20 @@ export function getRuntimeOffset(state: RuntimeState): number { // addedTime - time added by user (negative offset) // pausedTime - time the playback was paused (negative offset) // overtime - how long the timer has been over-running (negative offset) - return startOffset - addedTime - pausedTime + overtime; -} + const offset = startOffset - addedTime - pausedTime + overtime; -/** - * Calculates relative offset - * should always be calculated after the absolute offset - */ -export function getRelativeOffset(state: RuntimeState): number { - const { actualStart, plannedStart, offset } = state.runtime; - // eslint-disable-next-line no-unused-labels -- dev code path - DEV: { - // we know actualStart and plannedStart exists as long as a timer is running - if (actualStart === null || plannedStart === null) { - throw new Error('timerUtils.calculate: actualStart and plannedStart must be set'); - } + // offset between planned rundown start and actual rundown start + const rundownStartOffset = actualStart - plannedStart; + + // offset offset relative to the actual rundown start + const relativeOffset = offset + rundownStartOffset; + + // in time-to-end, offset is overtime + if (countToEnd) { + return { absoluteOffset: overtime, relativeOffset }; } - const relativeStartOffset = actualStart - plannedStart; - return offset + relativeStartOffset; + + return { absoluteOffset: offset, relativeOffset }; } /** diff --git a/apps/server/src/stores/runtimeState.ts b/apps/server/src/stores/runtimeState.ts index 269d9012b..50aac59b2 100644 --- a/apps/server/src/stores/runtimeState.ts +++ b/apps/server/src/stores/runtimeState.ts @@ -28,7 +28,6 @@ import { getCurrent, getExpectedEnd, getExpectedFinish, - getRelativeOffset, getRuntimeOffset, getTimerPhase, } from '../services/timerUtils.js'; @@ -89,7 +88,7 @@ export function getState(): Readonly { }; } -/* clear data related to the current event, but leav in place data about the global run state +/* clear data related to the current event, but leave in place data about the global run state * used when loading a new event but the playback is not interrupted */ export function clearEventData() { @@ -214,8 +213,9 @@ export function load( const firstStart = initialData?.firstStart; if (firstStart === null || typeof firstStart === 'number') { runtimeState.runtime.actualStart = firstStart; - runtimeState.runtime.offset = getRuntimeOffset(runtimeState); - runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState); + runtimeState.runtime.offset = absoluteOffset; + runtimeState.runtime.relativeOffset = relativeOffset; runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState); } if (typeof initialData.blockStartAt === 'number') { @@ -420,8 +420,9 @@ export function start(state: RuntimeState = runtimeState): boolean { runtimeState.timer.phase = getTimerPhase(runtimeState); // update offset - state.runtime.offset = getRuntimeOffset(state); - state.runtime.relativeOffset = getRelativeOffset(state); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState); + runtimeState.runtime.offset = absoluteOffset; + runtimeState.runtime.relativeOffset = relativeOffset; state.runtime.expectedEnd = state.runtime.plannedEnd - state.runtime.offset; return true; } @@ -482,8 +483,9 @@ export function addTime(amount: number) { runtimeState.timer.current += amount; // update runtime delays: over - under - runtimeState.runtime.offset = getRuntimeOffset(runtimeState); - runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState); + runtimeState.runtime.offset = absoluteOffset; + runtimeState.runtime.relativeOffset = relativeOffset; runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState); return true; @@ -528,8 +530,9 @@ export function update(): UpdateResult { runtimeState.timer.elapsed = runtimeState.timer.duration - runtimeState.timer.current; // update runtime, needs up-to-date timer state - runtimeState.runtime.offset = getRuntimeOffset(runtimeState); - runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState); + const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState); + runtimeState.runtime.offset = absoluteOffset; + runtimeState.runtime.relativeOffset = relativeOffset; runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState); const finishedNow =