初めに
今回のパートでは、early dialog周りを扱います。だんだんとフローが複雑になっていきますがしっかり解説していきます!
early dialogとは
INVITEフローによってUACとUAS間のダイアログが確立されますが、このダイアログは2種類存在します。それがearly dialogとconfirmed dialogです。
early dialogとは、暫定応答18xによって確立されるダイアログです。なぜこのタイミングでダイアログが確立されるのかはもうわかりますね?暫定応答18xのToヘッダにtagパラメータが付与され、ダイアログを識別できるようになるためです。early dialogは200 OKの最終応答を受けるとconfirmed dialogへ移行します。では、なぜearly dialogとconfirmed dialogを分ける必要があったのでしょうか。その答えとして、以下の2つが想定されるでしょう。
forking
forkingでは、ある端末のINVITEがプロキシ等で複数の端末にコピーして送信されます。そして、INVITEが送信された端末で一斉に呼び出しを行い、暫定応答18xをプロキシ等に返すこととなります。つまりearly dialogが複数できるわけです。その後、実際に応答する端末は1つなので、その時に「confirmed dialog」に移行します。
このように、ダイアログを2つにわけることで、応答前の複数ダイアログが発生しうる状況(early)と応答後の単一ダイアログの状態(confirmed)を分離できて、設計上うれしいのです。
early media
confiremed dialogとしてメディアセッションが確立する前に、音声を流したいことがあります。例えば、IMSからRing Back Toneを流したいとき、「この電話番号は現在使われておりません」などの案内を流したいときなどです。この場合、early dialog上でメディアセッションを確立する必要があります。これがearly mediaです。early mediaを再生するためにも、early dialogが必要になるということです。
そろそろメディアを流し始める
ここまでSIP、特にINVITEについて詳しく解説してきました。また、通常のメディアセッションとearly mediaも紹介し終えたので、そろそろメディア側を含めた解説を行っていきたいと思います。まず初めに解説しておかなければいけないのが、C-PlaneとU-Planeの分離です。
C/U分離
VoIPのNW設計の概念として重要なのが、制御信号とデータ信号の分離です。ここでいう「制御信号」はSIP、「データ信号」はRTPのことです。言い換えると「SIPとRTPは最低限の結合で扱いましょう」ということになります。これはSIPとRTPの目的や通信要件が違うことから、なるべくアーキテクチャ的に分離したほうが保守やスケーリングがしやすいためです。では、SIPとRTP間の「最低限の結合」とは何でしょうか?答えは、SDPというプロトコルになります。SDPには、RTPメディアセッションに使用するIPアドレスやコーデック等を記載し、INVITEフローを用いて、互いにこれらの情報を交換します。SDPの交換が正常に終了すると、記載された情報に基づいてRTPでメディアを送受信できるようになります。SIP、SDP、RTPの関係は以下の図のようになります。
SDP交換まで含めたINVITEフロー
実際に、どのようにSDPの交換が行われるか見てみます。以下がそのINVITEフローです。
まず、UACはUASに向かってINVITEリクエストを送りますが、このときリクエストボディにSDP offerを格納します。SDP offerには、UACがメディアセッションで使えるIPアドレスやポート、コーデックなどが記載されています。このSDP offerに対し、UASは200 OKのレスポンスでボディにSDP answerを格納して送ります。SDP answerには、UASがメディアセッションで使えるIPアドレスやポート、コーデックなどが記載されています。このように、通常INVITEではその最初のリクエストでSDP offer、最終応答でSDP answerが送信されます。このようなSDP交換のモデルをoffer/answerモデルと呼びます。
Media clipping
「これでうまくSDP交換もできたし、完璧に通話できる!」とならないのが難しいところです。例えば以下のようなフローを考えてみましょう。
UAS側のSIP端末で着側ユーザが応答すると、「200 OK」のレスポンスは当然UAC側に送られますが、同時にRTPも送信されるはずです。皆さん電話するとき、電話に応答したのに「もしもし」と話せるようになるまで時間がかかるということはありませんよね?このようなことからも、応答と同時に200レスポンスとRTPが並行して送信されることがわかります。そしてVoIPではC/U分離が基本であるため、SIPの200 OKレスポンスとRTPパケットが送信される経路は全く異なりうることがあります。その結果、RTPパケットが200 OKのパケットよりも早くUAC側へ到着することがあるのです。
さて、これは重大な問題でしょうか?実はここまでは、あまり問題になりません。なぜならUACはINVITEを送る時点で、RTPパケットを受信する準備ができるからです。
UAC側はSDP offerを送信した時点で、そのSDPに記載したIPアドレスのインターフェースを準備することができます。そしてUAS側では、準備されたインターフェースに向かってRTPを投げるので普通にユーザに音声を届けることができるわけです。
問題は、UAS側からの音声が届いてしまった結果、UAC側のユーザが発話した場合です。
UAC側のユーザが発話したとしても、SDP answerで相手のメディアIPがわかるまでは、RTPを送信することができません。その結果、実際は話しているのに、相手にはその音声が届いていないという問題が発生します。これがMedia Clippingです。ではMedia clippingを発生させないようにするには、どのようにSDP交換をすればよいでしょうか?答えはとてもシンプルで、200 OKのレスポンスではなくその前の18x暫定応答にSDPを載せればよいわけです。
このようにすると、もはやearly dialog上でメディアを流すことが可能になります。これがearly mediaの正体です。
でもまだ課題はある
early mediaが流せる設計になっても、実はまだ問題が残っています。それは、「180暫定応答は再送処理されないため、パケットロスしたらSDP answerが失われる」ということです。early mediaを用いないフローの場合、SDP answerは最終応答200 OKで送られていたため、再送処理によって確実にUAC側に届けられます。一方で、暫定応答18xはそのような再送処理がなされません。したがって、パケットロスが生じた場合、UACが相手のメディアIPを知る機会が失われることになります。
これはかなりの問題なので、SIPは拡張機能として信頼性のある暫定応答(PRACK)を導入しています。これは、暫定応答に対する確認応答PRACKを送ることで、ほかのリクエスト同様にタイマ・再送制御を行い、UACへ確実に暫定応答が届くよう保証するものです。PRACK導入により、以下のようなINVITEフローになります。
UAS側は180 Ringingに対するPRACKが送られてこなかった場合、途中でパケットが欠落したと判断して再送を行います。これにより暫定応答の中で確実にSDP answerをUACまで届けることが可能となります。
183 Session Progress
さて、先ほどのINVITEフローでは、「180 Ringing」にSDP answerを付与してレスポンスしていました。この部分について少し詳しく見てみます。RFC 3261では180 Ringingについて以下のように記載されています。
The UA receiving the INVITE is trying to alert the user.
This response MAY be used to initiate local ringback.
# INVITEを受信したUAは、ユーザに着信を通知しようとしている。
# この応答は、ローカルのリングバックトーンの再生を開始するために使用されることがある。
重要なのは、2つ目の文です。180 Ringingを受け取ったUASはローカルでRBTを鳴らすというように記載されています。つまり以下の図のような状況になります。
暫定応答の時点でSDP交換が終了し、RTPを流せる状況にもかかわらず、そのRTPセッションを使わずにローカルでRBTを再生するということになります。「別にいいじゃん、、、」と思うかもしれませんが、もしネットワーク経由でRBTが流せたら、通話が開始する前に音声が流れることを確認できたり、カスタムRBTを流すことができたりします。また、今回はUAどうしのフローを示していますが、そこにIMSなどが介入するとIMSがRBTを流したり、RBTを流す代わりにIVRを流したりと、できるサービスが増えるわけです。そのため、RBTの再生をローカルで行うだけでなく、ネットワーク経由で流すことも考えて「180 Ringing」以外の暫定応答が欲しくなります。そんな時に現れるのが「183 Session Progress」です。183 Session Progressに関してRFCでは、「他の応答コードでは表現できない通話進行状況を通知するための暫定応答」と書かれていますが、要は「180 Ringing」を使わないときはこれを使えということです(ちょっと暴論かな?)。
この新たな暫定応答によって、「呼制御の進行を伝達しつつ、early mediaからRBTを流す」というような挙動をとれるようになります。以下がそのフローです。
これで、early mediaを使ってRBTを流せるようになりました。また上の図ではPRACKを受け取ってからRBTを流していますが、この順番は逆でも勧告上は問題ありません。ただし、順番を逆にするとearly mediaのmedia clippingが発生しうるので注意しましょう。
ここまでで、PRACKを用いたINVITEフローを確認してきました。しかし実際の環境では、「PRACKを使わず、よりシンプルなINVITEフローにしたい」というUAの要望もあります。そこで本パートの最後として、PRACKを使用するかどうかがどのタイミングで決まるのかについて見ていきます。
100rel
結論から言えば、PRACKを使うかどうかは、INVITEに含まれる Supported: 100rel と、暫定応答18xの Require: 100rel によって決まります。ここで、「100rel」が信頼性のある暫定応答(PRACK)を示しているわけですね!つまり、PRACKを使うために、まずUACがSupported: 100relで「PRACKを使える」ことを示して、その後UASがRequire: 100relによって「PRACKを実際に必要としている」ことを示すわけです。フローは以下のようになります。
UACがSupported: 100relを送らない場合、またはUASがRequire: 100relを要求しない場合、INVITEフローはPRACKを使わないものとなります。この場合は双方向early mediaが保証されないため注意が必要です。
終わりに
ここまででINVITEフローとダイアログについてだいぶ理解が進みました!次回はもう少しearly mediaに関する話題を続けて、その後、また別の話題に移れればと思います!











