Twilioで在宅勤務の外線電話をステキな感じにする1(前置き編)

# 実装編は
着信処理
http://qiita.com/chabose/items/f098aa4ff28ad5492fa3
発信処理
http://qiita.com/chabose/items/71ea48b0e3bb4fa473fe

# 背景
数名の小さな会社で、ほとんどがリモートで仕事を行っているが、電話番号の公開が必要で、その番号にたまに着信がある場合のお話です。

これに対応するためには、

- 誰かの携帯電話の番号を公開する
- 固定電話を何処かに引く

ということになってしまうかと思いますが、

- 誰か一人の携帯電話に着信の負担が集中するのはツライ
- 不用意に携帯に着信したくない
- 固定電話を引いてもオフィスに人が居ない


複数名の会社ですので、誰かの番号を公開してしまえばその1人に着信の負担が集中しますし、プライベートとの切り替えも難しくなります。もし専用端末を用意したとしたととしても、端末の二台持ちも一部の携帯好き以外には嬉しいものではありません。と言った感じで・・・辛い。

なので、Twilioを使ってこの問題をステキな感じにしてみました。
(*Amazon Connectも気になりますね・・・)

# 作りたいもの
- 公開された番号に着信があった場合、どこにいても誰かが応対できる
- 仕事をしていない時は邪魔をされない

# 作るもの
![名称未設定-1.png](https://qiita-image-store.s3.amazonaws.com/0/59725/9198fc1e-d3fc-5dde-66b1-91d3a70f5a0b.png)
こんなイメージです。

## 着信
- 会社の番号をTwilioの番号にする
- Twilioの番号に着信すると、転送をかけ社員の携帯電話を一斉に呼び出す[^x]
- 一番最初に電話を取った社員と通話が開始され、その他の呼は切断される
- 発信者番号が表示される
- 営業時間外は電話を転送しない
- 着信履歴はSlackで共有する




[^x]: 今回は自動転送ではなく、発信者が任意のキーをおしたときだけ呼び出しがかかるようにしました 

## 発信
- Twilioの番号から発信できる
- 着信者はTwilioの番号から発信されたようにみえる

# 試行錯誤編
## 1.会社の番号をTwilioにする
Twilioでは、電話番号をWebから購入することができます。
費用は108円/月(税込)で050番号、1,620円/月(税込)で0120番号を取得することができます。
ただしいわゆる0AB-J番号と言われる、03-XXXX-XXXXのような固定電話らしい番号を取得することができません。

参考:
この問題については、こちらが詳しく書いてあります。
[03や06など、一般的な電話番号を利用できますか？](https://twilioforkwc.zendesk.com/hc/ja/articles/206345522-03%E3%82%8406%E3%81%AA%E3%81%A9-%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AA%E9%9B%BB%E8%A9%B1%E7%95%AA%E5%8F%B7%E3%82%92%E5%88%A9%E7%94%A8%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B)

### 問題1
**03等の地域固定番号を取得することができない**

## 2.着信を転送する(複数人に)
複数の人に転送してみて出れる人が出る。

TwilioではTwiMLというXMLベースの記述言語を使って、電話の動きを制御することができます。電話がTwilioの番号に着信すると指定したXMLが呼び出される仕組みです。

着信をきっかけに転送するには、`<Dial>`タグと`<Number>`タグを使います。
単純な転送電話なら

``` XML:TwiML
<Dial>
 	<Number>+8190XXXXXXXX(転送先電話番号)</Number>
</Dial>
```
で実現することができます。
ここで、Numberに指定している番号ですが、E.164という形式で、`+国番号(日本:81)と頭の0を取ったもの`[^0]を使います。携帯電話の例では、`+819012345678`といった感じです。

複数人に発信して、一番最初に取った人と通話するには、`<Number>`タグを複数行にするだけです。

[^0]: ちなみにあたまの0は国内プレフィックスといって、国内通話を示す記号だったりします。Twilioは世界中どこでも掛けれるので、国番号を明記する必要があるのです。
``` XML:TwiML
 <Dial>
 	<Number>+8190XXXXXXXX</Number>
 	<Number>+8180XXXXXXXX</Number>
 </Dial>
```

### 問題点
これで複数人に電話を転送する機能は実現できるのですが、一つ問題が。留守番電話問題です。

転送先が携帯電話のため、電源が切れていたり圏外にいたりすると、留守番電話もしくは圏外トーキが応答します。「電源が切れているか、電波の届かないところ・・・」というやつです。

複数発信時Twilioは最初に電話を取った相手に接続するので、超速で応答する留守番電話が一番最初応答することになります。

もう1人は取れたはずなのに、留守番電話が応答してしまっては使い物になりません。[^1]

[^1]: TwilioにはAMD(Answering Machine Detection,留守番電話検知)という機能が実はあるのですが、API経由の呼び出しのみに対応しTwiMLには対応していません。API経由の呼び出しで複数発信かつ最初に取ったものとつなぐには、会議通話を利用してコールステータスを見ながら制御すればできるはできるのですが、実装が煩雑になるので避けています。なおTwilioのAMDで実験して見たところ携帯電話の留守番電話はちゃんと検知できました。(2017.3にオープンベータになった新AMDは未確認です。)

### 問題2
**複数人一斉着信は留守番電話が応答すると成り立たない**

## 2.発信者番号
Twilioには、発信者番号を指定する機能があります。

``` XML:TwiML
<Dial callerId="+8150XXXXXXXX">

```
といったフォーマットで、発信者番号を指定できます。

これを使えば誰が固定電話にかけてきたか転送電話でもわかる。。とおもいきや勝手な番号を発信者番号にすることはできません。利用できるのは、購入した050番号のみ[^2]、です。(海外発信ではSMS認証できた番号もつかえます)
ちなみに勝手な番号を指定すると非通知になります。

[^2]: これは日本の総務省令、事業用電気通信設備規則における「異なる電気通信番号の送信の防止」という項で規定されており、利用者の番号以外を発信者番号に設定してはいけないことになっています。

### 問題3
**転送電話が誰から電話が掛かってきたかはわからない**

## 3.時間外は受け付けない
仕事してない時は電話を受けたくない。

これは割と簡単です。時間外かどうかはプログラムで判定する必要がありますが、時間を判定してそれ以外の場合はアナウンスを流して諦めてもらう、といったフローです。

アナウンスを流すには、このようなTwiMLで実現することができます。

``` XML:TwiML
<Say language="ja-jp">ごめんなさい、もう閉まりましたよ</Say>
```

ここのポイントはlanguage="ja-jp"を入れてあげることです。日本語であることを明示しています。

そのまま切断してもらえなかったら困るので、アナウンスが終わったらこちらからきります。

```XML:TwiML
<Hangup />
```

これで切ることができます。`/>`は、中身がない時の省略で、
正式には`<Hangup></Hangup>`になります。

例えば、土日、18時以降-9時未満の場合はアナウンスを再生する場合はこんな感じですかね・・・

``` js:Node.js
var currentHour = nowTime.getHours();
var currentDay = nowTime.getDay();

if(currentHour >= 18 || currentHour < 9 || currentDay === 0 || currentDay == 6 ){
    //休日用TwiMLを出力する
}
```
このへんは工夫しがいがあって、例えばgoogle calendarと連携して担当者の休暇日には電話を転送しないとかもできるかと思います。


## 4.Slackに通知する
電話かかってきたけど結局誰か取ったのか？など、きになる情報をSlackに通知してあげます。

Twilioには電話が掛かってきたり、電話のステータスが変わったりすると特定のURLにリクエストを送るWebhook機能があり、指定したURLにPOSTでメッセージを送ってくれます。

これを利用すれば、TwilioからきたPOSTリクエストを受けて、Slackのincoming webhookに投げ直すことでSlackへの通知を実現できます。

## 5.発信する
電話からTwilioの番号を使って発信するには、何らかの方法でTwilioに電話でつないであげる必要があります。かつ、繋ぐ先の番号をTwilio側に教えてあげる必要があります。

電話のみで実現しようとすると、twilioの別の番号を購入し、その番号にかけ、発信先の番号を入力され転送されるというのができそうですが、、面倒です。

### 問題4
**Twilioの番号から電話を使って発信するのは大変そう**

# 問題まとめ
- 03等の地域固定番号を取得することができない
- 複数人一斉着信は留守番電話が応答すると成り立たない
- 転送電話が誰から電話が掛かってきたかはわからない
- Twilioの番号から電話を使って発信するのは大変そう


# 解決方法
問題1については現状解決策がありません。
その他の問題については、通常の電話網(PSTN)を利用せず、今回はSIPを利用することで解決します。
![twilio2.png](https://qiita-image-store.s3.amazonaws.com/0/59725/142840f9-5207-12d4-31c4-e22730afac81.png)

## 問題1
- 03等の地域固定番号を取得することができない

この問題については、サービス側が提供していないものはどうしようもないのですが、１つだけ方法があります。ただこの手法を使って良いかどうか、に関してはここで判断することはできません。

Twilioには
- 日本版Twilio(https://twilio.kddi-web.com)
- 本家版Twilio(https://www.twilio.com/)

の２つが用意されていて、わずかに内容が異なります。

本家版Twilioにおいて日本の番号を購入しようとすると、03-から始まる番号が候補に表示され、実際に購入することができます。

ただこの番号を利用して発信した場合、発信者通知を利用することができません。かつ、日本側Twilioで公式に提供されていない機能となりますので、法的にも、動作的にも、個人的には利用の推奨はいたしません。

## 問題2
- 複数人一斉着信は留守番電話が応答すると成り立たない → SIP利用で解決

この問題については、留守番応答がない電話システムを利用することで解決します。
実際の携帯電話番号に接続するのではなく、携帯電話上のアプリ(ソフトフォン)に着信させてしまえば、留守番電話を気にせず使うことができます。

Twilioでは、プログラマブルVoiceの中に、「SIPドメイン」という項目があり、SIP Registration(登録)を受け付けて、SIPで発着信出来るSIPサーバのサービスを行っています。
 
SIP対応のアプリケーション(ソフトフォン)はスマートフォンにもインストールできるかつ、常時待受が可能なため、普通の電話と同様の使い勝手で利用することができます。

加えて、一般の携帯電話へ発信すると15円/min.かかっていたところがなんと、0.463円/min.と相当割安になり、運用コストも低減させることができます。(2017/4現在価格)

## 問題2
- 転送電話が誰から電話が掛かってきたかはわからない ->  SIP利用で解決

自由な発信者番号を電話転送に使えないのは、システム上の制限と、総務省令の影響です。
総務省令は今回の「SIPドメイン」には適用されないので、任意の発信者番号をつけることができます。

## 問題3
- 050番号を使って発信するのは大変そう ->これもSIPで解決

通常の番号への発信を「SIPドメイン」の機能を使ってソフトフォンからTwilioのSIPサーバで受け付けます。
SIPの発信(to:)に相手先の電話番号を含んでおき、Twilio側で解析し通常の電話網に転送します。


# とりあえずここまで
次回からこれを実装していきます。
その上で、AWS API GatewayとAWS Lambdaを利用しサーバーレス環境へ移行します。