수신 음성은 직접 출력
LiveKit이 받은 원본 오디오 트랙을 <audio>에 붙여 재생합니다. 앱의 마이크 보정 그래프를 통과하지 않습니다.
현재 Room은 webAudioMix를 켜지 않습니다. SDK 내부 Context가 존재하는 것과 수신 음성이 Web Audio로 출력되는 것은 별개입니다.
마지막 업데이트 2026-09-11
LiveKit / VoicePipeline 모드에서 AudioContext 처리와 생성·재개·폐기가 AI 음성의 지지직·드르륵·끊김에 미치는 영향을 확인하고 줄이기 위한 문서입니다.
LiveKit이 받은 원본 오디오 트랙을 <audio>에 붙여 재생합니다. 앱의 마이크 보정 그래프를 통과하지 않습니다.
현재 Room은 webAudioMix를 켜지 않습니다. SDK 내부 Context가 존재하는 것과 수신 음성이 Web Audio로 출력되는 것은 별개입니다.
원본 마이크를 Web Audio로 보정한 뒤 AI 입력용과 진행자·녹음용 스트림으로 나눕니다. AI 듣기 OFF는 AI 분기만 차단합니다.
Context는 페이지 수명으로 재사용하지만 그래프는 세션마다 구성합니다. 진행자 음소거 등 별도 전달 정책은 이후 경로에서 적용됩니다.
SDK용 Context의 생성·폐기는 별도 수명 문제입니다. 이를 공유하려고 webAudioMix를 켜면 출력 경로도 바뀌므로 기존 mute 제어와 함께 검토해야 합니다.
실제 스피커 재생 경로에는 사용하지 않습니다. 현재 LiveKit / VoicePipeline 게스트의 흐름은 WebRTC 수신 트랙 → <audio> → 스피커입니다. 앱은 webAudioMix를 켜지 않고 audioTrack.attach(audioElement)로 수신 트랙을 연결합니다.
① SDK 내부 Context는 존재합니다. LiveKit SDK는 연결·재생 시작 시 Context를 확보하고 재개합니다. 그러나 수신 트랙에 Context를 전달하는 것은 webAudioMix가 활성화된 경우입니다. 현재 설정에서는 AI 음성을 Web Audio 출력 그래프로 보내지 않습니다.
② AI 수신 음성의 진단 분기에는 사용합니다. 진단 창이 열리면 1.5초 동안 수신 트랙 → 별도 AudioContext → Analyser로 음량을 측정합니다. 이 분기는 context.destination에 연결하지 않으므로 스피커 출력의 중간 단계가 아닙니다. 정리 시 진단 Context도 닫습니다.
③ 아동 마이크 보정에는 사용합니다. 오른쪽 입력 그래프의 공유 Context는 아동 음성을 AI·진행자에게 보내는 경로입니다. AI 수신 음성의 직접 출력과 구분해야 합니다.
확인 근거: 앱의 connectLiveKitBrowserSession·startRemoteAudioProbe·createAudioLevelProbe, LiveKit client SDK 2.19.2의 Room.acquireAudioContext와 RemoteAudioTrack.attach.
가능합니다. SDK 내부 Context도 브라우저의 AudioContext입니다. 다만 시간 진행 저하와 실제 스피커 출력 렌더 밀림은 같은 측정값이 아닙니다. 예를 들어 suspended 상태에서 currentTime이 멈추는 것은 정상 동작이므로, 상태 전환을 구분해야 합니다.
LIVEKIT_AUDIO_CHAIN / Audio chain health는 아동 마이크 처리 Context를 측정합니다. SDK 내부 Context의 진행 저하를 확인한 로그가 아닙니다.확인 방법: SDK Context에 별도 식별자를 부여하고 state, currentTime, performance.now(), 생성·재개 요청/완료·폐기 시점을 기록합니다. 같은 Context의 연속 구간에서 진행률을 계산하고, 마이크 Context·진단 Context와 분리해 실제 AI 출력 이상 시점과 대조해야 합니다. 마이크 Context 로그로 SDK Context의 상태를 대신 판단하지 않습니다.
근거: Web Audio currentTime 사양 · LiveKit SDK Context 확보·재개·재생 상태 판단. 위 기록 추가는 검증 제안이며 이번 문서 작업에서 구현하지 않았습니다.
신호 공백 자체를 렌더 밀림으로 확정할 수 없습니다. 제공된 9월 8일 MP3의 14:30~14:45를 PCM 파형·스펙트럼으로 분석했습니다. 특히 14:39~14:45에서 약 1초마다 0.2초 안팎으로 신호가 거의 무음이 되는 패턴이 확인됩니다.
| 녹음 위치 | 저신호 구간 길이 |
|---|---|
| 14:39.385~14:39.585 | 200ms |
| 14:40.390~14:40.585 | 195ms |
| 14:41.410~14:41.610 | 200ms |
| 14:42.435~14:42.645 | 210ms |
| 14:43.470~14:43.635 | 165ms |
| 14:44.470~14:44.660 | 190ms |
측정: 48kHz 모노 MP3를 16비트 PCM으로 디코딩. 5ms 단위 RMS가 −85dBFS 미만으로 60ms 이상 이어진 구간을 탐지했습니다. 위 구간 평균 레벨은 약 −93~−94dBFS, 시작 간격은 1.00~1.035초입니다. 경계는 5ms 분석 해상도 기준의 근삿값입니다.
입력 Context 진행률 약 79.2%와 신호 공백 비율이 수치상 비슷해 보여도, 녹음 위치와 로그 시각을 정렬하지 않았으므로 같은 현상으로 연결할 수 없습니다. 모노 녹음만으로 아동 마이크·AI 음성 중 어느 원본 경로에서 공백이 생겼는지, 아동 스피커에서도 동일하게 들렸는지 역시 확정하지 않았습니다.
다음 확인: 녹음 시간과 로그의 실제 시각을 먼저 맞춘 뒤, 가능하면 아동·AI 개별 녹음 트랙과 수신 통계·Context 상태를 비교해 공백이 처음 생기는 지점을 찾습니다.
AudioContext를 통과한다는 사실 자체가 지연의 원인은 아닙니다. 아래 그림은 확인된 처리 경로와 시계 관측에, 실제 렌더 처리가 원활하지 않을 때 가능한 영향을 연결한 검증용 그림입니다.
9.403초의 차이는 누적 관측 차이입니다. 음성 버퍼에 그만큼 쌓였거나 스피커에서 그만큼 늦게 재생됐다는 뜻은 아닙니다. 실제 음성 손실량으로 환산할 수도 없습니다.
게스트 마이크 처리와 LiveKit SDK가 별도 Context를 사용하고 SDK Context는 세션 연결·종료에 따라 생성·폐기됩니다. 게스트의 공유 Context를 Room에 전달해 주요 입출력 처리를 통합하고, 생성·폐기 비용 감소와 실제 잡음 개선 여부를 검증합니다. 다중 Context가 이번 증상의 원인이라고 확정한 것은 아닙니다.
두 신호는 자동으로 섞이지 않습니다. 마이크의 MediaStreamAudioDestinationNode는 전송용 트랙을 만들고, context.destination은 스피커로 출력합니다. 마이크를 스피커 destination에 연결하지 않으면 Context 공유만으로 자기 목소리가 재생되지 않습니다.
// 구현 예정 예시 — 현재 PPI에 적용된 코드가 아닙니다.
const room = new Room({
adaptiveStream: false,
dynacast: false,
webAudioMix: { audioContext: sharedContext },
});
SDK 2.19.2는 외부 Context가 있으면 새 내부 Context 대신 이를 사용하고, Room 종료 시 직접 닫지 않습니다. 이 옵션은 Web Audio 수신 출력도 활성화하므로, 기존 <audio> 직접 출력이 유지되는 변경은 아닙니다.
마이크 프로세서와 Room 모두 사용 주체로 관리합니다. Room 종료·연결 실패·재접속에는 해당 노드와 참조만 정리하고 다른 사용자가 있는 Context를 닫지 않습니다. 페이지 종료·회복 불가능한 closed 상태·재개 실패의 교체 정책도 정의합니다.
AI 듣기 OFF는 마이크의 AI 분기만 차단하고 진행자·녹음 분기는 유지합니다. AI 출력 OFF는 핑퐁이 수신 분기에 적용합니다. SDK 출력 Gain과 <audio> mute/volume 제어를 정리하고, 종료 후 잔류 음성·중복 attach가 없는지 확인합니다.
수신 음량 진단·출력 프로브 등은 추가 Context를 생성할 수 있습니다. 주요 두 Context를 합치는 것과 페이지 전체를 정확히 하나로 만드는 것은 다릅니다. LiveKit / VoicePipeline 모드에서 살아 있는 Context를 계수하고, 진단 분기의 공유·정리 정책까지 정해야 ‘단일 Context’라고 검증할 수 있습니다.
잡음·신호 공백, 에코·음량·아동 음성 인식, 진행자 청취·녹음, AI 듣기/출력 OFF, 세션 전환·재접속·백그라운드 복귀를 확인합니다. Context 수 감소만으로 성공을 판정하지 않습니다. 공유 Context가 멈추면 입력과 출력이 함께 영향을 받는 점도 검증합니다.
현재 조사한 외부 자료에서 ‘동일 페이지의 두 AudioContext가 PPI와 같은 약 200ms 주기적 공백을 유발한다’는 직접 근거는 찾지 못했습니다. 공유 통합은 개선 가설을 검증하는 변경입니다.
Audio chain not rendering은 0건이며, 15417~16424행의 시각 차분에서 진행 부족을 계산했습니다. 단말·네트워크 근본 원인은 확정하지 않았습니다.tsx lib/voice-agent/livekit-client-session.test.ts 통과. 이전 분석 시 실행한 모의 환경 테스트이며 공유 통합·iPad 음질 검증 결과가 아닙니다.이 문서 추가에 따른 앱 런타임 변경은 없습니다. 현재 코드 기준과 실제 9월 8일 배포본 전체의 일치 여부는 별도 확인 대상입니다.