SDP(Session Description Protocol)は、マルチメディアセッションを記述するためのテキスト形式であり、参加者間の接続パラメータを調整するために設計されています。IETF RFC 8866(2021)によると、SDPはメディアストリーム、コーデック、トランスポートアドレス、その他のパラメータを記述する構造を定義し、メディアデータ自体を送信しません。このプロトコルはWebRTCの重要なコンポーネントとなり、ピアツーピア接続を確立する前にブラウザとモバイルアプリケーション間の情報交換を可能にします。
重要ポイント
SDPは、テキスト形式でマルチメディアセッションパラメータを記述するために設計されたアプリケーション層プロトコルです。IETFのMMUSIC(Multiparty Multimedia Session Control)ワーキンググループの下で開発され、1998年にRFC 2327で初めて標準化されました。2021年には、以前のバージョンRFC 4566に代わる最新仕様RFC 8866が公開されました。
SDPの主な役割は、セッション参加者に接続確立に必要なすべての情報を提供することです。どのメディアストリームが送信されるか、どのコーデックがサポートされているか、どのネットワークアドレスとポートで送信が行われるかなどです。SDPはメディアデータ自体を送信せず、接続をどのように構成するかを記述するだけです。
IETF RFC 8866によると、SDP形式は一連の行で構成され、各行は1文字のタイプで始まり、等号と値が続きます。たとえば、m=audio 5004 RTP/AVP 0という行は、セッションにポート5004でRTP/AVPトランスポートプロトコルとPCMUコーデック(タイプ0)を使用するオーディオストリームが含まれていることを意味します。
SDPの最初のバージョンは、1998年4月にRFC 2327としてMMUSICグループの作業成果として公開されました。このプロトコルは元々、Mbone(Multicast Backbone)内でマルチキャストセッションをアナウンスするために作成されました。VoIPとビデオ会議の発展に伴い、SDPの適用範囲は拡大し、2006年に更新版RFC 4566が公開されました。
SDPの使用における真の進歩は、2011年のWebRTCの登場とともに起こりました。Googleは、ブラウザベースのリアルタイム通信フレームワークにおいて、メディアセッションを記述する主要なメカニズムとしてSDPを統合しました。それ以来、SDPはブラウザからiOSやAndroidのモバイルアプリケーションに至るまで、あらゆるWebRTC実装の必須コンポーネントとなっています。
2021年、IETFワーキンググループはRFC 4566に代わる現在のSDP仕様RFC 8866を公開しました。更新版では、ICE(Interactive Connectivity Establishment)処理の明確化、DTLS(Datagram Transport Layer Security)サポートの強化、グループセッション記述機能の拡張が行われました。
SDPはデータ送信に参加しない点で、トランスポートプロトコルとは根本的に異なります。これは純粋に記述的な機能を果たし、マルチメディアファイルのメタデータに似ています。RTP(Real-time Transport Protocol)がオーディオとビデオのパケットを送信し、RTCPが送信品質を制御する一方、SDPは使用するコーデックとポートを指定するだけです。
ウェブ開発における例え:SDPはページ構造を記述するHTMLマークアップのようなものであり、RTPは実際の画像やテキストです。SDPがないと、ネットワーク接続がすでに確立されていても、セッション参加者は互いに接続する方法を知りません。NATトラバーサルメカニズム(ICE)も、ネットワーク候補に関する情報を送信するためにSDPに依存しています。
SDP構造はテキスト行のシーケンスとして構成され、各行はtype=value形式に従います。1文字のタイプが行の目的を定義し、値に対応する値が含まれます。すべての行はCRLF文字で区切られます。
RFC 8866標準は、いくつかの必須フィールドとオプションフィールドを定義しています。必須フィールドには、プロトコルバージョン(v=)、セッション名(s=)、セッションの開始時間と終了時間(t=)が含まれます。残りのフィールドはオプションですが、WebRTCセッションではメディア記述(m=)、属性(a=)、ネットワーク情報(c=)も必要です。
v=0
o=- 46116397 2 IN IP4 192.168.1.100
s=-
t=0 0
a=group:BUNDLE audio video
m=audio 5004 RTP/SAVPF 111 103 104
c=IN IP4 192.168.1.100
a=rtpmap:111 opus/48000/2
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
m=video 5006 RTP/SAVPF 96 97
a=rtpmap:96 VP8/90000
a=rtpmap:97 H264/90000
上記の例は、WebRTCセッションの典型的なSDPセグメントを示しています。v=0行はプロトコルバージョンを示します。o=フィールドにはセッション所有者の識別子とバージョンが含まれます。s=-行はセッション名を指定します(ハイフンは空の名前を意味します)。t=0 0フィールドはセッションに時間制限がないことを示します。
a=group:BUNDLE audio videoフィールドは、複数のメディアストリームを1つのトランスポートチャネルにグループ化する属性です。BUNDLEメカニズムにより、1つの接続でオーディオとビデオを送信することでネットワークリソースを節約できます。これは帯域幅が限られているモバイルデバイスにとって特に重要です。
RFC 8866仕様は、必須フィールドとオプションフィールドのセットを定義しています。必須フィールドにはv=(バージョン)、s=(セッション名)、t=(時間)が含まれます。o=(所有者)フィールドはRFC上は厳密には必須ではありませんが、実際の実装ではほとんどの場合存在します。
| フィールド | 目的 | 例 |
|---|---|---|
| v= | SDPプロトコルバージョン | v=0 |
| o= | セッション所有者と識別子 | o=- 46116397 2 IN IP4 192.168.1.100 |
| s= | セッション名 | s=Video Conference |
| t= | セッション開始時間と終了時間 | t=0 0 |
| m= | メディアストリームの記述 | m=audio 5004 RTP/SAVPF 111 |
| c= | ネットワーク情報 | c=IN IP4 192.168.1.100 |
| a= | セッションまたはメディア属性 | a=rtpmap:111 opus/48000/2 |
m=(media)フィールドは最も重要なものの1つです。特定のメディアストリームを記述し、メディアタイプ(audio、video、text、application)、ポート、トランスポートプロトコル、サポートされるコーデックのリストを含みます。WebRTCで最も一般的に使用されるタイプはaudioとvideoで、トランスポートプロトコルはRTP/SAVPF(Secure Audio/Video Profile with Feedback)またはUDP/TLS/RTP/SAVPFです。
a=(attribute)フィールドは最も柔軟で拡張性があります。rtpmap(コーデック番号から名前へのマッピング)、fmtp(コーデックパラメータ)、fingerprint(DTLSキーのフィンガープリント)、ice-ufragとice-pwd(ICE認証情報)など、多くの属性を含めることができます。属性を通じて、SDPは最新のセキュリティメカニズムとNATトラバーサルをサポートします。
WebRTCアーキテクチャでは、SDPは2つの参加者間でメディアセッションパラメータを記述およびネゴシエーションするためのシグナリングプロトコルとして機能します。SDP自体はこれらの記述を送信するメカニズムを定義しておらず、このタスクは開発者がWebSocket、HTTP、または他のプロトコルを介して独自に実装するシグナリングチャネルによって処理されます。
プロセスは、発信側(caller)がSDP Offerを作成することから始まります。ブラウザはRTCPeerConnectionオブジェクトのcreateOffer()メソッドを呼び出します。生成されたSDP記述には、発信側のすべてのセッションパラメータ(サポートされるコーデック、ネットワークアドレス、ICE候補、セキュリティ要件)が含まれます。
const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
const pc = new RTCPeerConnection(configuration);
// createOfferの前にメディアトラックを追加
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// SDP Offerを作成
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// シグナリングチャネルを介してリモートピアにSDPを送信
sendViaSignaling({ type: 'offer', sdp: offer.sdp });
Offerを作成し、setLocalDescription()でローカル記述を設定した後、発信側はシグナリングチャネルを介してSDP文字列をリモート参加者に送信します。リモート参加者はSDP Offerを受信すると、SDP Answerを作成して返送します。この交換をシグナリング交換と呼び、ピアツーピア接続を確立する前の必須ステップです。
W3C WebRTC仕様によると、SDP交換はICE候補の開始前に行われる必要があります。実際には、多くの実装がICE trickleメカニズムを使用してSDPと並行してICE候補を送信します。これにより、特に高レイテンシのモバイルネットワークでの接続確立時間が短縮されます。
ICE(Interactive Connectivity Establishment)は、SDP属性を使用してネットワーク候補に関する情報を送信するメカニズムです。ICE候補は、host(ローカルアドレス)、srflx(NAT経由後のアドレス、STUNで取得)、relay(TURNサーバーのアドレス)など、可能な接続経路を記述します。
SDPでは、ICE候補はa=candidate:属性を介して、またICEトラフィック認証用のice-ufragとice-pwdフィールドを介して送信されます。各候補には、トランスポートプロトコル(UDP、TCP)、IPアドレス、ポート、優先度が含まれます。成功した接続は、接続性チェックに合格した最初の候補を介して確立されます。ICE restartメカニズムにより、ネットワーク変更時に接続を更新できます。
モバイルアプリケーションの場合、デバイスはNATや企業ファイアウォールの背後にあることが多いため、ICE候補は特に重要です。ICEメカニズムは複雑なネットワーク環境でも機能する経路を見つけることができ、SDPはこの情報のトランスポートコンテナとして機能します。
WebRTCのSDPには、セキュリティ属性、特にDTLSフィンガープリントとSRTPパラメータが必ず含まれます。a=fingerprint:sha-256フィールドには、メディアストリームの認証と暗号化に使用されるDTLS証明書のフィンガープリントが含まれます。この属性がないと、WebRTC接続は確立されません。
追加のセキュリティメカニズムには、DTLSハンドシェイクの役割(active、passive、actpass)を定義するa=setup:属性と、サーバー側の簡略化されたICE実装のためのa=ice-lite:が含まれます。これらのパラメータはすべてSDP内で送信され、メディアデータの送信が開始される前に両方の参加者によって検証されます。
WebRTCモデルには、Offer(提案)とAnswer(回答)の2種類のSDPメッセージがあります。Offerは接続発信側によって作成され、希望するメディアセッションの完全な記述を含みます。Answerはリモート参加者によってOfferに応答して作成され、提案によって課された制約を考慮したその参加者の機能を含みます。
OfferとAnswerの主な違いは、属性のセマンティクスにあります。Offerは発信側が提案できるすべてのサポートされるコーデック、トランスポートプロトコル、ネットワークアドレスをリストします。Answerはリモート側がサポートするこれらの機能のサブセットを選択します。たとえば、Offerがopus、ISAC、PCMUを提案する場合、Answerは最も好ましいコーデックとしてopusのみを選択できます。
交換プロセスはW3C WebRTC仕様によって管理され、RTCPeerConnectionのいくつかの状態を含みます。createOffer()でOfferを作成し、ローカル記述として設定した後、接続はhave-local-offer状態になります。Answerを受信し、setRemoteDescription()でリモート記述として設定した後、接続はstable状態になり、メディア送信の準備が整います。
WebRTC用モバイルSDK(Android用Google WebRTCとiOS用WebRTC.framework)は、OfferとAnswerによるSDP交換を完全にサポートしています。Androidでは、ブラウザAPIと同様に、PeerConnectionクラスとcreateOffer()メソッドを使用してOfferを作成します。結果のSDP記述はシグナリングチャネルを介して文字列として送信されます。
iOSでは、SDPの操作はWebRTCフレームワークのRTCSessionDescriptionクラスを介して行われます。初期化時に、タイプ(RTCSdpTypeOfferまたはRTCSdpTypeAnswer)とSDP文字列が指定されます。プラットフォームは自動的にSDPを解析し、送信されたパラメータに従って接続を構成します。
val configuration = PeerConnection.RTCConfiguration(List())
val peerConnection = factory.createPeerConnection(configuration, object : PeerConnection.Observer {
override fun onIceCandidate(candidate: IceCandidate) { }
})
// AndroidでSDP Offerを作成
peerConnection.createOffer(object : SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription) {
peerConnection.setLocalDescription(this, sdp)
// リモートピアにSDP文字列を送信
sendSdpToRemotePeer(sdp.description)
}
}, new MediaConstraints())
SDP文字列を直接操作できるため、開発者は柔軟性を得られます。送信前にSDPを変更して、特定のコーデックを追加または削除したり、ICEパラメータを構成したり、カスタム属性を追加したりできます。Androidアプリケーションでは、ネットワーク帯域幅が低い場合にSDPでビデオを無効にする必要がよくあります。これはSDP記述から対応するm=行を削除することで行われます。
モバイル開発では、SDPは主にWebRTCのコンテキストで使用され、ビデオ通話、ボイスチャット、ストリーミングを行うアプリケーションを作成するために使用されます。AndroidとiOSのモバイルアプリケーションは、SDPメッセージの発信側と受信側の両方として機能でき、対称的なピアツーピア接続を可能にします。
モバイルアプリケーションの特徴は、変動するネットワーク品質条件下でSDPを操作する必要があることです。Wi-Fiとモバイルインターネットを切り替える場合や、帯域幅が変化する場合、新しいSDP記述の生成が必要になることがあります。これは再ネゴシエーションメカニズム(createOffer()とsetLocalDescription()を介した繰り返しのSDP交換)を使用して行われます。
Google WebRTCチーム(2023)によると、モバイルデバイス向けのSDP交換の最適化には、ネットワーク変更時のICE restartの使用、低ビットレートコーデック(オーディオ用opus、ビデオ用VP8)の優先、不要なメディアストリームを除外したSDP文字列サイズの最小化が含まれます。主な利点は、モバイルネットワーク条件下での接続確立時のレイテンシ低減です。
モバイルデバイスでSDPを操作する際の重要なタスクの1つは、SDP記述サイズを最小化することです。オーディオとビデオを含む典型的なWebRTCセッションの完全なSDPは2〜5KBになり、低速ネットワークでは重要です。最適化には、BUNDLE(ストリーム多重化)の使用、サポートされていないコーデックの削除、ICE候補の圧縮が含まれます。
モバイルデバイスに関する追加の問題は、SDPの寿命が限られていることです。不安定な接続状態では、リモート参加者が処理する前にSDPが古くなる可能性があります。解決策は、Answerを受信するための短いタイムアウトを使用し、必要に応じてSDPを再送信することです。ICE restartメカニズムにより、RTCPeerConnectionを完全に再作成せずに接続を更新できます。a=ice-lite属性は、サーバー側のICE実装を簡素化します。
モバイルアプリケーション開発者は、SDPの操作を簡素化する既製のライブラリにアクセスできます。libjingle_peerconnection(Google WebRTC)はAndroid用の主要ライブラリで、SDP管理のための完全なAPIを提供します。iOSでは、同様の機能を持つWebRTC.frameworkが使用されます。両方のライブラリは自動的にSDPを生成および解析しますが、必要に応じて生のSDP文字列へのアクセスも提供します。
SDPをより細かく制御するためのサードパーティソリューションもあります。SDPを解析および変更するためのsdp-transform(JavaScriptまたはNode.js)、ICE候補を操作するためのNICENICE(Java)、およびSDPを含むすべてのシグナリング交換を処理するWebRTCインフラストラクチャプロバイダーの既製SDKなどです。
よくある質問
SDPは、セッション参加者がサポートするコーデック、ポート、プロトコルを記述するテキスト形式です。ビデオやオーディオを送信せず、接続パラメータをネゴシエーションするだけです。例えるなら、SDPはメニューであり、RTPは実際の料理です。
SIPは、通話を確立、変更、終了するセッション制御プロトコルです。SDPは、メディアパラメータを送信するためにSIPメッセージ本文に埋め込まれる記述形式です。SIPは「誰が誰に電話しているか」という質問に答え、SDPは「どのコーデックとポートを使用するか」に答えます。
はい、接続を確立する前にSDP文字列を変更できます。開発者は特定のコーデックを強制選択したり、カスタム属性を追加したり、サポートされていないメディアストリームを削除したりするためにSDPを編集することがよくあります。ただし、変更は両方の参加者で合意する必要があり、そうでなければ接続は確立されません。
SDPは、開発者が独自に実装する別のシグナリングチャネルを介して送信されます。一般的なオプションには、Webアプリケーション用のWebSocket、HTTP POSTリクエスト(REST API)、モバイルアプリケーション用のネイティブプロトコルがあります。WebRTCはSDPの送信方法を定義せず、その形式のみを定義します。
BUNDLEは、複数のメディアストリーム(オーディオ、ビデオ、データ)を1つのトランスポートチャネルに結合するSDPメカニズムです。各ストリームに個別のポートを使用する代わりに、1つのポートと1つのICE接続を使用します。これにより、モバイルデバイスの負荷が軽減され、レイテンシが減少します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。