마지막 업데이트 2026-07-22
| 발생 일시 | 2026-06-02 11:00 ~ 11:24 UTC (KST 20:00 ~ 20:24) |
| 고객 | 아동114 양육자 / 아동274 아동 / 두부핑퐁 1반 |
| roomId | fd2ae140-44a6-4355-99ff-c9b44d7a2eda_1 |
| activity | 반응_1회기(New)_첫만남대화_지우 (activity-1780369006596-0) |
| 접속 이력 | ① 노트북(Win10/Chrome) → ② 갤럭시탭 접속 1 → ③ 갤럭시탭 접속 2 (재시작 4~5회 반복) |
| 증상 | "친구가 안 나타난다"(노트북) → "친구가 말이 없다 / 마이크 인식이 안 된다"(갤럭시탭). 진행자 모니터에서 "아동 음성이 안 들어온다" 확인. |
| 관련 시스템 | V2 (FSD, mediasoup SFU) + OpenAI Realtime + External STT |
| 분석 소스 | LogRocket — 노트북 1건 / 갤럭시탭 2건 (총 3 세션) |
근본 원인 ②
갤럭시탭: 아동 마이크가 트랙·producer 는 정상 생성되나 실제 오디오 샘플이 0인 "무음/정지 스트림" 상태.
OpenAI Realtime VAD 가 발화를 단 한 번도 감지하지 못했고(입력 transcription/speech 이벤트 전무),
External STT 는 DUPLICATE CHUNK SKIPPED 만 8초간 99회 연속 — 같은 프레임이 계속 반복된다는 것은 캡처 버퍼가 정지/무음이라는 결정적 신호.
무음의 위치 = 캡처 소스
LogRocket 전체 로그 정밀분석 결과, 무음은 다운스트림 처리가 아니라 마이크 캡처 소스(Android 오디오 HAL/OS 레벨)에서 발생.
External STT(메인 스레드 ScriptProcessor 경로)와 OpenAI Realtime(오디오/네트워크 스레드 + WebRTC Opus 경로)은 다운스트림이 완전히 별개인데 둘 다 동시에 무음이었다.
두 경로가 공유하는 건 raw getUserMedia 마이크 트랙 하나뿐 → 그 공유 소스가 0 샘플을 내보냈다는 의미. 만약 단순 메인스레드 과부하였다면 네이티브 노드 기반 Realtime 경로는 살아남아 AI 가 아동 소리를 들었어야 하지만, OpenAI VAD 입력은 0건이었다.
저사양 기기
문제 기기는 isLowPerformanceDevice: true 로 분류된 저가 Android 태블릿(Android 10, RAM 2GB, armv81).
한 탭에서 카메라 인코딩 + mediasoup produce + External STT(48kHz AudioContext) + AI 오디오 캡처(16kHz AudioContext) + OpenAI Realtime WebRTC 가 동시에 도는데,
오디오 경로에는 저사양 분기가 전혀 없다(비디오만 480p 로 낮춤). 저가 Android 오디오 HAL 이 이 다중 캡처 부하를 못 버텨 마이크가 무음을 송출했을 가능성이 높다.
망/소켓 끊김 아님
"인터넷이 끊겼어요" critical 토스트를 보고 망 문제를 의심했으나 로그상 반박됨.
무음 구간 내내 mediasoup transport 는 "connected" 유지, "disconnected"/"failed" 전이 0건, 네트워크 alert 로그 0건.
유일한 socket 끊김은 20:11:59 의 "io client disconnect" = 진행자 force-kick(수동 재시작) 이며 무음이 관측된 후 발생. 토스트는 재입장 공백에서 순간적으로 뜬 것.
근본 원인 ①
노트북: 첫 오프닝 영상 video_firstopeningJW.mp4 의 리소스 fetch 실패.
[RESOURCE_CACHE] Failed to fetch → hasUrl:false 인 채로 영상 스텝으로 전환 → 영상이 안 떠서 "친구가 안 나타난다". (오디오 출력 문제 아님 — 네트워크/캐시 fetch 실패.)
AI 출력 정상
핑퐁이 음성 출력 경로는 3회 모두 정상. AI audio started {audioElMuted:false, audioElVolume:1},
AI audio producer created 가 매 세션 정상. "친구가 말이 없다"는 출력 고장이 아니라 입력이 없어 AI 가 응답을 만들지 못한 하류 증상.
관전 포인트
권한 거부(NotAllowed)·디바이스 없음(NotFound) 에러는 전무. getUserMedia 는 매번 audioTracks:1 로 성공.
"권한/디바이스 획득"은 되는데 "신호"가 안 실리는 전형적 무음 캡처. 양육자의 "기본값으로 설정했는데도 인식 안 됨"과 일치.
| 후보 | 판정 | 근거 |
|---|---|---|
| ① AI 오디오 출력 | 정상 | AI audio started {muted:false, vol:1}, AI audio producer created. "대화시작" 인사·필러는 실제 재생됨. |
| ② 아동측 마이크 입력 | ★ 실제 원인 (갤럭시탭) | track·producer 는 성공하나 소리 미수록. OpenAI 입력 speech/transcription 이벤트 0건 + External STT DUPLICATE CHUNK 99회. |
| ③ 아동측 비디오 재생 오디오 출력 | 해당 없음 | 노트북 이슈는 영상 다운로드(fetch) 실패(오디오 출력 아님). 갤럭시탭에선 영상 정상 재생. 비디오 오디오 출력 실패 로그 없음. |
| 시각 | 이벤트 |
|---|---|
| 19:39~19:54 | 대기실. 디바이스/권한 정상, 자동 디바이스 선택 완료 |
| 20:00:00 | V2FlowRedirect → /client-guest/session 진입, Socket 연결 |
| 20:00:06 | [RESOURCE_CACHE] Failed to fetch resource video_firstopeningJW.mp4: "Failed to fetch" |
| 20:00:13 | Local media started {videoTracks:1, audioTracks:1}, mic·camera producer 정상 생성 |
| 20:00:26 | Failed to get resource for video_firstopeningJW.mp4 → hasUrl:false |
| 20:00:46 | Step changed → full:video / resource:video_firstopeningJW (URL 없는 영상으로 전환) → "친구가 안 나타남" |
| 20:06:11 | Duplicate connection detected - disconnecting socket — 갤럭시탭로 재입장하면서 노트북 세션 강제 종료 |
| 20:21:24 | 탭 정리, media cleanup |
| 시각 | 이벤트 |
|---|---|
| 20:06:21 | Local media started {videoTracks:1, audioTracks:1}, mic producer 정상 |
| 20:08:12 | 오프닝 영상 정상 재생(106초). ended 미발화 → onEnd fallback (경미) |
| 20:08:13 | AI 세션 시작, AI audio started {muted:false, vol:1}, AI audio producer created → 출력 경로 정상 |
| 20:08:14~49 | AI 자율 응답 없음. response.create 텍스트가 전부 주입 필러 — "대화시작" → "음......" → "음........." |
| 20:10:34 | 호스트 주입 "-다시말해줘" (아동 응답 유도). 입력 transcription/speech 이벤트 여전히 0건 |
| 20:11:44 | External STT 켬 → 즉시 DUPLICATE CHUNK SKIPPED 99회 연속 (~8초) = 무음/정지 스트림 |
| 20:11:59 | Guest force kicked — 진행자 강제 재시작 |
| 시각 | 이벤트 |
|---|---|
| 20:12 / 20:13 / 20:21 / 20:24 | 세션 재시작 4~5회. 매번 Mic audio producer created 정상(트랙은 계속 살아있음) |
| 매 세션 | AI 자율 응답 0건, 주입 텍스트만("대화시작", "음", "-다시말해줘"). 입력 speech/transcription 이벤트 0건 |
| 20:12 / 20:13 / 20:24 | 호스트가 마이크 토글·External STT 토글·세션 재시작 반복 → 증상 동일 |
Local media started successfully {audioTracks:1}. 권한 OK, 트랙 존재. NotAllowed/NotFound 에러 없음.Mic audio producer created 가 매 세션 반복 성공. 트랙이 mediasoup SFU 로 publish 됨.AI 의 모든 발화는 response.create 에 명시적 text 가 주입된 것뿐:
Sent response.create { text: "대화시작" } // 시작 트리거
Sent response.create { text: "음......" } // 주입 필러
Sent response.create { text: "음........." } // 주입 필러
Sent response.create { text: "-다시말해줘" } // 호스트 응답 유도
input_audio_buffer.speech_started / conversation.item.input_audio_transcription.completed 등 아동 발화 입력 이벤트가 단 한 건도 없음. 즉 OpenAI VAD 가 들을 소리 자체가 안 들어왔다.
[GUEST_SOCKET] Sending transcript via socket 는 AI 출력 transcript 를 호스트에 보내는 것이지 아동 입력이 아님. 혼동 주의.
External STT 활성화 직후(20:11:44~52) 동일 청크가 99회 연속 스킵됨:
[External STT] Audio streaming started (with HPF 100Hz + Limiter -3dBFS)
[External STT] ⚠️ DUPLICATE CHUNK SKIPPED (× 99, ~8초)
LogRocket: Duplicate event limit was reached, further matching events are suppressed
전체 로그(772 entries)를 시계열·다경로 교차분석한 결과, 무음의 위치는 마이크 캡처 소스(저사양 Android 오디오 HAL/OS) 로 좁혀진다. 핵심 추론은 "독립된 두 오디오 경로가 동시에 무음":
| 경로 | 다운스트림 처리 | 도는 스레드 | 결과 |
|---|---|---|---|
| External STT | ScriptProcessor(48kHz→16k) | 메인 스레드 | DUPLICATE 99회(무음) |
| OpenAI Realtime | 네이티브 노드 + Opus | 오디오/네트워크 스레드 | VAD 입력 0건(무음) |
getUserMedia 트랙 하나뿐 → 소스가 0 샘플을 내보낸 것. 단순 메인스레드 과부하였다면 네이티브 노드 기반 Realtime 은 살아남았어야 한다. 즉 무음은 다운스트림(샘플레이트/스레드)이 아니라 캡처 소스에 있다.
원인 후보 (재정렬):
| ① 저사양 기기 HAL 캡처 무음 | isLowPerformanceDevice:true(Android 10, 2GB, armv81). 카메라 인코딩 + AudioContext 다수(48k STT, 16k AI) + mediasoup + OpenAI Realtime 동시 구동을 저가 오디오 HAL 이 못 버텨 무음 송출. 오디오 경로에 저사양 분기 없음. 유력 |
| ② 마이크 점유 / OS 음소거·가림 | 다른 탭/앱 선점, Android 레벨 음소거, 케이스·손가락 가림. 소스 무음을 낼 수 있음. |
| ③ Speakerphone 라우팅 의사장치 | 이전 가설이나 근거 약함 — 진행자가 20:13 에 오디오 기기를 3회(AudioDeviceChanged ×3) 바꿔도 무음 동일. 특정 장치 문제가 아니라 기기 전반 캡처 문제를 시사. 격하 |
| ④ 망/소켓 끊김 | 반박됨 — transport "connected" 유지, disconnect 는 force-kick 뿐. 제외 |
⑤ noiseReduction far_field | 적용돼 있었으나 정지 스트림 원인은 아님. 무관. |
DUPLICATE CHUNK 폭주가 사라지고 transcription 이 들어오는지 모니터에서 확인 (마이크 정상화의 즉시 지표)readyState:"live" 만 보고 정상 판정(무음을 못 잡음).video_firstopeningJW.mp4 캐싱 실패 시 재시도·대체 URL·스킵. hasUrl:false 인 채로 영상 스텝 진입 방지.