diff --git a/internal/control/ui.html b/internal/control/ui.html
index 7ff20f8..eb211cd 100644
--- a/internal/control/ui.html
+++ b/internal/control/ui.html
@@ -1180,6 +1180,7 @@ input.input-error {
High Watermark Trend
@@ -1972,7 +1973,7 @@ function render() {
updateText('info-fmmod', fmtBool(cfg.fm?.fmModulationEnabled));
updateText('info-live', engine.state ? `${String(engine.state).toUpperCase()} / ${state.server.runtimeOk ? 'runtime ok' : 'runtime pending'}` : (state.server.configOk ? 'config only' : '--'));
- updateHealth(engine, audioStream);
+ updateHealth(engine, driver, audioStream);
updateFaultHistory(engine);
updateTransitionHistory();
updateResetHint(engine);
@@ -2077,8 +2078,9 @@ function notifyRuntimeTransition(engine, pushHistory = true) {
}
-function updateHealth(engine, audioStream) {
+function updateHealth(engine, driver, audioStream) {
engine = engine || {};
+ driver = driver || {};
updateText('health-http', state.server.configOk ? 'OK' : 'OFFLINE');
$('health-http').className = 'val ' + (state.server.configOk ? 'good' : 'err');
@@ -2175,6 +2177,35 @@ function updateHealth(engine, audioStream) {
queueFillEl.className = 'val ' + queueFillClass;
}
+ const streakEl = $('health-underrun-streak');
+ if (streakEl) {
+ const streakRaw = driver?.underrunStreak;
+ const streakMaxRaw = driver?.maxUnderrunStreak;
+ const streakCurrent = Number.isFinite(Number(streakRaw)) ? Number(streakRaw) : null;
+ const streakMax = Number.isFinite(Number(streakMaxRaw)) ? Number(streakMaxRaw) : null;
+ let streakLabel = '--';
+ if (streakCurrent != null) {
+ streakLabel = String(streakCurrent);
+ if (streakMax != null) {
+ streakLabel += ` (max ${streakMax})`;
+ }
+ } else if (streakMax != null) {
+ streakLabel = `Max ${streakMax}`;
+ }
+ let streakSeverity = '';
+ if (streakCurrent != null || streakMax != null) {
+ const highestStreak = Math.max(
+ streakCurrent != null ? streakCurrent : 0,
+ streakMax != null ? streakMax : 0
+ );
+ if (highestStreak >= 6) streakSeverity = ' err';
+ else if (highestStreak > 0) streakSeverity = ' warn';
+ else streakSeverity = ' good';
+ }
+ streakEl.textContent = streakLabel;
+ streakEl.className = 'val' + streakSeverity;
+ }
+
const last = Math.max(state.server.lastConfigAt || 0, state.server.lastRuntimeAt || 0);
updateText('health-last', ageString(last));