블로그 목록
실시간 통신12분 읽기

전화 음성에서 웹 자막까지 1 — SIP·RTP·PCM 지도와 IP·포트 첫 실습

SIP·RTP·PCM·RTC·Signaling이 맡는 일을 나누고 Mac과 Ubuntu VM의 주소, localhost, bind와 목적지를 구분합니다. 시리즈 목차와 VM 주소 조회 과제로 시작합니다.

PBX 입문SIPRTPPCMIP포트VM

전화 음성이 웹 자막이 되기까지는 여러 프로그램이 일을 나눕니다. 이 시리즈의 목표는 설치 명령을 외우는 것이 아니라, 지금 어떤 데이터가 어디까지 도착했는지 설명하는 것입니다. 처음에는 IP와 포트 하나만 익히고, 다음 편에서 전화 연결과 음성 패킷을 차례로 살펴봅니다.

시리즈 목차와 읽는 순서

순서글한 편을 마치고 할 수 있는 일
1현재 글: 전화 시스템 지도Mac과 VM의 주소·포트·localhost 구분
2Asterisk SIP 계정과 목적지계정 1001과 발신 목적지 7000 설명
3Wireshark로 SIP 읽기캡처 필터와 표시 필터를 구분하고 통화 흐름 읽기
4RTP 헤더와 G.711sequence·timestamp·SSRC와 음성 길이 계산
5Python Gateway 코드 읽기UDP 수신부터 20ms PCM 출력까지 추적
6PCM 전달과 Agora 녹음로컬 바이트 수신과 원격 음성 수신의 증거 구분
7Agora STT·Signaling 자막과 식별자토큰·UID·채널 및 말풍선 경계 설명
8계층별 장애 분석계층별 증거로 다음 확인 지점 선택

1–4편은 입문, 5–7편은 실제 코드 읽기, 8편은 적용 연습입니다. 하루에 한 편의 과제만 해도 됩니다. 패킷 분석 경험이 있다면 기존 Wireshark 장애 분석 글, 더 넓은 오디오 구조가 궁금하면 오디오 파이프라인을 함께 읽으세요.

실습 환경과 원본 코드

이 시리즈는 기존 PBX 프로젝트를 읽는 사례 해설입니다. 설치부터 시작하는 튜토리얼은 아니므로, 실습 종류에 따라 필요한 환경을 먼저 구분하세요.

실습필요한 준비
개념·패킷 예시 읽기본문의 설명과 코드 예시
샘플 수·바이트 수 계산Python 3가 설치된 로컬 환경
VM 주소·SIP·RTP 확인Mac의 Lima, 실행 중인 pbx-gateway Ubuntu VM, 구성된 Asterisk·Linphone
Gateway 코드·검증 JSON 읽기별도 원본 프로젝트의 pbx_gateway/ 소스와 증거 파일

본문의 /workspace/pbx_gateway는 원본 프로젝트의 VM 경로이며, 블로그 저장소에는 해당 소스와 검증 JSON이 포함돼 있지 않습니다. 원본 환경이 없다면 VM 명령과 파일 조회는 건너뛰고 본문 예시와 오프라인 계산부터 진행하세요. 예시 출력과 과거 측정값을 자신의 실행 결과로 기록하지 않습니다.

먼저 구분할 세 가지 기록

기준일은 2026년 10월 1일입니다. 본문에서 과거 검증은 원본 프로젝트의 9월 28일 실행 기록, 코드 확인은 당시 구현을 읽은 결과, 설명용 예시·예정 실습은 독자가 앞으로 확인할 내용을 뜻합니다.

과거에는 Linphone 실제 통화, PCM 처리, Agora 원격 녹음과 사용자 청취, Signaling 자막 수신이 확인됐습니다. 그러나 현재 초보자 훈련에서는 VM IP를 확인하는 과제의 응답을 아직 받지 않았습니다. Wireshark 설치와 VM 실행 상태는 확인됐지만 REGISTER·INVITE·RTP 패킷의 실제 내용 분석은 아직 하지 않았습니다. 앞선 통화 성공 기록이 있다고 해서 이번 패킷 실습까지 완료된 것은 아닙니다.

이 시리즈를 작성하면서 새 통화·VM 제어·패킷 캡처를 실행하지 않았습니다. 뒤에 나오는 실습 명령과 예상 출력은 독자를 위한 안내이며, 실행 결과로 제시한 기록과 구분해 읽으세요.

1. 이름을 외우기 전에 길을 그린다

우체국에 비유하면 SIP는 배송을 요청하고 끝내는 대화, RTP는 내용물을 나눠 운반하는 봉투, PCM은 봉투에서 꺼낸 음성 숫자입니다. 정확히 말하면 SIP는 세션 제어 프로토콜이고, RTP는 실시간 미디어의 순서·시각 정보를 갖는 패킷 프로토콜입니다. PCM은 네트워크 프로토콜이 아니라 샘플 값으로 표현한 디지털 음성입니다. SIP와 RTP의 역할 구분은 RFC 3261과 RFC 3550에 근거합니다.

Mac                                       Ubuntu VM
Linphone ── SIP: 등록·통화 요청 ────────────> Asterisk
Linphone ── RTP: 전화 음성 ─────────────────> Asterisk
                                               │ ARI: 통화 제어 이벤트
                                               │ External Media: RTP 음성
                                               v
                                         Python Gateway
                                               │ G.711 → PCM
                                               │ PCM을 SDK에 넣음
                                               v
                                           Agora RTC
                                               │ 음성 구독
                                               v
                                           Agora STT Agent
                                               │ 인식된 텍스트
                                               v
Mac 자막 웹 <── Signaling 메시지 채널 ────────── Agora Signaling

RTC는 이 구현에서 음성을 보내는 서비스 경로이고 Agora Signaling은 자막 메시지 경로입니다. Agora STT는 이 구성에서 음성을 인식해 자막을 만드는 역할을 합니다. 웹 시청자는 마이크를 켜거나 RTC 음성을 재생하지 않아도 Signaling으로 텍스트를 받습니다. 반대로 Signaling에 로그인했다고 음성이 전송되지는 않습니다.

Asterisk는 SIP 전화 처리와 미디어 중계를, Python은 ARI 이벤트 처리와 RTP→PCM 변환을 담당합니다. 현재 구현은 전화 음성을 Agora로 보내는 단방향 경로입니다. Agent의 답변 음성을 전화기에 돌려주는 양방향 전화 봇까지 구현한 것은 아닙니다.

과제: 위 그림에서 “전화 연결 요청”, “음성 숫자”, “자막 텍스트”에 해당하는 화살표를 각각 하나씩 고르세요. 답은 SIP, Gateway 내부 PCM, Signaling입니다.

2. IP는 장치의 주소, 포트는 그 안의 수신 창구다

192.168.64.2:5060을 보면 IP와 포트를 나눠 읽습니다. 앞은 과거 시험의 VM 주소이고 뒤는 Asterisk SIP 수신 포트입니다. VM IP는 다시 확인해야 합니다. 이 숫자를 새 환경에서도 고정 주소처럼 복사하지 마세요.

프로세스는 실행 중인 프로그램입니다. 한 VM 안에 Asterisk와 Python이 함께 실행돼도, 서로 다른 포트에서 각자 데이터를 받을 수 있습니다. TCP 5060과 UDP 5060도 같은 소켓이 아닙니다. 이 실습의 SIP는 UDP를 사용합니다.

위치주소·포트이번 구성에서 받는 것
VM AsteriskUDP 5060SIP 등록·통화 제어
VM AsteriskUDP 10000–10020 범위전화 RTP 음성
VM AsteriskTCP 8088, loopbackARI HTTP/WebSocket 제어
VM GatewayUDP 60000, loopbackAsterisk External Media RTP
VM 별도 PCM 수신기UDP 60002, 선택 출력디코딩된 raw PCM
Mac Next.jsTCP 3000웹 화면과 API 요청

10000–10020은 Asterisk의 설정 범위입니다. 모든 통화에서 전 포트를 동시에 쓰거나, 모든 RTP가 이 범위만 쓴다는 뜻은 아닙니다. Gateway 구간은 별도의 60000을 사용하며 Agora 클라우드 연결은 SDK가 관리합니다.

3. 첫 실습: VM 주소만 읽는다

이 단계는 주소를 조회할 뿐 VM을 새로 만들거나 통화를 시작하지 않습니다. 전제: 기존 pbx-gateway Lima VM이 실행 중입니다. 아직 실행하지 않은 독자 과제이며 아래 출력은 설명용입니다.

실행 위치: Mac 터미널

limactl shell --workdir /workspace pbx-gateway -- ip -4 -brief address show

limactl shell은 지정한 VM 안에서 명령을 실행합니다. --workdir /workspace는 VM 작업 폴더, pbx-gateway는 VM 이름입니다. 뒤의 ip는 Linux 네트워크 조회 도구이며 -4는 IPv4만, -brief는 간단히 표시하라는 뜻입니다.

이미 Ubuntu VM 터미널 안이라면 다음 명령만 사용합니다.

ip -4 -brief address show

설명용 예상 출력은 다음과 같습니다. 인터페이스 이름과 주소는 환경마다 다릅니다.

lo      UNKNOWN  127.0.0.1/8
eth0    UP       192.168.64.2/24

lo는 자기 자신에게 연결하는 loopback 인터페이스입니다. eth0와 같은 비-loopback 인터페이스의 IPv4가 VM 주소 후보입니다. /24는 네트워크 접두사 길이이며 Linphone의 서버 주소에 붙이는 포트가 아닙니다. 인터페이스가 여러 개라면 Mac에서 도달 가능한 네트워크인지도 확인해야 합니다. 주소가 출력된 것만으로 SIP 포트 접근까지 증명한 것은 아닙니다.

결과 기록: “명령 위치: Mac / VM 이름: … / 인터페이스: … / IPv4: … / 아직 확인하지 않은 것: SIP 접근”을 적으세요. 실제 출력이 없다면 빈칸을 유지합니다.

4. localhost와 bind를 구분한다

127.0.0.1 또는 localhost는 명령을 실행하는 환경 자신을 가리킵니다. Mac의 127.0.0.1:3000은 Mac 웹 서버, VM의 127.0.0.1:60000은 VM Gateway입니다. 공유 폴더에 같은 파일이 보인다고 네트워크까지 같은 것은 아닙니다.

bind는 “내 프로그램이 어느 로컬 주소에서 받을 것인가”라는 수신 설정입니다. 반대로 목적지 주소는 “내가 어느 상대에게 보낼 것인가”입니다. Asterisk PJSIP transport 설명에서 transport와 endpoint의 관계를 확인할 수 있습니다.

표현해석
Asterisk bind=0.0.0.0:5060VM의 모든 IPv4 인터페이스에서 SIP 수신
Linphone 서버 주소에 VM IPv4 입력Mac이 VM의 Asterisk를 목적지로 선택
Gateway 127.0.0.1:60000 수신같은 VM의 Asterisk로부터 RTP 수신

0.0.0.0은 Linphone에 입력할 목적지 주소가 아닙니다. 이 bind 설정이 방화벽을 열어 주는 것도 아닙니다. 전체 인터페이스 bind는 접속 경로 선택을 단순하게 하지만 노출 범위가 넓습니다. loopback bind는 같은 호스트로 접근을 제한하지만 Mac에서 직접 연결할 수 없습니다.

과제: Mac의 Linphone 서버 주소를 127.0.0.1로 적으면 기본적으로 어디를 찾을까요? 답은 Mac 자신입니다. 별도 포트 전달 구성이 없다면 VM Asterisk에 연결하는 주소가 아닙니다.

5. 막혔을 때 확인할 것

증상먼저 확인할 것
VM에서 limactl: command not found이미 VM 안인지 확인하고 Linux ip 명령만 사용
Mac에서 asterisk: command not foundAsterisk는 VM에 설치돼 있음. 실행 위치부터 구분
주소는 맞는데 전화 연결 안 됨주소 조회와 SIP 수신·방화벽·계정 인증은 별도 확인
Gateway 시작에 Address already in use같은 포트를 기존 프로세스가 점유했는지 확인. 두 번째 Gateway를 켜지 않음

확인 질문: SIP 연결이 성공했는데 음성이 안 들릴 수 있을까요? 그렇습니다. 미디어 목적지, 코덱, 포트 및 실제 RTP 수신을 별도로 확인해야 합니다. 다음 편에서는 연결의 첫 단계인 계정 등록부터 봅니다.

자료 기준과 다음 단계

구현 근거는 원본 프로젝트 pbx_gateway/README.md의 전체 아키텍처·실행 위치, pbx_gateway/VALIDATION.md의 후속 검증 절, docs/handoffs/pbx-blog-training.md의 훈련 상태입니다. 공개하지 않은 원본 음성·인증값·패킷 파일은 이 글에 포함하지 않았습니다. 표준 개념과 현재 구현의 선택은 구분해서 읽어야 합니다.

다음: 2편 — Asterisk SIP 계정과 목적지

© 2026 Frank Kim. All rights reserved.