전화 음성에서 웹 자막까지 8 — 계층별 장애 분석과 검증 기록
연결 성공, PCM 출력, 원격 수신, 자막 성공을 서로 다른 증거로 확인합니다. 과거 시험 수치의 경계, p95 해석, 무음·에코·포트 충돌의 진단 순서를 정리합니다.
자막이 보이지 않을 때 모든 서버를 다시 시작하면 원인도 함께 사라질 수 있습니다. 이 글에서는 마지막으로 성공을 증명한 지점 바로 다음 경계부터 확인합니다. 하나의 로그로 전체 시스템을 합격시키지 않는 것이 핵심입니다.
시리즈 목차 · 이전: PCM 이후 Agora STT·Signaling 자막
1. 연결과 데이터는 서로 다른 증거다
초인종을 눌러 문이 열린 것과 물건이 도착한 것은 다릅니다. 기술적으로는 연결·인증 성공과 애플리케이션 데이터 수신 성공을 구분해야 합니다. SIP의 세션 제어와 RTP의 데이터 전달 역시 다른 역할입니다. RFC 3261, RFC 3550
| 단계 | 확인할 증거 | 이것만으로 알 수 없는 것 |
|---|---|---|
| SIP 계정 등록 | REGISTER 응답과 contact | 7000 발신·음성 수신 성공 |
| ARI 연결 | Connected to ARI application | 통화가 bridge에 연결되고 RTP가 도착했는지 |
| 통화와 RTP | call 시작, packets_accepted 증가 | 디코딩·실시간 출력 성공 |
| PCM 출력 | output_frames, output_samples 증가 | Agora 원격 수신·청취 성공 |
| 로컬 녹음 | recording_status=complete | 음성이 정상인지, 원격으로 전달됐는지 |
| Agora 연결 | agora_connected | 비어 있지 않은 원격 PCM 수신 |
| 원격 수신 | observer PCM·형식·WAV·청취 | ASR 문장 정확도와 Signaling 라우팅 |
| Signaling 연결·구독 | 로그인·subscribe 완료 | Agent가 자막을 생성하고 웹이 수락했는지 |
| 웹 자막 | MESSAGE 수신, 검증 후 accepted 증가 | 음질 무결성·100명 동시 서비스 성능 |
과제: “ARI 연결 성공, RTP 수신 0”이라는 기록에서 현재 증명된 것은 무엇일까요? 제어 연결만 확인됐습니다. PCM 계산이나 말풍선 CSS를 먼저 고칠 근거는 없습니다.
2. 과거 시험 결과를 읽는 작은 실습
아래는 기존 초안이 2026년 9월 28일 내부 시험 기록에서 인용한 수치입니다. 원본 JSON·README와 실행 버전은 이 블로그에 공개돼 있지 않아 이번 편집에서 독립적으로 대조하지 못했습니다. 재실행하거나 재현성을 검증한 결과가 아닌 내부 관찰 요약으로 읽으세요. 시험별 입력과 측정 경계가 달라 하나의 합격표로 합치면 안 됩니다.
| 과거 시험 | 관찰값 | 가능한 결론과 한계 |
|---|---|---|
| 합성 RTP 300초 | 15,000 packets, 2,400,000 samples, p95 약 43.73ms, 손실·drop·sink 오류 0 | 해당 로컬 합성 입력 처리 안정성. 실제 전화·ASR 시험 아님 |
| 사용자 PCMU 실제 통화 | 310.36초, 15,518 packets, 2,482,880 samples, p95 약 46.02ms, 손실·drop·sink 오류 0 | 해당 PCMU 통화 처리. 모든 통화나 코덱의 보장값 아님 |
| 합성 440Hz → Agora | 5초 입력, 원격 16kHz mono PCM 500프레임·160,000B, 440Hz 에너지 비율 99.91% | 해당 합성 음성의 원격 전달. 사람 발화 인식률 시험 아님 |
| 사용자 실제 전화 → Agora | 원본 README에 22.72초 처리 및 원격 WAV 청취 양호 응답 기록 | 실제 음성 전달의 사용자 확인. 객관적 전체 음질 점수 아님 |
| Signaling UID 비교 | 수신자 둘이 각각 269건, final 각각 18건 | 다른 Signaling UID의 같은 MESSAGE 채널 구독 수신 성공 |
| 위 UID 분리 시험의 음성 출력 | sink_errors=131, live_drops=94 | 깨끗한 음질 시험으로 합격시킬 수 없음. 오류 원인까지 확정된 것은 아님 |
근거 파일은 pbx_gateway/evidence/soak-final.json, live-pcmu-310s.json, agora-arm64-smoke.json, v2v-rtm-uid-probe.json과 원본 README의 사용자 로그 요약입니다. 원본 VALIDATION.md의 초기 “미검증” 절만 읽으면 후속 실제 통화 결과를 놓칩니다. 반대로 후속 청취 성공이 있다고 초기 실패를 성공으로 바꾸면 안 됩니다.
실행 위치: Mac 터미널, Python 3가 있는 환경. 아래는 표의 숫자만 계산하는 오프라인 실습입니다. 네트워크·VM·음성 파일에 접근하지 않습니다.
설명용 기대 출력:
첫 줄은 sample 수÷sample rate, 둘째는 bytes÷(sample rate×channel 수×sample당 bytes)입니다. 셋째는 이 시험의 20ms G.711 패킷 가정입니다. 다른 ptime이나 codec의 패킷 수에 그대로 곱하지 마세요. 길이가 맞아도 전부 무음일 수 있으므로 원격 시험에는 비영 샘플·주파수 분석·청취 같은 다른 증거가 필요합니다.
확인 질문: 8kHz 송신 sample 수와 16kHz 수신 sample 수가 두 배 차이나면 손실인가요? 아닙니다. 각 형식으로 초 단위를 먼저 계산하고 실제 신호를 비교해야 합니다.
3. 무음·에코·포트 충돌을 단계별로 분리한다
| 증상 | 첫 확인 | 결과에 따른 다음 행동 |
|---|---|---|
| SIP 연결 실패 | 현재 VM 주소, SIP 수신, 계정·dialplan | 등록 문제와 목적지 7000 라우팅을 분리 |
| 통화 직후 종료, RTP 0 | ARI 오류의 HTTP 상태·채널 준비 상태 | External Media 생성과 bridge 추가 사이를 확인 |
| 통화 유지, PCM 0 | RTP 수신 여부·PT·코덱, 실제 미디어 목적지 | 수신 0이면 경로, 수신 뒤 reject면 parser/코덱 경계 확인 |
| PCM 증가, 원격 무음 | 샘플 형식·비영 데이터·구독 UID·observer | 로컬 출력과 원격 수신 녹음을 구분 |
| 느리거나 높은 목소리 | 8/16kHz, mono, PCM16 형식 | sample rate 라벨만 바꿨는지 실제 resample했는지 확인 |
| 내 목소리가 되돌아옴 | 스피커 출력과 마이크 입력의 관계 | 별도 예정 실습에서 헤드폰·마이크 음소거 비교 |
Address already in use | 해당 UDP 포트를 점유한 PID | 기존 Gateway와 새 수신기를 구별. 무작정 프로세스를 종료하지 않음 |
| Signaling 연결인데 자막 0 | Source RTC UID·음성 수신·Agent 상태·채널·메시지 수락 | 로그인 성공 이후 경계를 하나씩 확인 |
다음은 추후 진단용 읽기 명령입니다. 이번 블로그 작업에서 실행한 명령이 아닙니다.
실행 위치: Ubuntu VM 터미널
첫 명령의 -u는 UDP, -l은 수신 소켓, -n은 숫자 주소, -p는 프로세스 표시입니다. 권한이 있으면 60000을 점유한 프로세스를 확인할 수 있습니다. 출력에 Python이 있다는 것만으로 정상 음성 수신을 증명하지는 못합니다. 출력이 비어 있으면 해당 조회 범위에서 수신 소켓을 찾지 못한 것입니다.
둘째 명령은 실행 중인 Asterisk에 채널·통화 개수를 조회합니다. 전화 종료 후 active call이 0인지 보는 용도입니다. 채널 수와 사람 수를 같다고 해석하지 마세요. 한 통화에 External Media 같은 보조 채널이 있을 수 있습니다. 프롬프트와 Password: 문구는 복사하지 않습니다.
원본의 ARI 수정 사례에서는 External Media 생성 응답 직후 bridge 추가가 HTTP 422로 실패했습니다. 기록에 따르면 새 External Media 채널의 준비 시점 문제를 가정해, 해당 bridge 추가 단계에서 발생한 422에 대해 50ms 간격 최대 20회 재시도하도록 제한했습니다. 공개된 응답 본문과 채널 상태 기록이 없으므로 준비 경쟁이 원인이었다고 여기서 확정할 수는 없습니다. 모든 HTTP 오류를 무한 재시도하는 일반 규칙이 아닙니다. 404·409·500 등을 같은 이유로 취급하지 않습니다. 이 통합 경계는 Asterisk External Media 문서를 함께 읽으면 이해하기 쉽습니다.
4. p95가 낮아도 자막이 늦을 수 있다
p95는 수집한 표본 중 약 95%가 그 값 이하라는 통계입니다. “모든 요청의 최대 지연”이나 “전체 시스템의 평균 지연”이 아닙니다. 특히 측정 시작과 끝을 적지 않은 숫자는 비교하기 어렵습니다.
원본 arrival_to_output_p95_ms는 Gateway에 도착한 RTP부터 출력 소비 완료 경계까지 측정합니다. RTC 전송 이후 ASR·Signaling·화면 렌더링은 포함하지 않습니다. 과거 PCMU 수치는 첫 미디어 후 1초 워밍업을 제외하고 총 15,467표본 중 최근 15,000표본에 대한 값입니다. 이를 “전화에서 자막까지 46ms”라고 말하면 틀립니다.
추후 전체 지연 실습에서는 발화 기준 시각, 첫 partial 표시, final 표시를 나누고 시계 기준과 동기화 방법을 기록해야 합니다. 서로 다른 기계의 벽시계 값을 보정 없이 빼면 안 됩니다. 이 종단 지연은 이번 시리즈에서 측정하지 않았습니다.
과제: “Gateway p95 50ms, 사용자는 자막을 2초 뒤 봄”이라는 설명용 상황에서 모순이 있나요? 없습니다. 측정 범위가 다릅니다. 다음 확인 지점은 원격 수신·ASR 이벤트·Signaling 수신·화면 표시의 시간입니다.
5. 설계 선택에는 비용이 있다
| 선택 | 얻는 것 | 감수하거나 별도로 검증할 것 |
|---|---|---|
| jitter buffer를 둠 | 순서 뒤바뀜과 도착 간격 변동 흡수 | 기다리는 만큼 지연 증가. 너무 늦은 패킷은 사용하지 못함 |
| 실시간 큐 크기를 제한 | 느린 출력 때문에 지연이 끝없이 누적되는 것을 방지 | 프레임 drop 가능, 카운터 관찰 필요 |
| WAV writer와 실시간 sink 분리 | 디스크 문제와 실시간 전송의 결합을 줄임 | 녹음 오류·녹음 큐 손실을 별도로 추적 |
| 시청자가 Signaling 채널 직접 구독 | 이 검증 경로에서 별도 자막 relay 없이 수신 | 시청자별 인증·접근 제어·부하 검증은 별도 |
| 3초 inactivity 말풍선 | 음성 없이 자막 이벤트만으로 구현 가능 | 네트워크 지연과 실제 무음을 구분하지 못함 |
현재 웹은 시청만 하는 제품 화면이 아니라 각 페이지가 Agent 시작도 담당하는 진단 도구입니다. 100명 시청을 시험한다고 현재 페이지를 100개 열어 각각 시작하지 마세요. 엔진 생성 책임과 시청자 구독을 분리한 뒤 별도 부하 시험이 필요합니다. 이미 확인한 것은 수신자 두 명의 UID 분리입니다.
통합 채널명은 63자 이하로 맞춥니다. 당시 웹/API의 64자 허용과 Gateway의 63자 허용은 현재 구현의 경계 불일치입니다. 이 시리즈는 그 코드나 인증 경로를 변경하지 않았습니다.
6. 다음 실습에서 채울 기록
현재 초보자 훈련의 다음 단계는 1편의 VM 주소 조회 결과를 기록하는 것입니다. 이후 3편의 SIP 관찰과 4편의 RTP 분석을 진행할 때 아래 양식을 채웁니다. 이번 시리즈의 패킷 그림과 수치 예시는 실제 캡처 판독 결과가 아닙니다.
패킷이나 WAV 원본에는 주소·식별자·음성이 들어갈 수 있으므로 그대로 공개 자산으로 올리지 않습니다. 블로그를 보완할 때는 확인에 필요한 필드만 익명화하고, 설명용 예시를 실제 관찰로 교체한 날짜를 적으세요. 더 넓은 장애 분석은 시그널링과 미디어 분리, Wireshark 분석로 이어집니다.