perf(audio): 优化音频播放帧处理逻辑,升级版本至v1.0.50

- 为test.lua添加标准文件头部注释
- 将station_broadcast.lua版本从v1.0.49更新至v1.0.50
- 新增NATIVE_AUDIO_FRAME_SAMPLES常量,将音频处理拆分为128样本每帧
- 修复空音频样本输入的边界异常问题
- 优化原生扬声器播放的循环逻辑,提升兼容性与执行效率
This commit is contained in:
2026-08-03 09:49:01 +08:00
parent 394f81b9fa
commit bf1895ebc5
+61 -33
View File
@@ -1,6 +1,6 @@
-- 1. Configuration & Constants
local APP_VERSION_TEXT = "v1.0.49"
local APP_VERSION_TEXT = "v1.0.50"
local CONFIG = {
CLOUD_URL = "ws://stabadmin.fse-media.group",
@@ -32,6 +32,8 @@ local COLORS = {
SUCCESS = colors.green
}
local NATIVE_AUDIO_FRAME_SAMPLES = 128
-- 2. State Management
@@ -1170,46 +1172,70 @@ end
local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
if not Peripherals.speakers or #Peripherals.speakers == 0 then return false end
if waitForDrain == nil then waitForDrain = true end
local pending = {}
local totalSamples = #samples
if totalSamples == 0 then return true end
local speakerMap = {}
local nativeSpeakerCount = 0
for _, sp in ipairs(Peripherals.speakers) do
local name = peripheral.getName(sp)
if name then pending[name] = sp end
end
local usedNativePath = false
while next(pending) do
if shouldStop(playSeq) then return false end
for name, sp in pairs(pending) do
local ok = false
pcall(function()
if type(sp.playAudio) == "function" then
ok = sp.playAudio(samples, volume)
end
end)
if ok then
usedNativePath = true
pending[name] = nil
if name then
speakerMap[name] = sp
if type(sp.playAudio) == "function" then
nativeSpeakerCount = nativeSpeakerCount + 1
end
end
if next(pending) then
local ev = { os.pullEvent() }
if ev[1] == "audio_interrupt" and tonumber(ev[2]) and tonumber(ev[2]) >= playSeq then
end
local controller = Peripherals.speakers[1]
local usedNativePath = false
for frameStart = 1, totalSamples, NATIVE_AUDIO_FRAME_SAMPLES do
local frameEnd = math.min(frameStart + NATIVE_AUDIO_FRAME_SAMPLES - 1, totalSamples)
local frame = {}
for i = frameStart, frameEnd do
frame[#frame + 1] = samples[i]
end
if nativeSpeakerCount > 0 then
local pending = {}
for name, sp in pairs(speakerMap) do
if type(sp.playAudio) == "function" then
pending[name] = sp
end
end
while next(pending) do
if shouldStop(playSeq) then return false end
for name, sp in pairs(pending) do
local ok = false
pcall(function()
ok = sp.playAudio(frame, volume)
end)
if ok then
usedNativePath = true
pending[name] = nil
end
end
if next(pending) then
local ev = { os.pullEvent() }
if ev[1] == "audio_interrupt" and tonumber(ev[2]) and tonumber(ev[2]) >= playSeq then
return false
end
end
end
else
if not controller or type(controller.playAudioAll) ~= "function" then
return false
end
end
end
if usedNativePath then
Utils.log("INFO", string.format("Audio samples queued via native speaker.playAudio: samples=%d", #samples))
else
local controller = Peripherals.speakers[1]
if controller and type(controller.playAudioAll) == "function" then
Utils.log("WARN", "Falling back to controller.playAudioAll for decoded samples")
if frameStart == 1 then
Utils.log("WARN", "Falling back to controller.playAudioAll for decoded samples")
end
while true do
if shouldStop(playSeq) then return false end
local ok = false
pcall(function()
ok = controller.playAudioAll(samples, volume)
ok = controller.playAudioAll(frame, volume)
end)
if ok then break end
local ev = { os.pullEvent() }
@@ -1217,11 +1243,13 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
return false
end
end
else
return false
end
end
if usedNativePath then
Utils.log("INFO", string.format("Audio samples queued via native speaker.playAudio: samples=%d frame=%d", totalSamples, NATIVE_AUDIO_FRAME_SAMPLES))
end
if not waitForDrain then return true end
return waitForNativeSpeakersEmpty(Peripherals.speakers, playSeq)
end