feat(station-broadcast, cloud-server): 添加HLS播放与循环播放支持,更新脚本拉取地址

调整两个工具脚本的远程拉取地址,将固定commit哈希链接改为main分支链接;为云服务端添加loop参数与HLS音频播放支持,重构音频播放逻辑简化冗余代码;为station_broadcast.lua新增hls格式支持与循环播放控制,完善网络消息参数处理。
This commit is contained in:
2026-07-31 20:42:22 +08:00
parent 3f58d03d15
commit 6d65b8216a
4 changed files with 52 additions and 22 deletions
+27 -15
View File
@@ -244,6 +244,7 @@ async function sendAudioBufferToStation(stationName, fallbackWs, task) {
channels: Number(task.channels || 1),
audioFormat,
streamUrl,
loop: !!task.loop,
priority: Number(task.priority || 0),
interruptMode: task.interruptMode || getInterruptModeForPriority(Number(task.priority || 0)),
source: task.source || 'unknown'
@@ -2376,6 +2377,11 @@ app.post('/api/music/start', express.json(), (req, res) => {
stopStationMusic(name, ws);
stationMusicStates.set(name, { enabled: true, track, loop });
const streamName = getStationStreamName(name);
const hlsUrl = HLS_OUTPUT_MODE === 'local'
? getLocalHlsUrlForRequest(streamName, req)
: getStationHlsUrlForRequest(streamName, req);
const enqueueOnce = () => {
const currentWs = getStationWs(name);
if (!currentWs || currentWs.readyState !== WebSocket.OPEN) {
@@ -2384,6 +2390,24 @@ app.post('/api/music/start', express.json(), (req, res) => {
return;
}
if (HLS_ENABLE) {
enqueueHlsPush(name, [track]);
enqueueStationAudioTask(name, currentWs, {
audioFormat: 'hls',
streamUrl: hlsUrl,
durationSec: playbackAudio.durationSec,
priority: -1,
interruptMode: 'none',
source: 'music',
loop,
audioId: `music-${track}-${name}-${Date.now()}`,
requeueOnPreempt: true,
consoleStreamStart: { type: 'stream_start', station: name, seq: [`MUSIC:${track}`], streamName, hlsUrl },
consoleStreamEnd: { type: 'stream_end', station: name }
});
return;
}
enqueueStationAudioTask(name, currentWs, {
audioFormat: playbackAudio.audioFormat,
buffer: playbackAudio.buffer,
@@ -2392,23 +2416,11 @@ app.post('/api/music/start', express.json(), (req, res) => {
priority: -1,
interruptMode: 'none',
source: 'music',
loop,
audioId: `music-${track}-${name}-${Date.now()}`,
requeueOnPreempt: true,
consoleStreamStart: { type: 'stream_start', station: name, seq: [`MUSIC:${track}`], streamName: getStationStreamName(name), hlsUrl: getStationHlsUrl(getStationStreamName(name)) },
consoleStreamEnd: { type: 'stream_end', station: name },
onDone: (info) => {
const st = stationMusicStates.get(name);
if (!st || !st.enabled) return;
if (st.track !== track) return;
if (!st.loop) return;
// Only stop if cancelled by something else (like stopMusic or higher priority)
if (info && info.cancelled) {
// If it was just preempted, enqueueStationAudioTask handles the re-insertion
// If it was cancelled by stopStationMusic, st.enabled will be false
return;
}
enqueueOnce();
}
consoleStreamStart: { type: 'stream_start', station: name, seq: [`MUSIC:${track}`], streamName, hlsUrl },
consoleStreamEnd: { type: 'stream_end', station: name }
});
};