dev_data/trans.pcap を解析して判明した、3coins ワイヤレストランシーバーの通信仕様。
本書は観測ベースの推定であり、メーカー公式の仕様書ではない。
802.11 (radiotap) → LLC/SNAP → IPv4 → UDP → 独自プロトコル
子機2台 (192.168.1.1 ⇔ 192.168.1.100) が802.11上で直接または同一APを介してIP通信し、UDPで映像・音声・制御を送り合う。両機が同時に送受信する全二重動作。
| ポート (送信元) | 用途 | 典型ペイロード長 | パケットレート |
|---|---|---|---|
| 11011 / 11013 | 映像 (MJPEG) | 1336B (中間), 末尾は可変 | 約44 pps |
| 5008 | 音声 | 270B 固定 | 約50 pps |
| 11012 / 11014 | 制御/keep-alive | 28B 固定 | 数 pps |
それぞれ送信側と受信側のポートはペアになっている (11011↔11013 など)。
1枚のJPEG画像 (FFD8 ... FFD9) を1〜数十個のUDPパケットに分割して送る。各パケットは20バイトのカスタムヘッダ + JPEGフラグメントを持つ。
| Offset | Size | フィールド | 説明 |
|---|---|---|---|
| 0 | 1 | flag_and_frame_lo |
上位nibble = フラグ、下位nibble = フレーム番号 mod 16 |
| 1 | 1 | frag_seq |
フレーム内フラグメント連番 (0始まり) |
| 2 | 2 | proto_ver |
バージョン/フラグ。観測値 0x0604, 0x0704 |
| 4 | 4 | frame_id (LE u32) |
フレームID。フレーム毎に増分 |
| 8 | 4 | stream_const |
固定 0x03000000 |
| 12 | 4 | padding |
固定 0x00000000 |
| 16 | 4 | frag_bitmask (BE u32) |
このパケットまでの累積ビットマスク = 2^(frag_seq+1) - 1 |
| 値 | 意味 |
|---|---|
0x8 |
フレーム先頭パケット (このパケットの直後に FFD8 が現れる) |
0x0 |
中間パケット |
0x4 |
フレーム末尾パケット (末尾近くに FFD9 が現れる) |
下位nibble (frame_lo) は frame_id の下位4bitを使ってもよいが、観測値は単純なフレーム連番 (1, 2, 3, ... mod 16) として動く。
2^(frag_seq+1) - 1 を big-endian で詰めたもの。例:
frag_seq |
frag_bitmask |
|---|---|
| 0 | 00 00 00 01 |
| 1 | 00 00 00 03 |
| 2 | 00 00 00 07 |
| 3 | 00 00 00 0f |
| 4 | 00 00 00 1f |
| 5 | 00 00 00 3f |
これは「ここまでに何個のフラグメントを送ったか」を毎パケット示すための累積マスク。受信側が欠落フラグメントを検知できる。
- UDPペイロードの先頭20Bを剥がす。
frame_idでグループ化。- 各フレーム内で
frag_seq順にソートして連結。 - 先頭が
FFD8で始まり末尾がFFD9で終わる完全なJPEGバイト列になる。 frag_bitmaskの最大値やflag=0x4の有無で「最終フラグメント受信済み」と判定する。
無線環境のため重複パケット (frame_id + frag_seq が同一) が観測される。先勝ち or 後勝ちのどちらでもよい。
- baseline DCT
- 320 × 240, YCbCr 4:2:0, 8-bit precision
- 標準的なJPEG構造 (DQT / SOF0 / DHT / SOS / 圧縮データ / EOI)
- 観測実効フレームレート 約8〜9 fps
UDPペイロード270バイト固定 (UDP長278B = 8B UDPヘッダ + 270Bペイロード)。
| Offset | Size | フィールド | 説明 |
|---|---|---|---|
| 0 | 2 | seq_a (LE u16) |
パケット連番 |
| 2 | 2 | seq_b (LE u16) |
別系統連番 (おそらくストリーム内seq) |
| 4 | 4 | timestamp (LE u32) |
タイムスタンプ/グローバル連番 |
| 8 | 4 | session_id |
送信元固有のセッションID (例: 01 41 b4 f7, 4d ac fe 2a) |
| 12 | 2 | counter (LE u16) |
per-packetカウンタ |
| 14 | 2 | marker |
固定 0x5480 |
| 16 | 2 | marker |
固定 0x5480 |
| 18 | 2 | reserved |
通常 0x0000 |
| 20 | 250 | samples |
オーディオサンプル本体 |
- サンプリング周波数: 8000 Hz (一般的なテレフォニー帯域)
- ビット深度: 16-bit signed PCM
- チャンネル: モノラル
- エンディアン: little-endian
- 1パケット = 250 byte = 125 サンプル = 15.625ms 分
データレート: 250B × 50pps ≈ 12.5 kB/s。8kHz × 2byte = 16 kB/s より少し低いのは、無音区間で送信を間引いている、もしくは推定サンプルレートが若干違う可能性あり。
観測したキャプチャでは、両方向ともサンプル部の非ゼロ率が 0.03〜0.07% と極めて低く、実質的に完全な無音だった。PTT (Push-To-Talk) ボタン未押下時にもストリーム自体は流し続け、ペイロードは 0x00 で埋める仕様と思われる。
20バイト固定ペイロード (UDP長28B)。ハートビート + 呼び出しシグナリング + セッション中通知がこの1ポートに同居している。各メッセージは payload の byte0 (ステートコード) で識別する。
03 ff 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00
両方向から約1Hzで送信。byte0=0x03, byte1=0xff が "idle" を示す。
観測キャプチャでの呼び出し → 映像開始までのシーケンス:
| 時刻 (相対) | 方向 | byte0-1 | ペイロード末尾 | 意味(推定) |
|---|---|---|---|---|
| 12.013 | 1.1→1.100 | 03 ff × 4 |
idle | 呼び出し前の連打 |
| 12.021 | 1.100→1.1 | 09 4b |
0埋め | (a) 呼び出し応答(REQ) |
| 12.024 | 1.1→1.100 | 59 4b |
0埋め | (b) 確認(ACK, a XOR 0x50) |
| 15.027 | 1.1→1.100 | 03 ff |
末尾6Bに fa a9 4c b8 7e 17 |
(c) セッションID提示 |
| 15.948 | 1.1→1.100 | 0c 00 |
0埋め | (d) START要求(REQ) |
| 15.951 | 1.100→1.1 | 5c 00 |
0埋め | (e) OK応答(ACK, d XOR 0x50) |
| 16.026 | 1.1→1.100 | (映像 UDP 11011/11013) | ─ | 映像ストリーム開始(e の75ms後) |
リクエスト/レスポンスのペアは byte0 を XOR 0x50 することで応答を表す:
0x09 (REQ) -> 0x59 (ACK)
0x0c (REQ) -> 0x5c (ACK)
0x50 = bit4 + bit6。「リクエストの byte0 に 0x50 を OR」だけの単純なエンコーディング。SIPのような多段階レスポンスは持たず、各種state変化はすべて1往復で完結する。
通話確立後にも 1.100→1.1 方向で散発的に 44 バイト長のメッセージが流れる:
t=19.645 02 53 00 00 20 00 00 00 ... 07 00 00 00 ...
t=20.137 02 55 00 00 24 00 00 00 ... 07 00 00 00 ...
t=32.605 02 6f 00 00 11 00 00 00 ... 04 00 00 00 ...
書式: 02 [seq8] 00 00 [counter32 LE] ... [code8] 00 00 00 ...。1.100 側からのみ観測。状態通知ないし品質報告と推測されるが未解析。
tshark で IP src を見ると 802.11 受信エラーで radiotap デコードがズレ、192.168.81.62 や 89.119.100.2 のような無関係IPで5008/11011を名乗るパケットが極稀に観測される。フレーム数1で内容も正常パケットの劣化コピーなので無視してよい。
このプロトコルは独自仕様ながら構造は素直で、
- 映像 = カスタム断片化ヘッダ + 標準JPEG
- 音声 = カスタムシーケンスヘッダ + 生PCMサンプル
の組み合わせ。RTP風だがRTP互換ではない。バージョン情報やセッションID、累積ビットマスクなど、無線環境でのロス検知を意識した最小限の構造になっている。