mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-17 10:00:46 -04:00
remove duration limits
This commit is contained in:
@@ -27,8 +27,6 @@ audioForward:
|
|||||||
streamSuffix: "-fwd"
|
streamSuffix: "-fwd"
|
||||||
# Max upload payload accepted via VIP forward upload
|
# Max upload payload accepted via VIP forward upload
|
||||||
maxUploadBytes: 8388608
|
maxUploadBytes: 8388608
|
||||||
# Maximum playback duration per upload (seconds)
|
|
||||||
maxUploadSeconds: 45
|
|
||||||
|
|
||||||
audioLevels:
|
audioLevels:
|
||||||
# Gains are multipliers (0.0 - 4.0) applied globally to all rovers.
|
# Gains are multipliers (0.0 - 4.0) applied globally to all rovers.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const logger = require('../globals/logger').child('audioForwardService');
|
|||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../helpers/configLoader');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('./roverManager');
|
||||||
const { isVerified } = require('./verificationService');
|
const { isVerified } = require('./verificationService');
|
||||||
|
const turnService = require('./turnService');
|
||||||
|
|
||||||
const audioForwardEvents = new EventEmitter();
|
const audioForwardEvents = new EventEmitter();
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
@@ -19,9 +20,6 @@ const uploadsDir = path.join(runtimeDir, 'uploads');
|
|||||||
const maxUploadBytes = Number.isFinite(audioForwardConfig.maxUploadBytes)
|
const maxUploadBytes = Number.isFinite(audioForwardConfig.maxUploadBytes)
|
||||||
? Math.max(256 * 1024, Math.floor(audioForwardConfig.maxUploadBytes))
|
? Math.max(256 * 1024, Math.floor(audioForwardConfig.maxUploadBytes))
|
||||||
: 8 * 1024 * 1024;
|
: 8 * 1024 * 1024;
|
||||||
const maxUploadSeconds = Number.isFinite(audioForwardConfig.maxUploadSeconds)
|
|
||||||
? Math.max(1, Math.floor(audioForwardConfig.maxUploadSeconds))
|
|
||||||
: 45;
|
|
||||||
|
|
||||||
const states = new Map(); // roverId -> { state, source, error, startedAt, updatedAt }
|
const states = new Map(); // roverId -> { state, source, error, startedAt, updatedAt }
|
||||||
const workers = new Map(); // roverId -> worker
|
const workers = new Map(); // roverId -> worker
|
||||||
@@ -94,6 +92,9 @@ function ensureAudioForwardPermission(socket, roverId) {
|
|||||||
if (!roverManager.isDriver(roverId, socket)) {
|
if (!roverManager.isDriver(roverId, socket)) {
|
||||||
throw new Error('Audio forwarding is only allowed on your own rover');
|
throw new Error('Audio forwarding is only allowed on your own rover');
|
||||||
}
|
}
|
||||||
|
if (!turnService.canDrive(roverId, socket)) {
|
||||||
|
throw new Error('Only the current driver can play audio');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureFifo(fifoPath) {
|
function ensureFifo(fifoPath) {
|
||||||
@@ -247,8 +248,6 @@ function buildUploadWriterArgs(filePath) {
|
|||||||
'-vn',
|
'-vn',
|
||||||
'-af',
|
'-af',
|
||||||
'aresample=16000',
|
'aresample=16000',
|
||||||
'-t',
|
|
||||||
String(maxUploadSeconds),
|
|
||||||
'-f',
|
'-f',
|
||||||
's16le',
|
's16le',
|
||||||
'-ac',
|
'-ac',
|
||||||
@@ -296,6 +295,7 @@ function stopContentWriter(worker) {
|
|||||||
stopProc(worker.contentProc);
|
stopProc(worker.contentProc);
|
||||||
worker.contentProc = null;
|
worker.contentProc = null;
|
||||||
worker.contentKind = null;
|
worker.contentKind = null;
|
||||||
|
worker.activeOwnerSocketId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSilenceWriter(roverId) {
|
function startSilenceWriter(roverId) {
|
||||||
@@ -335,6 +335,7 @@ function startUploadWriter(roverId, filePath) {
|
|||||||
stopContentWriter(worker);
|
stopContentWriter(worker);
|
||||||
cleanupUploadFile(worker);
|
cleanupUploadFile(worker);
|
||||||
worker.activeUploadPath = filePath;
|
worker.activeUploadPath = filePath;
|
||||||
|
worker.activeOwnerSocketId = null;
|
||||||
const proc = spawnProcess(roverId, 'upload-writer', buildUploadWriterArgs(filePath), { captureStdout: true });
|
const proc = spawnProcess(roverId, 'upload-writer', buildUploadWriterArgs(filePath), { captureStdout: true });
|
||||||
worker.contentProc = proc;
|
worker.contentProc = proc;
|
||||||
worker.contentKind = 'upload';
|
worker.contentKind = 'upload';
|
||||||
@@ -432,9 +433,17 @@ function writeUploadFile(roverId, payload = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function playUploadedAudio(roverId, payload = {}) {
|
function playUploadedAudio(roverId, payload = {}) {
|
||||||
|
const ownerSocketId = typeof payload?.ownerSocketId === 'string' ? payload.ownerSocketId : null;
|
||||||
const uploadPath = writeUploadFile(roverId, payload);
|
const uploadPath = writeUploadFile(roverId, payload);
|
||||||
ensureWorker(roverId);
|
ensureWorker(roverId);
|
||||||
|
const worker = workers.get(roverId);
|
||||||
|
if (worker) {
|
||||||
|
worker.activeOwnerSocketId = ownerSocketId;
|
||||||
|
}
|
||||||
startUploadWriter(roverId, uploadPath);
|
startUploadWriter(roverId, uploadPath);
|
||||||
|
if (worker) {
|
||||||
|
worker.activeOwnerSocketId = ownerSocketId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopPlayback(roverId) {
|
function stopPlayback(roverId) {
|
||||||
@@ -481,13 +490,40 @@ roverManager.managerEvents.on('rover', ({ roverId, action } = {}) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function stopOwnedUploadIfUnauthorized(roverId, ownerSocketId, reason = 'driver_change') {
|
||||||
|
if (!roverId || !ownerSocketId) return;
|
||||||
|
const worker = workers.get(roverId);
|
||||||
|
if (!worker || worker.contentKind !== 'upload') return;
|
||||||
|
if (worker.activeOwnerSocketId !== ownerSocketId) return;
|
||||||
|
const ownerSocket = io.sockets.sockets.get(ownerSocketId);
|
||||||
|
const ownerIsDriver = ownerSocket ? roverManager.isDriver(roverId, ownerSocket) : false;
|
||||||
|
const ownerCanDrive = ownerSocket ? turnService.canDrive(roverId, ownerSocket) : false;
|
||||||
|
if (ownerIsDriver && ownerCanDrive) return;
|
||||||
|
logger.info('Stopping upload due to ownership/driver change', { roverId, ownerSocketId, reason });
|
||||||
|
startSilenceWriter(roverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
roverManager.managerEvents.on('driver', ({ socketId, roverId, action } = {}) => {
|
||||||
|
if (!socketId || !roverId) return;
|
||||||
|
if (action === 'remove' || action === 'add') {
|
||||||
|
stopOwnedUploadIfUnauthorized(roverId, socketId, action);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
turnService.turnEvents.on('activeDriver', ({ roverId } = {}) => {
|
||||||
|
if (!roverId) return;
|
||||||
|
const worker = workers.get(roverId);
|
||||||
|
if (!worker || worker.contentKind !== 'upload') return;
|
||||||
|
stopOwnedUploadIfUnauthorized(roverId, worker.activeOwnerSocketId, 'turn_change');
|
||||||
|
});
|
||||||
|
|
||||||
io.on('connection', (socket) => {
|
io.on('connection', (socket) => {
|
||||||
socket.on('audio:uploadPlay', (payload = {}, cb = () => {}) => {
|
socket.on('audio:uploadPlay', (payload = {}, cb = () => {}) => {
|
||||||
try {
|
try {
|
||||||
const roverId = String(payload?.roverId || '').trim();
|
const roverId = String(payload?.roverId || '').trim();
|
||||||
ensureAudioForwardPermission(socket, roverId);
|
ensureAudioForwardPermission(socket, roverId);
|
||||||
const normalized = String(roverId || '').trim();
|
const normalized = String(roverId || '').trim();
|
||||||
playUploadedAudio(normalized, payload);
|
playUploadedAudio(normalized, { ...(payload || {}), ownerSocketId: socket.id });
|
||||||
cb({ success: true, roverId: normalized });
|
cb({ success: true, roverId: normalized });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb({ error: err.message });
|
cb({ error: err.message });
|
||||||
|
|||||||
Reference in New Issue
Block a user