2026-09-20 01:32:11 +03:00
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
|
|
|
|
|
|
import { VolumeSlider, VoiceDeviceList } from '@/components/voice/VoiceControls';
|
|
|
|
|
import { useDeviceChoice } from '@/lib/useMediaDevices';
|
|
|
|
|
import { useVoiceStore } from '@/stores/voice';
|
|
|
|
|
import { SettingsSection } from '@/pages/settings/SettingsSection';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* «Аудио-видео»: выбор устройств ввода/вывода и громкости.
|
|
|
|
|
*
|
2026-09-20 18:51:31 +03:00
|
|
|
* Значения хранятся локально (zustand + localStorage) и применяются на лету:
|
|
|
|
|
* выбранное устройство сразу переключается в активной голосовой сессии.
|
2026-09-20 01:32:11 +03:00
|
|
|
*/
|
|
|
|
|
export function VoiceSettingsSection() {
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const mic = useDeviceChoice('audioinput');
|
|
|
|
|
const camera = useDeviceChoice('videoinput');
|
|
|
|
|
const output = useDeviceChoice('audiooutput');
|
|
|
|
|
const micVolume = useVoiceStore((state) => state.micVolume);
|
|
|
|
|
const outputVolume = useVoiceStore((state) => state.outputVolume);
|
|
|
|
|
const setMicVolume = useVoiceStore((state) => state.setMicVolume);
|
|
|
|
|
const setOutputVolume = useVoiceStore((state) => state.setOutputVolume);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<SettingsSection
|
|
|
|
|
title={t('settings.voice.title')}
|
|
|
|
|
description={t('settings.voice.description')}
|
|
|
|
|
>
|
|
|
|
|
<div className="mt-4 grid gap-4 sm:grid-cols-2">
|
|
|
|
|
<VoiceDeviceList
|
|
|
|
|
kind="audioinput"
|
|
|
|
|
label={t('settings.voice.input')}
|
|
|
|
|
value={mic.value}
|
|
|
|
|
onChange={mic.select}
|
|
|
|
|
/>
|
|
|
|
|
<VoiceDeviceList
|
|
|
|
|
kind="videoinput"
|
|
|
|
|
label={t('settings.voice.camera')}
|
|
|
|
|
value={camera.value}
|
|
|
|
|
onChange={camera.select}
|
|
|
|
|
/>
|
|
|
|
|
<VoiceDeviceList
|
|
|
|
|
kind="audiooutput"
|
|
|
|
|
label={t('settings.voice.output')}
|
|
|
|
|
value={output.value}
|
|
|
|
|
onChange={output.select}
|
|
|
|
|
/>
|
|
|
|
|
<div className="flex flex-col justify-end gap-2">
|
|
|
|
|
<VolumeSlider
|
|
|
|
|
label={t('settings.voice.micVolume')}
|
|
|
|
|
value={micVolume}
|
|
|
|
|
onChange={setMicVolume}
|
|
|
|
|
/>
|
|
|
|
|
<VolumeSlider
|
|
|
|
|
label={t('settings.voice.outputVolume')}
|
|
|
|
|
value={outputVolume}
|
|
|
|
|
onChange={setOutputVolume}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="mt-4 text-xs text-fg-muted">{t('settings.voice.stub')}</p>
|
|
|
|
|
</SettingsSection>
|
|
|
|
|
);
|
|
|
|
|
}
|