블로그 목록
Architecture25분 읽기

RTC 미디어 경로 해부 — RTP에서 Media Push·Cloud Recording까지

RTC 채널의 압축 프레임이 RTP로 패킷화되는 과정과 서버 측 미디어 제품이 그 흐름에 개입하는 지점을 추적합니다. Media Gateway·Media Pull·Cloud Transcoding·Media Push·Cloud Recording을 입력, 변환, 출력 기준으로 구분하고 CDN 송출과 stream fallback까지 같은 데이터 경로 위에서 설명합니다.

RTPRTCPMedia GatewayMedia PullMedia PushCloud RecordingCloud TranscodingCDN
목차(29개 항목)
  1. RTC 채널 안의 미디어 = 실시간으로 packetize된 압축 미디어
    1. Video
    2. Audio
    3. 네트워크에서 실제로 보이는 형태
    4. 왜 이 구조인가 — 파일이 아니라 패킷이어야 하는 이유
    5. 왜 TCP가 아니라 UDP인가
  2. 이 미디어가 Agora SD-RTN에서 어떻게 흐르는가
  3. Agora 클라우드 제품을 데이터 흐름으로 이해하기
    1. 전체 지도
    2. ① Media Gateway — "RTMP/SRT → RTP 변환기"
    3. ② Media Pull (Cloud Player) — "URL fetch → RTP 변환기"
    4. ③ Cloud Transcoding — "RTP subscribe → decode → 합성 → encode → RTP publish"
    5. ④ Media Push — RTC 미디어를 외부 ingest로 전달
  4. CDN이 RTMP를 받을 때 — "아무거나 받지 않는다"
    1. 조건 1 — RTMP Handshake 정상
    2. 조건 2 — Stream Key 인증
    3. 조건 3 — Codec 제한
    4. 조건 4 — Bitrate / FPS / GOP 제한
  5. CDN 내부에서 일어나는 일 — Agora의 책임은 여기까지
    1. CDN 내부 처리 4단계
    2. 전체 파이프라인 한눈에
    3. 세 가지 미디어 형태의 본질적 차이
    4. ⑤ Cloud Recording — "RTP subscribe → decode → 파일 저장"
  6. 패킷 레벨에서 보는 전체 변환 흐름
  7. Stream Fallback — 네트워크가 나쁠 때 음성 우선 정책
    1. Dual Stream Mode가 하는 일
    2. Fallback 설정 시 확인할 것
  8. 정리: 공개 계약과 구현 추정을 구분한다
  9. 참고 자료

Agora RTC 채널에서 미디어가 실제로 어떤 형태로 존재하고, 네트워크를 타고 어떻게 이동하는지를 먼저 이해해야 합니다. 그래야 Media Push, Media Pull, Cloud Transcoding 같은 클라우드 제품들이 "정확히 무엇을 하는 건지" 엔지니어 관점에서 파악할 수 있습니다.


RTC 채널 안의 미디어 = 실시간으로 packetize된 압축 미디어

웹 WebRTC에서는 압축 미디어를 RTP payload로 packetize하고 SRTP로 보호해 ICE가 선택한 경로로 보냅니다. UDP를 우선하지만 UDP가 막히면 TURN/TCP 또는 TURN/TLS를 사용할 수 있습니다. Agora Native SDK의 wire format과 내부 전송 프로토콜을 표준 RTP/UDP와 동일하다고 단정해서는 안 됩니다.

먼저 오해를 없애겠습니다:

❌ mp4 파일이 아닙니다
❌ 하나의 연속된 스트림이 아닙니다
❌ "영상 파일을 보내는 것"이 아닙니다

✅ 실시간 패킷 스트림입니다
✅ 각 패킷은 독립적으로 유실될 수 있습니다
✅ 순서가 뒤바뀔 수 있습니다
✅ 그래도 동작합니다

Video

카메라 (Raw Frame: YUV/NV12)
   ↓ 인코딩
Encoded Video Frame (H.264 NAL Unit / VP8 Frame)
   ↓ 패킷화
RTP Packets (MTU 이하로 분할)
   ↓ 전송
ICE가 선택한 transport 경로
  • 코덱: H.264, VP8, VP9
  • 인코딩 결과: H.264의 access unit은 하나 이상의 NAL unit으로 구성됩니다. I/P/B는 정확히는 slice type이며, IDR picture가 대표적인 random-access 지점입니다.
  • 왜 쪼개는가: 인코딩된 access unit이 경로 MTU보다 클 수 있어 RFC 6184 같은 codec payload 규격에 따라 여러 RTP packet으로 나눕니다. 1,200바이트 안팎은 fragmentation을 피하기 위한 보수적 목표값이지 MTU의 보편값은 아닙니다.

Audio

마이크 (Raw Audio: PCM)
   ↓ 인코딩
Encoded Audio Frame (예: Opus Frame)
   ↓ 패킷화
RTP Packet (보통 1개 프레임 = 1개 패킷)
   ↓ 전송
ICE가 선택한 transport 경로
  • 코덱: WebRTC endpoint는 Opus와 G.711 PCMA/PCMU를 필수 구현합니다. Agora의 지원 코덱은 SDK·플랫폼·모드별 문서를 확인해야 합니다.
  • 인코딩 결과: Opus는 2.5·5·10·20·40·60ms 프레임을 지원하며 packet은 여러 frame을 합쳐 최대 120ms를 담을 수 있습니다. byte 크기는 bitrate와 frame duration에 따라 달라집니다.
  • 비디오와의 차이: 오디오 payload는 보통 영상보다 작지만, "항상 한 frame이 한 packet"인 것은 아닙니다.

네트워크에서 실제로 보이는 형태

┌─────────────────────────────────────────────────┐
│                   RTP Packet                     │
├─────────────────────────────────────────────────┤
│  Header (12 bytes 고정 + extension)              │
│  ┌─────────────────────────────────────────────┐│
│  │ V=2  │ P │ X │ CC │ M │  PT (Payload Type)  ││
│  │ Sequence Number (16bit)                      ││
│  │ Timestamp (32bit)                            ││
│  │ SSRC - Synchronization Source (32bit)        ││
│  └─────────────────────────────────────────────┘│
├─────────────────────────────────────────────────┤
│  Payload                                         │
│  ┌─────────────────────────────────────────────┐│
│  │ H.264 NAL Unit slice                         ││
│  │ 또는 Opus encoded frame                      ││
│  │ 또는 VP8 partition                           ││
│  └─────────────────────────────────────────────┘│
└─────────────────────────────────────────────────┘

각 필드가 하는 일:

필드크기역할
SSRC32bit동기화 소스 식별자. 한 사용자가 simulcast·RTX/FEC 등 여러 SSRC를 쓸 수 있고 세션 중 바뀔 수도 있음
Timestamp32bit미디어 시간. 수신 측에서 재생 타이밍을 맞추는 기준
Sequence Number16bit패킷 순서. UDP는 순서 보장이 없으므로 수신 측에서 재정렬에 사용
PT (Payload Type)7bitpayload format 번호. dynamic 값의 codec mapping은 SDP 같은 세션 신호로 정함
M (Marker)1bit의미는 payload 규격별로 정의. H.264에서는 access unit의 마지막 packet을 표시
CSRC가변믹싱된 경우 원본 소스들의 SSRC 목록

왜 이 구조인가 — 파일이 아니라 패킷이어야 하는 이유

RTC는 본질적으로:

1. 실시간     — 1초 뒤 도착하는 데이터는 쓸모없음
2. packet loss 허용 — 일부 유실돼도 계속 재생
3. reorder 가능     — 패킷 순서가 뒤바뀔 수 있음
4. jitter buffer 있음 — 네트워크 지연 변동을 흡수하는 버퍼

파일 컨테이너는 헤더·index·sample 구조를 사용하고, 손상 영향은 빠진 위치와 복구 정보에 따라 달라집니다. RTC 수신기는 deadline이 지난 packet을 버리고 concealment·재전송·refresh 요청을 조합하지만, reference picture 손실은 이후 picture에도 영향을 줄 수 있습니다.

왜 TCP가 아니라 UDP인가

TCP: 패킷 유실 → 재전송 → 기다림 → 지연 누적
     실시간 미디어에서는 "늦게 도착한 패킷"은 쓸모없음

UDP: 애플리케이션이 deadline과 손실 복구 정책을 직접 제어
     WebRTC는 UDP를 우선하되 TCP/TLS relay fallback도 지원

RTP는 UDP 위에서 동작하되, 패킷 유실이 발생하면:

  • 비디오: 손실 영향은 reference 구조·packet 위치·concealment에 따라 다릅니다. NACK/RTX, FEC, PLI/FIR 같은 feedback을 조합할 수 있습니다.
  • 오디오: Opus decoder는 PLC와 선택적 in-band FEC를 지원하지만 결과는 loss pattern과 콘텐츠에 따라 달라집니다.

이 미디어가 Agora SD-RTN에서 어떻게 흐르는가

Agora는 SD-RTN을 공용 인터넷 위의 소프트웨어 정의 오버레이로 설명합니다. 아래 SFU 그림은 다자간 RTC의 일반적인 전달 모델을 설명하기 위한 개념도이며, Agora 내부 노드의 정확한 토폴로지나 암호화 경계를 공개 API 계약처럼 해석하면 안 됩니다.

  Host A                    Agora SD-RTN                    Viewer B
  ┌──────┐                 ┌──────────────┐                ┌──────┐
  │      │  RTP packets    │              │  RTP packets   │      │
  │ Send ├────────────────▶│  SFU Server  ├───────────────▶│ Recv │
  │      │  (encrypted)    │              │  (forwarded)   │      │
  └──────┘                 │  미디어를 디코딩 │                └──────┘
                           │  하지 않고     │
                           │  패킷을 그대로  │
                           │  전달 (forward) │
                           └──────────────┘

일반적인 SFU의 핵심은 압축 미디어를 합성하지 않고 수신자별로 계층을 선택해 전달하는 것입니다. RTP header rewrite·재전송·SRTP termination 여부는 구현과 E2EE 방식에 따라 달라집니다.

  MCU (Media Control Unit) — 옛날 방식:
  서버가 디코딩 → 합성 → 재인코딩 → 전달
  CPU 부하 높음, 지연 큼

  SFU (Selective Forwarding Unit) — 현대 방식:
  서버가 패킷을 선택적으로 전달만 함
  CPU 부하 낮음, 지연 낮음

그런데 여기서 중요한 질문이 생깁니다:

"SFU는 디코딩 안 하고 전달만 한다면서, Cloud Transcoding은 서버에서 합성/재인코딩을 한다고? 그럼 MCU 아닌가?"

여러 입력을 하나의 영상으로 합성하는 transcoding 경로는 decode·compose·encode를 수행한다는 점에서 MCU형 처리와 유사합니다. 이것이 Agora의 내부 배치 구조까지 증명하는 것은 아닙니다.


Agora 클라우드 제품을 데이터 흐름으로 이해하기

이제 RTP 패킷 레벨에서 각 제품이 정확히 무엇을 하는지 볼 수 있습니다.

전체 지도

                        ┌──────────────────────────────────┐
                        │         Agora SD-RTN Cloud        │
                        │                                   │
  외부 세계              │        RTC Channel (SFU)          │        외부 세계
                        │                                   │
  ┌──────────┐          │   👤 Real User A (SSRC: 0x1A)     │
  │ RTMP/SRT │──①──────▶│   👤 Real User B (SSRC: 0x2B)     │
  │ 송출 장비 │          │                                   │──④──▶ CDN (RTMP)
  └──────────┘          │   🤖 ① Media Gateway Bot          │
                        │   🤖 ② Cloud Player Bot           │──⑤──▶ Storage (MP4)
  ┌──────────┐          │   🤖 ③ Cloud Transcoder Bot       │
  │ URL 소스  │──②──────▶│   🤖 ④ Converter Bot (Media Push) │
  └──────────┘          │   🤖 ⑤ Recorder Bot               │
                        │                                   │
                        └──────────────────────────────────┘

① Media Gateway — "RTMP/SRT → RTP 변환기"

[외부 RTMP 스트림]                    [RTC Channel]
H.264 + AAC                          RTP Packets
FLV container                        UDP transport
TCP transport                        Agora 프로토콜

  OBS/인코더 ──RTMP──▶ Gateway Server
                         │
                         ├── FLV 컨테이너 해체 (demux)
                         ├── H.264 NAL units 추출
                         ├── AAC frames 추출  
                         ├── (선택) 트랜스코딩 (해상도/코덱 변환)
                         ├── RTP 패킷으로 재패킷화
                         └── RTC 채널에 publish (새 SSRC 할당)

패킷 레벨에서 일어나는 일:

  1. RTMP 패킷 수신 (TCP)
  2. FLV 컨테이너에서 H.264 NAL units + AAC frames 분리
  3. 타임스탬프를 RTP timestamp 체계로 변환
  4. RTP 헤더 생성 (SSRC, seq number, timestamp)
  5. Agora SD-RTN으로 전송

트랜스코딩을 활성화하면 한 입력에서 여러 해상도·bitrate 출력을 만들 수 있습니다. 아래 SSRC와 bitrate는 원리를 보여 주는 예시이며 실제 Agora 할당 방식이나 기본 ladder가 아닙니다.

RTMP Input (1080p)
   ↓ Gateway Transcoder
   ├── Layer 0: 1080p, 3800kbps (SSRC: 0xA0)
   ├── Layer 1: 720p,  2400kbps (SSRC: 0xA1)
   ├── Layer 2: 540p,  1500kbps (SSRC: 0xA2)
   └── Layer 3: 360p,  500kbps  (SSRC: 0xA3)
   
   수신 측 SDK가 네트워크 상태에 따라 자동 전환

② Media Pull (Cloud Player) — "URL fetch → RTP 변환기"

  Cloud Player Server
     │
     ├── HTTP/RTMP/HLS로 외부 URL에서 미디어 다운로드
     ├── 컨테이너 해체 (MP4 demux, HLS segment 파싱)
     ├── 코덱 프레임 추출
     ├── (선택) 트랜스코딩
     ├── RTP 패킷 생성
     └── 지정된 UID + SSRC로 채널에 publish

Gateway와의 RTP 레벨 차이:

  • Gateway: 외부에서 push → 서버가 수동적으로 받음
  • Pull: 서버가 능동적으로 fetch → HTTP GET / RTMP connect

두 경우 모두 외부 미디어가 RTC 채널의 publish 가능한 형식으로 변환됩니다. 정확한 packet format과 UID/SSRC 매핑은 공개된 제품 API에서 보장하는 범위만 사용해야 합니다.

③ Cloud Transcoding — "RTP subscribe → decode → 합성 → encode → RTP publish"

이것이 RTP 레벨에서 가장 복잡한 제품입니다.

  Input Phase (Subscribe)
  ──────────────────────────────
  Host A의 RTP packets (SSRC: 0x1A) ──subscribe──┐
  Host B의 RTP packets (SSRC: 0x2B) ──subscribe──┤
                                                  ▼
  Decode Phase
  ──────────────────────────────
  RTP reassembly (seq number로 재정렬)
     ↓
  Jitter Buffer (네트워크 지연 변동 흡수)
     ↓
  H.264 decode → Raw YUV frames (Host A)
  H.264 decode → Raw YUV frames (Host B)
  Opus decode  → Raw PCM samples (Host A)
  Opus decode  → Raw PCM samples (Host B)

  Processing Phase
  ──────────────────────────────
  Video Compositing:
     Canvas (960x480 빈 프레임 생성)
        ↓
     Host A의 YUV를 (0,0,320,360) 영역에 scale & paste
     Host B의 YUV를 (320,0,320,320) 영역에 scale & paste
     Watermark 이미지를 alpha blend
        ↓
     합성된 단일 YUV frame
  
  Audio Mixing:
     Host A PCM + Host B PCM → 샘플 단위로 합산 (clipping 방지)
        ↓
     믹싱된 단일 PCM stream

  Encode Phase
  ──────────────────────────────
  합성된 YUV → H.264 encode → NAL units
  믹싱된 PCM → Opus/AAC encode → audio frames

  Output Phase (Publish)
  ──────────────────────────────
  NAL units → RTP packets (새 SSRC: 0xC0, UID: 1000)
  Audio frames → RTP packets
     ↓
  출력 채널에 publish

SFU vs Cloud Transcoding 비교 (같은 2호스트 시나리오):

  SFU (기본):
  시청자가 받는 것 = Host A RTP + Host B RTP (2개 스트림)
  서버 CPU: decode/compose 경로보다 낮음
  시청자 CPU: 2x decode + 렌더링
  대역폭: 2x

  Cloud Transcoding:
  시청자가 받는 것 = 합성된 1개 스트림 (1개 SSRC)
  서버 CPU: 2x decode + compositing + 1x encode (높음)
  시청자 CPU: 1x decode만
  대역폭: 1x

④ Media Push — RTC 미디어를 외부 ingest로 전달

제품 버전에 따라 passthrough/remux가 가능한 경로와 transcoding 경로가 구분될 수 있습니다. 아래는 일반적인 구현 모델이며, 현재 API의 공식 모드 이름으로 보아서는 안 됩니다.

Raw Mode — decode 안 함 (핵심)

RTP stream (H.264/Opus)
   ↓
depacketize (RTP 헤더 제거, NAL unit 재조립)
   ↓
remux (FLV 컨테이너에 담기)
   ↓
RTMP stream (TCP)

Raw mode에서 일어나는 일:

  • 코덱·profile·parameter set·timestamp가 대상 ingest와 호환되면 video를 decode하지 않고 remux할 수 있습니다.
  • 오디오 codec이 대상 ingest와 다르면 audio transcode가 필요합니다.
  • 여러 사용자를 합성하려면 decode·mix/compose·encode 경로가 필요합니다.

remux 경로는 video 재인코딩 손실이 없고 transcoding보다 연산량이 작지만, 실제 사용 가능 조건과 과금·제한은 제품 문서를 확인해야 합니다.

Transcoding Mode — 완전히 새 영상을 만듦

RTP stream (여러 호스트)
   ↓
depacketize
   ↓
decode (H.264 → YUV frames, Opus → PCM)
   ↓
composite (캔버스에 합성, 워터마크)
   ↓
encode (YUV → H.264, PCM → AAC) ← 완전히 새로운 영상
   ↓
mux (FLV container)
   ↓
RTMP stream (TCP)

Transcoding mode에서 일어나는 일:

  • decode합니다. 압축을 풀어 raw 데이터로 만듭니다.
  • 합성합니다. 여러 호스트의 영상을 하나의 캔버스에 배치합니다.
  • encode합니다. 완전히 새로운 H.264 + AAC 스트림을 생성합니다.
  • bitrate, fps, 해상도, 레이아웃 모두 변경 가능합니다.

RTP vs RTMP — 근본적인 차이

WebRTC RTP:  packet 기반. SRTP/ICE를 사용하고 UDP를 우선하되 fallback 가능.
RTMP:        스트림 기반. 연속된 바이트 흐름. 유실 불가. TCP.
항목RTP (RTC)RTMP (CDN)
TransportICE가 선택한 UDP/TCP relay 등TCP 또는 TLS
구조packet 기반stream 기반
ContainerRTP payload formatRTMP audio/video message
TimestampRTP timestamp (비디오 90kHz, 오디오는 샘플레이트 기준: Opus 48kHz)FLV timestamp (ms)
패킷 유실 대응NACK/FECTCP 재전송 (자동)
지연경로·codec·buffer에 따라 달라짐ingest 및 downstream protocol·player buffer에 따라 달라짐

CDN이 RTMP를 받을 때 — "아무거나 받지 않는다"

Converter가 RTMP를 CDN에 밀어넣으면 끝일까? 아닙니다. CDN이 RTMP 스트림을 수락하려면 4가지 조건을 통과해야 합니다.

조건 1 — RTMP Handshake 정상

RTMP는 연결 시작 시 handshake를 합니다:

Client (Converter)              CDN Server
       │                            │
       ├── C0 (version) ──────────▶│
       ├── C1 (timestamp+random) ─▶│
       │◀── S0 (version) ──────────┤
       │◀── S1 (timestamp+random) ─┤
       │◀── S2 (echo C1) ──────────┤
       ├── C2 (echo S1) ──────────▶│
       │                            │
       │  handshake 완료, 연결 수립   │

handshake 실패하면 연결 자체가 안 됩니다.

조건 2 — Stream Key 인증

rtmp://youtube.com/live/STREAM_KEY
                         ▲
                         │
                    이게 틀리면 → 즉시 drop

CDN은 stream key로 "이 스트림을 받을 권한이 있는가"를 확인합니다. 틀리면 연결을 끊습니다. 이 key는 YouTube/Twitch/Facebook 등 각 플랫폼에서 발급합니다.

조건 3 — Codec 제한

전통적인 RTMP ingest가 흔히 받는 조합:

✅ Video: H.264가 가장 널리 호환됨
✅ Audio: AAC가 가장 널리 호환됨

❌ VP8 보내면 → reject 또는 깨짐
❌ VP9 보내면 → reject 또는 깨짐
❌ Opus 보내면 → reject 또는 깨짐

실제 허용 codec·profile·bitrate는 ingest 제공자와 protocol 버전에 따라 다릅니다. RTC의 Opus를 AAC만 받는 RTMP ingest로 보낸다면 audio transcode가 필요합니다.

조건 4 — Bitrate / FPS / GOP 제한

각 CDN마다 수용 가능한 스펙이 있습니다:

YouTube Live / Twitch / Facebook Live:
  해상도·fps·codec별 bitrate와 keyframe interval 요구가 서로 다르고 변경될 수 있음
  송출 직전에 각 플랫폼의 현재 공식 encoder 설정을 확인

맞지 않으면 buffering, reject, 또는 quality degrade가 발생합니다.


CDN 내부에서 일어나는 일 — Agora의 책임은 여기까지

중요한 오해를 먼저 없애겠습니다:

Media Push가 외부 CDN ingest로 전달하는 구성에서는 ingest 이후의 transcoding·packaging·배포를 해당 CDN/플랫폼이 담당합니다. Agora의 다른 제품이 HLS나 recording output을 만들 수 있으므로 이를 전체 Agora 서비스의 불변 경계로 일반화하면 안 됩니다.
  Agora 영역                          CDN 영역
  ──────────                          ──────────
  RTC Channel                         
     ↓                                
  Converter (RTMP 생성)                
     ↓                                
  RTMP push ──────────────────▶ CDN ingest 서버
                                     ↓
                               ┌─────────────────┐
                               │  CDN이 하는 일    │
                               │                  │
                               │  1. Transmux     │
                               │  2. Segment      │
                               │  3. Manifest     │
                               │  4. Edge 배포     │
                               └─────────────────┘
                                     ↓
                               시청자 (브라우저/앱)

CDN 내부 처리 4단계

1) Transmuxing — container만 변경 (가장 중요한 개념)

RTMP (FLV container)
   ↓ transmux
HLS (TS 또는 fMP4 container)

H.264 + AAC 코덱은 그대로 유지
container만 FLV → TS/fMP4로 변경

입력 codec을 그대로 유지하면 transmux만 할 수 있습니다. 실제 플랫폼은 ABR ladder 생성을 위해 transcoding을 함께 수행할 수 있습니다.

2) Segmentation — 스트림을 조각으로 자르기

연속된 비디오 스트림
   ↓
segment1.ts 또는 fMP4 fragment
segment2.ts 또는 fMP4 fragment
segment3.ts 또는 fMP4 fragment
...

왜 조각내는가: HTTP로 파일을 전송하려면 "파일"이 있어야 합니다. 연속 스트림을 작은 파일 조각으로 잘라서 HTTP GET으로 가져갈 수 있게 합니다.

3) Manifest 생성 — 재생 목록 파일

#EXTM3U
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.0,
segment0.ts
#EXTINF:6.0,
segment1.ts
#EXTINF:6.0,
segment2.ts

시청자의 플레이어는 이 .m3u8 파일을 주기적으로 polling해서 새 segment가 추가되었는지 확인하고, 순서대로 다운로드해서 재생합니다.

4) Edge 캐싱 & 글로벌 배포

Origin Server (RTMP 수신 + transmux)
   ↓ 
Edge Server (서울)     ← 한국 시청자
Edge Server (도쿄)     ← 일본 시청자  
Edge Server (LA)       ← 미국 시청자

segment 파일이 CDN edge 서버에 캐싱되어 시청자 가까이에서 서빙됩니다.

전체 파이프라인 한눈에

  카메라 → encode → RTP → Agora SFU → Converter → RTMP → CDN → HLS → 시청자
  
  ├── Agora 책임 ──────────────────────────────┤├── CDN 책임 ─────────┤
  │  RTP packets (UDP)                         ││  Transmux           │
  │  Converter: RTP → RTMP                     ││  Segment            │
  │  H.264 + AAC, FLV container               ││  Manifest (.m3u8)   │
  │                                            ││  Edge 캐싱/배포       │
  └────────────────────────────────────────────┘└─────────────────────┘

세 가지 미디어 형태의 본질적 차이

RTC (RTP):   "실시간 패킷"   — UDP, 유실 허용, 초저지연
RTMP:        "실시간 스트림"  — TCP, 유실 불가, 중간 지연
HLS/DASH:    "파일 조각"     — HTTP, 완전한 파일, 높은 지연
구분RTCRTMPHLS
전송UDPTCPHTTP
단위packetstreamfile segment
지연구성에 따라 달라짐구성에 따라 달라짐일반 HLS/LL-HLS와 player 설정에 따라 달라짐
유실허용불가 (TCP)불가 (HTTP)
인터랙션양방향단방향단방향
시청자 규모토폴로지·서비스 용량에 따라 달라짐배포 구조에 따라 달라짐CDN 용량에 따라 달라짐

⑤ Cloud Recording — "RTP subscribe → decode → 파일 저장"

  Recording Mode에 따라 파이프라인이 다릅니다:
  
  Individual Recording (decode 불필요):
     RTP depacketize → 인코딩된 프레임 그대로 → 파일에 mux
     참가자별 output을 저장할 수 있음. 정확한 파일명·container는 recording 설정에 따름
  
  Composite Recording (decode 필요):
     RTP → decode → 합성 → encode → 단일 MP4 파일
  
     ↓
  지원되는 recording output으로 mux/segment
     ↓
  S3/OSS/GCS 등 클라우드 스토리지에 업로드

패킷 레벨에서 보는 전체 변환 흐름

아래 표는 가능한 미디어 변환을 개념적으로 요약한 것입니다. 실제 제품은 선택한 모드와 codec 호환성에 따라 일부 단계만 수행합니다.

  ┌────────────────────────────────────────────────────────────┐
  │                    미디어 변환 스택                          │
  │                                                            │
  │   Transport:    UDP ←→ TCP                                 │
  │   Protocol:     RTP ←→ RTMP / SRT / HTTP                  │
  │   Container:    RTP payload ←→ RTMP message / MP4 / TS     │
  │   Codec:        H.264 ←→ VP8 / VP9  (선택적 트랜스코딩)     │
  │   Processing:   합성 / 믹싱 / 워터마크 (선택적)              │
  │                                                            │
  └────────────────────────────────────────────────────────────┘

  제품별 변환 경로:

  Media Gateway:   RTMP(TCP/FLV)  → [demux → repacketize]     → RTP(UDP)
  Media Pull:      HTTP/HLS/RTMP  → [fetch → demux → repack]  → RTP(UDP)
  Cloud Transcoding: RTP(UDP)     → [decode → 합성 → encode]  → RTP(UDP)
  Media Push(Raw): RTP(UDP)       → [depacketize → remux]      → RTMP(TCP/FLV)
  Media Push(TC):  RTP(UDP)       → [decode → 합성 → encode]  → RTMP(TCP/FLV)
  Cloud Recording: RTP(UDP)       → [decode → mux]            → MP4/M3U8(File)

Stream Fallback — 네트워크가 나쁠 때 음성 우선 정책

RTP 레벨에서 오디오와 비디오는 별도의 SSRC를 가진 독립 스트림입니다. 이 특성 덕분에 SDK가 비디오 스트림만 선택적으로 끌 수 있습니다.

  정상 네트워크:
  SSRC 0x1A (Video) ──▶ 전송 중 ✅
  SSRC 0x1B (Audio) ──▶ 전송 중 ✅

  대역폭 부족 감지:
  SSRC 0x1A (Video) ──▶ 저화질로 전환 (Dual Stream: Low layer)
  SSRC 0x1B (Audio) ──▶ 전송 유지 ✅

  대역폭 심각하게 부족한 경우의 가능한 정책:
  SSRC 0x1A (Video) ──▶ 전송 중단 ❌
  SSRC 0x1B (Audio) ──▶ audio-only로 전환 시도

Dual Stream Mode가 하는 일

  simulcast/dual-stream 기능을 활성화하면:

  인코더가 2개 스트림을 동시 생성:
  
  High Stream: 1080p, 2Mbps  → SSRC 0xA1B2C3D4 → RTP packets
  Low Stream:  360p, 200kbps → SSRC 0xE5F6A7B8 → RTP packets
  (해상도·bitrate·SSRC는 예시이며 실제 값은 SDK 설정·구현에 따름)
  
  수신 측 SDK가 네트워크 상태에 따라:
  - 양호: High Stream subscribe
  - 불안정: Low Stream으로 자동 전환
  - 최악: 둘 다 끄고 Audio만 유지

Fallback 설정 시 확인할 것

Agora Video SDK의 dual-stream/simulcast, local publish fallback, remote subscribe fallback, audio profile API는 플랫폼과 major version에 따라 이름과 signature가 달라집니다. enableDualStreamMode(true)나 두 인자를 받는 setAudioProfile 예제를 버전 표기 없이 복사하지 말고, 현재 SDK 레퍼런스의 method signature와 deprecation 상태를 기준으로 작성해야 합니다. Audio-only fallback은 필요한 대역폭을 크게 줄이지만, 극도로 나쁜 네트워크에서도 음성이 반드시 유지된다고 보장하지는 않습니다.


정리: 공개 계약과 구현 추정을 구분한다

Agora 제품은 RTC publish/subscribe, 외부 ingest·egress, recording, transcoding이라는 데이터 흐름으로 이해할 수 있습니다. 다만 "서버 봇", 정확한 SSRC, wire protocol은 공개 API 계약이 아닌 구현 비유입니다.

  • Gateway/Pull: 외부 프로토콜 → RTP로 변환해서 publish
  • Cloud Transcoding: RTP를 decode → 합성 → encode → 다시 RTP로 publish
  • Media Push: 호환 시 remux, 필요하면 transcode한 뒤 외부 ingest로 전달
  • Cloud Recording: individual/composite 설정에 따라 mux 또는 decode·compose·encode 후 저장

외부 CDN ingest로 넘기는 구성에서는 이후 동작이 해당 CDN 설정에 달려 있습니다:

  • 호환되는 codec이면 transmux할 수 있습니다
  • 필요하면 CDN이 transcoding·ABR ladder·segmentation을 수행합니다
  • CDN이 manifest를 생성합니다 (.m3u8 재생 목록)
  • CDN이 edge에 배포합니다 (글로벌 캐싱)

미디어는 그 여정 내내 형태가 바뀝니다:

카메라 → YUV (raw)
      → H.264 NAL units (encoded)
      → RTP packets (packetized, SRTP/ICE)
      → RTMP messages (remuxed or transcoded, TCP/TLS)
      → HLS segments (segmented, HTTP)
      → 화면 (decoded, rendered)

하지만 본질은 변하지 않습니다. 카메라에서 찍힌 프레임이 인코딩되고, 패킷화되고, 네트워크를 타고, 다시 디코딩되어 화면에 보이는 것. 클라우드 제품들은 이 파이프라인의 중간에 서버 사이드 처리를 끼워 넣는 것일 뿐입니다. 어떤 제품이든 "이건 어디서 subscribe하고, 무엇을 변환해서, 어디로 publish하는가?"로 이해하면 됩니다.


참고 자료

© 2026 Frank Kim. All rights reserved.