VoIP Push着信時にSIPサーバーから応答が返らない場合の対応


iOS13 で PushKit(VoIP Push)の縛りがきつくなった件、みなさんお悩みですよね。
 参考:VoIP Push (PushKit) は着信通知専用になりました・・・
 
VoIPアプリでは、プッシュ着信を受けた後に、セッションを張って通話を開始します。
特にSIP電話の場合、これまでは以下のような流れでした。

① プッシュ受ける(pushRegistry)
② SIPサーバーへ登録(REGISTER)
③ SIPサーバーからOK
④ SIPサーバーから着信(INVITE)
⑤ CallKitに着信を通知(CallKit:reportNewIncomingCall)
⑥ CallKitの着信画面表示
⑦ 着信応答(CallKit:provider CXAnswerAction)
⑧ SIPサーバーへ応答(200 OK)
⑨ 通話画面表示

しかし、xcode11 & iOS13 からは、VoIP Push を受信したらすぐにCallKitに通知(reportNewIncomingCall)することが義務付けられました。そのため、処理は以下のように変わることになります。

① プッシュ受ける(pushRegistry)
② CallKitに着信を通知(CallKit:reportNewIncomingCall)
③ CallKitの着信画面表示
④ SIPサーバーへ登録(REGISTER)
⑤ SIPサーバーからOK
⑥ SIPサーバーから着信(INVITE)
⑦ 着信応答(CallKit:provider CXAnswerAction)
⑧ SIPサーバーへ応答(200 OK)
⑨ 通話画面表示

問題点

問題は③〜⑤です。
SIPサーバーとのやりとりが素早く終わればほとんど問題はないかもしれません。
しかし、SIPサーバーとの間のネットワークに問題(遅い、ロストしやすい、不通など)があった場合、標準的には REGISTER のタイムアウトだけでも32秒程度かかる可能性があります。
結果、ユーザーが操作する時間が十分にあるため、以下のような流れも考えられます。

① プッシュ受ける(pushRegistry)
② 着信画面表示(CallKit:reportNewIncomingCall)
③ SIPサーバーへ登録(REGISTER)
④ 着信応答(CallKit:provider CXAnswerAction)
⑤ 通話画面表示
⑥ SIPサーバーからOK
⑦ SIPサーバーから着信(INVITE)
⑧ SIPサーバーへ応答(200 OK)

つまり、通話画面となってから実際に会話できるまでの⑥〜⑧は、通話画面なのに無音の状態となってしまいます。
最終的にネットワーク不通で⑥が返ってこなかった場合、ユーザーから見ると
 「着信に応答操作してもなぜか会話できずに切れてしまった」
という体験となってしまいます。
 
その他にもいろいろなパターンが考えられ、世のVoIP(SIP)電話アプリを作っている方はりんごさんに怒り心頭でしょう。。。

SIPサーバーから応答が返らない場合の対応

色々と課題と対応はありますが、とりあえず一つ、「通話画面なのに無音の状態」の対応を見つけました。

Responding to VoIP Notifications from PushKit
 →Respond to Call Hang Ups and Failures

以前からこのドキュメントがあったのかどうか分かりませんが、ユーザーが応答した際に呼ばれる provider(CXAnswerCallAction) で、SIPのコネクションが確立するまで(⑧を受け取るまで) fulfill() を返さないことだそうです。
これによって、CallKitの通話画面の表示は以下のようになり、ユーザーに接続中だと知らせることができるようになります。

なるほど! (って、ユーザー気づくかこれ??)
 
しかし、これはロック画面からの応答の際の話で、ロック解除中(操作中)に着信が入った際は、応答すると電話アプリが開きます。したがって、上記対応を入れつつ、アプリ画面でも接続中であることを知らせる画面を別途用意する必要があります・・・
 
その他、相手が先に切ったり、接続確立できなかった場合は reportCall(with:endedAt:reason:) で失敗の理由をシステムに伝えるように書かれてますので、それもしっかり対応しましょう。

最後に

上記で紹介した対応は、iOS13 による変化点対策の一部です。
準正常系、異常系の判断が大きく変わることになるので、修正は注意して行わなければならないです。
その他にも、チャットなど通話以外の機能でVoIP Pushを利用しているケースでは、通常のAPNs Pushに置き換えたりと大きな修正を余儀なくされているベンダーも多いことでしょう。
 
最近のモバイルアプリはセキュリティの観点から大きすぎる仕様変更が多いです。
開発者としては予想外の工数・費用がかかるため本当にやめて欲しいです。
セキュリティは大事ですが、影響の小さな仕様を考えて欲しいものです。。。