RTMPパケットの仕組み

Flash Media Serverで使われているRTMPプロトコルのことを知りたくてOpenSourceFlashにのってる「Mick’s Breakdown of RTMP」を訳しながら自分でも試してみました。

まずはRTMPサーバを動かしているサーバでtcpdumpしてみてます。

tcpdump -s 1600 -x -i eth0 src port 1935

ちなみに、ここで動かしてるRTMPサーバはKamaitachiです。

サンプルとして提供されているチャットサーバを起動しているサーバでのtcpdumpの結果は以下のようなものとなりました。(説明しやすくするために色をつけています)

0x0000: 4500 004a 5f2d 4000 4006 221d c0a8 0164
0x0010: cae5 2c72 078f f7fc 483c d4e8 2a1c 2f1d
0x0020: 5018 00e3 0e86 0000 0300 0000 0000 1614
0x0030: 0000 0000 0200 096f 6e4d 6573 7361 6765
0x0040: 0505 0200 0548 454c 4c4f

まずこのパケットの先頭20バイトはIPヘッダ、次の20バイトはTCPヘッダになるので、合計40バイトを無視します。(うすいグレーの部分)

するとRTMPとしての情報は03から4c4fまでの合計34バイト分になります。

改めて書いてみるとこの部分になります。

0300 0000 0000 1614
0000 0000 0200 096f 6e4d 6573 7361 6765
0505 0200 0548 454c 4c4f

以下、各byte列がどんな意味を持っているのか見ていきましょう。

ヘッダー長とAMFナンバー

■先頭1byte (03)

03(0x03)を2進数表記すると00000010になります。
これの先頭2bit分がRTMPパケットのヘッダ長を示します。
この例だと00なので、ヘッダ長は0byte、というわけではなく、以下の対照表でマッピングされます。

00 = 12 bytes
01 = 8 bytes
10 = 4 bytes
11 = 1 byte

なので先頭2bitが00なのでヘッダ長は12bytesということになりますね。
つまりヘッダは
0300 0000 0000 1614 0000 0000
となります。
 
さて先頭2bitがヘッダ長なのはわかりました。
残り6bitはなにを意味するかといいますと、AMFのオブジェクトナンバー(ID?)を意味するようです。
000010だと10進にすると2ですね。
 
ちょっと理解しづらいのですが、どうやらRTMPでは1つのパケットの中に「複数のAMFオブジェクトをごちゃ混ぜにして」やり取りするようです。

A single TCP socket connection between the Flash Player and the server will send multiple AMF objects back and forth between the client and the server. AMF objects are not queued, but are interweaved together so they show up at the other end at the same time.

interweavedって表現のあたりが直感的にわかりづらいんですが、要するに複数のAMFオブジェクトがごちゃ混ぜに織り込まれてパケットに詰め込まれているみたいです。

しかもAMFオブジェクトは128bytesのチャンクに分割されるので、パケットの中はよりごちゃ混ぜ感がつよくなります。
 
そのために「AMFナンバー」というものをオブジェクトごとに付与して管理しています。
 

タイムスタンプ??

■次の3bytes(000000)

the next three bytes are the time stamp. This is a big-endian integer and it is sent whenever the header size is 4 bytes or larger.

でも実際のところ、タイムスタンプではなさそうな気がします。
「Mick’s Breakdown of RTMP」のドキュメントの中にはこう書いてありました。

These bytes are unknown but are always in the same position and are always 3 bytes long. They can be transferred over when sending the video/audio data (via AMF) to the subscribers of the video/audio stream.

要するに良くわからないみたいですね。この3bytesはとりあえず無視。

ボディ長

■次の3bytes(000016

000016(0x16)を10進表記すると22です。この3bytesはAMFオブジェクトのサイズ、つまりボディ部分の長さをあらわします。
ボディは0200 096f 6e4d 6573 7361 6765 0505 0200 0548 454c 4c4fなので、22bytesであってますね。

パケットタイプ

■次の1bytes(14

こいつはパケットタイプを表します。以下の対照表を参照してください。

0x14 Function Call
0x09 Video data
0x08 Audio data

この例ですと14(0x14)なので、これはFunction Callである、ということがわかります。

ストリームID

■次の4bytes(0000 0000

ヘッダー部としては最後の4bytesです。この例だと0000 0000となっています。

この部分もやや不明確っぽいのですが、当該AMFオブジェクトのストリームIDをあらわすもののようです。

もしも当該AMFがクライアント→サーバなものであるのなら、この4bytesはAMFオブジェクトのソース(NetStreamオブジェクト)をあらわします。

逆に当該AMFがサーバ→クライアントなものであるのなら、このbytes列はAMFオブジェクトを受け付けるべきNetStreamオブジェクトをあらわします。

・・・ってなんだか良くわかりませんね。

原文にはこう書いてありました。

The final 4 bytes of the header is a stream id. This is a 32 bit integer that is little-endian encoded. These bytes are only included when the header is a full 12 bytes. (As mentioned in Mick’s Breakdown of RTMP linked below, it is possible that the stream id defines which NetStream/NetConnection object is the source or target of the message)

ボディ部(AMFオブジェクト)

■残り(0200 096f 6e4d 6573 7361 6765 0505 0200 0548 454c 4c4f

最後にボディです。これはAMFオブジェクトそのものになります。
この中身自体はAMFの仕様を勉強しないとわからないなぁ。

ちょっと複雑な例

「Mick’s Breakdown of RTMP」の最後の方にあるサンプルを写経します。

これは「2つのAMFオブジェクトが複数のチャンクに分割されたもの」が1つのパケットに収まっている状態のサンプルです。

03 00 00 01 00 01 05 14 00 00 00 00 02 00 07 63
6f 6e 6e 65 63 74 00 3f f0 00 00 00 00 00 00 03
00 03 61 70 70 02 00 16 73 61 6d 70 6c 65 5f 76
69 64 65 6f 63 6f 6e 66 65 72 65 6e 63 65 00 08
66 6c 61 73 68 56 65 72 02 00 0c 57 49 4e 20 37
2c 30 2c 31 39 2c 30 00 06 73 77 66 55 72 6c 02
00 78 66 69 6c 65 3a 2f 2f 5c 5c 77 6e 6d 69 68
65 72 72 65 73 30 33 5c 63 24 5c 44 6f 63 75 6d
65 6e 74 73 20 61 6e 64 20 53 65 74 04 00 00 01
00 01 05 14 00 00 00 00 02 00 07 63 6f 6e 6e 65
63 74 00 3f f0 00 00 00 00 00 00 03 00 03 61 70
70 02 00 16 73 61 6d 70 6c 65 5f 76 69 64 65 6f
63 6f 6e 66 65 72 65 6e 63 65 00 08 66 6c 61 73
68 56 65 72 02 00 0c 57 49 4e 20 37 2c 30 2c 31
39 2c 30 00 06 73 77 66 55 72 6c 02 00 78 66 69
6c 65 3a 2f 2f 5c 5c 77 6e 6d 69 68 65 72 72 65
73 30 33 5c 63 24 5c 44 6f 63 75 6d 65 6e 74 73
20 61 6e 64 20 53 65 74 c3 74 69 6e 67 73 5c 6d
69 63 6b 2e 68 65 72 72 65 73 2e 4d 49 43 4b 44
4f 4d 41 49 4e 5c 4d 79 20 44 6f 63 75 6d 65 6e
74 73 5c 46 6c 61 73 68 20 50 72 6f 6a 65 63 74
73 5c 56 69 64 65 6f 52 65 70 72 61 63 74 69 63
69 6e 67 2e 73 77 66 00 05 74 63 55 72 6c 02 00
2a 72 74 6d 70 3a 2f 2f 31 39 32 2e 31 36 38 2e
32 2e 31 34 2f 73 61 6d 70 6c 65 5f 76 69 64 65
6f 63 6f 6e 66 65 72 65 6e c4 74 69 6e 67 73 5c
6d 69 63 6b 2e 68 65 72 72 65 73 2e 4d 49 43 4b
44 4f 4d 41 49 4e 5c 4d 79 20 44 6f 63 75 6d 65
6e 74 73 5c 46 6c 61 73 68 20 50 72 6f 6a 65 63
74 73 5c 56 69 64 65 6f 52 65 70 72 61 63 74 69
63 69 6e 67 2e 73 77 66 00 05 74 63 55 72 6c 02
00 2a 72 74 6d 70 3a 2f 2f 31 39 32 2e 31 36 38
2e 32 2e 31 34 2f 73 61 6d 70 6c 65 5f 76 69 64
65 6f 63 6f 6e 66 65 72 65 6e c3 63 65 00 00 09
c4 63 65 00 00 09

03からは1つ目のAMFのヘッダとボディ(128byteまで)です。続いて04からが2つ目のAMFのヘッダとボディ(これも128bytes分)です。

これ以降、c3c4が各々のAMFオブジェクトを表すラベル的なbyteになっていて、それぞれ128byteづつのチャンクに区切られつつ交互に織り交ぜられていきます。なお最後の部分はどちらも端数(128byteに満たない)になっています。

このようにしてRTMPではAMFオブジェクトが細切れにされて1パケットに織り込まれていくようです。(上でも書きましたが、この様子がinterweavedってニュアンスなのかな)

ちなみに1パケットに突っ込めるAMFオブジェクトの数は全部で64個と決まっているみたいです。

あとどうでもいいことですが、「Mick’s Breakdown of RTMP」の一番最後の説明はなんか間違っている、というか何か違うものを説明しているような気がするので、信用しないほうがよさゲです。

まとめ

RTMPのことを知りたくて調べ始めたんだけど、なんか少し違う角度に入り込みすぎた気がするなぁ。正直こんなレベルまでしる必要はなかったような気がするし・・・。

でも少しだけパケットの中身がわかってRTMPに親近感が沸きました。
隣の席のN君には「変態」って言われたけど。