오디오 소스 선택 기능 추가

- AudioCaptureService.getDevices(): PowerShell로 Windows 오디오 디바이스 열거
- SettingsModal 오디오 탭: 마이크 선택 드롭다운 (기본 + 감지된 디바이스)
- 선택 변경 시 ConfigService에 저장 → 다음 녹음 시 적용
This commit is contained in:
Yun Chan 2026-04-05 10:05:47 +09:00
parent 48582e46ec
commit 438aa1de6c
2 changed files with 72 additions and 13 deletions

View file

@ -29,7 +29,8 @@ import KeyboardIcon from '@mui/icons-material/Keyboard'
import EditIcon from '@mui/icons-material/Edit'
import { d3roPalette } from '../theme'
import { HotkeyRecordModal } from './HotkeyRecordModal'
import type { ThemeMode, AppConfig, HotkeyBinding } from '@shared/types'
import MicIcon from '@mui/icons-material/Mic'
import type { ThemeMode, AppConfig, HotkeyBinding, AudioDevice } from '@shared/types'
interface SettingsModalProps {
open: boolean
@ -183,6 +184,10 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
const [hotkeyModalOpen, setHotkeyModalOpen] = useState(false)
const [hotkeyModalTarget, setHotkeyModalTarget] = useState<'dictation' | 'handsFree'>('dictation')
// 오디오 디바이스
const [audioDevices, setAudioDevices] = useState<AudioDevice[]>([])
const [selectedDeviceId, setSelectedDeviceId] = useState<string>('default')
// 설정 로드
useEffect(() => {
if (!open) return
@ -193,8 +198,10 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
window.electronAPI.hotkey.getDictationShortcut(),
window.electronAPI.hotkey.getHandsFreeShortcut(),
window.electronAPI.hotkey.isEnabled(),
window.electronAPI.audio.getDevices(),
window.electronAPI.audio.getSelectedDevice(),
])
.then(([configResult, dictResult, hfResult, enabledResult]) => {
.then(([configResult, dictResult, hfResult, enabledResult, devicesResult, selectedResult]) => {
if (configResult.success) setConfig(configResult.data)
if (dictResult.success && dictResult.data) setDictationBinding(dictResult.data)
if (hfResult.success && hfResult.data) setHandsFreeBinding(hfResult.data)
@ -202,6 +209,8 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
setHotkeyGlobalEnabled(enabledResult.data)
setDictationEnabled(enabledResult.data)
}
if (devicesResult.success) setAudioDevices(devicesResult.data)
if (selectedResult.success && selectedResult.data) setSelectedDeviceId(selectedResult.data)
})
.finally(() => setLoading(false))
}, [open])
@ -412,9 +421,34 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
{/* ── 오디오 탭 ────────────────────────────── */}
<TabPanel value={activeTab} index={1}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<Typography variant="body2" color="text.secondary">
.
.
<Typography variant="overline" sx={{ color: d3roPalette.text.label, letterSpacing: '1.5px' }}>
</Typography>
<FormControl size="small">
<InputLabel> </InputLabel>
<Select
label="입력 장치"
value={selectedDeviceId}
onChange={(e) => {
const deviceId = e.target.value
setSelectedDeviceId(deviceId)
window.electronAPI.audio.setSelectedDevice({ deviceId })
}}
startAdornment={<MicIcon sx={{ color: d3roPalette.text.inactive, mr: 1, fontSize: 18 }} />}
>
{audioDevices.map((device) => (
<MenuItem key={device.deviceId} value={device.deviceId}>
{device.label}{device.isDefault ? ' ()' : ''}
</MenuItem>
))}
</Select>
</FormControl>
<Divider sx={{ borderColor: d3roPalette.border.subtle }} />
<Typography variant="overline" sx={{ color: d3roPalette.text.label, letterSpacing: '1.5px' }}>
</Typography>
<FormControl size="small">