From 87e45de15bb409df13c36fae4d1493fc37fa4e1c Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Fri, 31 Jul 2026 22:46:47 +0800 Subject: [PATCH] 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. --- CloudServer/server.js | 4 ++-- station_broadcast.lua | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CloudServer/server.js b/CloudServer/server.js index d796e83..2935089 100644 --- a/CloudServer/server.js +++ b/CloudServer/server.js @@ -324,7 +324,7 @@ async function sendLiveWavChunksToStation(stationName, fallbackWs, task) { const sampleRate = 48000; const channels = 1; const bitsPerSample = 16; - const chunkDurationSec = 0.25; + const chunkDurationSec = 1.0; const chunkBytes = Math.max(4096, Math.floor(sampleRate * channels * (bitsPerSample / 8) * chunkDurationSec)); targetWs.send(JSON.stringify({ @@ -344,7 +344,7 @@ async function sendLiveWavChunksToStation(stationName, fallbackWs, task) { const ffmpegArgs = ['-hide_banner', '-loglevel', 'error']; 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'); - 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) => { let stderr = ''; diff --git a/station_broadcast.lua b/station_broadcast.lua index 94fe81e..afe3278 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -799,15 +799,29 @@ end local function pushWavChunkToSpeakers(payload, playSeq) local controller = Peripherals.speakers and Peripherals.speakers[1] or nil if controller and type(controller.speakWavAll) == "function" then + local retryCount = 0 while true do if shouldStop(playSeq) then return false end local ok = false + local queueSize = -1 + local isPlaying = false pcall(function() 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) if ok then + Utils.log("INFO", string.format("WAV chunk accepted: bytes=%d queue=%d playing=%s", #payload, queueSize, tostring(isPlaying))) return true 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 return false end @@ -820,6 +834,7 @@ local function pushWavChunkToSpeakers(payload, playSeq) if name then pending[name] = sp end end + local retryCount = 0 while next(pending) do if shouldStop(playSeq) then return false end for name, sp in pairs(pending) do @@ -831,6 +846,18 @@ local function pushWavChunkToSpeakers(payload, playSeq) end) if ok then pending[name] = nil 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 return false end