家の電話をasteriskでIP電話化してスマホ受けにする

# 1. はじめに
## 1.1. 動機

- 今の家の電話機は20年選手で買い替えたいが、買いたいと思うようなイケてる電話機がない
- 今の電話番号は維持したい。つまり [050Plus](https://www.ntt.com/personal/services/phone/ip/050plus.html) には変えない
- 複数子機を用意したいが世の中にあるものは専用端末で充電も独自だったりしてイケてない。一部スマホアプリを提供しているものもあるが、正直あまり期待できない
- 留守電をどこでも聞きたい
- ワーケーションや旅行で比較的長期間家以外の場所にいるときに家の電話を取りたい

といろいろ考えたら asterisk でIP化して、スマホで受けるのがいいんじゃないかという結論に自分の中でなった。

## 1.2. この記事の対象読者と制限

この記事の対象読者は「アナログ回線を電話番号そのままで維持し、ISP 非依存のまま IP 電話化したい人」となる。

記事執筆時点(2022年4月時点)では IP 電話化するには以下の選択肢がある

- ISP をフレッツ光にできる人
    - [ひかり電話](https://flets.com/hikaridenwa/)を利用することで電話番号を維持したまま IP 電話化できる
- ISP をフレッツ光にできない人
    - 電話番号を変えてもいい人
        - [050 Plus](https://www.ntt.com/personal/services/phone/ip/050plus.html)
        - [SMARTalk(旧 Fusion ip-phone)](https://ip-phone-smart.jp/smart/)
        - など・・・
    - 電話番号を変えたくない人
        - この記事の対象読者

また、2022年4月現在この記事通りに設定すると、IP電話としては機能するが、ナンバーディスプレイに対応できない。従って着信した相手の電話番号を表示できない。これは ATA 機器として使用している Grandstream HT813 のバグのため。

## 1.3. 調査 -> IP電話界隈はいろいろ難しい -> asterisk を素で使うことにした

とりあえず家電をIP化する！とだけ決めて調べたり試したりし始めた。

- まず用語がいろいろわからん。SIPとかATAとかPSTNとかPBXとかFXSとかFXOとか
- asterisk の設定がよくわからん。なんか設定ファイルが大量にある。
- FreePBXとかGUI提供してるけど自分には合わなかった
    - Raspberry Pi 用に公式イメージがない。有志(?)が提供しているものがあるが、自分の環境ではうまくうごかなかった
    - GUI自体も正直よくわからず、設定しやすいとは言い難い
- 紹介してるサイトがやたら多いがどれもいまいち。多くはNTTやフュージョン(現楽天)のIP電話と組み合わせた例か、かなり昔のもの。どれも断片的な記事で、これ一発でスパーンとわかるところはない感じ。

で2週間くらいいろいろ試した結果、askteriskを素のまま使うのが一番いいのではないかという結論に至った。理由は以下の通り。

- Raspberry Pi OS(debian)の標準repoから提供される。インストールもアップデートも `apt` コマンドで一発
- 設定ファイルのややこしさは結局の所慣れる

# 2. 構成と用語

以下のような構成にした
![asterisk構成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52237/9dec0b3b-dcb6-1026-b68f-a969e34eeba1.jpeg)

用語は以下のような意味に理解するといいっぽい

- SIP : ["Session Initiation Protocol" - IP電話の通信プロトコル(wikipedia)](https://ja.wikipedia.org/wiki/Session_Initiation_Protocol)。IP 電話機や交換機の間でやり取りされる。 HTTP や FTP のようなアプリケーション層のプロトコル
- PBX : ["Private Branch eXchange" - 電話の交換機(wikipedia)](https://ja.wikipedia.org/wiki/%E6%A7%8B%E5%86%85%E4%BA%A4%E6%8F%9B%E6%A9%9F)。家の中の IP 内線電話用に作る asterisk も PBX の一種ということになる
- PSTN : ["Public Switched Telephone Network" - 公衆回線網(wikipedia)](https://ja.wikipedia.org/wiki/%E5%85%AC%E8%A1%86%E4%BA%A4%E6%8F%9B%E9%9B%BB%E8%A9%B1%E7%B6%B2)。[ピポパと鳴るやつが "トーンダイヤル" とか "DTMF"](https://ja.wikipedia.org/wiki/DTMF)、[黒電話でダイヤルするやつが "ダイヤルパルス" という](https://ja.wikipedia.org/wiki/%E3%83%80%E3%82%A4%E3%83%A4%E3%83%AB%E3%83%91%E3%83%AB%E3%82%B9)らしい。
    - 日本のPSTNの規格書はNTTが公開している: https://web116.jp/shop/annai/gisanshi/analog/analog.html
    - 今回の話とは関係ないが[裏側ではすでにIP閉域網になっている](https://ja.wikipedia.org/wiki/Next_Generation_Network)ようだ。
- ATA : ["Analog Telephony Adapter"(wikipedia)](https://en.wikipedia.org/wiki/Analog_telephone_adapter)。要するに従来の電話機をVoIPネットワークに接続したり、家まで来ている公衆回線をVoIPネットワークに接続するための機器。
    - Amazonとかを見ていると ATA と呼ばれる機器は後述する FXS(Foreign eXchange Station, 電話機へのインターフェイス) のみを有する機器を指すようだが、一般的な定義としては FXS のみを有するもの、FXS および FXO 両方のインターフェイスを有するものも ATA と呼ぶらしい
    - [別の資料](https://www.rbbtoday.com/article/2007/05/09/41506.html)では、FXS のみを有する ATA を "POTS Gateway"、FXO のみを有する ATA を "PSTN Gateway" と呼んだりもするらしい
- FXS : ["Foreign eXchange Station"(wikipedia)](https://en.wikipedia.org/wiki/Foreign_exchange_service_(telecommunications)#Circuit_interfaces)。ATA機器に _電話機_ をつなげるための RJ-11 ポートのことを指す。
    - ISDN の TA ルーターだと "PHONE" というラベルがついているポートを指す
    - asterisk が動作するPCにモデムをつなげても FXS にはならない。これはよくある誤解らしい
- FXO : ["Foreign eXchange Office"(wikipedia)](https://en.wikipedia.org/wiki/Foreign_exchange_service_(telecommunications)#Circuit_interfaces)。ATA機器に _公衆回線_ をつなげるための RJ-11 ポートのことを指す。
    - ISDN の TA ルーターだと "LINE" というラベルがついているポートを指す
    - asterisk が動作するPCにモデムをつなげても FXO にはならない。これはよくある誤解らしい

# 3. 構築
## 3.1. asteriskのインストールと初期設定
### 3.1.1. asteriskのインストール
普通に Raspberry Pi OS を構築する。私は `rpi-imager` を使って bullseye without GUI を入れた。

起動したあと
```shell
$ sudo apt update
$ sudo apt upgrade
$ sudo apt install asterisk asterisk-voicemail
```

動いているか確認。動いてなかったら `systemctl enable asterisk; systemctl restart asterisk` で起動させる

```shell
$ sudo systemctl status asterisk
● asterisk.service - Asterisk PBX
     Loaded: loaded (/lib/systemd/system/asterisk.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2022-04-09 08:10:07 JST; 1 day 4h ago
       Docs: man:asterisk(8)
   Main PID: 6545 (asterisk)
      Tasks: 72 (limit: 1598)
        CPU: 17min 7.146s
     CGroup: /system.slice/asterisk.service
             ├─6545 /usr/sbin/asterisk -g -f -p -U asterisk
             └─6546 astcanary /var/run/asterisk/alt.asterisk.canary.tweet.tweet.tweet 6545
```

`asterisk -r` で動いている asterisk に接続できる。

```shell
# asterisk -r
Asterisk 16.16.1~dfsg-1+deb11u1, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.16.1~dfsg-1+deb11u1 currently running on asterisk (pid = 6545)
asterisk*CLI> exit
Asterisk cleanly ending (0).
Executing last minute cleanups
#
```

### 3.1.2. asteriskの初期設定

最低限の初期設定をする

```text:/etc/asterisk/sip.conf(記述していないところはデフォルトのまま)
[general]
tcpenable=yes
transport=tcp
language=ja
tonezone=jp
videosupport=NO
localnet=192.168.20.0/255.255.255.0 ; 家の中のLAN(OpenVPN側は書く必要がない)
nat=force_rport,comedia
directmedia=no
[pixel6]
type=friend
secret=1234
host=dynamic
context=house
[desktop]
type=friend
secret=1234
host=dynamic
context=house
```
それぞれの意味は以下のようになる

- `[general]`
    - `tcpenable=yes`, `transport=tcp` : SIPの通信をTCPにする。デフォルトはUDP。これは私の好み
    - `language=ja`, `tonezone=jp` : とりあえず日本対応にしたほうがいいと思って設定。正直よくわかってない
    - `videosupport=NO` : 別に内線でビデオ会議しないので NO
    - `nat=force_rport,comedia` : これを yes にすると NAT を意識していろいろするらしいが、正直よくわからなかった。私の環境ではこれで動作した。`nat=yes` と同義と書かれているものもあるが、私の環境では動作しなかったことを記述しておく
    - `directmedia=no` : デフォルトは yes で、RTPで発信側と受信側が asterisk を介さずに直接送受信するようだ。私の環境では yes ではうまく動かなかったので変更している。
- `[pixel6]`, `[desktop]` : スマホ、デスクトップ(=子機)のSIPクライアントの設定。ブラケットの中の文字が、Register(=ログイン)するときのユーザ名として扱われる
    - `type=friend` : `type=friend` および `type=peer` との発信着信両方できるの意味。特にIPアドレスの制限はかからない
        - 着信専用の場合は `type=user` にする。`type=peer` にするとIPアドレスベースで発着信を制御できる。`type=peer`と`host=dynamic`を組み合わせると Register できないので注意
        - 詳細は `/etc/asterisk/sip.conf` の中の `DEVICE CONFIGURATION` の部分を見ると書かれている
    - `secret=xxxx` : Register(=ログイン) するときのパスワード
    - `host=dynamic` : SIPクライアント側のIPアドレスを限定しない。外線発信のときに外部のSIPプロバイダーを指定するような場合はここにホスト名を書く
    - `context=house` : このSIPクライアントがどのダイヤルプランを使用するかを指定する。ダイヤルプランは後述する `/etc/asterisk/extensions.conf` で記述する

ここまで書いたら `systemctl reload asterisk` して、登録されたかどうか確認する

```shell
$ sudo systemctl reload asterisk
$ sudo asterisk -r
Asterisk 16.16.1~dfsg-1+deb11u1, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.16.1~dfsg-1+deb11u1 currently running on asterisk (pid = 11610)
asterisk*CLI> ip show peers
Name/username             Host                                    Dyn Forcerport Comedia    ACL Port     Status      Description                      
desktop/desktop           (Unspecified)                            D  No         No             0        Unmonitored                                  
pixel6/pixel6             (Unspecified)                            D  No         No             0        Unmonitored                                  
2 sip peers [Monitored: 0 online, 0 offline Unmonitored: 0 online, 2 offline]
```

### 3.1.3. SIPクライアントを用意

ここまでできたら SIP クライアントを用意する。私の場合はデスクトップ用に [Zoiper](https://www.zoiper.com/), スマホ用に [Grandstream Wave lite](https://play.google.com/store/apps/details?id=com.grandstream.wave)を使った。他にもいろいろあって、好みで選択できると思う。

以下のリンクが参考になるかもしれない

- Android
    - [AGEphone](https://play.google.com/store/apps/details?id=com.ageet.AGEphone)
    - [LivyTalk](https://play.google.com/store/apps/details?id=jp.co.softfront.livytalk)
    - [Zoiper](https://play.google.com/store/apps/details?id=com.zoiper.android.app)
- PC
    - このあたりなど [ソフトフォン - VoIp-Info.jp](https://www.voip-info.jp/index.php/%E3%82%BD%E3%83%95%E3%83%88%E3%83%95%E3%82%A9%E3%83%B3)

設定ははがんばる

接続できたら asterisk 側からは以下のような感じに見える

```shell
$ sudo asterisk -r
Asterisk 16.16.1~dfsg-1+deb11u1, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.16.1~dfsg-1+deb11u1 currently running on asterisk (pid = 11610)
asterisk*CLI> sip show peers
Name/username             Host                     Dyn Forcerport Comedia    ACL Port     Status      Description                      
desktop/desktop           192.168.20.245            D   Yes        Yes            53147    Unmonitored                                  
pixel6/pixel6             10.9.0.14                 D   Yes        Yes            46252    Unmonitored                                  
2 sip peers [Monitored: 0 online, 0 offline Unmonitored: 2 online, 0 offline]
```

### 3.1.4. asteriskの設定 : ダイヤル先の登録

ダイヤルしたら相手方に着信するようにする

```text:/etc/asterisk/extensions.conf(末尾に追加)
[house]
exten => 600,1,Dial(SIP/pixel6)
exten => 601,1,Dial(SIP/desktop)
```

上で書いたものはダイヤルプランと呼ばれる。要するにどのようにダイヤルするとどういう挙動になるかを指定している。

ここでは `600` とダイヤルするとスマホに、`601` とダイヤルするとデスクトップに着信するようにしている。

ここまで書いたら `systemctl reload asterisk` して、お互いに電話をかけてみる。かかれば OK。

ただこの設定だと、クライアントの着信画面に出る `pixel6` なり `desktop` に折返しの電話をかけようとするとつながらない。で、こういう風に変える。

```text:/etc/asterisk/extensions.conf
[house]
exten => 600,1,Dial(SIP/pixel6)
exten => pixel6,1,Dial(SIP/pixel6)
exten => 601,1,Dial(SIP/desktop)
exten => desktop,1,Dial(SIP/desktop)
```

変えたら `systemctl reload asterisk` して、お互いに電話をかけてみる。かかれば OK。

ここまでで初期設定はいったん完了。

## 3.2. 外線の接続
### 3.2.1. 機器の選定

今回の場合、すでに使っている電話回線(PSTN)を使用して外に発信するため、ゲートウェイが必要になる。世の中では以下の機器が利用できるようだ。ゲートウェイ機器はあまり個人使用を想定した機器がないので選択が限られるようだ。今回は SIP に TCP を使っていることもあるので、[Grandstream HT 813](https://grandstream.jp/%E8%A3%BD%E5%93%81%E6%83%85%E5%A0%B1/ata%E3%83%BB%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4/%E3%82%A2%E3%83%8A%E3%83%AD%E3%82%B0%E9%9B%BB%E8%A9%B1%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF/handytone-813/) にした。

- [Grandstream HT 813](https://grandstream.jp/%E8%A3%BD%E5%93%81%E6%83%85%E5%A0%B1/ata%E3%83%BB%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4/%E3%82%A2%E3%83%8A%E3%83%AD%E3%82%B0%E9%9B%BB%E8%A9%B1%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF/handytone-813/)
- [Cisco(Linksys) SPA3102(販売終了)](https://www.cisco.com/c/ja_jp/obsolete/unified-communications/cisco-spa3102-voice-gateway-with-router.html)
- [ICOM VE-AG1](https://www.icom.co.jp/lineup/products/VE-AG1/) (仕様を見る限りは UDP しかサポートしていない)

### 3.2.2. 接続、電源投入、設定画面

接続はそれぞれ以下のように行う。
- LAN回線を WAN ポートに
- アナログ電話回線を FXO ポートに

ACアダプタを取り付けると自動的に電源が入る。1分ほど待つと、地球のステータスランプが点灯する。この状態で(デフォルトではDHCPで自動的に)IPアドレスが割り当てられているので、ブラウザでログインする。デフォルトのユーザ名/パスワードは `admin` / `admin` 。

もし中古品を購入して、前のユーザの設定が残っているなどの理由で接続できない場合は電源が入った状態でリセットボタンを7秒以上押し続け、すべてのステータスランプが点灯したらボタンから手を離すと、工場出荷時の状態にリセットされる。これも1分程度時間がかかる。

この記事はファームウェアバージョン 1.0.13.3 で作成した。日本の回線対応は古いバージョンだと不具合があるらしいので、低い場合はバージョンアップしたほうがいいだろう。ファームウェアの最新バージョンは [http://www.grandstream.com/support/firmware](http://www.grandstream.com/support/firmware) からダウンロードできる。

ログイン後のステータス画面で、FXO の状態が `Idle` になっていればOK。接続がうまく言ってない場合は `Not Connected` となるので、それで接続が正しいか判断できる。FXO ステータスランプが点灯しているかどうかは関係ないので注意。

![2022-04-19-01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52237/37b87b3b-5103-fcdc-67bb-5266c4390b65.jpeg)

### 3.2.3. 設定
#### (1) BASIC SETTINGS

BASIC SETTINGS 画面では以下の項目をデフォルトから変更する
- Time Zone : `JST+9` に変更
- Device Mode : WAN Only

画面一番下の Apply ボタンを押す。Reboot するよう促されるので言われるがままに Reboot する。地球マークのステータスランプが点灯するまで待って、再度ログインして設定を続ける。

#### (2) ADVANCED SETTINGS

ADVANCED SETTINGS 画面では以下の項目をデフォルトから変更する
- System Ring Cadence : `c=1000/2000;`
- Dial Tone : `f1=400@-19,c=0/0;`
- Ringback Tone : `f1=400@-19,f2=385@-20,c=1000/2000;`
- Busy Tone : `f1=400@-19,c=500/500;`
- Reorder Tone : `f1=400@-19,c=250/250;`

画面一番下の Apply ボタンを押すと設定が反映される。ここでは再起動の必要はない。

#### (3) FXS PORT

ここは HT813 に直接電話機を取り付けるのでなければ設定しなくていい。ここではスキップする。

#### (4) FXO PORT

事前に asterisk 側で HT813 用の peer を作成しておく

```text:/etc/asterisk/sip.conf
[ht813]
type=friend
username=ht813
secret=1234
host=dynamic
context=house
```

FXO PORT 画面では以下の項目をデフォルトから変更する
- Primary SIP Server : asteriskのIPアドレスか、ホスト名
- SIP Transport : 使っているプロトコル。私は TCP を使っているのでここではTCPをチェック
- SIP User ID : ユーザ名(上のsip.confで設定したもの)
- Authenticate Password : パスワード(上のsip.confで設定したもの)
- SIP REGISTER Contact Header Uses : WAN Address
- Caller ID Scheme : Bellcore/Telcordia
- PSTN Disconnect Tone : `f1=400@-19,c=500/500;`
- Country-based : JAPAN
- Number of Rings : 2
- Stage Method (1/2) : 1

一番下の Apply ボタンを押して設定を反映する。Reboot する必要があれば Reboot する。SIP registerが成功すると FXOステータスランプが点灯する。

### 3.2.4. 外線発信テスト

asteriskにテスト用の設定を入れる

```text:/etc/asterisk/extensions.conf
[house]
exten => 117,1,Set(CALLERID(num)=0312345678)   ; <= 追加
exten => 117,2,Dial(SIP/${EXTEN}@ht813,120,T)  ; <= 追加
exten => 600,1,Dial(SIP/pixel6,10)
exten => pixel6,1,Dial(SIP/pixel6,10)
exten => 601,1,Dial(SIP/desktop,10)
exten => desktop,1,Dial(SIP/desktop,10)
```
`systemctl reload asterisk` して、SIPクライアントから 117 をダイヤルする。時報が聞こえればOK。

### 3.2.5. 外線着信テスト

HT813 の BASIC SETTINGS に以下の設定を追加する。宛先番号は今回 `699` にする。

- Unconditional Call Forward to VOIP : 宛先番号 @ Sip Server : ポート番号

続けて asterisk 側に設定を追加する

```text:/etc/asterisk/extensions.conf
[house]
exten => 117,1,Set(CALLERID(num)=0312345678)
exten => 117,2,Dial(SIP/${EXTEN}@ht813,120,T)
exten => 699,1,Set(CALLERID(num)=${EXTEN})  ; <= 追加
exten => 699,n,GotoIf($["${EXTEN:0:1}" = "0"]?gaisen,1) ; <= 追加
exten => 600,1,Dial(SIP/pixel6,10)
exten => pixel6,1,Dial(SIP/pixel6,10)
exten => 601,1,Dial(SIP/desktop,10)
exten => desktop,1,Dial(SIP/desktop,10)

exten => gaisen,1,Dial(SIP/desktop,10) ; <= 追加
```

`systemctl reload asterisk` して、外線の電話番号に電話をかける。SIPクライアント(上記の例では desktop)に着信して会話ができればOK。

### 3.2.6. 発信用ダイヤルプランの作成

上記で外線への発信、外線からの着信が確認できたので、特殊番号を含めた発信ルールを `extensions.conf` に実装する。以下の例は ["Wikipedia - 日本の電話番号"](https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E3%81%AE%E9%9B%BB%E8%A9%B1%E7%95%AA%E5%8F%B7) を愚直に実装してみた例だが、もっと簡略化している例はいろいろある。

パターンマッチの優先度は[本家のドキュメント](https://wiki.asterisk.org/wiki/display/AST/Pattern+Matching#PatternMatching-OrderofPatternMatching)に記述されている。おおむね期待通りの優先度付けになっていて、頭から順番に厳密な指定が優先されるように判断される。

またパターンマッチは桁数という条件は指定できない。

```text:/etc/asterisk/extensions.conf
[house]
; 発信ルールここから=================================
; 1XY 特番
exten => _1XX,1,System(echo "1XY")
exten => _1XX,n,Set(CALLERID(num)=0312345678)
exten => _1XX,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 0AB0 特番 + 0800フリーダイヤル
exten => _0ZZ0.,1,System(echo "0ZZ0")
exten => _0ZZ0.,n,Set(CALLERID(num)=0312345678)
exten => _0ZZ0.,n,Dial(SIP/${EXTEN}@ht813,120,T)
exten => _0800.,1,System(echo "0800")
exten => _0800.,n,Set(CALLERID(num)=0312345678)
exten => _0800.,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 0A0 特番 + 080/090/070の11桁通常電話
exten => _0Z0.,1,System(echo "0Z0 or normal 11")
exten => _0Z0.,n,Set(CALLERID(num)=0312345678)
exten => _0Z0.,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 市外局番 + 1XY 特番
exten => _0.177,1,System(echo "shigai+1XY")
exten => _0.177,n,Set(CALLERID(num)=0312345678)
exten => _0.177,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 00XY 特番 + 001国際電話 + 届出電気通信事業者（旧第二種電気通信事業者）
exten => _00Z.,1,System(echo "00XY or 001")
exten => _00Z.,n,Set(CALLERID(num)=0312345678)
exten => _00Z.,n,Dial(SIP/${EXTEN}@ht813,120,T)
; #特番
exten => _#[7-9].,1,System(echo "sharp 7-9")
exten => _#[7-9].,n,Set(CALLERID(num)=0312345678)
exten => _#[7-9].,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 通常の電話(0発信10桁)
exten => _0ZXXXXXXXX,1,System(echo "normal 10")
exten => _0ZXXXXXXXX,n,Set(CALLERID(num)=0312345678)
exten => _0ZXXXXXXXX,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 001国際電話
exten => _010.,1,System(echo "international call 001")
exten => _010.,n,Set(CALLERID(num)=0312345678)
exten => _010.,n,Dial(SIP/${EXTEN}@ht813,120,T)
; 発信ルールここまで=================================

; 着信ルールここから=================================
exten => 600,1,Dial(SIP/pixel6,10)
exten => pixel6,1,Dial(SIP/pixel6,10)
exten => 601,1,Dial(SIP/desktop,10)
exten => desktop,1,Dial(SIP/desktop,10)
exten => 699,1,Set(CALLERID(name)=gaisen)
exten => 699,n,Goto(gaisen,1)

exten => gaisen,1,Dial(SIP/pixel6,10)
; 着信ルールここまで=================================
```

`systemctl reload asterisk` して、以下のようにテストする
- LAN環境の外線発信と着信
- VPN環境の外線発信と着信

## 3.3. 追加設定
### 3.3.1. 留守電(Voicemail)設定

asterisk の留守電機能(Voicemail)は `sendmail -t` コマンドでメールを送るため、asterisk が動作するホスト上にsendmailサービスが必要になる。私はpostfixのほうが慣れているのでpostfixを入れた。

```shell
$ sudo apt install postfix mailutils
```

テストメールを送ってみる。root宛にメールが届いていればOK。

```shell
# sendmail -t
From: root
To: root
Subject: test1 
test1
.
# mail
"/var/mail/root": 1 message 1 new
>N   1 root@asterisk.int. Sun Apr 10 18:43  12/427   
? 1
Return-Path: <root@asterisk.int.example.org>
X-Original-To: root
Delivered-To: root@asterisk.int.example.org
Received: by asterisk.int.example.org (Postfix, from userid 0)
	id 7729E20C25; Sun, 10 Apr 2022 18:43:08 +0900 (JST)
From: root@asterisk.int.example.org
To: root@asterisk.int.example.org
Message-Id: <20220410094308.7729E20C25@asterisk.int.example.org>
Date: Sun, 10 Apr 2022 18:42:51 +0900 (JST)
Subject: test1

test1
? d
? q
# 
```

メールを普段使っているpostfixに転送する設定を入れる

```text:/etc/postfix/main.cf
relayhost=mail.int.example.com:25
```

```shell
$ sudo systemctl restart postfix
```

同じようにテストする

```shell
# sendmail -t
From: root
To: myaddress@mail.int.example.com
Subject: test2
test2
.
```

`myaddress@mail.int.example.com` で受信できていることを確認する

ここまでできたら asterisk の設定を行う。10秒間応答しなかったら発信音がなって留守録にきりかわる設定。

```text:/etc/asterisk/voicemail.conf (書いてないところはデフォルトのまま)
[general]
serveremail=asterisk@asterisk.int.example.org
tz=Asia/Tokyo
locale=ja_JP.UTF-8
[zonemessages]
japan=Asia/Tokyo|Q PHM 'jp-ni' 'vm-received'
[default]
500 => 1234,Oreno Namae,myaddress@mail.int.example.org,,tz=japan
```

それぞれの意味は以下の通り
- [general]
    - servermail : メールの From になる
    - tz : メールのタイムゾーン指定。[zonemessages]で上書きされるので設定しなくてもいいかも
    - locale : メールのロケールだけど効いてないっぽい
- [zonemessages]
    - japan : タイムゾーン変数。書式は <タイムゾーン>|<書式>
        - タイムゾーン : /usr/share/zoneinfo 以下のファイル名で書く
        - パイプ以降
            - Q : 「今日」「昨日」もしくは「曜日 月 日 年」になる
            - P : "AM" もしくは "PM"
            - H : 24時間の時
            - M : 分
            - 'jp-ni' : よくわからない
            - 'vm-received' : よくわからない
- [default]
    - 500 : これが extensions.conf から呼び出したときの宛先になる
    - 1234 : voicemailを呼び出すときのパスワード。今回は関係ない
    - Oreno Namae : 本文の中に埋め込まれる名前
    - myaddress@mail.int.example.org : メールの宛先
    - tz=japan : zonemessagesで指定したタイムゾーン

extensions.conf を修正する

```text:/etc/asterisk/extensions.conf
[house]
; (発信ルールは省略)
; 着信ルールここから=================================
exten => 600,1,Dial(SIP/pixel6,10)
exten => 600,n,Goto(kyotu,1)                 ; 追加
exten => pixel6,1,Dial(SIP/pixel6,10)
exten => pixel6,n,Goto(kyotu,1)              ; 追加
exten => 601,1,Dial(SIP/desktop,10)
exten => 601,n,Goto(kyotu,1)                 ; 追加
exten => desktop,1,Dial(SIP/desktop,10)
exten => desktop,n,Goto(kyotu,1)             ; 追加
exten => 699,1,Set(CALLERID(name)=gaisen)
exten => 699,n,Goto(gaisen,1)                ; 追加

exten => gaisen,1,Dial(SIP/pixel6,10)
exten => gaisen,n,Goto(kyotu,1)              ; 追加

exten => kyotu,1,Goto(stdexten-${DIALSTATUS},1)  ; 追加

exten => stdexten-NOANSWER,1,VoiceMail(500,s)    ; 追加
exten => stdexten-NOANSWER,n,Return()            ; 追加

exten => stdexten-BUSY,1,VoiceMail(500,s)        ; 追加
exten => stdexten-BUSY,n,Return()                ; 追加
; 着信ルールここまで=================================
```

それぞれの設定は以下の通りの意味。

- [Dial](https://wiki.asterisk.org/wiki/display/AST/Asterisk+19+Application_Dial)の第2引数の 10 は、10秒間無応答だと次の行に進むことを示す
- [Goto](https://wiki.asterisk.org/wiki/display/AST/Asterisk+19+Application_Goto)で別の処理に飛ぶ。`${DIALSTATUS}` には NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER のいずれかが入る
- `stdexten-NOANSWER` もしくは `stdexten-BUSY` の場合は `voicemail.conf` の中で定義した `500` の処理を行う
- [Return](https://wiki.asterisk.org/wiki/display/AST/Asterisk+19+Application_Return) で戻る。ただ戻ったあとには何も処理がないので通話は終わる

設定したら `systemctl reload asterisk` して、設定したとおりに動作するか確認する。wav の音声ファイルが添付されたメールが届けばOK。音声ファイルを mp3 にしたい衝動に駆られるが、asterisk-mp3 パッケージはどうやら圧縮には対応してないらしい、また標準の wav 形式でも今どき十分小さい(10秒で10KBくらい)ので、実用的な問題はなさそうだ。

ちなみに Android では VLC で wav ファイルは再生できる。

### 3.3.2. 留守電(Voicemail)用の音声案内を再生する

音声は以下のフォーマットにする必要がある
- モノラル
- PCM
- Microsoft WAV フォーマット
- サンプリング周波数 8k
- 16bit

sox であれば以下のようなコマンドで変換できる

```shell
sox test.wav -t wav -r 8000 -b 16 -c 1 rusu.wav
```

変換したファイルを asterisk 内に配置する。別にどこでもいい。例では `/var/lib/asterisk/sounds/rusu.wav` として配置した。

extensions.conf を以下のように修正する。

```text:/etc/asterisk/extensions.conf
[house]
; (発信ルールは省略)
; 着信ルールここから=================================
exten => 600,1,Dial(SIP/pixel6,10)
exten => 600,n,Goto(kyotu,1)
exten => pixel6,1,Dial(SIP/pixel6,10)
exten => pixel6,n,Goto(kyotu,1)
exten => 601,1,Dial(SIP/desktop,10)
exten => 601,n,Goto(kyotu,1)
exten => desktop,1,Dial(SIP/desktop,10)
exten => desktop,n,Goto(kyotu,1)
exten => 699,1,Set(CALLERID(name)=gaisen)
exten => 699,n,Goto(gaisen,1)

exten => gaisen,1,Dial(SIP/pixel6,10)
exten => gaisen,n,Goto(kyotu,1)

exten => kyotu,1,Goto(stdexten-${DIALSTATUS},1)

exten => stdexten-NOANSWER,1,Answer() ; 追加
exten => stdexten-NOANSWER,n,Wait(1) ; 追加
exten => stdexten-NOANSWER,n,PlayBack(/var/lib/asterisk/sounds/rusu) ; 追加
exten => stdexten-NOANSWER,1,VoiceMail(500,s)
exten => stdexten-NOANSWER,n,Return()

exten => stdexten-BUSY,1,Answer() ; 追加
exten => stdexten-BUSY,n,Wait(1) ; 追加
exten => stdexten-BUSY,n,PlayBack(/var/lib/asterisk/sounds/rusu) ; 追加
exten => stdexten-BUSY,1,VoiceMail(500,s)
exten => stdexten-BUSY,n,Return()
; 着信ルールここまで=================================
```

設定したら `systemctl reload asterisk` して、設定したとおりに動作するか確認する。外線着信させて、音声が再生された後に留守電になり、録音結果がメールで送付されれればOK。

# 4. 管理など

## 発信・着信履歴

`/var/log/asterisk/cdr-csv/Master.csv` に記録されていく。カラムの意味は `/etc/asterisk/cdr_custom.conf` を見ればわかる

## デバッグ方法

asterisk が動いている状態で、コマンドラインから `asterisk -rvvv` すればリアルタイムのデバッグ出力が出てくるので、なにかうまく動かないときは見てみるといい

# 5. さいごに

たぶんもう10年は設定いじらないと思うw

いろいろややこしいが、調べながら進めていくといろいろなことがわかって面白い。オタク向きというか。オフトピックなのでここでは書かないが、気になる人は調べてみると面白いかもしれない。