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:
+42
-14
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
-- 1. Configuration & Constants
|
-- 1. Configuration & Constants
|
||||||
local APP_VERSION_TEXT = "v1.0.49"
|
local APP_VERSION_TEXT = "v1.0.50"
|
||||||
|
|
||||||
local CONFIG = {
|
local CONFIG = {
|
||||||
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
||||||
@@ -32,6 +32,8 @@ local COLORS = {
|
|||||||
SUCCESS = colors.green
|
SUCCESS = colors.green
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local NATIVE_AUDIO_FRAME_SAMPLES = 128
|
||||||
|
|
||||||
|
|
||||||
-- 2. State Management
|
-- 2. State Management
|
||||||
|
|
||||||
@@ -1170,21 +1172,45 @@ end
|
|||||||
local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
|
local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
|
||||||
if not Peripherals.speakers or #Peripherals.speakers == 0 then return false end
|
if not Peripherals.speakers or #Peripherals.speakers == 0 then return false end
|
||||||
if waitForDrain == nil then waitForDrain = true 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
|
for _, sp in ipairs(Peripherals.speakers) do
|
||||||
local name = peripheral.getName(sp)
|
local name = peripheral.getName(sp)
|
||||||
if name then pending[name] = sp end
|
if name then
|
||||||
|
speakerMap[name] = sp
|
||||||
|
if type(sp.playAudio) == "function" then
|
||||||
|
nativeSpeakerCount = nativeSpeakerCount + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local controller = Peripherals.speakers[1]
|
||||||
local usedNativePath = false
|
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
|
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
|
||||||
local ok = false
|
local ok = false
|
||||||
pcall(function()
|
pcall(function()
|
||||||
if type(sp.playAudio) == "function" then
|
ok = sp.playAudio(frame, volume)
|
||||||
ok = sp.playAudio(samples, volume)
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
if ok then
|
if ok then
|
||||||
usedNativePath = true
|
usedNativePath = true
|
||||||
@@ -1198,18 +1224,18 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if usedNativePath then
|
|
||||||
Utils.log("INFO", string.format("Audio samples queued via native speaker.playAudio: samples=%d", #samples))
|
|
||||||
else
|
else
|
||||||
local controller = Peripherals.speakers[1]
|
if not controller or type(controller.playAudioAll) ~= "function" then
|
||||||
if controller and type(controller.playAudioAll) == "function" then
|
return false
|
||||||
|
end
|
||||||
|
if frameStart == 1 then
|
||||||
Utils.log("WARN", "Falling back to controller.playAudioAll for decoded samples")
|
Utils.log("WARN", "Falling back to controller.playAudioAll for decoded samples")
|
||||||
|
end
|
||||||
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
|
||||||
pcall(function()
|
pcall(function()
|
||||||
ok = controller.playAudioAll(samples, volume)
|
ok = controller.playAudioAll(frame, volume)
|
||||||
end)
|
end)
|
||||||
if ok then break end
|
if ok then break end
|
||||||
local ev = { os.pullEvent() }
|
local ev = { os.pullEvent() }
|
||||||
@@ -1217,11 +1243,13 @@ local function playChunkOnSpeakers(samples, volume, playSeq, waitForDrain)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
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
|
if not waitForDrain then return true end
|
||||||
return waitForNativeSpeakersEmpty(Peripherals.speakers, playSeq)
|
return waitForNativeSpeakersEmpty(Peripherals.speakers, playSeq)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user