fix(music): stream live dfpwm instead of pcm
Move live music streaming back onto the proven DFPWM playback path and silently ignore legacy train_arrival, train_departure, and play_sequence messages from older station clients so they no longer spam logs.
This commit is contained in:
+18
-11
@@ -286,13 +286,13 @@ async function sendAudioBufferToStation(stationName, fallbackWs, task) {
|
|||||||
return { audioId, cancelled: false, durationSec };
|
return { audioId, cancelled: false, durationSec };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendPcmStreamToStation(stationName, fallbackWs, task) {
|
async function sendLiveDfpwmToStation(stationName, fallbackWs, task) {
|
||||||
const targetWs = getStationWs(stationName, fallbackWs);
|
const targetWs = getStationWs(stationName, fallbackWs);
|
||||||
if (!targetWs) throw new Error(`Station "${stationName}" not connected`);
|
if (!targetWs) throw new Error(`Station "${stationName}" not connected`);
|
||||||
|
|
||||||
const sourcePath = String(task.sourcePath || '').trim();
|
const sourcePath = String(task.sourcePath || '').trim();
|
||||||
if (!sourcePath) throw new Error('PCM stream sourcePath required');
|
if (!sourcePath) throw new Error('Live DFPWM sourcePath required');
|
||||||
if (!fs.existsSync(sourcePath)) throw new Error(`PCM source missing: ${sourcePath}`);
|
if (!fs.existsSync(sourcePath)) throw new Error(`Live DFPWM source missing: ${sourcePath}`);
|
||||||
|
|
||||||
const audioId = String(task.audioId || `${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
const audioId = String(task.audioId || `${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
||||||
const durationSec = Number(task.durationSec || 0);
|
const durationSec = Number(task.durationSec || 0);
|
||||||
@@ -306,8 +306,7 @@ async function sendPcmStreamToStation(stationName, fallbackWs, task) {
|
|||||||
byteLength: 0,
|
byteLength: 0,
|
||||||
sampleRate: 48000,
|
sampleRate: 48000,
|
||||||
channels: 1,
|
channels: 1,
|
||||||
audioFormat: 'pcm',
|
audioFormat: 'dfpwm',
|
||||||
pcmEncoding: 's8',
|
|
||||||
loop,
|
loop,
|
||||||
priority: Number(task.priority || 0),
|
priority: Number(task.priority || 0),
|
||||||
interruptMode: task.interruptMode || getInterruptModeForPriority(Number(task.priority || 0)),
|
interruptMode: task.interruptMode || getInterruptModeForPriority(Number(task.priority || 0)),
|
||||||
@@ -317,12 +316,13 @@ async function sendPcmStreamToStation(stationName, fallbackWs, task) {
|
|||||||
const ffmpegArgs = ['-hide_banner', '-loglevel', 'error'];
|
const ffmpegArgs = ['-hide_banner', '-loglevel', 'error'];
|
||||||
if (loop) ffmpegArgs.push('-stream_loop', '-1');
|
if (loop) ffmpegArgs.push('-stream_loop', '-1');
|
||||||
ffmpegArgs.push('-re', '-i', sourcePath, '-f', 's8', '-acodec', 'pcm_s8', '-ac', '1', '-ar', '48000', 'pipe:1');
|
ffmpegArgs.push('-re', '-i', sourcePath, '-f', 's8', '-acodec', 'pcm_s8', '-ac', '1', '-ar', '48000', 'pipe:1');
|
||||||
log('INFO', `PCM music stream start for ${stationName}: ${path.basename(sourcePath)}${loop ? ' (loop)' : ''}`);
|
log('INFO', `Live DFPWM music stream start for ${stationName}: ${path.basename(sourcePath)}${loop ? ' (loop)' : ''}`);
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
let settled = false;
|
let settled = false;
|
||||||
let proc = null;
|
let proc = null;
|
||||||
|
const encoder = new dfpwm.Encoder();
|
||||||
|
|
||||||
const finish = (result, error) => {
|
const finish = (result, error) => {
|
||||||
if (settled) return;
|
if (settled) return;
|
||||||
@@ -376,7 +376,10 @@ async function sendPcmStreamToStation(stationName, fallbackWs, task) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ws.send(chunk);
|
const encoded = encoder.encode(Buffer.from(chunk));
|
||||||
|
if (encoded && encoded.length > 0) {
|
||||||
|
ws.send(encoded);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
finish(null, err);
|
finish(null, err);
|
||||||
}
|
}
|
||||||
@@ -392,7 +395,7 @@ async function sendPcmStreamToStation(stationName, fallbackWs, task) {
|
|||||||
|
|
||||||
proc.on('close', (code, signal) => {
|
proc.on('close', (code, signal) => {
|
||||||
const cancelled = token && token.cancelled;
|
const cancelled = token && token.cancelled;
|
||||||
log(cancelled ? 'INFO' : 'SUCCESS', `PCM music stream end for ${stationName}: ${path.basename(sourcePath)}${cancelled ? ' (cancelled)' : ''}`);
|
log(cancelled ? 'INFO' : 'SUCCESS', `Live DFPWM music stream end for ${stationName}: ${path.basename(sourcePath)}${cancelled ? ' (cancelled)' : ''}`);
|
||||||
if (!cancelled && code !== 0) {
|
if (!cancelled && code !== 0) {
|
||||||
finish(null, new Error((stderr || `ffmpeg exited with code ${code ?? 'unknown'} signal ${signal ?? 'none'}`).trim()));
|
finish(null, new Error((stderr || `ffmpeg exited with code ${code ?? 'unknown'} signal ${signal ?? 'none'}`).trim()));
|
||||||
return;
|
return;
|
||||||
@@ -584,8 +587,8 @@ async function processStationAudioQueue(stationName, fallbackWs) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (task.consoleStreamStart) broadcastToConsole(task.consoleStreamStart);
|
if (task.consoleStreamStart) broadcastToConsole(task.consoleStreamStart);
|
||||||
const result = task.audioFormat === 'pcm'
|
const result = task.audioFormat === 'dfpwm-live'
|
||||||
? await sendPcmStreamToStation(cleanStation, fallbackWs, task)
|
? await sendLiveDfpwmToStation(cleanStation, fallbackWs, task)
|
||||||
: await sendAudioBufferToStation(cleanStation, fallbackWs, task);
|
: await sendAudioBufferToStation(cleanStation, fallbackWs, task);
|
||||||
if (task.consoleStreamEnd) {
|
if (task.consoleStreamEnd) {
|
||||||
if (result.cancelled) {
|
if (result.cancelled) {
|
||||||
@@ -1370,6 +1373,10 @@ function handleMessage(ws, data) {
|
|||||||
case 'station_register':
|
case 'station_register':
|
||||||
handleStationRegister(ws, data);
|
handleStationRegister(ws, data);
|
||||||
break;
|
break;
|
||||||
|
case 'train_arrival':
|
||||||
|
case 'train_departure':
|
||||||
|
case 'play_sequence':
|
||||||
|
break;
|
||||||
case 'request_station_time':
|
case 'request_station_time':
|
||||||
handleStationTimeRequest(ws, data);
|
handleStationTimeRequest(ws, data);
|
||||||
break;
|
break;
|
||||||
@@ -2379,7 +2386,7 @@ app.post('/api/music/start', express.json(), (req, res) => {
|
|||||||
|
|
||||||
if (playbackAudio.sourcePath) {
|
if (playbackAudio.sourcePath) {
|
||||||
enqueueStationAudioTask(name, currentWs, {
|
enqueueStationAudioTask(name, currentWs, {
|
||||||
audioFormat: 'pcm',
|
audioFormat: 'dfpwm-live',
|
||||||
sourcePath: playbackAudio.sourcePath,
|
sourcePath: playbackAudio.sourcePath,
|
||||||
durationSec: playbackAudio.durationSec,
|
durationSec: playbackAudio.durationSec,
|
||||||
priority: -1,
|
priority: -1,
|
||||||
|
|||||||
Reference in New Issue
Block a user