| @@ -1167,6 +1167,8 @@ input.input-error { | |||||
| <div class="health-line"><div class="name">Fault Count</div><div class="val" id="health-fault-count">--</div></div> | <div class="health-line"><div class="name">Fault Count</div><div class="val" id="health-fault-count">--</div></div> | ||||
| <div class="health-line"><div class="name">Last Fault</div><div class="val" id="health-last-fault">--</div></div> | <div class="health-line"><div class="name">Last Fault</div><div class="val" id="health-last-fault">--</div></div> | ||||
| <div class="health-line"><div class="name">Audio Buffer</div><div class="val" id="health-audio">--</div></div> | <div class="health-line"><div class="name">Audio Buffer</div><div class="val" id="health-audio">--</div></div> | ||||
| <div class="health-line"><div class="name">Buffer Duration</div><div class="val" id="health-buffer-duration">--</div></div> | |||||
| <div class="health-line"><div class="name">High Watermark</div><div class="val" id="health-buffer-highwater">--</div></div> | |||||
| <div class="health-line"><div class="name">Last Update</div><div class="val" id="health-last">--</div></div> | <div class="health-line"><div class="name">Last Update</div><div class="val" id="health-last">--</div></div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -1720,6 +1722,12 @@ function fmtTime(seconds) { | |||||
| return `${s}s`; | return `${s}s`; | ||||
| } | } | ||||
| function fmtDurationSeconds(value) { | |||||
| if (!Number.isFinite(value) || value < 0) return '--'; | |||||
| if (value >= 1) return `${value.toFixed(2)} s`; | |||||
| return `${(value * 1000).toFixed(0)} ms`; | |||||
| } | |||||
| function fmtBool(v) { | function fmtBool(v) { | ||||
| return v == null ? '--' : (v ? 'ON' : 'OFF'); | return v == null ? '--' : (v ? 'ON' : 'OFF'); | ||||
| } | } | ||||
| @@ -2079,6 +2087,24 @@ function updateHealth(engine, audioStream) { | |||||
| updateText('health-audio', audioLabel); | updateText('health-audio', audioLabel); | ||||
| $('health-audio').className = audioClass; | $('health-audio').className = audioClass; | ||||
| const bufferedDurationSeconds = Number(audioStream?.bufferedDurationSeconds); | |||||
| updateText('health-buffer-duration', fmtDurationSeconds(bufferedDurationSeconds)); | |||||
| const highWatermarkRaw = audioStream?.highWatermark; | |||||
| const highWatermarkFrames = Number.isFinite(Number(highWatermarkRaw)) ? Number(highWatermarkRaw) : null; | |||||
| const highWatermarkDurationRaw = audioStream?.highWatermarkDurationSeconds; | |||||
| const highWatermarkDuration = Number.isFinite(Number(highWatermarkDurationRaw)) ? Number(highWatermarkDurationRaw) : null; | |||||
| let highWatermarkLabel = '--'; | |||||
| if (highWatermarkDuration !== null) { | |||||
| highWatermarkLabel = fmtDurationSeconds(highWatermarkDuration); | |||||
| if (highWatermarkFrames !== null) { | |||||
| highWatermarkLabel += ` (${highWatermarkFrames} frames)`; | |||||
| } | |||||
| } else if (highWatermarkFrames !== null) { | |||||
| highWatermarkLabel = `${highWatermarkFrames} frames`; | |||||
| } | |||||
| updateText('health-buffer-highwater', highWatermarkLabel); | |||||
| const last = Math.max(state.server.lastConfigAt || 0, state.server.lastRuntimeAt || 0); | const last = Math.max(state.server.lastConfigAt || 0, state.server.lastRuntimeAt || 0); | ||||
| updateText('health-last', ageString(last)); | updateText('health-last', ageString(last)); | ||||