概要
SIP REGISTER リクエストの有効期間
REGISTER リクエストには有効期間 (Expires) を指定することができます。
- http://www.softfront.co.jp/tech/ietfdoc/trans/rfc3261j.txt (Page 56 - 60 を参照)
REGISTER の有効期間に関する動作を簡単にまとめると以下のような感じです。
- クライアントは、REGISTER リクエストの Expires に希望する期間を指定して、送信。
- サーバーは、レスポンスにサーバー自身が希望する期間を指定して、送信。サーバーが指定した期間は、クライアントが希望した値かもしれないし、サーバーが希望する別の値に変更しているかもしれない。
- クライアントは、レスポンスに書かれた期間を過ぎた後(または期間に近づいた際に)、 REGISTER リクエストを再送信することが必要。
Android SIP API の auto registration 機能
Android SIP API には auto registration 機能があり、この機能を有効にした場合は REGISTER リクエストの送信・再送信は android 側が行ってくれます。
auto registration を使用しない場合、SipManager.register(SipProfile localProfile, int expiryTime, SipRegistrationListener listener)、SipSession.register(int expiryTime) を使用して REGISTER リクエストの送信を指示します。引数expiryTime
に期間を指定できます。
問題
Android SIP API の auto registration を使用する場合、どのくらいの期間を指定しているのか、サーバーからの応答に指示された期間をどう処理しているのか、わからなかったためコードを調べました。
コードの調査
以下のサイトを使用しました。ブランチは android-7.0.0_r35
としました。
結論
結論を先に書きます。
auto registration 機能を使用する場合には
- REGISTER リクエストには有効期間に 3600 秒を設定して送信している。
- REGISTER リクエストのレスポンスに書かれた有効期間の60秒前に、REGISTER リクエストを再送する。
- (レスポンスに書かれた有効期間が 3600 秒であれば、3600 - 60 秒後に再送信)
- レスポンスに有効期間が書かれていない場合は、有効期間を3600秒として動作する。
SipManager.open からの呼び出し階層
auto registration を使用する場合は、
SipManager.open(SipProfile localProfile, PendingIntent incomingCallPendingIntent, SipRegistrationListener listener) を使用すると思います。呼び出しをたどってみます。
SipManager.open(SipProfile localProfile, PendingIntent incomingCallPendingIntent, SipRegistrationListener listener)
→ SipService.open3(SipProfile localProfile, PendingIntent incomingCallPendingIntent, SipRegistrationListener listener, String opPackageName)
→ SipSessionGroupExt.openToReceiveCalls()
→ SipAutoReg.start(SipSessionGroup group)
→ SipSessionImpl.unregister
→ SipSessionImpl.doCommandAsync(final EventObject command)
→ SipSessionImpl.processCommand(EventObject command)
→ SipSessionImpl.process(EventObject command)
→ SipSessionImpl.readyForCall(EventObject evt)
→ SipSessionImpl.readyForCall, 1091
SipSessionImpl.unregister ...
まずは、既にサーバーに登録されている状態を解除しようとするようです。
(解除は、REGISTER リクエストを使用しますが、Expires に 0 を指定)
SipSessionImpl.readyForCall ...
SipHelper.sendRegister が REGISTER リクエストを送信しているようです。
mState は SipSession.State.DEREGISTRING になります。
REGISTER リクエストのレスポンス処理
レスポンスを正常に受信できたと仮定すると、以下の呼び出しになるはずです。
SipSessionGroup.processResponse(ResponseEvent event)
→ SipSessionGroup.process(EventObject event)
→ SipSessionImpl.process(EventObject evt)
→ SipSessionImpl.registeringToReady(EventObject evt)
→ SipSessionImpl.onRegistrationDone(int duration)
→ SipAutoReg.onRegistrationDone(ISipSession session, int duration)
→ SipAutoReg.run()
→ SipSessionImpl.register(int duration)
SipSessionImpl.registeringToReady ...
ステータスコードが 200 だった場合は、mState は SipSession.State.REGISTER ではないので、引数 duration に -1 を渡して onRegistrationDone を実行します。
SipSessionImpl.onRegistrationDone ...
mProxy のメソッド呼び出しにより、mProxy にセットされているリスナが呼び出されます。
SipAutoReg.onRegistrationDone ...
引数 duration は -1 のため、run() が実行されます。
SipAutoReg.run ...
引数 duration に 定数 EXPIRE_TIME を渡して register を実行します。
REGISTER リクエストの送信に関するコード
SipHelper.sendRegister について調べてみます。
1
REGISTER リクエストを作成しているのは、SipHelper.sendRegister(SipProfile userProfile, String tag, int expiry)。
222 行 : 引数 expiry
がリクエストにセットされる。
2
SipHelper.sendRegister
の呼び出し元は、SipSessionImpl.readyForCall(EventObject evt) 。
引数expriy
には、変数duration
を指定している。
変数duration
は、RegisterCommand.getDuration()
の値がセットされている。
3
RegisterCommand.getDuration() は、インスタンス時の引数duration
を返す。
RegisterCommand
を作成しているのは、SipSessionGroup.register(int duration) 。
SipSessionGroup.register
の引数duration
を変更せず使用して、RegisterCommand
をインスタンス化する。
4
SipSessionGroup.register
の呼び出し元はいくつかあるが、auto registration 時は以下の2つ。
どちらも、定数EXPIRY_TIME
を指定している。EXPIRY_TIME は 3600。
REGISTER リクエストの応答処理に関するコード
REGISTER リクエストに対するレスポンスの処理を調べてみます。
1
レスポンスから Expires
を取得しているのは、SipSessionImpl.getExpiryTime(Response response)。
取得できなかった場合は、EXPRIY_TIME (3600) を返している。
2
SipSessionImpl.getExpiryTime(Response response)
の呼び出し元は、SipSessionImpl.registeringToReady(EventObject evt)。
getExpiryTime
で取得した値は、SipSessionImpl.onRegistrationDone に渡す。
3
SipSessionImpl.onRegistrationDone
は mProxy.onRegistrationDone
を呼ぶ。
mProxy
は、setListener
でセットされる。呼び出し元をたどると以下のように SipAutoReg
クラスがある。
SipSessionImpl.setListener
← new SipSessionImpl
← SipSessionImpl.createSession
← SipAutoReg.start
SipAutoReg.onRegistrationDone
は、SipAutoReg.restart
に duration - MIN_EXPIRY_TIME
を渡す。
MIN_EXPIRY_TIME は 60 。
(おそらく、期限が切れる60秒前に再送するため)
4
SipAutoReg.restart はタイマーを実行する。タイマーの期間は duration * 1000
ミリ秒後。
タイマーにより、SipAutoReg.run が実行され、mSession.register
を実行。
(mSession.register ... REGISTER リクエストの送信指示)
参考
- http://www.softfront.co.jp/tech/ietfdoc/trans/rfc3261j.txt (page 56 - 60 : REGISTERリクエストについて)