SIPレジストを使って、Twilio環境だけでSIPソフトフォンを使ってみた

# はじめに
# この記事について

本稿は、Twilio Advent Calendar 2016の
[SIPレジストを使って、Twilioで固定電話をつかってみる](https://qiita.com/mobilebiz/items/26f91550556088545c49)
の記事の内容をTwilio Functionsを利用してやってみた、という記事です。

具体的には、TwilioのSIPドメインとFunctionsを使い、Twilio電話番号経由で、SIPソフトフォンと手持ちのスマートフォンとの発着信をしてみました。
ちなみに、私はSIPに関する知識はないため、本来の利用方法とは異なる点などがあるものと推測しています。その点ご留意ください。

## 元記事と異なる点
ほぼほぼ、元記事と同じことをしています。
元記事には用語解説やフローの説明、制限事項なども掲載されていますので、ぜひ参照してください。

本稿で元記事と異なる点を予め記載しておきます。

* IP電話機 > SIPソフトフォン

 IP電話機ではなく、SIPソフトフォンを利用して、発着信の確認を行なっています。
こちらではAndroidのフリーのアプリを利用しましたが、おそらく一般的なSIPソフトフォンであれば問題なく利用できるものと思います。

 ただし、あくまでIP電話機の代わりとしてSIPソフトフォンを利用する、すなわち、SIPソフトフォンを固定電話として利用する、という想定で行なっております。

* TwiML Bins > Functions

 元記事ではSIP電話機への着信用のTwiMLの設定に TwiML Bins を使用していましたが、これを Functions でTwiMLを出力するように置き換えました。

* TwiMLを返すためのプログラムの実行環境 > Functions

 元記事ではSIP電話機への発信用のTwiMLを返すためのプログラムの実行環境を別途用意、となっていましたが、これを Functions で用意しました。

* 内線考慮 > 内線未考慮

 本稿では、内線を考慮せず、ただただ「Twilioで購入した050電話番号を、SIPソフトフォンで使う」ということだけを実現するようにしています。


# 実践

## 概要

以下の設定を行っていきます。
1. Twilio Functionsの設定(SIP着信)
2. Twilio Functionsの設定(SIP発信)
3. Twilio SIPドメインの作成
4. SIPソフトフォンの設定
5. 電話番号設定
6. 発着信

## 1. Twilio Functionsの設定(SIP着信)

まずは、SIP着信用のTwiMLを返す Functions の設定をしてしまいます。

管理コンソールの Runtime を選択し、さらに Functions を選択します。(Manageが開きます)
以下の内容で、Functionsを新規作成します。
<img width="821" alt="SIP着信.png" src="https://qiita-image-store.s3.amazonaws.com/0/174697/9588403e-24d1-c9c3-9b8a-a5d6bb517845.png">

FUNCTION NAME は任意です。
PATHの文字列も自由に決められますが、ここでは「/sipin」と入力しました。

EVENTに「Incoming Voice Calls」を選択し、CODEに以下のコードをコピペします。

```js:SipIn
exports.handler = function(context, event, callback) {
  // 宛先
  const toNumber = event.To || '';
  // 宛先を元にSIPユーザ名に変換
  const userName = '0' + toNumber.substring(3);
  // SIP宛先
  const sip = 'sip:' + userName + '@[SIPドメイン名].sip.us1.twilio.com';

  const twiml = new Twilio.twiml.VoiceResponse();
  twiml.dial().sip(sip);

  console.log(twiml.toString());
  callback(null, twiml);
}
```

SAVEボタンを押して保存します。
Functionの内容が更新され、すぐにデプロイが開始されます。
少し待ってデプロイが成功すると、「Your Function has successfully been deployed.」と表示されます。

## 2. Twilio Functionsの設定(SIP発信)

同様に以下の内容で、もう一つFunctionsを新規作成します。
<img width="1009" alt="SIP発信.png" src="https://qiita-image-store.s3.amazonaws.com/0/174697/8ce9e73d-ffe6-593a-6033-015a398c2cda.png">

PATHの文字列は「/sipout」です。
EVENTは、初期値のままです。

CODEに以下のコードをコピペします。

```js:SipOut
exports.handler = function(context, event, callback) {
  // 宛先
  const to = event.To || '';
  // 発信者番号
  const from_ = event.From || '';
  // 宛先/発信者番号から電話番号を抽出 'XXXXXXXXXXX@xxx.sip.us1.twilio.com' -> 'XXXXXXXXXXX'
  const toNumber = to.indexOf("@") > 0 ? to.substring(4, to.indexOf("@")) : '';
  const fromNumber = from_.indexOf("@") > 0 ? from_.substring(4, from_.indexOf("@")) : '';
  // 0AB〜Jを+81に変換
  const number =  (toNumber.substring(0, 1) === '+' ? toNumber : '+81' + toNumber.substring(1));
  const callerId = (fromNumber.substring(0, 1) === '+' ? fromNumber : '+81' + fromNumber.substring(1)); 

  const twiml = new Twilio.twiml.VoiceResponse();
  twiml.say("お繋ぎします。少しお待ちください。", {voice: 'alice', language: 'ja-JP'});
  twiml.dial({callerId: callerId}).number(number);

  console.log(twiml.toString());
  callback(null, twiml);
}
```
その後、SAVEボタンを押し、デプロイが成功することまで確認します。

また、PATHの一番右にある Copy ボタンを押して、SipOutのURLをコピーしておきます。(SIPドメインの設定で使います)

## 3. Twilio SIPドメインの作成
続いて、SIPドメインの作成です。
元記事の、[ハンズオン](https://qiita.com/mobilebiz/items/26f91550556088545c49#%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3)に記載の内容と、[SIPドメインの作成](https://qiita.com/mobilebiz/items/26f91550556088545c49#sip%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90)の内容を元に、SIPドメインを作成します。

この時、音声通話設定の REQUEST URL に、先ほどコピーしたSipOutのURLを貼り付けます。
最終的なSIPドメイン設定は以下のようになりました。
<img width="954" alt="SIPドメイン.png" src="https://qiita-image-store.s3.amazonaws.com/0/174697/9817dc0b-4537-b258-5f38-a0a87a225109.png">

ここで、SIPドメインのクレデンシャルリストに一つ仕掛けを設けています。
クレデンシャルユーザ名は任意で決められますが、これをTwilioで購入した電話番号にしています。これは、電話番号とユーザ名を関連づけるためです。
<img width="1017" alt="クレデンシャルリスト.png" src="https://qiita-image-store.s3.amazonaws.com/0/174697/5d3eaa40-cbc5-36d9-b3a9-96d4e6814dde.png">

関連する処理は、SipInの toNumber(event.To)の情報を、ユーザ名に変換している箇所です。ここは宛先のユーザ名を何らかの方法で特定できれば良いのでどのような形でも良いと思います。今回は１対１なので固定文字列でもよかったのですが、せっかく Functions を使うのであえて面倒なことをしてみました。

(本当は、電話番号リストを参照し、フレンドリーネームとクレデンシャルリストのユーザ名を紐付けるなどしたかったのですが、電話番号リストの参照方法が分からず…)

## 4. SIPソフトフォンの設定

さて、SIPソフトフォンの設定です。
設定方法はアプリによってそれぞれ異なると思いますが、使う情報は以下くらいと思います。

* ユーザ名：SIPドメインのクレデンシャルリストに登録したユーザ名
* パスワード：同じく登録したパスワード
* SIPサーバ：[SIPドメイン名].sip.us1.twilio.com
* ポート：5060

私が試したアプリでは、以下のように設定することで「登録済み」の状態になりました。

アカウントの追加 > Basic

| 設定項目    | 設定例     | 補足          |
|:-----------|:----------|:-------------|
| アカウント名 | twilio    | 任意          |
| ユーザー名 | 05000000000 | クレデンシャルユーザ名 |
| サーバ | [SIPドメイン名].sip.us1.twilio.com:5060 | [SIPドメイン名]を自身のものに変更 |
| パスワード | xxxxxxxxxxxx | クレデンシャルユーザのパスワード |

アカウントの追加を保存すると続いてSIPレジストへの登録が行われます。登録に成功し、ステータスが「登録済み」の状態になると、この時点でSIPソフトフォンからの発信が可能になっているはずです。

## 5. 電話番号設定

最後に、SIPソフトフォンへの着信時の設定を行います。

言い換えると、「Twilio電話番号宛の着信を、SIPソフトフォン宛てに転送する」設定を行います。
そこで、SIPドメインではなく、対象の電話番号の設定を行います。

管理コンソールの電話番号を選択し、さらに対象の電話番号を選択します。
Voice&Faxの A CALL COMES IN で Function を選択し、続いて SipIn を選択します。
<img width="1022" alt="電話番号設定.png" src="https://qiita-image-store.s3.amazonaws.com/0/174697/8b2e4c25-0bf5-2312-c4cf-f5bfcc780f45.png">

保存ボタンを押して設定を保存します。

## 6. 発着信
以上の設定で、SIPソフトフォンからの発信と、SIPソフトフォンへの着信の両方が実現できました。

# 最後に

今回は、やってみた、だけの簡単な内容でしたが、それでもSIPドメインの概要を垣間見ることができ、Functionsの便利さを感じることもできました。
Functionsは現状Beta実装ですが、非常に強力なツールと感じます。と言っても使いこなせれば、なので今後いろいろと試していきたいと思います。

ちなみに、本稿の動作確認は通話料金が発生しますので、その点ご注意ください。（おそらく、少額で済むものと思いますが）