From c73bceaec7e9837e35b5db4bab738578a2c3a9c7 Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Fri, 31 Jul 2026 19:29:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=A4=96=E9=83=A8?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E5=B9=B6=E6=96=B0=E5=A2=9EWAV=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除install和update脚本中的aukit/austream下载配置与目标,不再部署辅助脚本 - 替换station_broadcast.lua的aukit库为CC内置dfpwm模块,重写音频播放逻辑 - 添加原生扬声器API支持,支持WAV格式音频播放 - 重写云端服务器音频处理逻辑,支持直接传输WAV文件无需预转换 - 新增WAV文件时长解析、音频序列合成等辅助功能 --- CloudServer/server.js | 183 ++++++++++++++++++-------------- install_station_broadcast.lua | 8 +- station_broadcast-warning.lua | 50 ++++++++- station_broadcast.lua | 191 +++++++++++++++++++++++++++++----- update_station_broadcast.lua | 8 +- 5 files changed, 320 insertions(+), 120 deletions(-) diff --git a/CloudServer/server.js b/CloudServer/server.js index 9fa6cc5..9e604bb 100644 --- a/CloudServer/server.js +++ b/CloudServer/server.js @@ -177,21 +177,23 @@ function sendAudioControl(stationName, msg, fallbackWs) { } } -async function sendDfpwmBufferToStation(stationName, fallbackWs, task) { +async function sendAudioBufferToStation(stationName, fallbackWs, task) { const targetWs = getStationWs(stationName, fallbackWs); if (!targetWs) throw new Error(`Station "${stationName}" not connected`); const audioId = String(task.audioId || `${Date.now()}-${Math.random().toString(16).slice(2)}`); const buf = task.buffer; - const durationSec = buf.length / 6000; + const durationSec = Number(task.durationSec || 0); + const audioFormat = String(task.audioFormat || 'dfpwm').toLowerCase(); const startMsg = { type: 'audio_start', stationName, audioId, byteLength: buf.length, - sampleRate: 48000, - channels: 1, + sampleRate: Number(task.sampleRate || 48000), + channels: Number(task.channels || 1), + audioFormat, priority: Number(task.priority || 0), interruptMode: task.interruptMode || getInterruptModeForPriority(Number(task.priority || 0)), source: task.source || 'unknown' @@ -254,29 +256,73 @@ function listMusicTracks() { return Array.from(out).sort((a, b) => a.localeCompare(b)); } -function getDfpwmBufferByBaseName(baseName) { +function getWavDurationSec(buffer) { + if (!Buffer.isBuffer(buffer) || buffer.length < 44) return 0; + if (buffer.toString('ascii', 0, 4) !== 'RIFF' || buffer.toString('ascii', 8, 12) !== 'WAVE') return 0; + + let offset = 12; + let sampleRate = 0; + let channels = 0; + let bitsPerSample = 0; + let dataSize = 0; + + while (offset + 8 <= buffer.length) { + const chunkId = buffer.toString('ascii', offset, offset + 4); + const chunkSize = buffer.readUInt32LE(offset + 4); + const dataOffset = offset + 8; + if (dataOffset + chunkSize > buffer.length) break; + + if (chunkId === 'fmt ' && chunkSize >= 16) { + channels = buffer.readUInt16LE(dataOffset + 2); + sampleRate = buffer.readUInt32LE(dataOffset + 4); + bitsPerSample = buffer.readUInt16LE(dataOffset + 14); + } else if (chunkId === 'data') { + dataSize = chunkSize; + break; + } + + offset = dataOffset + chunkSize + (chunkSize % 2); + } + + if (!sampleRate || !channels || !bitsPerSample || !dataSize) return 0; + return dataSize / (sampleRate * channels * (bitsPerSample / 8)); +} + +function getPlaybackAudioByBaseName(baseName) { const base = normalizeBaseName(baseName); if (!base) throw new Error('Invalid track name'); + const wavCandidates = [ + path.join(audioGeneralDir, `${base}.wav`), + path.join(audioStationDir, `${base}.wav`) + ]; + for (const p of wavCandidates) { + if (fs.existsSync(p)) { + const buffer = fs.readFileSync(p); + return { + buffer, + audioFormat: 'wav', + durationSec: getWavDurationSec(buffer) || 0 + }; + } + } + const dfCandidates = [ path.join(audioGeneralDir, `${base}.dfpwm`), path.join(audioStationDir, `${base}.dfpwm`) ]; for (const p of dfCandidates) { - if (fs.existsSync(p)) return fs.readFileSync(p); + if (fs.existsSync(p)) { + const buffer = fs.readFileSync(p); + return { + buffer, + audioFormat: 'dfpwm', + durationSec: buffer.length / 6000 + }; + } } - const wavCandidates = [ - path.join(audioGeneralDir, `${base}.wav`), - path.join(audioStationDir, `${base}.wav`) - ]; - const wavPath = wavCandidates.find(p => fs.existsSync(p)) || null; - if (!wavPath) throw new Error(`Audio not found: ${base}`); - - const dfpwmPath = wavPath.replace(/\.wav$/i, '.dfpwm'); - if (!fs.existsSync(dfpwmPath)) convertToDfpwm(wavPath); - if (!fs.existsSync(dfpwmPath)) throw new Error(`DFPWM build failed: ${base}`); - return fs.readFileSync(dfpwmPath); + throw new Error(`Audio not found: ${base}`); } function stopStationMusic(stationName, fallbackWs) { @@ -357,7 +403,7 @@ async function processStationAudioQueue(stationName, fallbackWs) { try { if (task.consoleStreamStart) broadcastToConsole(task.consoleStreamStart); - const result = await sendDfpwmBufferToStation(cleanStation, fallbackWs, task); + const result = await sendAudioBufferToStation(cleanStation, fallbackWs, task); if (task.consoleStreamEnd) { if (result.cancelled) { broadcastToConsole(task.consoleStreamEnd); @@ -767,6 +813,25 @@ function buildConcatListFile(seq) { return listPath; } +function buildSequenceWavBuffer(seq) { + const listPath = buildConcatListFile(seq); + if (!listPath) return null; + + const outWavPath = path.join(tmpDir, `sequence-${Date.now()}-${Math.random().toString(16).slice(2)}.wav`); + try { + execSync(`ffmpeg -hide_banner -loglevel error -y -f concat -safe 0 -i "${listPath}" -ac 1 -ar 48000 -c:a pcm_s16le "${outWavPath}"`); + const buffer = fs.readFileSync(outWavPath); + return { + buffer, + audioFormat: 'wav', + durationSec: getWavDurationSec(buffer) || 0 + }; + } finally { + try { fs.unlinkSync(listPath); } catch {} + try { fs.unlinkSync(outWavPath); } catch {} + } +} + function runFfmpegRtmpPush(streamName, seq) { const state = getOrCreateHlsStreamState(streamName); const listPath = buildConcatListFile(seq); @@ -1412,52 +1477,8 @@ function handlePlaySequence(ws, data) { log('INFO', `Playing sequence for ${correctStation}: ${seq.join(', ')}`); - // Process files sequentially - let combinedBuffer = []; - for (const file of seq) { - if (file === '__DELAY_1__') { - const silence = Buffer.alloc(6000, 0xAA); - combinedBuffer.push(silence); - continue; - } - - let foundPath = null; - - const candidates = [ - path.join(audioStationDir, `${file}.dfpwm`), - path.join(audioGeneralDir, `${file}.dfpwm`), - path.join(audioStationDir, `${file}.wav`), - path.join(audioGeneralDir, `${file}.wav`) - ]; - - for (const p of candidates) { - if (fs.existsSync(p)) { - foundPath = p; - break; - } - } - - if (foundPath) { - let dfpwmPath = foundPath; - if (foundPath.endsWith('.wav')) { - dfpwmPath = foundPath.replace(/\.wav$/, '.dfpwm'); - if (!fs.existsSync(dfpwmPath)) { - convertToDfpwm(foundPath); - } - } - - if (fs.existsSync(dfpwmPath)) { - combinedBuffer.push(fs.readFileSync(dfpwmPath)); - } else { - log('WARN', `Could not get DFPWM for: ${file}`); - } - } else { - log('WARN', `Audio missing on server: ${file}`); - } - } - - if (combinedBuffer.length > 0) { - const finalBuffer = Buffer.concat(combinedBuffer); + const builtAudio = buildSequenceWavBuffer(seq); + if (builtAudio) { const priority = Number.isFinite(Number(data.priority)) ? Number(data.priority) : (String(data.category || '').toLowerCase() === 'station' ? 0 : 1); @@ -1467,7 +1488,9 @@ function handlePlaySequence(ws, data) { const audioId = String(requestId || `${Date.now()}-${Math.random().toString(16).slice(2)}`); enqueueStationAudioTask(cleanStation, ws, { - buffer: finalBuffer, + buffer: builtAudio.buffer, + audioFormat: builtAudio.audioFormat, + durationSec: builtAudio.durationSec, priority, interruptMode, source, @@ -1476,6 +1499,8 @@ function handlePlaySequence(ws, data) { consoleStreamStart: { type: 'stream_start', station: cleanStation, seq: seq, streamName, hlsUrl }, consoleStreamEnd: { type: 'stream_end', station: cleanStation } }); + } else { + log('WARN', `Unable to build WAV sequence for ${cleanStation}`); } } @@ -2171,18 +2196,12 @@ function buildTempBroadcastFromWav(prefixWavPath, contentWavPath) { ].join(';'); execSync(`ffmpeg -hide_banner -loglevel error -y -i "${prefixWavPath}" -i "${contentWavPath}" -filter_complex "${filterComplex}" -map "[a]" -ac 1 -ar 48000 -c:a pcm_s16le "${outWavPath}"`); - - convertToDfpwm(outWavPath); - - const dfpwmPath = outWavPath.replace(/\.wav$/i, '.dfpwm'); - if (!fs.existsSync(dfpwmPath)) throw new Error('DFPWM build failed'); - const dfpwmBuf = fs.readFileSync(dfpwmPath); - const durationSec = dfpwmBuf.length / 6000; + const wavBuf = fs.readFileSync(outWavPath); + const durationSec = getWavDurationSec(wavBuf) || 0; return { broadcastId, wavPath: outWavPath, - dfpwmPath, durationSec }; } @@ -2254,10 +2273,10 @@ app.post('/api/temp-broadcast/publish', (req, res) => { if (urgency !== 'normal' && urgency !== 'emergency') return res.status(400).json({ success: false, message: 'Invalid urgency' }); const wavPath = path.join(tempBroadcastDir, `temp_${broadcastId}.wav`); - const dfpwmPath = wavPath.replace(/\.wav$/i, '.dfpwm'); - if (!fs.existsSync(dfpwmPath)) return res.status(404).json({ success: false, message: 'Temp broadcast not found (dfpwm)' }); + if (!fs.existsSync(wavPath)) return res.status(404).json({ success: false, message: 'Temp broadcast not found (wav)' }); - const dfpwmBuf = fs.readFileSync(dfpwmPath); + const wavBuf = fs.readFileSync(wavPath); + const durationSec = getWavDurationSec(wavBuf) || 0; const priority = urgency === 'emergency' ? 2 : 0; const interruptMode = urgency === 'emergency' ? 'all' : 'none'; const source = urgency === 'emergency' ? 'temp_emergency' : 'temp_normal'; @@ -2277,7 +2296,9 @@ app.post('/api/temp-broadcast/publish', (req, res) => { continue; } enqueueStationAudioTask(name, ws, { - buffer: dfpwmBuf, + buffer: wavBuf, + audioFormat: 'wav', + durationSec, priority, interruptMode, source, @@ -2305,9 +2326,9 @@ app.post('/api/music/start', express.json(), (req, res) => { if (!track) return res.status(400).json({ success: false, message: 'track required' }); if (!Array.isArray(stationsReq) || stationsReq.length === 0) return res.status(400).json({ success: false, message: 'stations required' }); - let dfpwmBuf; + let playbackAudio; try { - dfpwmBuf = getDfpwmBufferByBaseName(track); + playbackAudio = getPlaybackAudioByBaseName(track); } catch (e) { return res.status(404).json({ success: false, message: e?.message || String(e) }); } @@ -2338,7 +2359,9 @@ app.post('/api/music/start', express.json(), (req, res) => { } enqueueStationAudioTask(name, currentWs, { - buffer: dfpwmBuf, + buffer: playbackAudio.buffer, + audioFormat: playbackAudio.audioFormat, + durationSec: playbackAudio.durationSec, priority: -1, interruptMode: 'none', source: 'music', diff --git a/install_station_broadcast.lua b/install_station_broadcast.lua index 9678391..f3e7184 100644 --- a/install_station_broadcast.lua +++ b/install_station_broadcast.lua @@ -1,6 +1,4 @@ -local STATION_BROADCAST_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/station_broadcast.lua?sign=xXsMwezjnEs4c6QrjkJkbvz1rARokmm87zwDcDDS5dk=:0" -local AUKIT_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/aukit.lua?sign=02_QDktYbSrHrtCDsFlKMkbEOWJGDautZaOtWkvg5q8=:0" -local AUSTREAM_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/austream.lua?sign=DrLbf9CIX1ZY8DaL8vliZiCMQzGos10nhG26Wf5lbgA=:0" +local STATION_BROADCAST_URL = "https://gitea.fse-media.group/Henry_Du/CC-StationBroadcast/raw/commit/e4b4fa5cdb2bc42279fd87098fef0d27a90e23d5/station_broadcast.lua" local function fetch(url) if not http then @@ -66,9 +64,7 @@ local function downloadTo(url, path) end local targets = { - { url = STATION_BROADCAST_URL, path = shell.resolve("/startup") }, - { url = AUKIT_URL, path = shell.resolve("/aukit.lua") }, - { url = AUSTREAM_URL, path = shell.resolve("/austream.lua") } + { url = STATION_BROADCAST_URL, path = shell.resolve("/startup") } } for _, t in ipairs(targets) do diff --git a/station_broadcast-warning.lua b/station_broadcast-warning.lua index 22729fa..e405590 100644 --- a/station_broadcast-warning.lua +++ b/station_broadcast-warning.lua @@ -10,6 +10,8 @@ local COLORS = { SUCCESS = colors.green } +local dfpwm = require "cc.audio.dfpwm" + -- Debug output function local function debugPrint(level, message) local timestamp = os.date("%H:%M:%S") @@ -21,6 +23,52 @@ local function debugPrint(level, message) term.setTextColor(oldColor) end +local function playDfpwmFile(path, volume) + local speakers = { peripheral.find("speaker") } + if #speakers == 0 then + debugPrint("ERROR", "No speakers found") + return false + end + + local file = fs.open(path, "rb") + if not file then + debugPrint("ERROR", "Cannot open audio file: " .. path) + return false + end + + local decoder = dfpwm.make_decoder() + local controller = speakers[1] + while true do + local chunk = file.read(16 * 1024) + if not chunk then break end + local samples = decoder(chunk) + + if controller and type(controller.playAudioAll) == "function" then + while not controller.playAudioAll(samples, volume) do + os.pullEvent("speaker_audio_empty") + end + else + local pending = {} + for _, sp in ipairs(speakers) do + pending[peripheral.getName(sp)] = sp + end + while next(pending) do + for name, sp in pairs(pending) do + if sp.playAudio(samples, volume) then + pending[name] = nil + end + end + if next(pending) then + os.pullEvent("speaker_audio_empty") + end + end + end + end + + file.close() + return true +end + -- Add random audio playback function local function playRandomAudio() local audioFiles = {"aqtx", "jzxy"} @@ -29,7 +77,7 @@ local function playRandomAudio() if fs.exists(path) then debugPrint("INFO", "Attempting to play: "..path) - shell.run("austream "..path.." volume=3.0") + playDfpwmFile(path, 3.0) debugPrint("INFO", "Finished playing: "..randomFile) else debugPrint("ERROR", "Audio file not found: "..path) diff --git a/station_broadcast.lua b/station_broadcast.lua index b53fa6b..e94ff54 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -14,7 +14,7 @@ local CONFIG = { DEBUG = true } -local aukit = require "aukit" +local dfpwm = require "cc.audio.dfpwm" local COLORS = { INFO = colors.white, @@ -527,12 +527,14 @@ end function Audio.enqueueDfpwm(dfpwmData) if type(dfpwmData) ~= "string" or #dfpwmData == 0 then return end - Audio.enqueueItem({ dfpwmData = dfpwmData, priority = 1 }) + Audio.enqueueItem({ audioData = dfpwmData, audioFormat = "dfpwm", priority = 1 }) end function Audio.enqueueItem(item) if type(item) ~= "table" then return end - if type(item.dfpwmData) ~= "string" and type(item.dfpwmData) ~= "table" then return end + item.audioData = item.audioData or item.dfpwmData + item.audioFormat = tostring(item.audioFormat or (item.dfpwmData and "dfpwm") or "dfpwm"):lower() + if type(item.audioData) ~= "string" and type(item.audioData) ~= "table" then return end item.priority = tonumber(item.priority) or 0 local idx = 1 while idx <= #State.audioQueue do @@ -578,6 +580,19 @@ local function shouldStop(playSeq) return State.interruptSeq ~= playSeq end +local function waitForInterruptibleDelay(playSeq, seconds) + local timer = os.startTimer(seconds) + while true do + 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] == timer then + return true + end + end +end + local function playChunkOnSpeakers(samples, volume, playSeq) if not Peripherals.speakers or #Peripherals.speakers == 0 then return false end local controller = Peripherals.speakers[1] @@ -639,6 +654,82 @@ local function playChunkOnSpeakers(samples, volume, playSeq) return true end +local function areHqSpeakersBusy(speakers) + for _, sp in ipairs(speakers) do + local playing = false + local queued = 0 + pcall(function() + if type(sp.speakIsPlaying) == "function" then + playing = sp.speakIsPlaying() and true or false + end + if type(sp.speakQueueSize) == "function" then + queued = tonumber(sp.speakQueueSize()) or 0 + end + end) + if playing or queued > 0 then return true end + end + return false +end + +local function playHqAudioItem(item) + if not Peripherals.speakers or #Peripherals.speakers == 0 then + Utils.log("WARN", "No speakers found; cannot play audio") + return + end + + local playSeq = State.interruptSeq + local payload = item.audioData + if type(payload) ~= "string" or #payload == 0 then return end + + local format = tostring(item.audioFormat or "file"):lower() + local controller = Peripherals.speakers[1] + local called = false + + if controller then + local ok, result = pcall(function() + if format == "wav" and type(controller.speakWavAll) == "function" then + return controller.speakWavAll(payload, CONFIG.AUDIO_VOLUME) + elseif type(controller.speakFileAll) == "function" then + return controller.speakFileAll(payload, CONFIG.AUDIO_VOLUME) + end + end) + if ok and result ~= false then + called = true + end + end + + if not called then + for _, sp in ipairs(Peripherals.speakers) do + local ok, result = pcall(function() + if format == "wav" and type(sp.speakWav) == "function" then + return sp.speakWav(payload, CONFIG.AUDIO_VOLUME) + elseif type(sp.speakFile) == "function" then + return sp.speakFile(payload, CONFIG.AUDIO_VOLUME) + end + end) + if ok and result ~= false then + called = true + end + end + end + + if not called then + Utils.log("ERROR", "HQ speaker API not available for format " .. format) + return + end + + while areHqSpeakersBusy(Peripherals.speakers) do + if shouldStop(playSeq) then + Audio.stop("current") + return + end + if not waitForInterruptibleDelay(playSeq, 0.1) then + Audio.stop("current") + return + end + end +end + function Audio.playDfpwmItem(item) if not Peripherals.speakers or #Peripherals.speakers == 0 then Utils.log("WARN", "No speakers found; cannot play audio") @@ -646,25 +737,44 @@ function Audio.playDfpwmItem(item) end local playSeq = State.interruptSeq - local source = item.dfpwmData + local source = item.audioData -- Support both static string data and streaming functions if type(source) == "table" and source.read then source = source.read end - local ok, iter = pcall(aukit.stream.dfpwm, source, 48000, 1, false) - if not ok then - Utils.log("ERROR", "Failed to create audio stream: " .. tostring(iter)) - return + if type(source) ~= "function" then + local data = source + source = function() + local chunk = data + data = nil + return chunk + end end - for chunk in iter do + local decoder = dfpwm.make_decoder() + while true do if shouldStop(playSeq) then break end - if not playChunkOnSpeakers(chunk[1], CONFIG.AUDIO_VOLUME, playSeq) then break end + local chunk = source() + 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 + break + end + end end end +function Audio.playItem(item) + local format = tostring(item.audioFormat or "dfpwm"):lower() + if format == "wav" or format == "file" then + return playHqAudioItem(item) + end + return Audio.playDfpwmItem(item) +end + function Audio.playerLoop() while true do if #State.audioQueue == 0 then @@ -674,7 +784,7 @@ function Audio.playerLoop() State.currentPlaying = item State.currentPriority = tonumber(item.priority) or 0 - local ok, err = pcall(Audio.playDfpwmItem, item) + local ok, err = pcall(Audio.playItem, item) if not ok then Utils.log("ERROR", "Audio Playback Crash: " .. tostring(err)) end @@ -927,6 +1037,23 @@ function Network.syncFiles() end function Network.messageLoop() + local function finishAudioRx() + if not State.audioRx then return end + local rx = State.audioRx + if rx.stream then + rx.stream.finish() + else + Audio.enqueueItem({ + audioData = table.concat(rx.chunks or {}), + audioFormat = rx.audioFormat or "wav", + priority = rx.priority, + source = rx.source, + audioId = rx.audioId + }) + end + State.audioRx = nil + end + while true do local event, url, msg = os.pullEvent() if event == "websocket_message" and url == CONFIG.CLOUD_URL then @@ -937,6 +1064,7 @@ function Network.messageLoop() pcall(State.audioRx.stream.finish) end local priority = tonumber(data.priority) or 0 + local audioFormat = tostring(data.audioFormat or "dfpwm"):lower() local interruptMode = tostring(data.interruptMode or "") if interruptMode == "" then if priority >= 2 then interruptMode = "all" @@ -950,27 +1078,31 @@ function Network.messageLoop() Audio.stop("current", priority) end - local stream = Audio.createStream() State.audioRx = { audioId = data.audioId, expectedBytes = tonumber(data.byteLength) or 0, receivedBytes = 0, - stream = stream, priority = priority, - source = data.source or data.category + source = data.source or data.category, + audioFormat = audioFormat } - -- Start playing immediately by enqueuing the stream - Audio.enqueueItem({ - dfpwmData = stream, - priority = priority, - source = State.audioRx.source, - audioId = data.audioId - }) + if audioFormat == "dfpwm" then + local stream = Audio.createStream() + State.audioRx.stream = stream + Audio.enqueueItem({ + audioData = stream, + audioFormat = audioFormat, + priority = priority, + source = State.audioRx.source, + audioId = data.audioId + }) + else + State.audioRx.chunks = {} + end elseif data.type == "audio_end" then if State.audioRx and (not data.audioId or data.audioId == State.audioRx.audioId) then - State.audioRx.stream.finish() - State.audioRx = nil + finishAudioRx() end elseif data.type == "audio_stop" then local scope = tostring(data.scope or "") @@ -1001,14 +1133,19 @@ function Network.messageLoop() -- Memory protection: limit to 10MB per audio item if State.audioRx.receivedBytes + #msg > 10 * 1024 * 1024 then Utils.log("ERROR", "Audio item too large, discarding") - State.audioRx.stream.finish() + if State.audioRx.stream then + State.audioRx.stream.finish() + end State.audioRx = nil else - State.audioRx.stream.push(msg) + if State.audioRx.stream then + State.audioRx.stream.push(msg) + else + table.insert(State.audioRx.chunks, msg) + end State.audioRx.receivedBytes = State.audioRx.receivedBytes + #msg if State.audioRx.expectedBytes > 0 and State.audioRx.receivedBytes >= State.audioRx.expectedBytes then - State.audioRx.stream.finish() - State.audioRx = nil + finishAudioRx() end end end diff --git a/update_station_broadcast.lua b/update_station_broadcast.lua index c2747c8..fa04ce9 100644 --- a/update_station_broadcast.lua +++ b/update_station_broadcast.lua @@ -1,6 +1,4 @@ -local STATION_BROADCAST_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/station_broadcast.lua?sign=xXsMwezjnEs4c6QrjkJkbvz1rARokmm87zwDcDDS5dk=:0" -local AUKIT_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/aukit.lua?sign=02_QDktYbSrHrtCDsFlKMkbEOWJGDautZaOtWkvg5q8=:0" -local AUSTREAM_URL = "https://cloud.fse-media.group/d/API/StationBroadcast/austream.lua?sign=DrLbf9CIX1ZY8DaL8vliZiCMQzGos10nhG26Wf5lbgA=:0" +local STATION_BROADCAST_URL = "https://gitea.fse-media.group/Henry_Du/CC-StationBroadcast/raw/commit/e4b4fa5cdb2bc42279fd87098fef0d27a90e23d5/station_broadcast.lua" local function fetch(url) if not http then @@ -66,9 +64,7 @@ local function downloadTo(url, path) end local targets = { - { url = STATION_BROADCAST_URL, path = shell.resolve("/startup") }, - { url = AUKIT_URL, path = shell.resolve("/aukit.lua") }, - { url = AUSTREAM_URL, path = shell.resolve("/austream.lua") } + { url = STATION_BROADCAST_URL, path = shell.resolve("/startup") } } for _, t in ipairs(targets) do