mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
feat(audio): per-user horn/TTS/forward volume with admin-capped ceilings
Every user now gets a personal 0-1 volume for horn, TTS, and mic forward. The value is stored as a fraction of the ceiling that applies to them, so lowering the global admin gain quiets everyone immediately instead of leaving stale absolute values behind. Ceilings resolve in three layers: the global admin gain is the default ceiling; the audioGainBoost flag raises it to an admin-editable hard cap (default 0.5x horn, 0.8x TTS, 0.4x forward); Math.max keeps the flag from ever lowering a ceiling if the global gain is set higher than a cap. Preferences live in identity feature state rather than a cookie so they follow the user and cannot be raised client-side. The rover exposes gain as three ALSA masters, so the resolved gains pushed to a rover are those of the socket currently holding audio control -- re-pushed on driver join/leave and every turn rotation. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@ const {
|
||||
getUserIdForSocket,
|
||||
} = require('../identityService');
|
||||
const { getAudioForwardState, audioForwardEvents } = require('../audioForwardService');
|
||||
const { getAudioLevels, audioLevelsEvents } = require('../audioLevelsService');
|
||||
const { getAudioLevels, getAudioGainStateForSocket, audioLevelsEvents } = require('../audioLevelsService');
|
||||
const { getButtonBoxState } = require('../buttonBoxService');
|
||||
const { getState: getInterInstanceState, interInstanceEvents } = require('../interInstanceService');
|
||||
const {
|
||||
@@ -223,6 +223,7 @@ function buildSession(socket) {
|
||||
isVerified: Boolean(socket?.data?.isVerified),
|
||||
audioForward: getAudioForwardState(),
|
||||
audioLevels: getAudioLevels(),
|
||||
audioGains: getAudioGainStateForSocket(socket),
|
||||
buttonBox: getButtonBoxState(),
|
||||
/*
|
||||
Inter-instance state is a read-only directory snapshot. It is included in
|
||||
@@ -454,7 +455,18 @@ audioForwardEvents.on('change', () => {
|
||||
syncAll();
|
||||
});
|
||||
|
||||
audioLevelsEvents.on('change', () => {
|
||||
audioLevelsEvents.on('change', ({ scope, userId } = {}) => {
|
||||
/*
|
||||
A user dragging their own volume slider only changes their own payload, so
|
||||
it resyncs just that user's tabs. Admin gain and cap edits still change
|
||||
everyone's ceiling and keep the full broadcast.
|
||||
*/
|
||||
if (scope === 'user' && userId) {
|
||||
io.sockets.sockets.forEach((socket) => {
|
||||
if (getUserIdForSocket(socket) === userId) syncSocket(socket);
|
||||
});
|
||||
return;
|
||||
}
|
||||
syncAll();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user