AI 음성 재생 · 원격 수신
입력 체인을 통과하지 않는다. 아래 입력 처리량 감소가 AI 재생을 개선하는지는 별도 검증한다.
마지막 업데이트 2026-09-11
설계 제안 · 코드 미반영 · 개선 효과 미검증LiveKit 입력 체인에서 설정상 OFF인 EQ·컴프레서·리미터 노드를 실제 그래프에서도 제외하는 것을 우선한다. 핵심 구현은 한 파일로 제한하고, 효과가 부족하면 RMS 립싱크 간소화를 별도로 비교한다. 공유 AudioContext 개선안은 덕킹 문제로 철회되었다.
좁은 화면에서는 표를 가로로 스크롤할 수 있습니다.
2026-09-11 적용 현황. 이 설계와 별도로 1차 대응이 코드에 반영됐다 — 영어 가드 LiveKit OFF(커밋 4ca9c122), 저전력 모드 프로브, AI 원격 오디오 재생 지연 감시(dry-run). 아래 OFF 노드 우회·RMS 간소화는 그 문서의 B층(WebAudio 축소)과 짝이 되며 아직 미반영이다. 상세는 PPI-1290 · iPad AI 음성 밀림 1차 대응.
| 순서 | 방법 | 변경 규모 | 판단 |
|---|---|---|---|
| 즉시 대응 | 수업 전 저전력 모드 OFF 확인 | 코드 없음 | 보고된 실험 조건에 가장 직접적으로 대응하는 운영 완화책 |
| 1차 개선 | OFF인 EQ·컴프레서·리미터 노드 제외 | 핵심 구현 1파일 + 관련 테스트 | 설정으로 이미 꺼진 처리를 실제로 우회. 최대 5개 처리 노드 제외 |
| 2차 개선 | iPad 게스트 RMS 립싱크 간소화 | 구현 약 2~3파일 + 테스트·Storybook | 분석·Canvas 합성 부하 감소 후보. 음량에 맞춘 입 모양의 정밀도는 감소 |
| 후속 검토 | 외부 STT 처리 최적화·ScriptProcessor 전환 | 별도 설계 필요 | 현장 기여도를 확인한 뒤 범위를 정한다 |
저전력 모드는 충전 케이블 연결만으로 OFF라고 판단하지 않는다. Apple은 iPad가 80% 이상 충전되면 자동 해제된다고 설명한다. 수업 전에 설정 또는 제어 센터에서 OFF를 직접 확인한다. 배터리 20%라는 값만으로 모든 iPad에서 자동 활성화된다고 가정하지 않는다. Apple iPad 저전력 모드 안내
| 근거 | 확인 내용 | 해석의 한계 |
|---|---|---|
| 실험 보고 | 2026-09-09~10 iPad 1대에서 저전력 ON + AudioWorklet 150% 부하일 때 밀림. 저전력 단독 및 정상 전원에서의 다른 부하 조건은 음성 정상 | 사용자 청감 관찰. 이번 문서 작업에서 실험을 재수행하지 않았다. 모든 iPad·iPadOS에 대한 충분조건으로 일반화하지 않는다 |
| 현재 코드 | LiveKit 원격 AI 트랙은 audioTrack.attach(args.audioElement)로 재생. 입력 체인의 기본 EQ·컴프레서·리미터 설정은 OFF지만 해당 노드는 모두 생성·연결 | 실제 세션 설정은 /api/livekit/config 응답으로 덮일 수 있다. 현장 설정값과 부하는 별도 확인 대상 |
| 개선 가설 | 불필요한 처리 노드를 제외하면 저전력 상태의 실시간 처리 여유가 늘어날 수 있음 | 스레드 경쟁·CoreAudio 버퍼 확대·특정 앱 그래프의 기여도 및 개선 효과는 미확정 |
실험 원문은 iPad AI 음성 밀림 재현 — 저전력 모드 × WebAudio 렌더 부하다. 이 문서는 재현 기록을 바탕으로 현재 코드의 실행 조건을 재검토한 후속 설계다.
f4cc99f0의 실제 코드에는 입력 ctx 재사용 호출이 남아 있으므로, 철회 결정을 “모든 관련 코드가 제거됨”이라는 확인으로 해석하지 않는다. 잔존 코드 정리는 이번 제안 범위에 포함하지 않는다.입력 체인을 통과하지 않는다. 아래 입력 처리량 감소가 AI 재생을 개선하는지는 별도 검증한다.
원본 마이크의 별도 analyser 분기는 입력 레벨 분석에 계속 사용한다. 두 전달 분기의 독립 제어를 보존한다.
확인 경로: apps/web/lib/voice-agent/livekit-client-session.ts:3103, :3590–3638 · apps/web/lib/voice-agent/livekit-audio-chain-processor.ts:250–348
LIVEKIT_BROWSER_AUDIO_PROFILE.chain의 eqEnabled, compressorEnabled, limiterEnabled 기본값은 모두 false다. 현재 buildGraph()는 EQ 노드 3개와 컴프레서 노드 2개를 항상 만들며, OFF이면 EQ를 allpass, 컴프레서 비율을 1로 설정한다.
| 조건 | 현재 동작 | 제안 동작 |
|---|---|---|
| chain OFF 또는 EQ OFF | BiquadFilterNode 3개 생성 → allpass로 연결 | 세 노드를 생성하지 않고 다음 활성 단계에 연결 |
| chain OFF 또는 컴프레서 OFF | DynamicsCompressorNode 생성 → ratio 1로 연결 | 컴프레서 생성·연결 생략 |
| chain OFF 또는 리미터 OFF | DynamicsCompressorNode 생성 → ratio 1로 연결 | 리미터 생성·연결 생략 |
| 각 기능 ON | EQ → 컴프레서 → 리미터 순서로 설정 적용 | 켜진 기능은 같은 순서와 파라미터로 연결 |
recognitionGate.audioChain 값을 기록해, 서버 설정이 기본값을 덮었는지 구분한다.제외 가능한 노드는 최대 5개다. 실제 CPU 절감률과 가청 지연 감소량은 아직 측정하지 않았다. 해당 설정이 모두 ON인 현장에서는 이 변경으로 제외되는 노드가 없다.
먼저 RMS가 켜진 테스트 아바타의 기존 설정을 OFF로 바꿔 비교한다. 이는 새 구현 없이 가능한 진단이다. 설정 변경은 운영 전체가 아닌 테스트 대상으로 제한하며, 이 문서 작성 과정에서는 설정을 변경하지 않았다.
효과가 확인되면 iPad의 LiveKit 게스트에 한해 아바타용 RMS 분석과 Canvas 합성을 끄고, 기존 isPeerTalking 기반 idle/talking 영상 전환을 사용한다. AI 재생과 다른 소비자가 사용하는 원본 스트림은 유지하고, 아바타 분석 경계에만 간소화 조건을 적용한다.
MeetAvatar의 RMS OFF 경로는 비발화 중에도 talking 영상을 재생할 수 있다. 간소화 모드에서는 비발화 시 talking 영상을 pause하고, RMS가 바꾼 재생속도를 정상값으로 복구한다.이 안은 새로운 공유 ctx를 만들거나 기존 ctx를 일괄 close하는 설계가 아니다. 1차 개선과 동시에 적용하지 않고 각각의 기여도를 확인한다.
| 후보 | 현재 코드 확인 | 설계 판단 |
|---|---|---|
| 노이즈 가드 | noiseGuardEnabled && isRealtimeMode. resolved runtime이 LiveKit이면 비활성 | LiveKit 게스트 부하 절감 대상으로 잡지 않는다 |
| AiAudioEqualizer | MonitorMediaDisplay의 localhost 조건 안에서 렌더 | 이번 dev 배포 게스트 증상의 개선 대상이 아니다 |
| 영어 가드 | !isLowPerfDevice && (override ?? enabled). 활성 시 ScriptProcessor와 MFCC 분석 | 실제로 켜진 세션에서만 비교한다. 해제하면 영어 발화 감지·중단 기능도 감소하므로 운영 자동 해제를 기본안으로 삼지 않는다 |
| 외부 STT | 활성 시 아동 마이크 처리와 AI 재전사에 각각 그래프 사용 | 전체 OFF는 아동 입력 처리에도 영향을 준다. 필요하면 AI 재전사 분기를 먼저 독립적으로 비교 |
| 영상 loopback | iOS 게스트에서 영상 오디오 덕킹 회피를 담당 | 단순 제거·스텝별 재생성은 후순위. 원인 기여도와 재개 시 음량·무음을 검증한 별도 설계 필요 |
이번 첫 변경에는 공유 ctx 확대, ScriptProcessor 3곳의 일괄 AudioWorklet 전환, rAF 30fps·outputLatency 기반 저전력 자동 감지, 주기적 재접속·audio 재부착을 포함하지 않는다. 재현 조건만으로는 이 추가 제어들의 이득과 복구 안정성을 설명하기 어렵다.
아래 항목은 아직 실행하지 않은 계획이다. 단위 테스트 통과나 노드 수 감소만으로 iPad 밀림 개선을 판정하지 않는다.
| 검증 | 방법 | 합격 또는 판단 기준 |
|---|---|---|
| 최종 설정 확인 | 세션에 적용된 EQ·컴프레서·리미터·입력 Gain 설정 기록 | 기존/변경 버전의 설정이 같고, 실제 제외되는 노드를 설명할 수 있음 |
| 처리 그래프와 실패 정리 | OFF/ON 혼합 설정, 연결 순서, 초기화 실패·재시작·종료를 검증하는 최소 harness | 필요한 전달 분기가 유지되고 실패·종료 뒤 중복 그래프나 살아 있는 불필요 트랙이 남지 않음 |
| 입력 품질·제어 | 고정 음성 입력으로 아동 음량·인식 결과, AI 듣기 ON/OFF, 진행자 전달 비교 | 의도한 gate 분리와 Gain 동작 유지. 인식·가청 품질 악화 없음 |
| 실제 수업 A/B | 동일 iPad·iPadOS·출력 장치·네트워크, 저전력 ON + 하네스 OFF. 동일 영상↔AI 흐름을 기존/변경/기존 순서로 반복 | 권장 최소 3회 및 회기 후반까지 관찰. 실제 스피커 출력의 밀림 발생·누적 추세가 반복적으로 개선되어야 함 |
| 덕킹·수명 회귀 | 영상→AI→영상, AI 세션 재시작, 백그라운드 복귀, AI 듣기 OFF 상태의 진행자 청취 | 추가 무음·음량 급감·중복 재생·진행자 전달 중단 없음 |
| RMS 후속안 | 실제 backend·socket·media device 없이 일반/RMS 간소화/발화/비발화/숨김 상태 story | 기본 발화 표시와 영상 pause 동작 확인. 관련 Storybook 정적 빌드 검증 |
현재 livekit-audio-chain-processor.test.ts에는 buildGraph를 대체하는 테스트가 많아 노드 구성 변경의 보호막으로 충분하지 않다. 구현 시 관련 baseline을 먼저 실행하고, 실제 연결·출력 제어를 검증하는 최소 harness를 보강한 뒤 코드를 변경한다. 입력 파형·지연 차이는 브라우저의 실제 오디오 처리 결과로도 확인한다.
isPeerTalking, audio_play_requested만으로 실제 재생 지연을 측정했다고 하지 않는다.ΔcurrentTime / (Δperformance.now() / 1000)은 입력 처리 시계의 보조 지표다. 현재 브랜치의 health는 currentTimeAdvanced 등을 기록하며 ratio를 직접 제공하지 않는다. ratio 계측이 필요하면 구현 시 별도로 추가한다. 0.98을 보편적 장애 기준이나 원인 확정값으로 사용하지 않는다.ΔjitterBufferDelay / ΔjitterBufferEmittedCount, 패킷 손실·concealment 변화를 함께 비교한다. 분모 0과 트랙 교체 시 누적값 초기화를 처리한다. 이 통계도 스피커까지의 전체 지연을 뜻하지 않는다. W3C WebRTC 통계 명세필요한 계측은 기존 그래프·통계 경계에서 수집한다. 계측만을 위해 새 AudioContext나 부하 루프를 만들지 않는다. 이번 단계의 목표는 누적 지연의 예방 가능성 확인이며, 이미 쌓인 지연을 강제로 비우는 복구 기능은 별도 문제다. 그 복구 기능은 AI 음성 밀림 복구 절차 설계에서 다룬다(2026-09-11).
아래 줄 번호는 PPI-1290의 f4cc99f0 기준이다. 개선 구현이 들어간 커밋 번호가 아니다.
| 근거 | PPI 저장소 상대 경로 |
|---|---|
| LiveKit 기본 OFF 설정 | apps/web/hooks/audio-processing-presets.ts:125 |
| 서버 설정 해석·적용 | apps/web/lib/voice-agent/browser-audio-profile-resolver.ts:37 apps/web/lib/voice-agent/livekit-recognition-config.ts:258 |
| 처리 노드 생성·연결 / 입력 gate / health | apps/web/lib/voice-agent/livekit-audio-chain-processor.ts:237, :250, :394 |
| AI 원격 오디오 재생 / 프로세서 설치 | apps/web/lib/voice-agent/livekit-client-session.ts:3103, :3609 |
| RMS 생성·정리 / 기본 영상 전환 | apps/web/hooks/use-avatar-rms.ts:65 apps/web/shared/ui/meet-avatar.tsx:86 |
| 가드 활성 조건 / AI 외부 STT 캡처 | apps/web/entities/guest-page-session/model/use-guest-page-session.ts:1473, :1529, :1771 |
| localhost 모니터 이퀄라이저 | apps/web/shared/ui/monitor-media-display.tsx:482 |
| 입력 처리 테스트의 현재 한계 | apps/web/lib/voice-agent/livekit-audio-chain-processor.test.ts:16 |
PPI-1290, 기준 f4cc99f0. 공유 ctx 개선안은 덕킹 문제로 철회. 사용자 별도 지시 전 앱 코드·설정 변경 금지. 첫 구현 후보는 LiveKitAudioChainProcessor에서 OFF인 EQ 3개·컴프레서·리미터를 생성하지 않는 조건부 연결. 입력 Gain, analyser, AI 입력 gate, 진행자 relay, 실패 시 입력 차단 계약 유지. 행동 변경이므로 관련 harness를 먼저 보강. 실제 저전력·하네스 OFF 수업 A/B로 개선 확인. RMS 간소화는 독립 후속안이며 비발화 talking 영상 pause·속도 복구 및 Storybook 검증 필요. 현장 원인·성능 효과·이미 누적된 지연의 복구는 미확정.