PPI-1290 · AUDIO PERFORMANCE · DESIGN PROPOSAL

iPad AI 음성 밀림
최소 변경 완화 설계

마지막 업데이트 2026-09-11

설계 제안 · 코드 미반영 · 개선 효과 미검증

LiveKit 입력 체인에서 설정상 OFF인 EQ·컴프레서·리미터 노드를 실제 그래프에서도 제외하는 것을 우선한다. 핵심 구현은 한 파일로 제한하고, 효과가 부족하면 RMS 립싱크 간소화를 별도로 비교한다. 공유 AudioContext 개선안은 덕킹 문제로 철회되었다.

작성: 2026-09-10코드 확인: PPI-1290 · f4cc99f0실험 출처: PPI-1290-TEST · iPad 1대구현 착수: 사용자 별도 지시 후

좁은 화면에서는 표를 가로로 스크롤할 수 있습니다.

권장 순서와 범위

2026-09-11 적용 현황. 이 설계와 별도로 1차 대응이 코드에 반영됐다 — 영어 가드 LiveKit OFF(커밋 4ca9c122), 저전력 모드 프로브, AI 원격 오디오 재생 지연 감시(dry-run). 아래 OFF 노드 우회·RMS 간소화는 그 문서의 B층(WebAudio 축소)과 짝이 되며 아직 미반영이다. 상세는 PPI-1290 · iPad AI 음성 밀림 1차 대응.

1차 반영 후보: OFF인 처리 노드를 생성하지 않는 실제 우회(bypass). 저전력 모드 자동 감지나 새 ctx 관리 계층을 추가하지 않고, 기존 설정에 따라 입력 처리량을 줄인다. 앱 그래프가 현장 밀림을 유발한다는 인과와 이 변경의 개선 폭은 실기기로 검증해야 한다.
순서방법변경 규모판단
즉시 대응수업 전 저전력 모드 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 렌더 부하다. 이 문서는 재현 기록을 바탕으로 현재 코드의 실행 조건을 재검토한 후속 설계다.

공유 ctx 결정: 사용자 판단에 따라 공유 AudioContext 개선안은 덕킹 문제로 철회했다. 이 설계는 ctx 공유·재활용 범위를 확대하지 않는다. f4cc99f0의 실제 코드에는 입력 ctx 재사용 호출이 남아 있으므로, 철회 결정을 “모든 관련 코드가 제거됨”이라는 확인으로 해석하지 않는다. 잔존 코드 정리는 이번 제안 범위에 포함하지 않는다.

변경 지점은 마이크 입력 그래프

AI 음성 재생 · 원격 수신

LiveKit 원격 AI 오디오 트랙
↓ audioTrack.attach
HTMLAudioElement
iPad 스피커 / 선택된 출력 기기

입력 체인을 통과하지 않는다. 아래 입력 처리량 감소가 AI 재생을 개선하는지는 별도 검증한다.

아동 마이크 · 로컬 입력 / 송신

원본 마이크 → 기존 Gate Gain
EQ × 3 → 컴프레서 → 리미터
제안: 켜진 처리만 생성·연결
기존 출력 Gain
↙ AI 입력 gate · destination
↘ 진행자 전달 destination

원본 마이크의 별도 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

1차 설계: OFF인 처리 노드의 실제 우회

LIVEKIT_BROWSER_AUDIO_PROFILE.chaineqEnabled, compressorEnabled, limiterEnabled 기본값은 모두 false다. 현재 buildGraph()는 EQ 노드 3개와 컴프레서 노드 2개를 항상 만들며, OFF이면 EQ를 allpass, 컴프레서 비율을 1로 설정한다.

조건현재 동작제안 동작
chain OFF 또는 EQ OFFBiquadFilterNode 3개 생성 → allpass로 연결세 노드를 생성하지 않고 다음 활성 단계에 연결
chain OFF 또는 컴프레서 OFFDynamicsCompressorNode 생성 → ratio 1로 연결컴프레서 생성·연결 생략
chain OFF 또는 리미터 OFFDynamicsCompressorNode 생성 → ratio 1로 연결리미터 생성·연결 생략
각 기능 ONEQ → 컴프레서 → 리미터 순서로 설정 적용켜진 기능은 같은 순서와 파라미터로 연결
  1. 설정의 소유권: 기존 세션 설정을 그대로 사용한다. 적용 전 실험에서 최종 recognitionGate.audioChain 값을 기록해, 서버 설정이 기본값을 덮었는지 구분한다.
  2. 변경 파일: apps/web/lib/voice-agent/livekit-audio-chain-processor.ts의 노드 생성·연결·실패 시 정리·종료 정리를 조건부 노드에 맞게 수정한다. 새 ctx 관리자나 플랫폼 정책 계층을 추가하지 않는다.
  3. 계속 유지할 책임: 입력 Gain, 레벨 analyser, AI 입력 gate, 두 destination과 트랙 수명 관리는 기존 프로세서가 담당한다. AI 듣기 OFF여도 진행자에게 아동 음성이 전달되는 계약을 보존한다.
  4. 적용 시점: 기존 초기화·재시작에서 그래프를 구성한다. 저전력 상태 추정에 따라 발화 중 노드를 반복해서 연결·해제하는 기능은 추가하지 않는다.
  5. 실패 처리: 생성된 노드만 정리하고 기존 프로세서 설치 실패 처리를 유지한다. 오류 시 AI 입력 gate를 우회해 원본 마이크를 임의로 송신하지 않는다.
행동 변경으로 검증한다. allpass는 주파수별 위상 관계를 바꾸고, DynamicsCompressorNode는 고정 look-ahead 지연을 갖는다. OFF 노드를 제거하면 기존 파형의 위상·입력 지연이 달라질 수 있다. 기능 OFF의 의도에 맞춘 우회이지만, 동일 파형을 보장하는 정리 작업으로 취급하지 않는다. allpass 명세 · DynamicsCompressorNode 명세

제외 가능한 노드는 최대 5개다. 실제 CPU 절감률과 가청 지연 감소량은 아직 측정하지 않았다. 해당 설정이 모두 ON인 현장에서는 이 변경으로 제외되는 노드가 없다.

2차 설계: RMS 립싱크 간소화

먼저 RMS가 켜진 테스트 아바타의 기존 설정을 OFF로 바꿔 비교한다. 이는 새 구현 없이 가능한 진단이다. 설정 변경은 운영 전체가 아닌 테스트 대상으로 제한하며, 이 문서 작성 과정에서는 설정을 변경하지 않았다.

효과가 확인되면 iPad의 LiveKit 게스트에 한해 아바타용 RMS 분석과 Canvas 합성을 끄고, 기존 isPeerTalking 기반 idle/talking 영상 전환을 사용한다. AI 재생과 다른 소비자가 사용하는 원본 스트림은 유지하고, 아바타 분석 경계에만 간소화 조건을 적용한다.

이 안은 새로운 공유 ctx를 만들거나 기존 ctx를 일괄 close하는 설계가 아니다. 1차 개선과 동시에 적용하지 않고 각각의 기여도를 확인한다.

현재 실행 조건으로 다시 정렬한 후보

후보현재 코드 확인설계 판단
노이즈 가드noiseGuardEnabled && isRealtimeMode. resolved runtime이 LiveKit이면 비활성LiveKit 게스트 부하 절감 대상으로 잡지 않는다
AiAudioEqualizerMonitorMediaDisplay의 localhost 조건 안에서 렌더이번 dev 배포 게스트 증상의 개선 대상이 아니다
영어 가드!isLowPerfDevice && (override ?? enabled). 활성 시 ScriptProcessor와 MFCC 분석실제로 켜진 세션에서만 비교한다. 해제하면 영어 발화 감지·중단 기능도 감소하므로 운영 자동 해제를 기본안으로 삼지 않는다
외부 STT활성 시 아동 마이크 처리와 AI 재전사에 각각 그래프 사용전체 OFF는 아동 입력 처리에도 영향을 준다. 필요하면 AI 재전사 분기를 먼저 독립적으로 비교
영상 loopbackiOS 게스트에서 영상 오디오 덕킹 회피를 담당단순 제거·스텝별 재생성은 후순위. 원인 기여도와 재개 시 음량·무음을 검증한 별도 설계 필요

이번 첫 변경에는 공유 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를 보강한 뒤 코드를 변경한다. 입력 파형·지연 차이는 브라우저의 실제 오디오 처리 결과로도 확인한다.

실제 수업에서 재현되지 않으면: 변경 후에도 정상이라는 사실만으로 수정 완료라고 결론 내리지 않는다. 처리량 감소 후보 검증과 현장 원인 규명을 구분한다. 150% 인위적 과부하는 보조 스트레스 조건이며, 이를 계속 켠 상태의 무조건 정상 재생을 합격 기준으로 삼지 않는다.

계측에서 구분할 지표

필요한 계측은 기존 그래프·통계 경계에서 수집한다. 계측만을 위해 새 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 / healthapps/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 검증 필요. 현장 원인·성능 효과·이미 누적된 지연의 복구는 미확정.