Fix emit loop zero-delay restart and resume initial-delay checks

This commit is contained in:
Jage9
2026-02-28 21:07:34 -05:00
parent 429b295a64
commit aa5bcd12cc
2 changed files with 23 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
// Maintainer-controlled web client version. // Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
window.CHGRID_WEB_VERSION = "2026.03.01 R329"; window.CHGRID_WEB_VERSION = "2026.03.01 R330";
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit"; window.CHGRID_TIME_ZONE = "America/Detroit";

View File

@@ -227,19 +227,27 @@ export class ItemEmitRuntime {
element.playbackRate = initialRates.playbackRate; element.playbackRate = initialRates.playbackRate;
const initialDelaySeconds = resolveEmitInitialDelaySeconds(item); const initialDelaySeconds = resolveEmitInitialDelaySeconds(item);
const loopDelaySeconds = resolveEmitLoopDelaySeconds(item); const loopDelaySeconds = resolveEmitLoopDelaySeconds(item);
const resumeState = this.resumeStateByItemId.get(item.id);
const matchingResumeState = resumeState && resumeState.soundUrl === soundUrl ? resumeState : null;
const onEnded = () => { const onEnded = () => {
const delaySeconds = this.outputs.get(item.id)?.loopDelaySeconds ?? 0; const current = this.outputs.get(item.id);
if (!current || current.element !== element) return;
const delaySeconds = current.loopDelaySeconds ?? 0;
if (delaySeconds <= 0) {
this.nextEmitStartAtMs.delete(item.id);
this.tryStartEmitPlayback(item.id, element);
return;
}
this.nextEmitStartAtMs.set(item.id, Date.now() + delaySeconds * 1000); this.nextEmitStartAtMs.set(item.id, Date.now() + delaySeconds * 1000);
}; };
element.addEventListener('ended', onEnded); element.addEventListener('ended', onEnded);
const resumeState = this.resumeStateByItemId.get(item.id); if (matchingResumeState) {
if (resumeState && resumeState.soundUrl === soundUrl) {
const nowMs = Date.now(); const nowMs = Date.now();
const elapsedSeconds = Math.max(0, (nowMs - resumeState.savedAtMs) / 1000); const elapsedSeconds = Math.max(0, (nowMs - matchingResumeState.savedAtMs) / 1000);
const effectiveRate = resumeState.playbackRate > 0 ? resumeState.playbackRate : 1; const effectiveRate = matchingResumeState.playbackRate > 0 ? matchingResumeState.playbackRate : 1;
const durationSeconds = resumeState.durationSeconds; const durationSeconds = matchingResumeState.durationSeconds;
if (durationSeconds && durationSeconds > 0) { if (durationSeconds && durationSeconds > 0) {
const loopDelaySeconds = Math.max(0, resumeState.loopDelaySeconds); const loopDelaySeconds = Math.max(0, matchingResumeState.loopDelaySeconds);
const playWallSeconds = durationSeconds / effectiveRate; const playWallSeconds = durationSeconds / effectiveRate;
const cycleWallSeconds = playWallSeconds + loopDelaySeconds; const cycleWallSeconds = playWallSeconds + loopDelaySeconds;
const seekAndPlayNow = (targetTimeSeconds: number) => { const seekAndPlayNow = (targetTimeSeconds: number) => {
@@ -273,10 +281,13 @@ export class ItemEmitRuntime {
} else { } else {
seekAndPlayNow(0); seekAndPlayNow(0);
} }
} else if (resumeState.wasPlaying) { } else if (matchingResumeState.wasPlaying) {
const playRemainingWallSeconds = Math.max(0, (durationSeconds - Math.max(0, resumeState.currentTimeSeconds)) / effectiveRate); const playRemainingWallSeconds = Math.max(
0,
(durationSeconds - Math.max(0, matchingResumeState.currentTimeSeconds)) / effectiveRate,
);
if (elapsedSeconds < playRemainingWallSeconds) { if (elapsedSeconds < playRemainingWallSeconds) {
seekAndPlayNow(Math.max(0, resumeState.currentTimeSeconds) + elapsedSeconds * effectiveRate); seekAndPlayNow(Math.max(0, matchingResumeState.currentTimeSeconds) + elapsedSeconds * effectiveRate);
} else { } else {
const afterTrackSeconds = elapsedSeconds - playRemainingWallSeconds; const afterTrackSeconds = elapsedSeconds - playRemainingWallSeconds;
if (cycleWallSeconds > 0) { if (cycleWallSeconds > 0) {
@@ -329,7 +340,7 @@ export class ItemEmitRuntime {
gain, gain,
panner, panner,
}); });
if (!resumeState && !this.nextEmitStartAtMs.has(item.id) && initialDelaySeconds > 0) { if (!matchingResumeState && !this.nextEmitStartAtMs.has(item.id) && initialDelaySeconds > 0) {
this.nextEmitStartAtMs.set(item.id, Date.now() + initialDelaySeconds * 1000); this.nextEmitStartAtMs.set(item.id, Date.now() + initialDelaySeconds * 1000);
} }
this.resumeStateByItemId.delete(item.id); this.resumeStateByItemId.delete(item.id);