fix(audio): 修复导致完全没有声音的回归错误,添加超时防止挂起,修复等待缓冲区清空的逻辑

This commit is contained in:
2026-08-16 11:58:31 +08:00
parent af00d57e68
commit 1d99634957
2 changed files with 26 additions and 4 deletions
+5
View File
@@ -61,6 +61,7 @@ local function playDfpwmFile(path, volume)
for _, sp in ipairs(speakers) do
pending[peripheral.getName(sp)] = sp
end
local maxAttempts = 20
while next(pending) do
for name, sp in pairs(pending) do
if sp.playAudio(samples, volume) then
@@ -68,6 +69,10 @@ local function playDfpwmFile(path, volume)
end
end
if next(pending) then
maxAttempts = maxAttempts - 1
if maxAttempts <= 0 then
break
end
local timerId = os.startTimer(0.05)
while true do
local ev = { os.pullEvent() }
+21 -4
View File
@@ -1,6 +1,6 @@
-- 1. Configuration & Constants
local APP_VERSION_TEXT = "v1.0.66"
local APP_VERSION_TEXT = "v1.0.67"
local CONFIG = {
CLOUD_URL = "ws://stabadmin.fse-media.group",
@@ -1216,12 +1216,17 @@ local function waitForNativeSpeakersEmpty(speakers, playSeq)
if name then waiting[name] = true end
end
local timerId = os.startTimer(2.0) -- Maximum 2 seconds wait for empty
while next(waiting) do
if shouldStop(playSeq) then return false end
local ev = { os.pullEvent() }
if ev[1] == "audio_interrupt" and tonumber(ev[2]) and tonumber(ev[2]) >= playSeq then
return false
end
if ev[1] == "timer" and ev[2] == timerId then
Utils.log("WARN", "Timeout waiting for native speakers to empty")
break
end
if ev[1] == "speaker_audio_empty" and ev[2] and waiting[ev[2]] then
waiting[ev[2]] = nil
end
@@ -1284,6 +1289,7 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
end
local usedNativePath = false
local maxAttempts = 20
while next(pending) do
if shouldStop(playSeq) then return false end
for name, sp in pairs(pending) do
@@ -1299,6 +1305,11 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
end
end
if next(pending) then
maxAttempts = maxAttempts - 1
if maxAttempts <= 0 then
Utils.log("WARN", "Speaker buffer full or failed, skipping chunk")
break
end
local timerId = os.startTimer(0.05)
while true do
local ev = { os.pullEvent() }
@@ -1319,6 +1330,7 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
local controller = Peripherals.speakers[1]
if controller and type(controller.playAudioAll) == "function" then
Utils.log("WARN", "Falling back to controller.playAudioAll for decoded samples")
local maxAttempts = 20
while true do
if shouldStop(playSeq) then return false end
local ok = false
@@ -1326,6 +1338,11 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
ok = controller.playAudioAll(samples, volume)
end)
if ok then break end
maxAttempts = maxAttempts - 1
if maxAttempts <= 0 then
Utils.log("WARN", "Controller buffer full or failed, skipping chunk")
break
end
local timerId = os.startTimer(0.05)
while true do
local ev = { os.pullEvent() }
@@ -1765,7 +1782,7 @@ function Audio.playDfpwmItem(item)
if chunk == nil then break end
if type(chunk) == "string" and #chunk > 0 then
local samples = decoder(chunk)
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq) then
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq, false) then
break
end
end
@@ -1826,7 +1843,7 @@ function Audio.playPcmItem(item)
if chunk == nil then break end
if type(chunk) == "string" and #chunk > 0 then
local samples = decodePcmS8Chunk(chunk)
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq) then
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq, false) then
Audio.stop("current")
break
end
@@ -1888,7 +1905,7 @@ function Audio.playPcmS16LEItem(item)
if chunk == nil then break end
if type(chunk) == "string" and #chunk > 0 then
local samples = decodePcmS16LEChunk(chunk)
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq) then
if samples and not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq, false) then
Audio.stop("current")
break
end