1. SDPの概要
1.1 SDPとは何か
SDP (Session Description Protocol)は「セッション記述プロトコル」の略称です。簡単に言えば、SDPは人々が電話をかける前に交換する「名刺」のようなもので、相手にどのような機能をサポートし、どの方法で通信するかを伝えます。
1.2 WebRTCにおけるSDPの役割
WebRTCビデオ通話において、SDP交換は次のプロセスを経て行われます:
- 発信側がOfferを作成
- Offerが信令サーバーを介して受信側に送信
- 受信側がAnswerを作成
- Answerが発信側に送信される
- 両者がSDP情報に基づいてP2P接続を確立
1.3 SDPの4つの主要な役割
- メディアネゴシエーション - 双方がどのフォーマットを使用して通信するか
- ネットワークネゴシエーション - 双方がどのように相手を見つけるか
- セキュリティネゴシエーション - 通信の安全性をどのように確保するか
- 能力ネゴシエーション - 双方が何ができるか
2. SDPの構造の詳細
2.1 SDP全体構造
SDPは「セッションレベル」と「メディアレベル」の2つの主要な部分で構成されます:
- セッションレベル: 通話全体の基本情報を記述
- メディアレベル: 特定のオーディオまたはビデオストリームを記述
2.2 SDP行タイプの詳細
SDPの各行は特定の意味を持つ「タイプ=値」の形式です:
| タイプ | 名称 | 簡単な説明 | 必須 |
|---|---|---|---|
| v= | バージョン | SDPのバージョン番号 | 必須 |
| o= | 発信元 | セッションの発信者情報 | 必須 |
| s= | セッション名 | セッションの名前 | 必須 |
| t= | タイミング | セッションの開始と終了時間 | 必須 |
| m= | メディア記述 | メディアタイプとコーデック | 必須 |
2.3 完全なSDP例の解析
以下に実際のSDP例を示し、各行を詳細に解説します:
v=0
o=- 1234567890 1234567890 IN IP4 192.168.1.100
s=-
t=0 0
a=group:BUNDLE 0 1
a=msid-semantic: WMS localStream
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:abcd
a=ice-pwd:abcdefghijklmnopqrstuvwx
a=ice-options:trickle
a=fingerprint:sha-256 12:34:56:78:90:AB:CD:EF...
a=setup:actpass
a=mid:0
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:12345678 cname:user1
a=ssrc:12345678 msid:localStream audioTrack
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 124 125
a=mid:1
a=rtpmap:96 VP8/90000
a=rtpmap:100 H264/90000
a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=ssrc:87654321 cname:user1
a=ssrc:87654321 msid:localStream videoTrack
3. 主要なSDPフィールドの詳細
3.1 セッションレベルフィールド
v= (バージョン)
v=0
SDPプロトコルのバージョン番号。現在は常に0です。
o= (発信元)
o=<username> <nettype> <addrtype>
セッションの発信者情報を示します。
a=group:BUNDLE
a=group:BUNDLE 0 1
オーディオ(mid:0)とビデオ(mid:1)を同じ接続にバンドルします。
3.2 メディアレベルフィールド
m= (メディア)
m=<media> <port> <proto> <fmt> ...
メディアタイプ、ポート、プロトコル、サポートされるコーデックを指定します。
a=ice-ufrag / a=ice-pwd
a=ice-ufrag:abcd
a=ice-pwd:abcdefghijklmnopqrstuvwx
ICE接続認証のためのユーザー名とパスワードです。
a=fingerprint
a=fingerprint:sha-256 12:34:56:78:90:AB:CD:EF...
DTLS証明書のハッシュ値で、接続の安全性を確認します。
a=sendrecv / sendonly / recvonly
a=sendrecv // 双方向通信
a=sendonly // 送信のみ
a=recvonly // 受信のみ
メディアストリームの方向を指定します。
3.3 コーデック関連フィールド
a=rtpmap
a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
Payload Typeを特定のコーデックにマッピングします。
a=fmtp
a=fmtp:<payload type> <format specific parameters>
コーデックの詳細な設定パラメータを指定します。
4. Offer/Answerモデル
4.1 Offer/Answerとは
Offer/AnswerはSDP交換の標準モデルで、2つのデバイスがどのように通信するかをネゴシエートするプロセスです。
4.2 Offer/Answerの詳細な流れ
- 発信側がcreateOffer()を呼び出してOfferを作成
- 発信側がsetLocalDescription()を呼び出してローカル記述を設定
- Offerが受信側に送信される
- 受信側がsetRemoteDescription()を呼び出してリモート記述を設定
- 受信側がcreateAnswer()を呼び出してAnswerを作成
- 受信側がsetLocalDescription()を呼び出してローカル記述を設定
- Answerが発信側に送信される
- 発信側がsetRemoteDescription()を呼び出してリモート記述を設定
4.3 OfferとAnswerの主な違い
| 項目 | Offer | Answer |
|---|---|---|
| コーデックリスト | サポートされるすべてのコーデックをリスト | td>共通のコーデックを1つ選択|
| DTLSロール | a=setup:actpass(ロール未定) | a=setup:activeまたはa=setup:passive(ロール確定) |
5. SDPタイプの判定
5.1 SDPがOfferかAnswerかを判定する方法
fun parseSdpType(sdp: String): String {
return if (sdp.contains("a=setup:actpass")) "offer" else "answer"
}
原理:Offerには"a=setup:actpass"が含まれ、Answerには"a=setup:active"または"a=setup:passive"が含まれます。
5.2 SDPの検証
fun validateSdp(sdp: String): Boolean {
if (sdp.isEmpty()) {
Log.e(TAG, "[sdp] SDP内容が空です")
return false
}
if (!sdp.contains("v=")) {
Log.e(TAG, "[sdp] SDP形式が無効です。バージョン行がありません")
return false
}
return true
}
6. コーデックの詳細
6.1 オーディオコーデック
| コーデック | Payload Type | サンプリングレート | 特徴 |
|---|---|---|---|
| Opus | 111 | 48kHz | 高品質、ビットレート自動調整 |
| PCMU | 0 | 8kHz | G.711 μ-law、北米標準 |
| PCMA | 8 | 8kHz | G.711 A-law、欧州標準 |
6.2 ビデオコーデック
| コーデック | Payload Type | 特徴 | 推奨シーン |
|---|---|---|---|
| VP8 | 96 | オープンソース、ソフトウェアエンコード効率が高い | 一般的なシーン |
| H.264 | 100 | ハードウェアアクセラレーションサポート良好、モバイルフレンドリー | モバイルデバイス |
6.3 コーデックネゴシエーションプロセス
発信側がサポートするコーデックのリストをOfferに含め、受信側が共通のコーデックを選択してAnswerで返信します。
7. SDPとICEの関係
7.1 ICE候補者のSDPでの表現
a=candidate:<foundation> <transport> <priority> <port> typ [raddr rport ]
ICE候補者のタイプ:
- host: ローカルアドレス(LAN IP)
- srflx: サーバーリフレクションアドレス(グローバルIP)
- relay: リレーアドレス(TURNサーバー)
7.2 Trickle ICE
Trickle ICEは、ICE候補者が収集されるたびに段階的に送信する方式で、接続確立を高速化します。
a=ice-options:trickle
8. SDPの再ネゴシエーション
8.1 再ネゴシエーションが必要な場合
- メディアトラックの追加/削除
- メディア方向の切り替え
- ICEの再起動(ネットワーク切り替え時)
- 画面共有の開始/停止
8.2 再ネゴシエーションプロセス
再ネゴシエーションのプロセスは初期ネゴシエーションと同じOffer/Answerモデルに従います。
9. SDPデバッグ手法
9.1 SDPログの読み方
SDPログを確認する際の重要なポイント:
- コーデックネゴシエーションの結果
- ICE認証情報
- DTLS設定
- メディア方向
9.2 一般的な問題のトラブルシューティング
- ビデオが再生されない:コーデックネゴシエーションの失敗
- ICE接続がCHECKING状態のまま:ICE候補者の交換に問題
- DTLS接続の失敗:フィンガープリントの不一致
- 相手が音声を聞けない:メディア方向の設定エラー
10. SDPのベストプラクティス
10.1 処理に関する推奨事項
- SDPを手動で変更しない
- SDP交換の順序を正しく処理する
- ICE候補者を適切なタイミングで処理する
- 再ネゴシエーションを実装する
10.2 パフォーマンスの最適化
- BUNDLEを使用する
- Trickle ICEを使用する
- 適切なコーデックを選択する
- RTCPフィードバックを有効にする
11. 参考資料
11.1 関連RFCドキュメント
| RFC番号 | タイトル | 説明 |
|---|---|---|
| RFC 4566 | SDP: Session Description Protocol | SDPプロトコル仕様 |
| RFC 3264 | An Offer/Answer Model with SDP | Offer/Answerモデル |
| RFC 5245 | Interactive Connectivity Establishment (ICE) | ICEプロトコル |
11.2 プロジェクト関連ファイル
| ファイルパス | 説明 |
|---|---|
| SdpManager.kt | SDP管理、検証、タイプ判定、キャッシュ処理を含む |
| WebRTCClient.kt | td>WebRTCクライアント、Offer/Answerの作成と処理を含む|
| IceCandidateManager.kt | ICE候補者管理 |