fix(music): add wav chunk diagnostics and larger chunks

Increase live WAV chunk size to one second and log chunk acceptance, queue depth, and retry state on stations so the HQ speaker path can be diagnosed from runtime logs.
This commit is contained in:
2026-07-31 22:46:47 +08:00
parent f7755953b4
commit 87e45de15b
2 changed files with 29 additions and 2 deletions
+2 -2
View File
@@ -324,7 +324,7 @@ async function sendLiveWavChunksToStation(stationName, fallbackWs, task) {
const sampleRate = 48000; const sampleRate = 48000;
const channels = 1; const channels = 1;
const bitsPerSample = 16; const bitsPerSample = 16;
const chunkDurationSec = 0.25; const chunkDurationSec = 1.0;
const chunkBytes = Math.max(4096, Math.floor(sampleRate * channels * (bitsPerSample / 8) * chunkDurationSec)); const chunkBytes = Math.max(4096, Math.floor(sampleRate * channels * (bitsPerSample / 8) * chunkDurationSec));
targetWs.send(JSON.stringify({ targetWs.send(JSON.stringify({
@@ -344,7 +344,7 @@ async function sendLiveWavChunksToStation(stationName, fallbackWs, task) {
const ffmpegArgs = ['-hide_banner', '-loglevel', 'error']; const ffmpegArgs = ['-hide_banner', '-loglevel', 'error'];
if (loop) ffmpegArgs.push('-stream_loop', '-1'); if (loop) ffmpegArgs.push('-stream_loop', '-1');
ffmpegArgs.push('-re', '-i', sourcePath, '-f', 's16le', '-acodec', 'pcm_s16le', '-ac', String(channels), '-ar', String(sampleRate), 'pipe:1'); ffmpegArgs.push('-re', '-i', sourcePath, '-f', 's16le', '-acodec', 'pcm_s16le', '-ac', String(channels), '-ar', String(sampleRate), 'pipe:1');
log('INFO', `Live WAV chunk stream start for ${stationName}: ${path.basename(sourcePath)}${loop ? ' (loop)' : ''}`); log('INFO', `Live WAV chunk stream start for ${stationName}: ${path.basename(sourcePath)}${loop ? ' (loop)' : ''} chunk=${chunkDurationSec}s`);
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
let stderr = ''; let stderr = '';
+27
View File
@@ -799,15 +799,29 @@ end
local function pushWavChunkToSpeakers(payload, playSeq) local function pushWavChunkToSpeakers(payload, playSeq)
local controller = Peripherals.speakers and Peripherals.speakers[1] or nil local controller = Peripherals.speakers and Peripherals.speakers[1] or nil
if controller and type(controller.speakWavAll) == "function" then if controller and type(controller.speakWavAll) == "function" then
local retryCount = 0
while true do while true do
if shouldStop(playSeq) then return false end if shouldStop(playSeq) then return false end
local ok = false local ok = false
local queueSize = -1
local isPlaying = false
pcall(function() pcall(function()
ok = controller.speakWavAll(payload, CONFIG.AUDIO_VOLUME) ok = controller.speakWavAll(payload, CONFIG.AUDIO_VOLUME)
if type(controller.speakQueueSize) == "function" then
queueSize = tonumber(controller.speakQueueSize()) or -1
end
if type(controller.speakIsPlaying) == "function" then
isPlaying = controller.speakIsPlaying() and true or false
end
end) end)
if ok then if ok then
Utils.log("INFO", string.format("WAV chunk accepted: bytes=%d queue=%d playing=%s", #payload, queueSize, tostring(isPlaying)))
return true return true
end end
retryCount = retryCount + 1
if retryCount == 1 or retryCount % 20 == 0 then
Utils.log("WARN", string.format("WAV chunk waiting: bytes=%d queue=%d playing=%s retries=%d", #payload, queueSize, tostring(isPlaying), retryCount))
end
if not waitForInterruptibleDelay(playSeq, 0.05) then if not waitForInterruptibleDelay(playSeq, 0.05) then
return false return false
end end
@@ -820,6 +834,7 @@ local function pushWavChunkToSpeakers(payload, playSeq)
if name then pending[name] = sp end if name then pending[name] = sp end
end end
local retryCount = 0
while next(pending) do while next(pending) do
if shouldStop(playSeq) then return false end if shouldStop(playSeq) then return false end
for name, sp in pairs(pending) do for name, sp in pairs(pending) do
@@ -831,6 +846,18 @@ local function pushWavChunkToSpeakers(payload, playSeq)
end) end)
if ok then pending[name] = nil end if ok then pending[name] = nil end
end end
if next(pending) then
retryCount = retryCount + 1
if retryCount == 1 or retryCount % 20 == 0 then
local pendingCount = 0
for _ in pairs(pending) do
pendingCount = pendingCount + 1
end
Utils.log("WARN", string.format("WAV chunk waiting on %d speakers: bytes=%d retries=%d", pendingCount, #payload, retryCount))
end
else
Utils.log("INFO", string.format("WAV chunk accepted by fallback speakers: bytes=%d", #payload))
end
if next(pending) and not waitForInterruptibleDelay(playSeq, 0.05) then if next(pending) and not waitForInterruptibleDelay(playSeq, 0.05) then
return false return false
end end