Post

RTMP

RTMP (Real-Time Messaging Protocol)

RTMP는 Adobe Flash Player나 Adobe Air와 같은, Adobe Flash platform에서 multimedia data를 전송하기 위해 개발한 protocol이다. RTMP는 TCP transport layer위에서 동작하는 application layer이다. full-duplex 방식의 통신을 하고 있으며 state-full하다. Control command나 audio/video 데이터와 같은 모든 데이터를 message라는 구조로 추상화 시켜서 통신을 한다.

한 번에 전송할 수 있는 RTMP packet은 기본적으로 audio의 경우 64 byte, video의 경우 128 byte로 설정되어 있다. 따라서 하나의 message를 fragmentation하여 여러 RTMP packet으로 보내데, 이 단위를 chunk라고 한다.

RTMP는 live streaming을 구현하기에 적합한 protocol이다. 하지만 browser에서 재생을 하기 위해서는 Flash Player와 같은 별도의 plug-in이 필요하다. 2021년 현재 browser에서는 plug-in을 퇴출하였고 서버와 browser간의 HTTP tunneling을 하지 않은, 순수 RTMP 통신은 불가능하다. 하지만 간편한 protocol 설계와 low-latency의 장점으로 native app과 server와의 통신에서는 유효하다.

본 문서는 Reference [0]의 spec문서를 기반으로 작성되어 있다.

Handshake

RTMP는 client와 server가 각각 3개의 chunk를 보냄으로써 handshake 과정을 거친다. Handshake는 client가 c0 chunk를 보내면서 시작된다. Handshake과정의 도식화인 Fig. 0에서 ci와 si는 각각 같은 구조의 chunk이다. 각각의 chunk는 다음과 같은 내용을 포함한다.

  • c0/s0: RTMP version 정보
  • c1/s1: 동기화 할 시간, peer를 구분할 random data
  • c2/s2: 각자 peer의 c1/s1에 대한 echo

c1/s1의 random data는 identifier로 쓸 수 있을만큼 복잡해야하며, c2/s2에서 각자 s1/c1에서 보낸 정보를 확인 함으로써 handshake과정이 종료된다.

Diagram of RTMP Handshake Fig. 0: Diagram of RTMP Handshake [0]

Chunking

Message는 chunk단위로 fragmentation되어 보내지며, 수신 단에서 다시 reassembly과정을 거쳐 온전한 message가 된다. RTMP connection은 multiplex될 수 있으며, 각각의 stream을 구분하기 위해 chunk stream ID를 사용한다. Chunk format은 Fig. 1과 같으며 각각의 요소가 가변 크기를 갖는.

Chunk Format Fig. 1: Chunk Format [0]

  • Basic Header (1 / 2 / 3 byte)
  • Message Header (0 / 3 / 7 / 11 byte)
  • Extended Timestamp (0 / 4 byte)
  • Chunk Data

Basic Header

Basic Header는 Fig. 2의 (a) / (b) / (c)로 보여지는 Type 0 / Type 1 / Type 2 하나의 형태로 구성되어 있다.

Basic Header Fig. 2: Basic Header, (a): Type 0, (b): Type 1, (c) Type 2

  • fmt (2): Chunk format, Message Header의 type을 결정
  • cs id: Chunk stream ID
    • Type 0 (6): 3 - 64 범위, 0은 2 byte extension, 1은 3 byte extension을 의미하며 chunk stream ID로 사용 불가
    • Type 1 (14): 64 - 319 범위, “second byte” + 64
    • Type 2 (22): 64 - 65599 범위, “third byte” * 256 + “second byte” + 64

Message Header

그 다음에 오는 Message Header는 Chunk Header의 fmt에 따라 Type 0/ Type 1 / Type 2 / Type 3으로 나뉜다.

Message Header Fig. 3: Message Header, (a): Type 0, (b): Type 1, (c) Type 2

  • Message Types
    • Type 0 (11 byte): Chunk stream의 시작 혹은 seek에 의해 timestamp가 뒤로 갔을 때 사용된다.
    • Type 1 (7 byte): 이전 message와 message stream ID가 같으며, chunk의 size가 변하는 경우에 사용.
    • Type 2 (3 byte): 이전 message와 message stream ID가 같으며, chunk의 size가 일정한 message에 사용.
    • Type 3 (0 byte): 하나의 message가 여러 개의 chunk로 나눠진 경우 가장 앞의 chunk만 message header를 붙이며, 이후의 chunk들은 Type 3로 전달.
  • Common Header Fields
    • timestamp (24): Absolute timestamp, 16777215 (0xFFFFFF) 이상일 때는 0xFFFFFF로 기록하며 나머지 정보는 Extended Timestamp에 기록.
    • timestamp delta (24): 이전 chunk의 timestamp와의 차이. 16777215 (0xFFFFFF) 이상일 때는 0xFFFFFF로 기록하며 나머지 정보는 Extended Timestamp에 기록.
    • message length (24): Message의 길이. 일반적으로 message가 여러 개의 chunk로 나눠지기 때문에 마지막 chunk까지의 chunk payload의 크기를 모두 합친 값.
    • message type id (8): message의 type
    • message stream id (32): Message stream id. Multiplexing을 하지 않는 이상 하나의 chunk stream id 안에서 message stream id는 같다. 따라서 type 0 message는 연결된 이후 한번만 보낸다.

Extended Timestamp

Timestamp에 기록해야 하는 숫자가 16777215 (0xFFFFFF) 이상일 때, 더 많은 bit (32 bit)를 이용하서 timestamp를 기록하기 위한 영역. Type 0 / Type 1 / Type 2의 timestamp 영역이 0xFFFFFF인 경우에만 존재.

RTMP Message Payload

Reference [0]에 기술되어있는 주요 Message payload에 대한 내용들이다. <> 안의 숫자는 message type을 의미한.

Protocol Control Message <1 / 2 / 3/ 5 / 6>

Message Type ID 1 / 2 / 3 / 5 / 6는 protocol control message로 사용된다. 이 경우 message stream ID는 0, message stream ID는 2로 보내야 한다. Protocol control message에 해당하는 messge들은 다음과 같으며 <>안의 숫자는 message type을 의미한다.

  • Set Chunk Size <1>: Maximum chunk size를 재설정
  • Abort Message <2>: Message 수신하기 위해 chunk를 모으고 있을 때, 해당 message를 버리라는 명령
  • Acknowledgement <3>: Server / Client는 window size만큼의 데이터를 받으면 그 값을 message로 보낸다
  • Window Acknowledgement Size <5>: Window size로 사용할 값을 peer에 알리기 위해 사용
  • Set Peer Bandwidth <6>: Peer의 output bandwidth를 지정

User Control Message <4>

Message Type ID 4는 user control message를 의미하며, message stream ID는 0, message stream ID는 2로 보내야 한다. 이 message는 Event type(16)과 Event data로 구성되어 있다. Event 목록은 다음과 같으며, <>안의 숫자는 Event type을 의미한다.

  • Server -> Client
    • Stream Begin <0>: Stream이 가용 가능
    • Stream EOF <1>: Playback의 종료
    • Stream Dry <2>: Stream에 더 이상 데이터가 없음
    • Stream Is Recorded <4>: 현재 stream이 저장되고 있음을 알림
    • Ping Request <6>: Client가 연결되어 있는지 확인
  • Client -> Server
    • Set Buffer <3>: Stream을 통해 전달될 버퍼의 시간 길이 (ms)
    • Ping Response <7>: Ping Request에 대한 응답

Command Message <20 / 17>

Server와 client 는 AMF-encoded command message를 주고 받는다. Message type 20은 AMF0으로 encoding된 message이며, message type 17은 AMF3으로 encoding된 메세지이다. Sender는 command name, transaction ID, 관련된 값들을 포함하는 command object를 보낸다. command RPC와 같이 RTMP위에서 command를 호출하며, response onStatus로 결과를 반환.

Command Message는 NetConnection과 NetStream으로 나눠진다. NetConnection은 server / client간의 connection을 추상화 하였고, NetStream stream 및 data 교환 그리고 그 밖의 command들을 추상화 했다.

  • NetConnection
    • connect
    • call
    • close:
    • createStream
  • NetStream
    • play
    • play2
    • deleteStream
    • closeStream
    • receiveAudio
    • receiveVideo
    • publish
    • seek
    • pause
    • onStatus

Data Message <18, 15>

Meta data 혹은 user data를 전달하기 위한 message type. Message type 18은 AMF0으로 encoding된 message이며, message type 15 AMF3으로 encoding된 메세지이다.

Audio Message <8>

Audio data를 위한 message type

Video Message <9>

Video data를 위한 message type

References

This post is licensed under CC BY 4.0 by the author.