diff --git a/CloudServer/server.js b/CloudServer/server.js index 652638c..4c87be1 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 = 1.0; + const chunkDurationSec = 0.5; const chunkBytes = Math.max(4096, Math.floor(sampleRate * channels * (bitsPerSample / 8) * chunkDurationSec)); targetWs.send(JSON.stringify({ diff --git a/station_broadcast.lua b/station_broadcast.lua index 8c7fc2f..4e74fea 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -2,7 +2,7 @@ -- ============================================================================ -- 1. Configuration & Constants -- ============================================================================ -local APP_VERSION_TEXT = "v1.0.3" +local APP_VERSION_TEXT = "v1.0.4" local CONFIG = { CLOUD_URL = "ws://stabadmin.fse-media.group", @@ -591,8 +591,30 @@ local function waitForInterruptibleDelay(playSeq, seconds) end end -local function playChunkOnSpeakers(samples, volume, playSeq) +local function waitForNativeSpeakersEmpty(speakers, playSeq) + local waiting = {} + for _, sp in ipairs(speakers or {}) do + local name = peripheral.getName(sp) + if name then waiting[name] = true end + end + + 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] == "speaker_audio_empty" and ev[2] and waiting[ev[2]] then + waiting[ev[2]] = nil + end + end + + return true +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 = {} for _, sp in ipairs(Peripherals.speakers) do local name = peripheral.getName(sp) @@ -645,24 +667,8 @@ local function playChunkOnSpeakers(samples, volume, playSeq) end end - local waiting = {} - for _, sp in ipairs(Peripherals.speakers) do - local name = peripheral.getName(sp) - if name then waiting[name] = true end - end - - 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] == "speaker_audio_empty" and ev[2] and waiting[ev[2]] then - waiting[ev[2]] = nil - end - end - - return true + if not waitForDrain then return true end + return waitForNativeSpeakersEmpty(Peripherals.speakers, playSeq) end local function decodePcmS8Chunk(chunk) @@ -1105,7 +1111,7 @@ function Audio.playWavStreamItem(item) tonumber(meta and meta.channels) or 0, tonumber(meta and meta.bitsPerSample) or 0 )) - if not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq) then + if not playChunkOnSpeakers(samples, CONFIG.AUDIO_VOLUME, playSeq, false) then Audio.stop("current") return end @@ -1119,6 +1125,11 @@ function Audio.playWavStreamItem(item) end end + if not waitForNativeSpeakersEmpty(Peripherals.speakers, playSeq) then + Audio.stop("current") + return + end + while areHqSpeakersBusy(Peripherals.speakers) do if shouldStop(playSeq) then Audio.stop("current")