fix: 오디오 테스트를 실시간 레벨 미터로 개선

단발성 평균값 → 100ms 간격 실시간 RMS 스트리밍.
AudioCaptureService 직접 시작/5초 자동 중지.
테스트 버튼 누르면 레벨 바가 왔다갔다 반응.
This commit is contained in:
Yun Chan 2026-04-08 09:07:29 +09:00
parent 7a925bdeb9
commit 6197ceb132
3 changed files with 70 additions and 15 deletions

View file

@ -3,10 +3,37 @@
import { ipcMain } from 'electron'
import { IPC_CHANNELS } from '@shared/ipc-channels'
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
import { getAudioCaptureService } from '../services/AudioCaptureService'
import { getAudioCaptureService, calculateRMS } from '../services/AudioCaptureService'
import { getMainWindow } from '../windows/WindowManager'
import { configGet, configSet } from '../services/ConfigService'
import { getLogger } from '../services/LoggerService'
import type { SetDeviceParams } from '@shared/types'
const logger = getLogger('audio-handlers')
let testTimer: ReturnType<typeof setTimeout> | null = null
let testAudioHandler: ((payload: { buffer: Buffer; timestamp: number }) => void) | null = null
let testLevelInterval: ReturnType<typeof setInterval> | null = null
let testLastRms = 0
function stopAudioTest(): void {
const service = getAudioCaptureService()
if (testAudioHandler) {
service.off('audio-data', testAudioHandler)
testAudioHandler = null
}
if (testLevelInterval) {
clearInterval(testLevelInterval)
testLevelInterval = null
}
if (testTimer) {
clearTimeout(testTimer)
testTimer = null
}
testLastRms = 0
service.stop().catch(() => { /* ignore */ })
}
export function registerAudioHandlers(): void {
ipcMain.handle(IPC_CHANNELS.AUDIO.GET_DEVICES, async () => {
try {
@ -32,10 +59,39 @@ export function registerAudioHandlers(): void {
ipcMain.handle(IPC_CHANNELS.AUDIO.TEST_DEVICE, async () => {
try {
// 이전 테스트가 진행 중이면 정리
stopAudioTest()
const service = getAudioCaptureService()
const result = await service.testCapture(2000)
return ipcSuccess(result)
await service.start()
// 오디오 데이터에서 RMS 추적
testAudioHandler = (payload: { buffer: Buffer; timestamp: number }) => {
testLastRms = calculateRMS(payload.buffer)
}
service.on('audio-data', testAudioHandler)
// 100ms 간격으로 레벨을 렌더러에 전송
testLevelInterval = setInterval(() => {
const level = testLastRms > 0 ? Math.min(1.0, Math.pow(testLastRms, 0.28)) : 0
const win = getMainWindow()
if (win && !win.isDestroyed()) {
win.webContents.send('audio:testLevel', { level })
}
}, 100)
// 5초 후 자동 중지
testTimer = setTimeout(() => {
stopAudioTest()
const win = getMainWindow()
if (win && !win.isDestroyed()) {
win.webContents.send('audio:testLevel', { level: 0 })
}
}, 5000)
return ipcSuccess({ averageLevel: 0, peakLevel: 0, hasAudio: true })
} catch (err) {
stopAudioTest()
return ipcError(
ErrorCode.AudioDeviceNotFound,
`Audio test failed: ${err instanceof Error ? err.message : String(err)}`,