refactor: stricter domain: voice-session

This commit is contained in:
2026-04-11 15:12:54 +02:00
parent 7a0664b3c4
commit 52912327ae
9 changed files with 30 additions and 25 deletions

View File

@@ -0,0 +1,99 @@
import { STORAGE_KEY_VOICE_SETTINGS } from '../../../../core/constants';
import {
DEFAULT_LATENCY_PROFILE,
DEFAULT_SCREEN_SHARE_QUALITY,
LATENCY_PROFILES,
SCREEN_SHARE_QUALITIES,
type LatencyProfile,
type ScreenShareQuality
} from '../../../../shared-kernel';
export interface VoiceSettings {
inputDevice: string;
outputDevice: string;
inputVolume: number;
outputVolume: number;
audioBitrate: number;
latencyProfile: LatencyProfile;
includeSystemAudio: boolean;
noiseReduction: boolean;
screenShareQuality: ScreenShareQuality;
askScreenShareQuality: boolean;
}
export const DEFAULT_VOICE_SETTINGS: VoiceSettings = {
inputDevice: '',
outputDevice: '',
inputVolume: 100,
outputVolume: 100,
audioBitrate: 96,
latencyProfile: DEFAULT_LATENCY_PROFILE,
includeSystemAudio: false,
noiseReduction: true,
screenShareQuality: DEFAULT_SCREEN_SHARE_QUALITY,
askScreenShareQuality: true
};
export function loadVoiceSettingsFromStorage(): VoiceSettings {
try {
const raw = localStorage.getItem(STORAGE_KEY_VOICE_SETTINGS);
if (!raw)
return { ...DEFAULT_VOICE_SETTINGS };
return normaliseVoiceSettings(JSON.parse(raw) as Partial<VoiceSettings>);
} catch {
return { ...DEFAULT_VOICE_SETTINGS };
}
}
export function saveVoiceSettingsToStorage(patch: Partial<VoiceSettings>): VoiceSettings {
const nextSettings = normaliseVoiceSettings({
...loadVoiceSettingsFromStorage(),
...patch
});
try {
localStorage.setItem(STORAGE_KEY_VOICE_SETTINGS, JSON.stringify(nextSettings));
} catch {}
return nextSettings;
}
function normaliseVoiceSettings(raw: Partial<VoiceSettings>): VoiceSettings {
return {
inputDevice: typeof raw.inputDevice === 'string' ? raw.inputDevice : DEFAULT_VOICE_SETTINGS.inputDevice,
outputDevice: typeof raw.outputDevice === 'string' ? raw.outputDevice : DEFAULT_VOICE_SETTINGS.outputDevice,
inputVolume: clampNumber(raw.inputVolume, 0, 100, DEFAULT_VOICE_SETTINGS.inputVolume),
outputVolume: clampNumber(raw.outputVolume, 0, 200, DEFAULT_VOICE_SETTINGS.outputVolume),
audioBitrate: clampNumber(raw.audioBitrate, 32, 256, DEFAULT_VOICE_SETTINGS.audioBitrate),
latencyProfile: LATENCY_PROFILES.includes(raw.latencyProfile as LatencyProfile)
? raw.latencyProfile as LatencyProfile
: DEFAULT_VOICE_SETTINGS.latencyProfile,
includeSystemAudio: typeof raw.includeSystemAudio === 'boolean'
? raw.includeSystemAudio
: DEFAULT_VOICE_SETTINGS.includeSystemAudio,
noiseReduction: typeof raw.noiseReduction === 'boolean'
? raw.noiseReduction
: DEFAULT_VOICE_SETTINGS.noiseReduction,
screenShareQuality: SCREEN_SHARE_QUALITIES.includes(raw.screenShareQuality as ScreenShareQuality)
? raw.screenShareQuality as ScreenShareQuality
: DEFAULT_VOICE_SETTINGS.screenShareQuality,
askScreenShareQuality: typeof raw.askScreenShareQuality === 'boolean'
? raw.askScreenShareQuality
: DEFAULT_VOICE_SETTINGS.askScreenShareQuality
};
}
function clampNumber(
value: unknown,
min: number,
max: number,
fallback: number
): number {
if (typeof value !== 'number' || Number.isNaN(value)) {
return fallback;
}
return Math.max(min, Math.min(max, value));
}