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:
@@ -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 = '';
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user